Skip to content

LangChain4j

简介

在生成式AI技术爆发的时代,如何将大语言模型(LLM)快速集成到Java应用中?LangChain4j作为Java生态中的新兴框架,为开发者提供了开箱即用的解决方案。本文将带您快速了解这个工具的核心功能,并通过实战示例展示其应用价值。

什么是LangChain4j?

LangChain4j是LangChain的Java实现版本,专为简化大语言模型集成而设计。它具有以下突出特性:

  • 轻量级:仅需添加Maven/Gradle依赖即可使用
  • 模块化:支持OpenAI、Azure OpenAI、HuggingFace等主流模型
  • 链式编程:通过流畅的API构建复杂对话流程
  • 本土化:完美兼容Spring Boot等Java主流框架

如何使用

创建模型实例

openai

添加Maven依赖:

xml
<properties>
    <langchain4j.version>1.0.0-beta3</langchain4j.version>
</properties>
<dependencies>
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j</artifactId>
        <version>${langchain4j.version}</version>
    </dependency>

    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j-open-ai</artifactId>
        <version>${langchain4j.version}</version>
    </dependency>
</dependencies>

OpenAI密钥申请

java
import dev.langchain4j.model.openai.OpenAiChatModel;

public class Langchain4jOpenAi {
    public static void main(String[] args) {
        
        // 1. 创建模型实例
        OpenAiChatModel model = OpenAiChatModel.builder()
                // .baseUrl("https://代理服务器")
                .apiKey("sk-...")
                .modelName("gpt-3.5-turbo")
                .temperature(0.3)
                .build();

        // 2. 发送请求
        String response = model.chat("Hello world!");
        
        System.out.println(response);
    }
}

ollama模型实例

添加Maven依赖:

xml
<properties>
    <langchain4j.version>1.0.0-beta3</langchain4j.version>
</properties>
<dependencies>
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j</artifactId>
        <version>${langchain4j.version}</version>
    </dependency>

    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j-ollama</artifactId>
        <version>${langchain4j.version}</version>
    </dependency>
</dependencies>

和open-ai区别是ollama没有apiKey

java
public class Langchain4jOllama {

    public static void main(String[] args) {
        // 1. 创建模型实例
        OllamaChatModel model = OllamaChatModel.builder()
                .baseUrl("http://你的IP:11434")
                .modelName("deepseek-r1:1.5b")
                .temperature(0.8) // 创意性控制(0-1)
                .timeout(Duration.ofSeconds(120)) // 超时设置120秒
                .build();

        // 2. 发送请求
        String response = model.chat("Hello world!");

        System.out.println(response);
    }
}

基本模板

java
PromptTemplate template = new PromptTemplate("将以下文本翻译成{{language}}: {{text}}");

Map<String, Object> variables = new HashMap<>();
variables.put("language", "英语");
variables.put("text", "你好,世界!");

Prompt prompt = template.apply(variables);

// model为上面创建的模型实例
String response = model.chat(prompt.text());

AiService 机制

AiService 是 LangChain4j 中用于构建智能体的组件,它能够将 LLM 和工具组合在一起,创建出可以执行特定任务的智能代理。AiService 的核心在于将 LLM 与各种工具进行集成,通过定义一组工具和相应的调用逻辑,让 LLM 在处理任务时能够像调用函数一样使用这些工具,从而实现更复杂的功能。

ChatMemory 机制

在多轮对话中,为了使对话更加连贯和自然,LangChain4j 提供了 ChatMemory 机制来管理对话历史。ChatMemory 作为 ChatMessage 的容器,可以存储和管理对话过程中的消息。它可以根据不同的策略和需求,对消息进行保存、更新、删除等操作,为 LLM 提供上下文信息,使其能够基于完整的对话历史进行响应生成。

实现类描述
MessageWindowChatMemory作为滑动窗口保留最近的N条消息,并驱逐不再符合条件的较旧消息。由于每条消息包含的 token 数可能不同,MessageWindowChatMemory 主要用于快速原型开发。
TokenWindowChatMemory也是滑动窗口,但重点是保留最近的N个token,并根据需要驱逐较旧的消息。消息是不可分割的。如果某条消息不符合条件,它将被完全驱逐。 TokenWindowChatMemory 需要一个Tokenizer来统计每条ChatMessage中的 token 数。
java
public class Langchain4jOllama {

    interface Assistant {
        String chat(@MemoryId int memoryId, @UserMessage String userMessage);
    }

