从 LangChain 到 LangChain4j:Java 开发者的 AI 应用实战指南
和Spring AI。如果你是 Spring 生态的重度用户,两者都可以选。与 LangChain(Python)概念高度对应,迁移成本低Spring Boot 起步依赖,配置即用声明式@AiService注解,代码极简内置 RAG、Tools、会话记忆等高阶能力官网:https://docs.langchain4j.dev用@Tool描述方法作用,用@P@Tool("预约志愿填报服务") pub
如果你已经熟悉 Python 版的 LangChain,那 LangChain4j 的核心概念你基本都能对上号。但 Java 生态有它自己的玩法,尤其在 Spring Boot 整合、声明式 API 和工具调用方面,LangChain4j 的设计更贴合 Java 开发者的习惯。
一、为什么是 LangChain4j?
Java 调用大模型的主流框架有两个:LangChain4j 和 Spring AI。如果你是 Spring 生态的重度用户,两者都可以选。LangChain4j 的优势在于:
- 与 LangChain(Python)概念高度对应,迁移成本低
- Spring Boot 起步依赖,配置即用
- 声明式
@AiService注解,代码极简 - 内置 RAG、Tools、会话记忆等高阶能力
官网:https://docs.langchain4j.dev
二、快速入门:5 分钟跑通第一个对话
2.1 引入依赖
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
<version>1.0.1</version>
</dependency>
LangChain4j 使用 OpenAI 兼容协议,所以阿里云百炼、DeepSeek 等平台只需换
baseUrl即可。
2.2 构建模型 & 发起对话
OpenAiChatModel model = OpenAiChatModel.builder()
.baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
.apiKey(System.getenv("API-KEY")) // 推荐:从环境变量读取
.modelName("qwen-plus")
.logRequests(true) // 开发阶段开启日志
.logResponses(true)
.build();
String result = model.chat("你好,介绍一下自己");
System.out.println(result);
对比 LangChain(Python):
| 操作 | LangChain (Python) | LangChain4j (Java) |
|---|---|---|
| 构建模型 | ChatOpenAI(model=..., api_key=...) |
OpenAiChatModel.builder()...build() |
| 发起对话 | model.invoke("...") |
model.chat("...") |
| 日志调试 | 需手动配置 logging | .logRequests(true).logResponses(true) |
核心差异:LangChain4j 用 Builder 模式 替代 Python 的关键字参数,日志开关是内建的。
三、Spring Boot 整合:配置驱动
纯 Java 方式能用,但实际项目必然要和 Spring 结合。LangChain4j 提供了起步依赖,做到配置即注入。
3.1 引入起步依赖
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
<version>1.0.1-beta6</version>
</dependency>
3.2 application.yml 配置
langchain4j:
open-ai:
chat-model:
base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
api-key: ${API-KEY}
model-name: qwen-plus
log-requests: true
log-responses: true
logging:
level:
dev.langchain4j: debug
配置完成后,IOC 容器自动注入 OpenAiChatModel 对象,直接 @Autowired 使用。
3.3 接口开发
@RestController
public class ChatController {
@Autowired
private OpenAiChatModel model;
@RequestMapping("/chat")
public String chat(String message) {
return model.chat(message);
}
}
到这里,一个可用的 AI 对话接口就完成了。但直接用 model.chat() 做高阶功能(会话记忆、RAG、Tools)会很麻烦——所以 LangChain4j 提供了 AiServices。
四、AiServices:LangChain4j 的灵魂(原理:动态代理)
LangChain4j 中,AiServices 是对 LangChain(Python)中 Chain 的替代方案。它把模型、记忆、检索、工具等能力封装到一个接口的动态代理中,用起来像调用普通方法一样简单。
4.1 编程式使用
// 1. 声明接口
public interface ConsultantService {
String chat(String message);
}
// 2. 用 AiServices 创建代理对象
@Configuration
public class CommonConfig {
@Autowired
private OpenAiChatModel model;
@Bean
public ConsultantService consultantService() {
return AiServices.builder(ConsultantService.class)
.chatModel(model)
.build();
}
}
4.2 声明式使用(推荐)
更简洁的方式——直接在接口上加 @AiService 注解,LangChain4j 自动扫描创建代理:
@AiService(
wiringMode = AiServiceWiringMode.EXPLICIT, // 手动装配
chatModel = "openAiChatModel"
)
public interface ConsultantService {
String chat(String message);
}
不需要写 @Configuration,不需要手动构建 Bean,一个注解搞定。
对比 LangChain(Python):
| 概念 | LangChain (Python) | LangChain4j (Java) |
|---|---|---|
| 链式调用 | chain = LLMChain | prompt | memory |
@AiService 注解 + 属性配置 |
| 装配方式 | 代码串联 | 声明式注解,Spring 自动注入 |
| 扩展能力 | 传参给 Chain 构造函数 | @AiService 的属性指定 Bean 名 |
LangChain4j 的声明式风格对 Java 开发者更友好——不需要记住 Chain 的嵌套顺序,在注解里指明用哪个组件就行。
五、流式调用:从阻塞到实时
阻塞式调用一次性返回完整结果,用户体验差。流式调用逐 Token 推送,类似打字机效果。
5.1 配置流式模型
langchain4j:
open-ai:
streaming-chat-model: # 流式模型配置
base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
api-key: ${API-KEY}
model-name: qwen-plus
5.2 引入 WebFlux 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-reactor</artifactId>
<version>1.0.1-beta6</version>
</dependency>
5.3 接口返回 Flux
@AiService(
wiringMode = AiServiceWiringMode.EXPLICIT,
chatModel = "openAiChatModel",
streamingChatModel = "openAiStreamingChatModel"
)
public interface ConsultantService {
Flux<String> chat(@MemoryId String memoryId, @UserMessage String message);
}
Controller 返回 Flux<String>,前端通过 SSE 接收实时推送。
六、消息注解:SystemMessage 与 UserMessage
大模型的行为由消息类型决定。SystemMessage 设定 AI 角色和规则,UserMessage 携带用户输入。
6.1 SystemMessage:设定 AI 人设
// 方式一:直接写在注解里
@SystemMessage("你是志愿填报顾问,只回答高考志愿相关问题")
Flux<String> chat(@MemoryId String memoryId, @UserMessage String message);
// 方式二:从外部文件加载(推荐,方便管理长提示词)
@SystemMessage(fromResource = "system.txt")
Flux<String> chat(@MemoryId String memoryId, @UserMessage String message);
6.2 UserMessage:模板化用户消息
可以在用户消息前后拼接预设内容,通过 {{it}} 或 @V 注解引用参数:
// 使用默认占位符 {{it}}
@UserMessage("你是AI助手。{{it}}")
Flux<String> chat(String message);
// 自定义占位符名称
@UserMessage("你是AI助手。{{msg}}")
Flux<String> chat(@V("msg") String message);
七、会话记忆:从无状态到有上下文
大模型本身没有记忆,每次对话都是独立的。会话记忆的原理是把历史消息一起发给模型,让它"看到"之前的对话。
7.1 基本实现
@Bean
public ChatMemory chatMemory() {
return MessageWindowChatMemory.builder()
.maxMessages(20) // 最多保留 20 条,超出淘汰最早的
.build();
}
@AiService(
wiringMode = AiServiceWiringMode.EXPLICIT,
chatModel = "openAiChatModel",
chatMemory = "chatMemory" // 注入会话记忆
)
为什么要限制条数?两个原因:大模型上下文有上限(约 10 万 Token);消息越多,Token 消耗越大,费用越高。
7.2 会话隔离
不同用户不能共享同一个记忆对象。通过 ChatMemoryProvider + @MemoryId 实现:
@Bean
public ChatMemoryProvider chatMemoryProvider() {
return memoryId -> MessageWindowChatMemory.builder()
.id(memoryId)
.maxMessages(20)
.build();
}
@AiService(
wiringMode = AiServiceWiringMode.EXPLICIT,
chatModel = "openAiChatModel",
chatMemoryProvider = "chatMemoryProvider"
)
public interface ConsultantService {
@SystemMessage(fromResource = "system.txt")
Flux<String> chat(@MemoryId String memoryId, @UserMessage String message);
}
LangChain4j 根据 memoryId 查找或创建对应的 ChatMemory 对象,实现用户间记忆隔离。
对比 LangChain(Python):
| 操作 | LangChain (Python) | LangChain4j (Java) |
|---|---|---|
| 记忆管理 | ConversationBufferMemory |
MessageWindowChatMemory |
| 消息窗口 | ConversationBufferWindowMemory(k=20) |
.maxMessages(20) |
| 会话隔离 | 手动管理 session_id | ChatMemoryProvider + @MemoryId |
7.3 持久化:记忆存到 Redis
默认的 MessageWindowChatMemory 使用内存存储,重启即丢失。实现 ChatMemoryStore 接口即可持久化:
@Repository
public class RedisChatMemoryStore implements ChatMemoryStore {
@Autowired
private StringRedisTemplate redisTemplate;
@Override
public List<ChatMessage> getMessages(Object memoryId) {
String json = redisTemplate.opsForValue().get(memoryId);
return ChatMessageDeserializer.messagesFromJson(json);
}
@Override
public void updateMessages(Object memoryId, List<ChatMessage> list) {
String json = ChatMessageSerializer.messagesToJson(list);
redisTemplate.opsForValue().set(memoryId.toString(), json, Duration.ofDays(1));
}
@Override
public void deleteMessages(Object memoryId) {
redisTemplate.delete(memoryId.toString());
}
}
然后在 ChatMemoryProvider 中指定使用:
@Bean
public ChatMemoryProvider chatMemoryProvider() {
return memoryId -> MessageWindowChatMemory.builder()
.id(memoryId)
.maxMessages(20)
.chatMemoryStore(redisChatMemoryStore) // 使用 Redis 存储
.build();
}
八、RAG 知识库:让 AI 拥有专属知识
RAG(Retrieval Augmented Generation)的本质:先检索相关知识,再让模型结合知识生成答案。
8.1 RAG 工作原理
用户提问 → 向量化 → 在向量数据库中检索相似片段
→ 把「问题 + 检索到的片段」一起发给大模型 → 生成答案
核心概念:
- 向量:文本的数学表示,多维坐标中的一个点
- 余弦相似度:衡量两个向量的方向接近程度,值越大越相似(0~1)
- 向量数据库:专门存储和检索向量的数据库(Milvus、Chroma、RedisSearch 等)
8.2 快速入门:内存版 RAG
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-easy-rag</artifactId>
<version>1.0.1-beta6</version>
</dependency>
@Bean
public EmbeddingStore store() {
// 1. 加载文档
List<Document> documents = ClassPathDocumentLoader.loadDocuments("content");
// 2. 构建内存向量数据库
InMemoryEmbeddingStore store = new InMemoryEmbeddingStore();
// 3. 分割 + 向量化 + 存储(一步搞定)
EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
.embeddingStore(store)
.build();
ingestor.ingest(documents);
return store;
}
@Bean
public ContentRetriever contentRetriever(EmbeddingStore store) {
return EmbeddingStoreContentRetriever.builder()
.embeddingStore(store)
.minScore(0.5) // 最低相似度阈值
.maxResults(3) // 最多返回 3 个片段
.build();
}
@AiService(
wiringMode = AiServiceWiringMode.EXPLICIT,
chatModel = "openAiChatModel",
chatMemoryProvider = "chatMemoryProvider",
contentRetriever = "contentRetriever" // 配置检索器
)
三步搞定:存文档 → 建检索器 → 配到 @AiService。
8.3 核心组件详解
RAG 涉及五个核心 API,LangChain4j 把大部分细节封装到了 EmbeddingStoreIngestor 中:
① 文档加载器
| 加载器 | 用途 |
|---|---|
ClassPathDocumentLoader |
从 classpath 加载 |
FileSystemDocumentLoader |
从本地磁盘加载 |
UrlDocumentLoader |
从 URL 加载 |
② 文档解析器
| 解析器 | 支持格式 |
|---|---|
ApacheTikaDocumentParser(默认) |
几乎所有格式 |
ApachePdfBoxDocumentParser |
|
ApachePoiDocumentParser |
Office 文件 |
TextDocumentParser |
纯文本 |
③ 文档分割器
| 分割器 | 策略 |
|---|---|
DocumentByParagraphSplitter |
按段落 |
DocumentByLineSplitter |
按行 |
DocumentBySentenceSplitter |
按句子 |
DocumentSplitters.recursive()(默认) |
段落 → 行 → 句子 → 词,逐级递归 |
递归分割器最实用,还支持配置片段重叠保持语义连贯:
DocumentSplitter ds = DocumentSplitters.recursive(500, 100);
// 500 = 每个片段最大字符数
// 100 = 相邻片段重叠字符数(防止语义断裂)
④ 向量模型
内存版向量模型功能有限,生产环境建议替换为百炼的 text-embedding-v3:
langchain4j:
open-ai:
embedding-model:
base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
api-key: ${API-KEY}
model-name: text-embedding-v3
注入后交给 EmbeddingStoreIngestor 和 EmbeddingStoreContentRetriever:
@Autowired
private EmbeddingModel embeddingModel;
// 存储时用
EmbeddingStoreIngestor.builder()
.embeddingStore(store)
.embeddingModel(embeddingModel)
.build();
// 检索时也用
EmbeddingStoreContentRetriever.builder()
.embeddingStore(store)
.embeddingModel(embeddingModel)
.build();
⑤ 向量数据库
内存版 InMemoryEmbeddingStore 重启即丢,生产环境用 RedisSearch:
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-community-redis-spring-boot-starter</artifactId>
<version>1.0.1-beta6</version>
</dependency>
langchain4j:
community:
redis:
host: localhost
port: 6379
配置后自动注入 RedisEmbeddingStore,替换 InMemoryEmbeddingStore 即可。
8.4 LangChain vs LangChain4j RAG 对比
| 环节 | LangChain (Python) | LangChain4j (Java) |
|---|---|---|
| 文档加载 | PyPDFLoader / DirectoryLoader |
ClassPathDocumentLoader / FileSystemDocumentLoader |
| 文本分割 | RecursiveCharacterTextSplitter |
DocumentSplitters.recursive() |
| 向量模型 | OpenAIEmbeddings() |
EmbeddingModel(yml 配置注入) |
| 向量数据库 | FAISS / Chroma / Pinecone |
InMemoryEmbeddingStore / RedisEmbeddingStore |
| 检索器 | retriever = vectorstore.as_retriever() |
EmbeddingStoreContentRetriever |
| 整合方式 | RetrievalQA.from_chain_type() |
@AiService(contentRetriever=...) |
关键差异:LangChain4j 用 @AiService 注解的 contentRetriever 属性挂载检索器,比 Python 的 Chain 组装更简洁。
九、Tools 工具:让 AI 调用你的代码
Tools(原 Function Calling)让大模型能调用你定义的 Java 方法。典型场景:AI 在对话中识别用户意图,自动调用预约接口写入数据库。
9.1 工作原理
用户提问 → 大模型判断是否需要调用工具
→ 返回工具名称 + 参数 → AI 应用执行工具方法
→ 把执行结果发回大模型 → 大模型生成最终回答
大模型不直接执行你的代码,它只是告诉你"该调用哪个方法、传什么参数",由你的程序执行后把结果回传。
9.2 定义工具方法
用 @Tool 描述方法作用,用 @P 描述参数含义:
@Component
public class ReservationTool {
@Autowired
private ReservationService reservationService;
@Tool("预约志愿填报服务")
public void addReservation(
@P("考生姓名") String name,
@P("考生性别") String gender,
@P("考生手机号") String phone,
@P("预约沟通时间,格式:yyyy-MM-dd'T'HH:mm") String communicationTime,
@P("考生所在省份") String province,
@P("考生预估分数") Integer estimatedScore
) {
Reservation reservation = new Reservation(null, name, gender, phone,
LocalDateTime.parse(communicationTime), province, estimatedScore);
reservationService.insert(reservation);
}
@Tool("根据考生手机号查询预约单")
public Reservation findReservation(@P("考生手机号") String phone) {
return reservationService.findByPhone(phone);
}
}
9.3 配置工具
@AiService(
wiringMode = AiServiceWiringMode.EXPLICIT,
chatModel = "openAiChatModel",
streamingChatModel = "openAiStreamingChatModel",
chatMemoryProvider = "chatMemoryProvider",
contentRetriever = "contentRetriever",
tools = "reservationTool" // 挂载工具
)
用户说"我想预约,我叫张三,电话13800000001",大模型会自动解析出参数并调用 addReservation 方法。
对比 LangChain(Python):
| 操作 | LangChain (Python) | LangChain4j (Java) |
|---|---|---|
| 工具定义 | @tool 装饰器 或 StructuredTool |
@Tool + @P 注解 |
| 工具挂载 | agent = Agent(tools=[...]) |
@AiService(tools="beanName") |
| 参数描述 | Pydantic BaseModel 的 Field | @P("描述") |
| 自动执行 | Agent 自动调用 | LangChain4j 自动调用 |
十、全能力配置:最终形态
把所有能力整合到一个 @AiService 接口上:
@AiService(
wiringMode = AiServiceWiringMode.EXPLICIT,
chatModel = "openAiChatModel", // 对话模型
streamingChatModel = "openAiStreamingChatModel", // 流式模型
chatMemoryProvider = "chatMemoryProvider", // 会话记忆(Redis 持久化)
contentRetriever = "contentRetriever", // RAG 知识库检索
tools = "reservationTool" // Tools 工具
)
public interface ConsultantService {
@SystemMessage(fromResource = "system.txt") // 系统人设
Flux<String> chat(@MemoryId String memoryId, @UserMessage String message);
}
一个接口,五个注解属性,覆盖了 AI 应用开发的核心能力。
十一、总结:LangChain vs LangChain4j 核心映射
| 能力 | LangChain (Python) | LangChain4j (Java) |
|---|---|---|
| 模型调用 | ChatOpenAI() |
OpenAiChatModel.builder() 或 yml 配置 |
| 链式编排 | LLMChain \| SequentialChain |
@AiService 声明式注解 |
| 会话记忆 | ConversationBufferMemory |
MessageWindowChatMemory + ChatMemoryProvider |
| 消息模板 | ChatPromptTemplate |
@SystemMessage / @UserMessage 注解 |
| RAG | RetrievalQA + 各种 Loader |
EmbeddingStoreIngestor + ContentRetriever |
| 工具调用 | @tool + Agent |
@Tool + @P + tools="beanName" |
| 流式输出 | astream() |
Flux<String> + WebFlux |
| Spring 整合 | 不适用 | 起步依赖 + yml 配置即注入 |
LangChain4j 的核心设计哲学:用声明式注解替代编程式组装,用 Spring 生态替代手动管理。 如果你已经理解了 LangChain 的概念,迁移到 LangChain4j 只需要换一套 API 风格——底层原理完全一致。
更多推荐


所有评论(0)