LangChain4j 介绍
这一篇把"在 JVM 生态里怎么用一套类 LangChain 的方式做大模型应用"讲清楚:LangChain4j 是什么、解决了哪些问题、它的核心抽象、什么时候应该用它而不是 Spring AI。
1. 什么是 LangChain4j
LangChain4j 是 LangChain 在 JVM 生态(Java / Kotlin / Scala)上的官方实现,由 LangChain 团队与社区共同维护。
它的目标可以一句话概括:
把 Python 生态中 LangChain 已经验证过的"Chain / Agent / RAG / Tool"这套抽象,在不丢失语义的前提下,迁移到 JVM 上来。
它不是 Spring AI 的替代品,但也绝对不是"另一套轮子"——大多数核心概念(ChatLanguageModel、ChatMemory、ToolSpecification、EmbeddingStore、Retrieval-Augmented Generation)在两个项目里几乎一一对应,只在 API 风格和生态集成上有些差异。
2. 它想解决的核心问题
LangChain4j 的设计哲学可以概括成三层:
- 统一抽象:屏蔽"模型厂商"差异,
ChatLanguageModel是顶层接口,任何厂商(OpenAI / Anthropic / Azure / Ollama / Qwen / DeepSeek / vLLM / 内部推理网关)都是它的一种实现。 - 可组合:高层 API 用
Chain、Agent、AiServices等 builder 风格类,把"Prompt + Memory + Tool + RAG"像乐高一样拼起来。 - 可嵌入:不强绑定 Web 框架,不强迫 Spring。可以是 Spring Boot、Quarkus、Micronaut、Ktor、Vert.x,甚至是普通
main方法。
这三点合在一起,它的目标用户是:"既不想被某个 LLM 厂商绑死,又不想自己手撕函数调用/RAG/记忆机制的 Java 团队"。
3. 核心模块一览
3.1 三大核心抽象
ChatLanguageModel:对话模型顶层接口。所有厂商都实现它。ChatMessage/UserMessage/AiMessage/SystemMessage/ToolExecutionResultMessage:与 OpenAI 的多角色协议对齐。ChatMemory:对话记忆抽象,常见实现有MessageWindowChatMemory、TokenWindowChatMemory。
3.2 高层 API:AiServices 与 Agent
AiServices.create(YourAssistant.class, model)会动态生成一个接口的实现:- 方法参数作为 prompt 输入;
- 方法返回值可以是
String、普通 POJO(自动结构化映射)甚至Result<Pojo>(拿到 token 用量等元信息)。
- 同一个接口上能用
@Tool/@ToolMemoryId/@SystemMessage等注解声明"需要被模型调用""需要按 user 隔离记忆""需要把方法描述变成 system 提示词"。
一个最简示例:
interface Assistant {
@SystemMessage("你是一个严谨的中文技术助手,回答不超过 200 字。")
String chat(@UserMessage String userMessage);
}
ChatLanguageModel model = OpenAiChatModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.modelName("gpt-4o-mini")
.build();
Assistant assistant = AiServices.create(Assistant.class, model);
String answer = assistant.chat("用一句话解释什么是 RAG。");3.3 工具调用(Agent 基础)
- 用
@Tool把普通方法暴露给模型。 ToolSpecification+ToolExecutor是底层的协议侧接口,大多数业务方用注解就够了。- 函数调用是 LangChain4j 中"Agent 自己决定什么时候调、怎么调、调哪个"的基础。
class WeatherTools {
@Tool("根据城市名查询当前天气")
String currentWeather(
@P("城市名,例如 '上海'") String city
) {
return city + " 当前晴,25°C";
}
}
Assistant agent = AiServices.builder(Assistant.class)
.chatLanguageModel(model)
.tools(new WeatherTools())
.build();3.4 RAG(检索增强生成)
LangChain4j 的 RAG 链路抽象相对完整:
DocumentSource -> DocumentLoader -> DocumentParser
-> DocumentSplitter
-> EmbeddingModel -> EmbeddingStore
检索:Query -> EmbeddingModel -> EmbeddingStore.search() -> 文档
-> Prompt 拼装 -> ChatLanguageModel- 内置解析:
PdfDocumentParser、TextDocumentParser、ApachePoiDocumentParser(Word/PPT/Excel)、JsoupDocumentParser(HTML)。 - 切分器:
DocumentSplitter接口,默认实现有按字符、按 token(TokenTextSplitter)、按段落、按正则等。 - 向量库:
EmbeddingStore接口,支持内存版、Pinecone、Milvus、Qdrant、Chroma、Weaviate、PGvector、Redis、ES、Neo4j、Vespa 等。
3.5 MCP 集成
- LangChain4j 同时支持 MCP 客户端 / 服务端,可以用
@McpTool等注解把方法暴露为 MCP 工具。 - 对需要"内部能力协议化、被多个 Agent(无论 Java 还是 Python)消费"的场景非常合适。
3.6 可观测性
- 内置 Micrometer 集成,自动暴露模型调用次数、token 用量、错误率、延迟等。
- 同时支持 OpenTelemetry:
LangChain4j自带OpenTelemetry*Integration。 - 对接 Prometheus / Grafana / Tempo 与 Spring Boot Actuator / Quarkus 配合很顺。
4. Spring AI vs LangChain4j:怎么选
这两个项目在抽象层上几乎可以对齐,差异主要在"风格 / 集成 / 团队习惯"。
| 维度 | Spring AI | LangChain4j |
|---|---|---|
| 出身 | Spring 团队(VWare/Broadcom) | LangChain 团队 + Java 社区 |
| 编程风格 | Spring 风格:ChatClient.Builder、注解、RestTemplate-like | Builder/AiServices 风格:动态代理接口 + 注解 |
| 框架绑定 | 与 Spring Boot 强绑定(虽然不是不行但不是主场) | 完全框架无关(Spring/Quarkus/Ktor/裸 main 都行) |
| 高层 API | ChatClient、Advisor 环绕 | AiServices 接口代理 |
| Agent / 工作流 | 偏"组合 Advisor"自己做 | 同样能力 + AgenticScope、LangGraph4j 组合 |
| 厂商支持 | OpenAI / Anthropic / Vertex / Bedrock / Ollama / 大量社区 starter | 同样主流厂商齐备,列表略小一点但主流都在 |
| 与 Java 生态集成 | Spring 全家桶(Actuator/Security/Integration) | 不绑定 Spring,但有 Spring Boot starter 和 Quarkus 扩展 |
| 适合场景 | 已有 Spring 重资产的工程团队 | 多框架/多厂商/想跟 LangChain Python 对齐的团队 |
经验法则:
- Spring 包袱大、团队以 Spring 为主 -> Spring AI
- 想用 Java 写 LangChain 风格的代码,或同时维护 Python/Java 两套 -> LangChain4j
- 两者完全可以混用,但同一个项目里只选一套更省心
5. 一个最小可运行的 Agent
// 1. 模型
ChatLanguageModel model = AnthropicChatModel.builder()
.apiKey(System.getenv("ANTHROPIC_API_KEY"))
.modelName("claude-3-5-sonnet-latest")
.build();
// 2. 工具
class OrderTools {
@Tool("根据订单号查询当前订单状态")
String orderStatus(@P("订单号") String orderId) {
// 调内部订单服务
return orderId + " 已发货,预计明天到";
}
}
// 3. 助手接口
interface OrderAssistant {
@SystemMessage("你是订单助手,先用工具查真实订单再回答。")
String ask(String userMessage);
}
// 4. 装配
OrderAssistant agent = AiServices.builder(OrderAssistant.class)
.chatLanguageModel(model)
.tools(new OrderTools())
.chatMemory(MessageWindowChatMemory.withMaxMessages(10))
.build();
// 5. 使用
String reply = agent.ask("帮我看看订单 D20260714-001 的状态");只要把 AnthropicChatModel 换成 OpenAiChatModel / OllamaChatModel / QwenChatModel,其他一行都不用改。
6. 常见坑与经验
- Prompt 不要过长:
@SystemMessage里塞大量规则,不仅挤占上下文窗口,还会让模型注意力漂移;真正稳定的规则应该拆成"顾问 / 工具 / Few-shot 示例"。 - 工具描述要"人话":
@Tool("...")的 description 是模型判断"什么时候调"的关键信息,务必用业务可理解的语言,而不是 Java 方法名复制。 - 结构化输出用 POJO 而非 Map:
@Description注解 + 嵌套 record,比Map<String,Object>让模型更稳定。 - 多轮记忆按用户隔离:
ChatMemory默认是单例,生产环境务必按userId/sessionId隔离(MessageWindowChatMemory配ChatMemoryProvider)。 - RAG 不要追求 100% 召回:真正决定效果的是 chunking 粒度 + 检索 query 改写 + 模型回答时的"允许拒答"约束,而不是换更强的向量库。
7. 进一步阅读
- 官方站:
https://docs.langchain4j.dev/ - GitHub:
https://github.com/langchain4j/langchain4j - LangGraph4j:在 LangChain4j 上做有状态/可分支 Agent 工作流
- 对照阅读:本目录下
1-springAi/springAi-介绍了解 Spring 生态的另一条路
(后续本子分类会按需补充:Prompt 与 AiServices 进阶、工具调用与权限隔离、RAG 实战、可观测与评估、多 Agent 协作等专题。)