    public static void main(String[] args) {
        // 1. 创建模型实例
        OllamaChatModel model = OllamaChatModel.builder()
                .baseUrl("http://你的IP:11434")
                .modelName("deepseek-r1:1.5b")
                .temperature(0.8) // 创意性控制(0-1)
                .timeout(Duration.ofSeconds(120)) // 超时设置120秒
                .build();

        ChatMemoryProvider chatMemoryProvider = memoryId -> MessageWindowChatMemory.builder()
                .id(memoryId) // 设置聊天内存的唯一标识符
                .maxMessages(20) // 设置最大消息数为 20
                .build();
//        ChatMemory chatMemory = MessageWindowChatMemory.withMaxMessages(20);

        Assistant assistant = AiServices.builder(Assistant.class)
                .chatLanguageModel(model)
//                .chatMemory(chatMemory)
                .chatMemoryProvider(chatMemoryProvider)
                .build();

        // 连续对话
        String response1 = assistant.chat(1, "Hello, World!");
        System.out.println(response1);
        System.out.println("----等待输入---");
        Scanner scanner = new Scanner(System.in); // 中文
        String response2 = assistant.chat(1, scanner.next()); // 能记住上下文
//        String response2 = assistant.chat(2, scanner.next());


        System.out.println("-------");
        System.out.println(response2);
    }
}

内容检索(Rag)

LangChain4j 提供了三种RAG(Retrieval-Augmented Generation,检索增强生成)的实现方式:

  • Easy RAG:这是最简单的方式,适合初学者快速上手。用户只需将文档丢给LangChain4j,无需了解嵌入、向量存储、正确的嵌入模型选择以及如何解析和拆分文档等复杂内容。这种方式非常适合快速体验 RAG 功能。
  • Naive RAG:这是一种基础的RAG实现方式(使用向量搜索),主要通过简单的索引、检索和生成过程完成任务。它通常涉及将文档拆分为片段,并使用向量搜索进行检索。然而,Naive RAG存在一些局限性,例如检索的相关性较差、生成的答案可能不连贯或重复。
  • Advanced RAG:这是一种模块化的RAG框架,允许添加额外的步骤,如查询转换、从多个来源检索以及重排序(reranking)。Advanced RAG通过引入更高级的技术(如语义分块、查询扩展与压缩、元数据过滤等)来提高检索质量和生成答案的相关性。

注意将下面代码中的你的IP替换成可用的IP地址。

java
package com.switolor;

import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.splitter.DocumentSplitters;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.embedding.onnx.allminilml6v2.AllMiniLmL6V2EmbeddingModel;
import dev.langchain4j.model.ollama.OllamaChatModel;
import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.store.embedding.EmbeddingStoreIngestor;
import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@Slf4j
public class TestApplication {

    interface Assistant {
        String chat(String userMessage);
    }

    // 辅助方法读取 InputStream
    private String readStream(InputStream is) throws IOException {
        return new BufferedReader(new InputStreamReader(is))
                .lines().collect(Collectors.joining("\n"));
    }
    @Test
    public void EasyRagExample() throws IOException {
        // 假设你的文件放在 src/main/resources/rag 目录下
        // 我这里放的是java开发手册
        Resource[] resources = new PathMatchingResourcePatternResolver()
                .getResources("classpath:rag/*");
        List<Document> documents = new ArrayList<>();
        for (Resource res : resources) {
            try (InputStream is = res.getInputStream()) {
                Document doc = Document.from(readStream(is));
                documents.add(doc);
            }
        }

        // 在调用模型前设置代理
        // System.setProperty("http.proxyHost", "localhost");
        // System.setProperty("http.proxyPort", "8888");

        // 创建模型实例
        OllamaChatModel chatModel = OllamaChatModel.builder()
                .baseUrl("http://你的IP:11434")
                .modelName("deepseek-r1:1.5b")
                .temperature(0.8) // 创意性控制(0-1)
                .timeout(Duration.ofSeconds(120)) // 超时设置120秒
                .build();

        // 创建嵌入模型
        EmbeddingModel embeddingModel = new AllMiniLmL6V2EmbeddingModel();
        InMemoryEmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>();

        // 配置 Ingestor
        EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
                .documentSplitter(DocumentSplitters.recursive(500, 0))
                .embeddingModel(embeddingModel)
                .embeddingStore(embeddingStore)
                .build();
        ingestor.ingest(documents);
        log.info("嵌入存储注入完成");

        // 构建助手对象
        Assistant assistant = AiServices.builder(Assistant.class)
                .chatLanguageModel(chatModel) // 设置聊天语言模型
//                .chatMemory(MessageWindowChatMemory.withMaxMessages(10)) // 设置聊天记忆,最多保留 10 条消息
                .contentRetriever(EmbeddingStoreContentRetriever.from(embeddingStore)) // 设置内容检索器,使用嵌入存储进行检索
                .build();

        // 使用助手回答问题
        String answer = assistant.chat("介绍一下Java 开发手册");
        log.info("结果:{}", answer);
    }
}
java
package com.switolor;

