主题
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>
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注入, 将文档解析识别做成单例,避免重复创建。