前言
在上一篇文章中,我们成功地将大模型能力封装成了一个标准的Spring Boot服务。我们有了Controller、Service,通过依赖注入管理着OpenAIClient
。这是一个巨大的进步,我们的AI应用已经具备了企业级开发的雏形。
但是,当我们想实现更复杂的功能时,挑战也随之而来:
- 多轮对话:如何让AI记住我们之前的谈话内容?我们需要手动管理一个
List<ChatMessage>
,并在每次请求时都把它传来传去,这非常繁琐且容易出错。 - 结构化输出:如何确保AI返回的是一个我们可以直接转换为Java对象的JSON,而不是一段随心所欲的文本?
- 连接外部知识:如何让AI回答关于我们自己公司产品文档的问题?
- 调用工具:如何让AI在回答问题时,能去调用一个外部API(比如查询实时天气)?
只靠我们目前使用的官方SDK,要实现这些功能,需要编写大量复杂的“胶水代码”。幸运的是,社区已经为我们准备好了一个功能极其强大的“瑞士军刀”——LangChain4j。
今天,我们将正式引入这个Java领域最流行的LLM应用开发框架,看看它是如何将我们从繁杂的底层逻辑中解放出来的。
第一步:什么是LangChain4j?它解决了什么问题?
我们可以用一个简单的类比来理解:
如果说官方SDK(如
openai-java-client
)是为我们提供了一台性能强劲的汽车引擎,那么LangChain4j就是为我们提供了整车的底盘、变速箱、方向盘和智能驾驶系统。
它不是要替代SDK,而是构建于SDK之上,让我们能更轻松地“驾驶”AI,构建完整的、复杂的应用。
LangChain4j的核心思想是 “链(Chain)” ,也就是将与大模型交互的多个步骤串联起来,形成一个自动化的工作流。它将复杂的AI应用抽象为几个核心组件:
- 语言模型 (Language Models):对不同AI服务商(如OpenAI, DeepSeek, Google Gemini)的统一接口。
- 提示模板 (Prompt Templates):创建可复用、可动态填充的提示词。
- 记忆 (Memory):为对话提供短期或长期的记忆能力。
- 输出解析器 (Output Parsers):将模型的文本输出强制转换为结构化的Java对象。
- 检索器 (Retrievers) 与 文档 (Documents):用于实现RAG(检索增强生成),让AI能连接外部知识库。
今天,我们先从它最神奇、最简单的功能之一AiServices
入手,直观感受它的威力。
第二步:在Spring Boot中集成LangChain4j
LangChain4j与Spring Boot的集成非常成熟,我们只需要引入它的spring-boot-starter
。
修改
pom.xml
在pom.xml
中,添加LangChain4j的Spring Boot Starter依赖。注意:你可以移除上一章添加的openai-java-client
依赖,因为langchain4j-open-ai-spring-boot-starter
已经包含了它。<dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-open-ai-spring-boot-starter</artifactId> <version>0.32.0</version> <!-- 使用最新的稳定版本 --> </dependency>
修改
application.properties
LangChain4j的配置项遵循着清晰的命名空间。我们将之前的配置修改为LangChain4j的格式:# 服务器端口号 server.port=8080 # LangChain4j Configuration for DeepSeek langchain4j.open-ai.chat-model.api-key=${DEEPSEEK_API_KEY:} langchain4j.open-ai.chat-model.base-url=https://api.deepseek.com/v1/ langchain4j.open-ai.chat-model.model-name=deepseek-chat langchain4j.open-ai.chat-model.temperature=0.7 langchain4j.open-ai.chat-model.max-tokens=1024
仅仅这样配置,LangChain4j的Starter就会自动为我们创建一个配置好的
ChatLanguageModel
Bean。我们已经不需要自己写AiClientConfig
了!
第三步:代码重构 – 见证AiServices
的魔力
现在,我们将重构上一章的ChatService
,让你看看代码可以被简化到什么程度。LangChain4j提供了一个名为AiServices
的工厂,它可以将一个Java接口,自动转换成一个可以与AI交互的实现类。
创建一个AI助手接口
在service
包下,创建一个新的接口Assistant.java
:package com.example.aidemoapp.service; public interface Assistant { String chat(String userMessage); }
这是一个普通的Java接口,只有一个
chat
方法。修改配置类
删除上一章的AiClientConfig.java
。新建一个AiServiceConfig.java
:package com.example.aidemoapp.config; import com.example.aidemoapp.service.Assistant; import dev.langchain4j.memory.chat.ChatMemoryProvider; import dev.langchain4j.memory.chat.MessageWindowChatMemory; import dev.langchain4j.model.chat.ChatLanguageModel; import dev.langchain4j.service.AiServices; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class AiServiceConfig { // 将LangChain4j自动配置好的ChatLanguageModel注入进来 @Bean public Assistant assistant(ChatLanguageModel chatLanguageModel) { // AiServices会为Assistant接口创建一个代理实现 return AiServices.builder(Assistant.class) .chatLanguageModel(chatLanguage-model) .build(); } }
重构
ChatService
现在我们的ChatService
变得异常简单:package com.example.aidemoapp.service; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @Service @RequiredArgsConstructor public class ChatService { // 直接注入我们定义的Assistant接口 private final Assistant assistant; public String getChatResponse(String userPrompt) { // 直接调用接口方法,就像调用一个普通的Java方法一样 return assistant.chat(userPrompt); } }
ChatController
完全不需要任何改动!
第四步:对比与思考
我们来对比一下前后的变化:
- 之前 (纯SDK):我们需要在
ChatService
中手动构建ChatCompletionCreateParams
对象,然后调用client.chat().completions().create()
,再从复杂的响应对象中解析出结果。 - 现在 (用LangChain4j):我们只定义了一个接口
Assistant
,然后就像调用一个本地方法一样调用assistant.chat()
。所有的API请求构建和响应解析都被LangChain4j在幕后优雅地处理了。
这到底发生了什么?
AiServices.create()
是一个神奇的工厂。当你调用assistant.chat("你好")
时,LangChain4j的代理实现会自动:
- 创建一个
ChatMessage
,角色是user
,内容是"你好"
。 - 构建一个完整的API请求。
- 调用我们配置好的
ChatLanguageModel
(也就是DeepSeek模型)。 - 等待响应,并自动解析出内容。
- 将内容作为
String
返回。
这就是框架的力量:它让你能够用业务逻辑的语言(assistant.chat(...)
)来编程,而不是用技术实现的语言。
总结
今天我们只是揭开了LangChain4j神秘面纱的一角,但其强大的生产力已经可见一斑。通过AiServices
,我们以一种前所未有的优雅方式重构了我们的AI服务。
我们不再需要自己去管理和创建OpenAIClient
,也不再需要手动拼装请求参数。LangChain4j的Spring Boot Starter和AiServices
工厂为我们处理了这一切。
但这仅仅是开始。LangChain4j真正的威力在于它那些可组合的模块。如何让我们的Assistant
拥有记忆?如何让它返回一个Java对象而不是String
?
下一篇预告:
《Java大模型开发入门 (6/15):对话的灵魂 – 深入理解LangChain4j中的模型、提示和解析器》—— 我们将深入LangChain4j的核心,学习如何通过提示模板(Prompt Templates)和输出解析器(Output Parsers)来驯服AI,让它按照我们的意愿进行思考和输出!