import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.splitter.DocumentSplitters;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.embedding.onnx.allminilml6v2.AllMiniLmL6V2EmbeddingModel;
import dev.langchain4j.model.ollama.OllamaStreamingChatModel;
import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.service.TokenStream;
import dev.langchain4j.store.embedding.EmbeddingStoreIngestor;
import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@Slf4j
public class TestApplication {

    interface Assistant {
        TokenStream chat(String userMessage); // 返回 TokenStream
    }

    // 辅助方法读取 InputStream
    private String readStream(InputStream is) {
        return new BufferedReader(new InputStreamReader(is)).lines().collect(Collectors.joining("\n"));
    }

    @Test
    public void EasyRagExample() throws IOException {
        // 假设你的文件放在 src/main/resources/rag 目录下
        // 我这里放的是java开发手册
        Resource[] resources = new PathMatchingResourcePatternResolver().getResources("classpath:rag/*");
        List<Document> documents = new ArrayList<>();
        for (Resource res : resources) {
            try (InputStream is = res.getInputStream()) {
                Document doc = Document.from(readStream(is));
                documents.add(doc);
            }
        }

        // 创建模型实例 - 流式处理
        OllamaStreamingChatModel chatModel = OllamaStreamingChatModel.builder()
                .baseUrl("http://你的IP:11434")
                .modelName("deepseek-r1:1.5b").
                temperature(0.8) // 创意性控制(0-1)
                .timeout(Duration.ofSeconds(600)) // 超时设置600秒
                .build();

        // 创建嵌入模型
        EmbeddingModel embeddingModel = new AllMiniLmL6V2EmbeddingModel();
        InMemoryEmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>();

        // 配置 Ingestor
        EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder().documentSplitter(DocumentSplitters.recursive(500, 0)).embeddingModel(embeddingModel).embeddingStore(embeddingStore).build();
        ingestor.ingest(documents);
        log.info("嵌入存储注入完成");

        // 构建助手对象
        Assistant assistant = AiServices.builder(Assistant.class).streamingChatLanguageModel(chatModel) // 设置聊天语言模型
//                .chatMemory(MessageWindowChatMemory.withMaxMessages(10)) // 设置聊天记忆,最多保留 10 条消息
                .contentRetriever(EmbeddingStoreContentRetriever.from(embeddingStore)) // 设置内容检索器,使用嵌入存储进行检索
                .build();

        // 获取 TokenStream
        TokenStream tokenStream = assistant.chat("介绍一下Java 开发手册");

        // 使用 CountDownLatch 确保测试线程等待流式完成
        CountDownLatch latch = new CountDownLatch(1);

        // 实时处理每个 Token
        tokenStream.onPartialResponse(partial -> log.info("片段: {}", partial)) // 实时输出片段
                .onRetrieved(contents -> log.debug("检索到内容: {}", contents)) // 可选:处理检索到的内容
                .onCompleteResponse(response -> {
                    log.info("完整结果: {}", response.aiMessage().text());
                    latch.countDown(); // 完成时释放锁
                }).onError(error -> {
                    log.error("错误", error);
                    latch.countDown();
                }).start();

        try {
            latch.await(); // 阻塞等待流式完成
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}
xml
<properties>
    <langchain4j.version>1.0.0-beta3</langchain4j.version>
</properties>
<dependencies>
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j</artifactId>
        <version>${langchain4j.version}</version>
    </dependency>

    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j-ollama</artifactId>
        <version>${langchain4j.version}</version>
    </dependency>

    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j-embeddings-all-minilm-l6-v2</artifactId>
        <version>${langchain4j.version}</version>
    </dependency>
</dependencies>

在实际执行中可以使用spring boot风格管理OllamaChatModel注入, 将文档解析识别做成单例,避免重复创建。

粤ICP备20009776号