第1903篇:LangChain4j与Spring AI的横向对比——各自擅长的场景分析
第1903篇:LangChain4j与Spring AI的横向对比——各自擅长的场景分析
这个话题我被问了很多次了。
每次有同学来问"老张,我新项目该用 LangChain4j 还是 Spring AI?",我都得先问他们几个问题:项目是什么类型的?团队熟悉哪套技术体系?有没有强 Spring 依赖?对流式输出有没有特殊要求?
不同答案会导向不同的选择。今天这篇文章,我想从一个实际踩过坑的工程师角度,认真聊聊这两个框架的差异——不是那种官方文档式的功能列表对比,而是在真实项目里你会感受到什么。
两个框架的定位差异
先说一个根本性的区别,这决定了所有后续的设计取舍:
LangChain4j 是一个独立的 AI 应用框架,它对你的整体技术栈没有强依赖。你可以在 Spring Boot 项目里用它,也可以在 Quarkus、Micronaut 甚至普通 Java 应用里用它。它的核心思想借鉴自 Python 的 LangChain,强调组件化和链式调用。
Spring AI 是 Spring 生态的 AI 扩展,它的设计哲学和 Spring 框架高度一致:约定优于配置、依赖注入、Starter 自动配置。它的目标是让 Spring 开发者以最小的学习成本接入 AI 能力。
这个定位差异导致的实际影响:
| 维度 | LangChain4j | Spring AI |
|---|---|---|
| 框架耦合度 | 低,可独立使用 | 高,强依赖 Spring |
| 学习曲线 | 中,需要理解 LC4j 概念 | 低,Spring 开发者几乎零成本 |
| 生态深度 | 自带生态更完整 | 复用 Spring 生态更彻底 |
| 配置方式 | 代码优先 | 配置文件优先 |
LangChain4j 的强项:AI 优先的工程体验
1. AiServices 的声明式接口
这是 LangChain4j 我最喜欢的特性之一。你定义一个 Java 接口,用注解描述行为,框架帮你生成实现:
public interface CustomerSupportAgent {
@SystemMessage("""
你是一个专业的客服助手,负责处理用户的订单查询和退款申请。
回答要简洁专业,如果信息不足请主动询问。
当前时间:{{current_time}}
""")
@UserMessage("{{userMessage}}")
String chat(
@MemoryId String sessionId,
@V("userMessage") String userMessage,
@V("current_time") String currentTime
);
}这种声明式风格非常干净,业务逻辑和 AI 交互完全解耦。更重要的是,接口方法可以有不同的返回类型——String、AiMessage、Response<AiMessage>,还可以直接返回结构化对象(框架自动解析 JSON):
public interface DataExtractor {
@UserMessage("从以下文本中提取出联系人信息:{{text}}")
ContactInfo extractContactInfo(@V("text") String text);
@UserMessage("分析以下评论的情绪:{{review}}")
SentimentResult analyzeSentiment(@V("review") String review);
}
@Data
public class ContactInfo {
private String name;
private String phone;
private String email;
private String company;
}2. RAG 管道的模块化
LangChain4j 对 RAG(检索增强生成)有非常完善的支持,整个 pipeline 的每个环节都可以单独替换:
// 构建 RAG 管道
EmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>();
EmbeddingModel embeddingModel = OpenAiEmbeddingModels.builder()
.apiKey(API_KEY)
.modelName("text-embedding-3-small")
.build();
// 文档加载和处理
DocumentLoader loader = new FileSystemDocumentLoader();
Document document = loader.load(Paths.get("knowledge-base.pdf"));
DocumentSplitter splitter = DocumentSplitters.recursive(500, 50);
List<TextSegment> segments = splitter.split(document);
EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
.documentSplitter(splitter)
.embeddingModel(embeddingModel)
.embeddingStore(embeddingStore)
.build();
ingestor.ingest(document);
// 构建带 RAG 的 AI 服务
ContentRetriever retriever = EmbeddingStoreContentRetriever.builder()
.embeddingStore(embeddingStore)
.embeddingModel(embeddingModel)
.maxResults(3)
.minScore(0.7)
.build();
KnowledgeBaseAssistant assistant = AiServices.builder(KnowledgeBaseAssistant.class)
.chatLanguageModel(model)
.contentRetriever(retriever)
.chatMemoryProvider(memoryProvider)
.build();3. 工具调用的优雅程度
LangChain4j 的工具调用写起来真的很爽,@Tool 注解加上方法,自动生成 function schema,不需要手动写 JSON:
@Component
public class OrderTools {
@Tool("查询指定订单的状态和物流信息")
public OrderStatus getOrderStatus(
@P("订单ID,格式:ORD-XXXXXXXX") String orderId) {
return orderService.getStatus(orderId);
}
@Tool("申请订单退款,需要提供退款原因")
public RefundResult requestRefund(
@P("订单ID") String orderId,
@P("退款原因,必须是:质量问题/错发漏发/不想要了 之一") String reason) {
return refundService.apply(orderId, reason);
}
}Spring AI 的强项:Spring 生态的无缝集成
1. 自动配置和 Starter 机制
如果你的项目已经是 Spring Boot,Spring AI 的接入成本低得惊人:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
chat:
options:
model: gpt-4o
temperature: 0.7
max-tokens: 2000然后直接注入使用:
@Service
public class ChatService {
@Autowired
private ChatClient chatClient;
public String chat(String message) {
return chatClient.prompt()
.user(message)
.call()
.content();
}
}就这样,完事。不需要理解任何额外概念。
2. Advisor 机制:Spring 风格的 AOP
Spring AI 的 Advisor 链是我认为它比 LangChain4j 更优雅的地方之一。借助 Spring AOP 的思想,你可以在请求前后插入各种处理逻辑:
@Bean
public ChatClient chatClient(ChatClient.Builder builder) {
return builder
.defaultAdvisors(
// 会话记忆
new MessageChatMemoryAdvisor(chatMemory),
// 日志记录
new SimpleLoggerAdvisor(),
// RAG 检索
new QuestionAnswerAdvisor(vectorStore,
SearchRequest.defaults().withTopK(4)),
// 自定义:审计日志
new AuditAdvisor(auditService),
// 自定义:内容安全
new ContentSafetyAdvisor(safetyService)
)
.build();
}每个 Advisor 只专注一件事,可插拔,可复用,测试也容易。这个设计思路在 Java 生态里非常自然。
3. 响应式支持:WebFlux 的一等公民
Spring AI 和 WebFlux 的集成是原生支持的,流式输出直接返回 Flux:
@RestController
public class StreamController {
@Autowired
private ChatClient chatClient;
@GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> stream(@RequestParam String message) {
return chatClient.prompt()
.user(message)
.stream()
.content();
}
}如果你的系统整体是响应式架构,Spring AI 能和 WebFlux 的背压机制完美配合,而 LangChain4j 的流式支持就显得比较基础。
场景分析:什么时候选哪个
选 LangChain4j 的典型场景:
- 复杂 Agent 应用:需要多轮工具调用、条件分支、状态管理的自主 Agent,LangChain4j 的工具链体系更完善。
- 非 Spring 技术栈:如果你用 Quarkus 或者其他框架,LangChain4j 是更自然的选择。
- 大规模 RAG 系统:LangChain4j 的 RAG 组件更完善,支持更多向量数据库,pipeline 定制能力更强。
- 快速原型迭代:LangChain4j 的声明式接口让 AI 业务逻辑的迭代非常快,修改
@SystemMessage就能调整 AI 行为。
选 Spring AI 的典型场景:
- Spring Boot 存量系统的 AI 改造:有大量 Spring 存量代码,想最小改动接入 AI,Spring AI 是最省力的选择。
- 响应式架构:系统已经是 WebFlux + R2DBC 的响应式全栈,Spring AI 的 Flux 支持无缝集成。
- 企业内部工具:安全、审计、权限都已经在 Spring Security 里实现了,Spring AI 通过 Advisor 链可以复用这些基础设施。
- 团队以 Spring 为核心:如果团队对 Spring 生态非常熟悉,用 Spring AI 的学习成本和认知负担更低。
一个实际对比:实现相同功能的代码量
来看一个具体例子:实现一个带会话记忆和工具调用的客服助手。
LangChain4j 实现:
// 接口定义
public interface CustomerAssistant {
@SystemMessage("你是客服助手,可以查询订单和申请退款")
String assist(@MemoryId String sessionId, @UserMessage String message);
}
// 工具类
@Component
public class OrderToolProvider {
@Tool("查询订单状态")
public String getOrderStatus(@P("订单号") String orderId) {
return orderService.getStatus(orderId).toString();
}
}
// 配置
@Bean
public CustomerAssistant customerAssistant(
ChatLanguageModel model,
OrderToolProvider tools,
ChatMemoryProvider memoryProvider) {
return AiServices.builder(CustomerAssistant.class)
.chatLanguageModel(model)
.tools(tools)
.chatMemoryProvider(memoryProvider)
.build();
}Spring AI 实现:
// 工具定义(函数式)
@Bean
@Description("查询订单状态")
public Function<OrderStatusRequest, String> getOrderStatus() {
return request -> orderService.getStatus(request.orderId()).toString();
}
// ChatClient 配置
@Bean
public ChatClient customerChatClient(ChatClient.Builder builder,
ChatMemory chatMemory) {
return builder
.defaultSystem("你是客服助手,可以查询订单和申请退款")
.defaultAdvisors(new MessageChatMemoryAdvisor(chatMemory))
.defaultFunctions("getOrderStatus")
.build();
}
// 使用
@Service
public class CustomerService {
@Autowired
private ChatClient chatClient;
public String assist(String sessionId, String message) {
return chatClient.prompt()
.user(message)
.advisors(a -> a.param(CHAT_MEMORY_CONVERSATION_ID_KEY, sessionId))
.call()
.content();
}
}两者代码量相近,但风格不同。LangChain4j 更接口化、声明式;Spring AI 更函数式、配置化。
我踩过的坑
LangChain4j 的坑:
版本升级变化大。LangChain4j 目前还没到 1.0,API 变化比较频繁。0.27 到 0.31 之间我升级了三次,每次都有接口变动,特别是
ToolProvider那块改了好几遍。建议锁定版本,升级前先看 changelog。AiServices 的错误信息不够友好。当工具执行出错或者 LLM 返回格式不对时,抛出的异常往往是运行时异常,堆栈信息不能直接定位问题,需要开启 DEBUG 日志才能看清楚。
结构化输出依赖 JSON 解析,有时不稳定。当你让 LangChain4j 返回结构化对象时,底层是让 LLM 返回 JSON 然后解析。如果 LLM 返回了带注释的 JSON 或者格式稍微不对,就会解析失败。可以给 systemMessage 加"请严格按 JSON 格式返回,不要有额外内容"来缓解。
Spring AI 的坑:
工具调用的函数注册方式比较繁琐。你需要用
@Description注解、Function<Request, Response>的函数签名,还要在 Builder 里注册函数名称字符串。这个字符串和 Bean 名称的对应关系不够直观,拼错了会静默忽略(工具不可用但不报错)。Advisor 的执行顺序问题。多个 Advisor 的执行顺序依赖
getOrder()方法,默认顺序有时会导致意外行为。比如QuestionAnswerAdvisor应该在MessageChatMemoryAdvisor之前运行(先检索知识库再结合记忆),但默认顺序可能相反。每次加新 Advisor 都要想清楚顺序。响应式和命令式混用容易出问题。如果你的系统大部分是命令式(阻塞式),只有 AI 部分想用 Flux 流式,这种混合编程模型会带来很多麻烦,特别是数据库访问和会话管理。要么都是响应式,要么都是命令式。
总结
不存在绝对的"哪个更好",只有"哪个更适合当前场景"。
LangChain4j 的优势在于:AI 功能更完整、声明式 API 更优雅、不依赖 Spring 生态、更适合 AI-First 的项目。
Spring AI 的优势在于:Spring 集成成本为零、WebFlux 支持原生、Advisor 链设计优雅、团队学习成本低。
如果让我给一个简单的判断标准:新建的 AI-First 应用选 LangChain4j,Spring Boot 存量系统的 AI 改造选 Spring AI。
当然现实中很多项目没这么清晰,两者也可以共存——LangChain4j 负责核心 AI 逻辑,Spring AI 负责对接其他 Spring 组件。这个混合用法我们在项目里真的实践过,有机会单独写一篇。
