Spring AI 不是 LangChain 的 Java 翻译
配套代码:
https://github.com/refinex-space/Refinex-SpringAI-Examples/tree/main/spring-ai-getting-started
本文重点:
Spring AI 的核心价值不是「调用 LLM 的 SDK」,而是将 AI 能力纳入 Spring 的 IoC + Auto-configuration 体系,使 AI 组件成为可测试、可替换、可观测的一等公民。选择 Spring AI 还是 LangChain4j,取决于你要的是「Spring 生态的 AI 扩展」还是「独立的 AI 编排引擎」。
前置知识:
- Auto-configuration
- Spring IoC 容器基础
- 对 LLM API 的基本了解(知道什么是 Chat Completion 即可)
一个危险的类比正在误导 Java 社区
当 Java 开发者第一次接触 Spring AI,最自然的反应是:「这是 LangChain 的 Java 版本吧?」
这个类比直觉上合理——两者都提供 Chat Model 抽象、都支持 RAG、都有 Tool Calling。Spring AI 官方文档甚至明确写道:"The project draws inspiration from notable Python projects, such as LangChain and LlamaIndex, but Spring AI is not a direct port of those projects."(该项目从著名的 Python 项目(如 LangChain 和 LlamaIndex)中汲取灵感,但 Spring AI 并不是这些项目的直接移植。)
问题在于,「灵感来源」和「设计哲学」是两回事。 把 Spring AI 当成 LangChain 的 Java 移植来理解,会导致三个具体的工程错误:
- 你会尝试用「链式编排」思维来组织代码,而忽略 Spring AI 真正的扩展机制——Advisor(顾问)拦截器链
- 你会把 ChatModel 当成核心入口,而不是 ChatClient——后者才是挂载 Memory、Tool、RAG 的管道
- 你会手动管理组件生命周期,而不是利用 Auto-configuration 获得开箱即用的可观测性和健康检查
你需要明确的是,Spring AI 的架构锚点是 Spring Framework 本身,不是 LangChain 的概念模型。 理解这一点,你才能正确使用这个框架,而不是把它当成一个蹩脚的 Python 翻译。
一、Spring AI 到底在封装什么?
1.1 不是 SDK 封装,是 Spring-native 集成
大多数 LLM SDK(包括 OpenAI 的官方 Java SDK)做的事情是:把 HTTP API 调用封装成类型安全的 Java 方法。调用 openai.chat.completions.create() 和调用 chatModel.call(prompt) 在本质上没有区别——都是发一个 HTTP 请求,拿一个响应。
而 Spring AI 做的事情完全不同,它把 AI 组件纳入了 Spring 的核心基础设施:
可以看到,所有 AI 组件都通过 IoC 容器管理,而不是由开发者手动 new 出来。这意味着:
- 可替换性:切换 Provider 只需要换一个 Starter 依赖 + 改配置,不需要改业务代码
- 可测试性:在单元测试中可以用
@MockBean替换ChatModel,不需要真实调用 LLM - 可观测性:Micrometer 的 Trace 和 Metric 通过 Auto-configuration 自动注入,无需手动埋点
- 配置外部化:API Key、Endpoint、模型参数全部通过
application.yml或环境变量管理,遵循 12-Factor 原则
1.2 一个具体的例子:替换 Provider 的真实成本
假设你的应用当前使用 OpenAI,需要切换到 DeepSeek(国内合规要求)。
如果你用的是裸 SDK:
// 改动前:OpenAI SDK 直接调用
// 你的业务代码与 OpenAI 的请求/响应类型深度耦合
OpenAiChatCompletionRequest request = new OpenAiChatCompletionRequest();
request.setModel("gpt-4o");
request.setMessages(List.of(new OpenAiMessage("user", userInput)));
OpenAiChatCompletionResponse response = openAiClient.createChatCompletion(request);
String answer = response.getChoices().get(0).getMessage().getContent();切换 Provider 意味着:替换请求类、替换响应类、替换客户端实例、修改所有调用点。如果你有 30 个调用 LLM 的地方,你需要改 30 处。
如果你用的是 Spring AI:
// 业务代码不变——ChatClient 是唯一入口
// Provider 切换只发生在配置层,不侵入业务逻辑
String answer = chatClient.prompt()
.user(userInput)
.call()
.content();切换 Provider 的全部改动:
# application.yml:删掉 OpenAI 配置,加上 DeepSeek 配置
# 不需要改任何 Java 代码
spring:
ai:
deepseek:
api-key: ${DEEPSEEK_API_KEY}
chat:
options:
model: deepseek-chat<!-- pom.xml:换一个 Starter -->
<!-- 删除 spring-ai-starter-model-openai -->
<!-- 添加 spring-ai-starter-model-deepseek -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-deepseek-spring-boot-starter</artifactId>
</dependency>改动范围:1 个配置文件 + 1 个依赖声明。零行 Java 代码变更。
这不是理论上的优势——这是 Spring AI 架构设计的直接产物。Auto-configuration 根据 classpath 上的 Starter 自动装配对应的 ChatModel Bean,业务代码通过 ChatClient(依赖注入获得)与 AI 交互,永远不直接接触 Provider 实现类。
二、LangChain4j vs Spring AI:两种哲学,两种适用场景
2.1 设计哲学对比
这不是「哪个更好」的问题——而是「你要解决什么问题」的问题。
LangChain4j 的哲学:AI-first 编排引擎。 它的核心概念是 Chain(链)——把 Prompt 构造、Model 调用、Output 解析、Memory 管理串成一条可复用的处理链。框架本身不依赖 Spring,可以在任何 Java 环境中运行。
Spring AI 的哲学:Spring-native AI 集成。 它的核心概念不是 Chain,而是 Spring Bean 生命周期内的组件协作——ChatClient 是 Fluent API 入口,Advisor 是拦截器链,ChatModel 是可替换的 SPI。框架深度绑定 Spring Boot 的 Auto-configuration 和 Externalized Configuration 机制。
关键区别: LangChain4j 的数据流是开发者显式编排的 Chain;Spring AI 的数据流是 ChatClient 请求经过 Advisor 拦截器链后到达 ChatModel——这与 Spring MVC 中 HandlerInterceptor 的工作方式同构。如果你熟悉 Spring 的拦截器模式,你已经理解了 Spring AI 的核心架构。
2.2 选型决策表
| 决策维度 | LangChain4j | Spring AI | 判断 / 推荐 |
|---|---|---|---|
| 与 Spring 生态集成 | 可选集成(有 Spring Boot Starter,但非必须) | 原生深度集成(Auto-config、Actuator、Micrometer) | 如果你的应用已经是 Spring Boot → 选 Spring AI。 原生集成意味着零额外配置的可观测性、健康检查、配置管理 |
| 非 Spring 环境 | 完全支持(Quarkus、Micronaut、纯 Java) | 强依赖 Spring Boot(脱离 Spring 基本不可用) | 如果你不用 Spring Boot → 选 LangChain4j。 Spring AI 没有脱离 Spring 运行的设计意图 |
| AI 编排复杂度 | 内置丰富的 Chain 编排原语(SequentialChain、ConditionalChain 等) | 通过 Advisor 链实现,编排能力相对基础 | 如果你需要复杂的多步 AI 管道编排 → LangChain4j 的 Chain 模型更直观。 Spring AI 的 Advisor 更适合横切关注点(日志、限流、缓存),不适合业务流程编排 |
| Provider 覆盖度 | 支持 15+ Provider | 支持 20+ Provider(含 OpenAI SDK Official 新模式) | Provider 覆盖度两者接近,不是选型的关键变量 |
| MCP 协议支持 | 无内置支持 | 完整支持(Client + Server + 5 种传输模式) | 如果你需要 MCP 生态 → 只有 Spring AI。 这是 Spring AI 1.1.x 的差异化能力 |
| 可测试性 | 需要手动 Mock 或使用测试替身 | 与 Spring Test 深度集成(@MockBean、Testcontainers 支持) | Spring AI 的测试体验显著优于 LangChain4j,因为 AI 组件是标准 Spring Bean |
| 学习曲线 | 需要学习 LangChain 概念模型(Chain、Memory、Retriever 等) | 如果你已经懂 Spring Boot,增量学习成本很低 | 对 Spring 开发者 → Spring AI 学习成本更低。 概念模型复用了你已有的 Spring 知识 |
| 社区成熟度 | 社区活跃,API 稳定性较高 | API 仍在快速演进(1.0→1.1 有 Breaking Changes) | 两者都尚未完全稳定,但 Spring AI 有 Spring 团队的长期维护承诺 |
2.3 我的结论
对于 Spring Boot 技术栈的团队,我推荐 Spring AI 作为默认选择。 理由不是它 "更好",而是它的成本结构更优:
- 集成成本趋近于零 — 加一个 Starter 依赖就获得 Auto-configured 的 ChatModel、Observability、Health Check
- 认知成本趋近于零 — Advisor ≈ HandlerInterceptor,ChatClient ≈ WebClient,PromptTemplate ≈ Thymeleaf,所有概念都有 Spring 世界的对应物
- 运维成本趋近于零 — Micrometer 的 Trace/Metric 自动注入,与你已有的 Prometheus/Grafana 体系无缝对接
唯一不推荐 Spring AI 的场景: 你的应用不在 Spring 生态中(例如使用 Quarkus 或 Vert.x),或者你需要极其复杂的 AI 工作流编排(此时 LangChain4j 的 Chain 模型更有表达力)。
三、Spring AI 的核心抽象模型
3.1 四层抽象架构
Spring AI 的组件不是平铺的——它们有明确的层次关系:
这张图揭示了一个关键的设计意图:业务代码只应该接触第 1 层(ChatClient),而不应该直接调用第 3 层(ChatModel)。
为什么?因为 ChatClient 的 Fluent API 不仅仅是语法糖——它是一个请求管道,Advisor 链挂载在这个管道上。如果你绕过 ChatClient 直接调用 ChatModel,你会丢失:
- Memory Advisor(对话记忆自动注入)
- RAG Advisor(检索增强自动注入)
- Tool Calling Advisor(工具调用自动路由)
- 你自己实现的任何自定义 Advisor(日志、限流、缓存等)
3.2 Auto-configuration 的实际工作机制
当你在 pom.xml 中添加 spring-ai-starter-model-openai 时,Spring Boot 的 Auto-configuration 会做以下事情:
最不显眼但最关键的一步: @ConditionalOnClass 检测。这意味着 Spring AI 的 Provider 装配是声明式的——classpath 上有哪个 Starter,就自动装配哪个 Provider。你不需要写任何 @Bean 配置方法来创建 ChatModel。
这与 Spring Data 的设计一脉相承:spring-boot-starter-data-jpa 自动配置 EntityManagerFactory,spring-ai-starter-model-openai 自动配置 OpenAiChatModel。Spring AI 不是在发明新概念,而是把已经被证明有效的 Spring 模式应用到 AI 领域。
3.3 Spring AI 的概念映射表
如果你已经熟悉 Spring 生态,以下映射表会帮助你快速建立心智模型:
| Spring AI 概念 | Spring 生态中的对应物 | 为什么这么设计 |
|---|---|---|
| ChatClient | WebClient / RestClient | Fluent API 构建请求,支持同步和响应式两种调用模式 |
| Advisor | HandlerInterceptor / AOP Advice | 在请求到达 Model 之前/之后执行横切逻辑(Memory、RAG、Tool) |
| ChatModel | JdbcTemplate / RestTemplate | 底层基础设施抽象,业务代码不应直接使用 |
| PromptTemplate | Thymeleaf / StringTemplate | 参数化模板,支持变量替换和资源文件加载 |
| Structured Output Converter | HttpMessageConverter / Jackson ObjectMapper | 将非结构化的 LLM 输出转换为类型安全的 Java 对象 |
| VectorStore | Spring Data Repository | 统一的向量存储抽象,屏蔽底层引擎差异 |
| Auto-configuration | spring-boot-starter-data-jpa 等 | 基于 classpath 和配置自动装配 AI 组件 |
如果你理解 WebClient 的设计思路,你就理解了 ChatClient;如果你理解 HandlerInterceptor,你就理解了 Advisor。Spring AI 没有要求你学习全新的概念体系——它复用了你已有的 Spring 知识。
四、生产环境的失败模式
理解框架定位不仅是学术讨论——错误的定位认知会直接导致生产事故。以下是我观察到的三种最常见的失败模式:
4.1 失败模式一:绕过 ChatClient 直接调用 ChatModel
// ❌ 错误:直接注入 ChatModel 并调用
// 后果:丢失所有 Advisor(Memory、RAG、Tool、Observability)
@Service
public class ChatService {
private final ChatModel chatModel;
// 这样写可以 "跑通",但你丢失了 Spring AI 80% 的能力
public String chat(String input) {
return chatModel.call(new Prompt(input))
.getResult().getOutput().getText();
}
}// ✅ 正确:使用 ChatClient 作为入口
// ChatClient 会自动经过 Advisor 链处理
@Service
public class ChatService {
private final ChatClient chatClient;
// ChatClient.Builder 是 Spring Bean,通过构造器注入
public ChatService(ChatClient.Builder builder) {
this.chatClient = builder.build();
}
public String chat(String input) {
return chatClient.prompt()
.user(input)
.call()
.content();
}
}4.2 失败模式二:把 Spring AI 当成编排引擎
// ❌ 错误:试图用 Spring AI 实现 LangChain 风格的链式编排
// Spring AI 没有 Chain 原语,硬写会变成难以维护的面条代码
public String complexPipeline(String input) {
// 第一步:分类
String category = chatClient.prompt().user("分类:" + input).call().content();
// 第二步:根据分类选择不同的处理逻辑
if (category.contains("技术")) {
// 第三步:检索相关文档...
// 第四步:生成回答...
}
// 这种代码会迅速膨胀到不可维护
}// ✅ 正确:复杂编排逻辑用 Advisor 链 + 标准 Spring Service 层实现
// Advisor 负责横切关注点,Service 层负责业务流程
@Service
public class SmartChatService {
private final ChatClient chatClient;
public SmartChatService(ChatClient.Builder builder,
QuestionAnswerAdvisor ragAdvisor,
MessageChatMemoryAdvisor memoryAdvisor) {
this.chatClient = builder
.defaultAdvisors(memoryAdvisor, ragAdvisor)
.build();
}
// Advisor 链自动处理 Memory 和 RAG,业务代码保持简洁
public String chat(String conversationId, String input) {
return chatClient.prompt()
.user(input)
.advisors(a -> a.param("chat_memory_conversation_id", conversationId))
.call()
.content();
}
}4.3 失败模式三:忽略 Auto-configuration 的条件装配
# ❌ 危险:同时引入两个 Chat Provider 的 Starter 但不指定主选
# Spring Boot 会装配两个 ChatModel Bean,注入时报 NoUniqueBeanDefinitionException
# pom.xml 中同时有:
# - spring-ai-starter-model-openai
# - spring-ai-starter-model-deepseek# ✅ 正确方案 A:只引入一个 Starter(推荐)
# ✅ 正确方案 B:如果确实需要多 Provider,用 @Qualifier 区分
# ✅ 正确方案 C:禁用其中一个的 Auto-configuration
spring:
ai:
openai:
chat:
enabled: false # 禁用 OpenAI Chat,保留 DeepSeek五、已知局限与本文建议不适用的场景
每个技术推荐都有边界条件。以下是 Spring AI「Spring-native 集成」哲学的已知局限:
5.1 强绑定 Spring Boot
Spring AI 不是一个可以在 Quarkus、Micronaut 或纯 Java 环境中运行的框架。它的 Auto-configuration、Externalized Configuration、Observability 集成全部依赖 Spring Boot 基础设施。如果你的技术栈不是 Spring Boot,Spring AI 不适合你。
5.2 API 稳定性仍在演进
Spring AI 1.0 到 1.1 之间存在 Breaking Changes(FunctionCallback → ToolCallback、Advisor 接口变更)。虽然有 Spring 团队的长期维护承诺,但在 API 完全稳定之前(预计 2.0),你需要为版本升级预留迁移成本。
5.3 编排能力弱于专用引擎
如果你的场景需要复杂的多步 AI 管道(条件分支、并行执行、循环重试、人工审批节点),Spring AI 的 Advisor 链不是为此设计的。此时建议:
- 业务编排逻辑用 Spring 标准的 Service 层 + 状态机实现
- AI 调用通过 ChatClient 在编排的每一步中完成
- 或者评估 LangChain4j 的 Chain 模型是否更匹配你的需求
5.4 Provider 专有特性的泄漏
Spring AI 的 ChatModel 抽象屏蔽了 Provider 差异,但某些 Provider 的专有特性(如 OpenAI 的 Function Calling 特定参数、Anthropic 的 XML 格式偏好)需要通过 Provider 特定的 ChatOptions 子类访问。一旦使用这些特性,Provider 切换成本不再为零。