第2045篇:Spring AI vs LangChain4j——选哪个框架做AI应用
第2045篇:Spring AI vs LangChain4j——选哪个框架做AI应用
适读人群:正在选型Java AI框架的架构师和工程师 | 阅读时长:约19分钟 | 核心价值:深度对比两个框架的设计理念和功能细节,给出不同场景下的选型建议
团队讨论选型的时候,有人说用Spring AI,因为"Spring官方出的,质量有保证";有人说用LangChain4j,因为"社区更活跃,文档更好"。
争了半天,没人说清楚两个框架在技术上到底有什么差别。
我两个框架都用过,来说说真实的感受。
两个框架的定位差异
先说一个基本判断:这两个框架面向不同类型的Java开发者。
Spring AI的定位:让已有的Spring Boot项目平滑集成AI能力。如果你的项目已经是Spring全家桶,Spring AI是最自然的选择——配置方式、Bean管理、Autoconfigure都和Spring生态无缝衔接。
LangChain4j的定位:Java版的AI应用开发框架,功能更聚焦在AI应用的构建模式上。它的@AiService声明式接口,是它最大的差异化特性。
模型接入方式对比
// ===== Spring AI的模型配置 =====
// application.yml配置
// spring:
// ai:
// openai:
// api-key: ${OPENAI_API_KEY}
// chat:
// model: gpt-4o-mini
// temperature: 0.3
@Service
@RequiredArgsConstructor
public class SpringAiService {
// 直接注入,Autoconfigure自动配置
private final ChatClient chatClient;
public String ask(String question) {
return chatClient.prompt()
.user(question)
.call()
.content();
}
// 带System Prompt
public String askWithContext(String systemMsg, String userMsg) {
return chatClient.prompt()
.system(systemMsg)
.user(userMsg)
.call()
.content();
}
// 结构化输出
public ProductInfo extractProductInfo(String text) {
return chatClient.prompt()
.user("从以下文本提取商品信息:" + text)
.call()
.entity(ProductInfo.class); // 自动解析到DTO
}
}
// ===== LangChain4j的模型配置 =====
@Configuration
public class LangChain4jConfig {
@Bean
public ChatLanguageModel chatModel() {
return OpenAiChatModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.modelName("gpt-4o-mini")
.temperature(0.3)
.build();
}
}
@Service
@RequiredArgsConstructor
public class LangChain4jService {
private final ChatLanguageModel chatModel;
public String ask(String question) {
return chatModel.generate(question);
}
// 结构化输出(通过AI Service)
@AiService
interface ExtractorService {
@SystemMessage("从文本中提取商品信息,返回JSON格式")
ProductInfo extractProductInfo(String text);
}
}差别:Spring AI的配置更Spring-friendly(yml配置、Autoconfigure),LangChain4j需要手动写@Bean配置,但更灵活。
AI Service声明式接口
这是两个框架差别最大的地方:
// ===== LangChain4j的AI Service =====
// 这是LangChain4j最大的特色功能
@AiService
public interface ContractAnalysisService {
@SystemMessage("你是专业合同律师,请分析合同中的风险条款")
String analyzeRisks(String contractText);
@SystemMessage("从合同文本中提取关键信息")
ContractInfo extractInfo(String contractText);
@UserMessage("请分析合同:{{contract}},重点关注:{{focus}}")
String analyzeWithFocus(
@V("contract") String contractText,
@V("focus") String focusArea
);
// 带记忆的对话
@SystemMessage("你是合同咨询助手")
String chat(@MemoryId String sessionId, @UserMessage String message);
}
// 使用方式:像调普通Service一样
contractService.analyzeRisks(text);
contractService.chat("session-001", "这个违约金条款合理吗?");
// ===== Spring AI的等效实现 =====
// Spring AI 1.0以后也支持类似功能,但实现方式不同
@Service
public class SpringAiContractService {
private final ChatClient chatClient;
// 没有声明式接口,需要手写Service方法
public String analyzeRisks(String contractText) {
return chatClient.prompt()
.system("你是专业合同律师,请分析合同中的风险条款")
.user(contractText)
.call()
.content();
}
public ContractInfo extractInfo(String contractText) {
return chatClient.prompt()
.system("从合同文本中提取关键信息")
.user(contractText)
.call()
.entity(ContractInfo.class);
}
// Spring AI的Advisor机制(类似LangChain4j的记忆)
public String chat(String sessionId, String message) {
return chatClient.prompt()
.system("你是合同咨询助手")
.user(message)
.advisors(new MessageChatMemoryAdvisor(
new InMemoryChatMemory(), sessionId, 10))
.call()
.content();
}
}从代码量来看,LangChain4j的AI Service在接口定义清晰度上更有优势;Spring AI的写法更像标准的Spring Service,对传统Java开发者更熟悉。
RAG实现对比
// ===== Spring AI的RAG =====
@Configuration
public class SpringAiRagConfig {
// Spring AI的VectorStore(多种实现,配置风格统一)
@Bean
public VectorStore vectorStore(EmbeddingModel embeddingModel) {
return new PgVectorStore(jdbcTemplate, embeddingModel);
}
@Bean
public EmbeddingModel embeddingModel() {
return new OpenAiEmbeddingModel(
new OpenAiApi(System.getenv("OPENAI_API_KEY")));
}
}
@Service
@RequiredArgsConstructor
public class SpringAiRagService {
private final ChatClient chatClient;
private final VectorStore vectorStore;
public String query(String question) {
return chatClient.prompt()
.user(question)
// QuestionAnswerAdvisor自动检索相关文档,注入上下文
.advisors(new QuestionAnswerAdvisor(vectorStore,
SearchRequest.defaults().withTopK(5)))
.call()
.content();
}
// 文档入库
public void ingestDocument(String content, Map<String, Object> metadata) {
Document doc = new Document(content, metadata);
vectorStore.add(List.of(doc));
}
}
// ===== LangChain4j的RAG =====
@Configuration
@RequiredArgsConstructor
public class LangChain4jRagConfig {
@Bean
public KnowledgeBaseAssistant kbAssistant(
ChatLanguageModel model,
EmbeddingModel embeddingModel,
EmbeddingStore<TextSegment> store) {
ContentRetriever retriever = EmbeddingStoreContentRetriever.builder()
.embeddingStore(store)
.embeddingModel(embeddingModel)
.maxResults(5)
.minScore(0.7)
.build();
return AiServices.builder(KnowledgeBaseAssistant.class)
.chatLanguageModel(model)
.contentRetriever(retriever)
.build();
}
}
@AiService
interface KnowledgeBaseAssistant {
@SystemMessage("你是知识库助手,基于提供的文档内容回答问题")
String ask(String question);
}两个框架的RAG实现思路相似,Spring AI用Advisor注入,LangChain4j用ContentRetriever注入。Spring AI的Advisor机制更通用(不只是RAG),LangChain4j的ContentRetriever API更直观。
Tool Calling对比
// ===== Spring AI的Function Calling =====
@Service
public class WeatherFunction implements Function<WeatherRequest, WeatherResponse> {
@Override
public WeatherResponse apply(WeatherRequest request) {
// 调用天气API
String weather = callWeatherApi(request.city());
return new WeatherResponse(request.city(), weather, "25°C");
}
public record WeatherRequest(String city) {}
public record WeatherResponse(String city, String condition, String temperature) {}
}
// 注册Function
@Configuration
public class FunctionConfig {
@Bean
@Description("查询指定城市的当前天气")
public Function<WeatherFunction.WeatherRequest, WeatherFunction.WeatherResponse>
weatherFunction(WeatherFunction fn) {
return fn;
}
}
// 使用时指定Function名称
String response = chatClient.prompt()
.user("北京今天天气怎么样")
.functions("weatherFunction") // 通过Bean名称指定
.call()
.content();
// ===== LangChain4j的Tool =====
@Component
public class WeatherTools {
@Tool("查询指定城市的当前天气,返回天气状况和温度")
public String getWeather(@P("城市名称,如北京、上海") String city) {
String weather = callWeatherApi(city);
return String.format("%s当前天气:%s,温度:25°C", city, weather);
}
}
// 注册到AI Service(全局生效,不需要每次指定)
AiServices.builder(WeatherAssistant.class)
.chatLanguageModel(model)
.tools(weatherTools)
.build();LangChain4j的@Tool更简洁,注册后对整个AI Service全局生效;Spring AI需要在每次调用时通过.functions()指定启用哪些工具,更灵活但也更繁琐。
流式输出
// ===== Spring AI的流式输出 =====
@GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> streamResponse(@RequestParam String question) {
return chatClient.prompt()
.user(question)
.stream()
.content(); // 返回Flux<String>
}
// ===== LangChain4j的流式输出 =====
@GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter streamResponse(@RequestParam String question) {
SseEmitter emitter = new SseEmitter();
// LangChain4j使用StreamingChatLanguageModel
streamingModel.generate(
List.of(UserMessage.from(question)),
new StreamingResponseHandler<AiMessage>() {
@Override
public void onNext(String token) {
try {
emitter.send(token);
} catch (IOException e) {
emitter.completeWithError(e);
}
}
@Override
public void onComplete(Response<AiMessage> response) {
emitter.complete();
}
@Override
public void onError(Throwable error) {
emitter.completeWithError(error);
}
}
);
return emitter;
}Spring AI的流式输出更现代,直接返回Reactor的Flux;LangChain4j的StreamingResponseHandler是回调风格,集成Spring WebFlux需要额外封装。
综合对比
| 维度 | Spring AI | LangChain4j |
|---|---|---|
| 与Spring生态集成 | 原生无缝 | 良好(有Starter) |
| 声明式AI Service | 不支持(需手写Service) | 核心特性,非常成熟 |
| 流式输出 | Flux风格,与WebFlux天然集成 | 回调风格,需手动封装 |
| Tool/Function Calling | 需每次指定Function | 注册后全局生效 |
| RAG支持 | Advisor机制 | ContentRetriever机制 |
| 配置方式 | YAML + Autoconfigure | Java代码配置 |
| 文档质量 | 中等,更新频繁 | 较好,示例丰富 |
| 版本稳定性 | 1.0 GA(2024年) | 0.3x,接口变化较大 |
我的选型建议
选Spring AI的场景:
- 已有Spring Boot项目,需要快速集成AI能力
- 团队熟悉Spring生态,不想引入新的框架概念
- 需要与Spring Security、Spring Data等深度集成
- 项目使用响应式编程(WebFlux),需要Flux风格的流式输出
选LangChain4j的场景:
- 新项目,AI功能是核心能力,需要声明式接口降低代码复杂度
- AI Service有多个能力组合(记忆+工具+RAG),LangChain4j的AI Service组合更优雅
- 需要频繁迭代AI功能,声明式接口让改动更安全
- 团队是AI应用开发主攻方向,愿意接受框架的学习成本
实际上,两个框架的差别没有大到"选错了要推倒重来"的程度。如果你现在犹豫不决,就选Spring AI——和Spring生态的集成是它最大的优势,而且1.0 GA版本的接口稳定性更可靠。
