LangChain4j Agent 开发指南:用 Java 构建智能应用
前言
随着大语言模型(LLM)的快速发展,越来越多的开发者希望将 AI 能力集成到自己的应用中。LangChain4j 是 LangChain 的 Java 实现版本,为 Java 开发者提供了构建 AI 应用的完整工具链。
本文将从零开始,介绍如何使用 LangChain4j + Spring Boot 构建一个功能完整的 AI Agent,包括:
- ✅ AI Services 构建模式
- ✅ Function Calling 工具系统
- ✅ 对话记忆管理
- ✅ 流式响应处理
- ✅ 对话历史持久化
什么是 LangChain4j?
LangChain4j 是一个用于开发由大语言模型驱动的应用程序的 Java 框架,提供了以下核心能力:
- 统一的 LLM 抽象: 支持 OpenAI、Azure OpenAI、Google Gemini、Claude 等多种模型
- AI Services: 通过接口 + 注解定义 AI 能力
- Function Calling: 让 AI 自动调用 Java 方法获取数据
- 对话记忆: 管理对话上下文,支持多种存储策略
- 流式输出: 实时流式返回 AI 响应

LangChain4j Layered Architecture
LangChain4j 架构图
快速开始
1. 添加依赖
在 pom.xml 中添加 LangChain4j 依赖:
<dependencies> <!-- LangChain4j Spring Boot Starter --> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-spring-boot-starter</artifactId> <version>0.35.0</version> </dependency>
<!-- OpenAI 集成 (可替换为其他模型提供商) --> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-open-ai-spring-boot-starter</artifactId> <version>0.35.0</version> </dependency></dependencies>2. 配置 LLM 连接
在 application.yml 中配置模型参数:
langchain4j: open-ai: chat-model: api-key: ${OPENAI_API_KEY} base-url: https://api.openai.com/v1 # 或自定义 API 端点 model-name: gpt-4o-mini temperature: 0.7 timeout: 60s💡 提示: 可以使用兼容 OpenAI API 的其他模型(如 GLM-4、Qwen、DeepSeek 等),只需修改
base-url和model-name。
核心概念 Services
什么是 AI Services?
AI Services 是 LangChain4j 的核心抽象,通过 接口 + 注解 的方式定义 AI 能力,类似于 Spring Data JPA 的 Repository 模式。
定义 AI Agent 接口
import dev.langchain4j.service.SystemMessage;import dev.langchain4j.service.UserMessage;import dev.langchain4j.service.MemoryId;import dev.langchain4j.service.TokenStream;
public interface DataAnalystAgent {
@SystemMessage(""" 你是一个数据分析助手。你的职责是: 1. 根据用户问题,选择合适的工具查询数据 2. 分析数据趋势,识别异常模式 3. 生成专业的分析报告
【可用工具】 - queryStatistics: 查询统计数据 - analyzeTrend: 分析趋势 - generateReport: 生成报告
【工作流程】 1. 理解用户问题,确定需要哪些数据 2. 依次调用工具收集原始数据 3. 进行分析和总结 4. 用专业但易懂的语言回复用户 """) TokenStream chat( @MemoryId String conversationId, @UserMessage String question );}注解说明
@SystemMessage: 定义 AI 的系统提示词(角色、能力、工作流程)@UserMessage: 标记用户输入参数@MemoryId: 标识对话会话 ID(用于记忆管理)- 返回值
TokenStream: 流式返回 AI 响应
Function Calling:让 AI 调用 Java 方法
什么是 Function Calling?
Function Calling 允许 AI 在回答问题时,自动调用 Java 方法获取实时数据。

Function Calling 工作流程
定义工具类
使用 @Tool 注解定义可被 AI 调用的方法:
import dev.langchain4j.agent.tool.Tool;import dev.langchain4j.agent.tool.P;import lombok.RequiredArgsConstructor;import org.springframework.stereotype.Component;
@Component@RequiredArgsConstructorpublic class DataQueryTools {
private final DataRepository dataRepository;
@Tool("查询指定时间范围内的统计数据") public String queryStatistics( @P("开始日期,格式 YYYY-MM-DD") String startDate, @P("结束日期,格式 YYYY-MM-DD") String endDate ) { // 查询数据库 List<DataRecord> records = dataRepository.findByDateBetween(startDate, endDate);
// 统计分析 long totalCount = records.size(); double avgValue = records.stream() .mapToDouble(DataRecord::getValue) .average() .orElse(0.0);
// 返回格式化结果 return String.format( "时间范围: %s 至 %s\n" + "记录总数: %d 条\n" + "平均值: %.2f", startDate, endDate, totalCount, avgValue ); }
@Tool("查询最近N天的趋势数据") public String queryTrend( @P("查询天数,例如 7 表示最近7天") int days ) { LocalDate endDate = LocalDate.now(); LocalDate startDate = endDate.minusDays(days);
List<DataRecord> records = dataRepository.findByDateBetween(startDate, endDate);
// 按日期分组统计 Map<LocalDate, Double> dailyAvg = records.stream() .collect(Collectors.groupingBy( DataRecord::getDate, Collectors.averagingDouble(DataRecord::getValue) ));
// 格式化输出 StringBuilder result = new StringBuilder("每日趋势:\n"); dailyAvg.entrySet().stream() .sorted(Map.Entry.comparingByKey()) .forEach(entry -> { result.append(String.format( "%s: %.2f\n", entry.getKey(), entry.getValue() )); });
return result.toString(); }}注解说明
@Tool("工具描述"): 告诉 AI 这个方法的用途,AI 会根据描述决定是否调用@P("参数说明"): 描述参数的含义和格式要求,帮助 AI 正确传参
⚠️ 重要: 工具描述和参数说明要清晰准确,这直接影响 AI 的调用准确率。
配置 AI Agent Bean
使用 AiServices 构建器将接口、模型、工具组装起来:
import dev.langchain4j.memory.chat.MessageWindowChatMemory;import dev.langchain4j.model.chat.StreamingChatLanguageModel;import dev.langchain4j.model.openai.OpenAiStreamingChatModel;import dev.langchain4j.service.AiServices;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;
@Configuration@RequiredArgsConstructorpublic class LangChain4jConfig {
private final DataQueryTools dataQueryTools; private final AnalysisTools analysisTools;
@Value("${langchain4j.open-ai.chat-model.api-key}") private String apiKey;
@Value("${langchain4j.open-ai.chat-model.base-url}") private String baseUrl;
@Value("${langchain4j.open-ai.chat-model.model-name}") private String modelName;
@Bean public StreamingChatLanguageModel streamingChatLanguageModel() { return OpenAiStreamingChatModel.builder() .apiKey(apiKey) .baseUrl(baseUrl) .modelName(modelName) .temperature(0.7) .timeout(Duration.ofSeconds(60)) .build(); }
@Bean public DataAnalystAgent dataAnalystAgent( StreamingChatLanguageModel model ) { return AiServices.builder(DataAnalystAgent.class) .streamingChatLanguageModel(model) .chatMemoryProvider(memoryId -> MessageWindowChatMemory.withMaxMessages(20) // 保留最近20条消息 ) .tools(dataQueryTools, analysisTools) // 注册工具 .build(); }}配置说明
streamingChatLanguageModel(): 配置流式 LLM 客户端chatMemoryProvider(): 配置对话记忆,保留最近 N 条消息tools(): 注册工具类,AI 可以调用这些工具中的@Tool方法
对话记忆管理
为什么需要对话记忆?
AI 需要理解上下文才能进行连贯的对话。例如:
用户: 查询最近7天的数据AI: [返回数据统计]
用户: 趋势如何? 👈 AI 需要记住之前讨论的是"最近7天"AI: 趋势呈上升态势...内置记忆策略
LangChain4j 提供多种记忆实现:
| 记忆类型 | 说明 | 适用场景 |
|---|---|---|
MessageWindowChatMemory | 保留最近 N 条消息 | 短对话,内存有限 |
TokenWindowChatMemory | 保留最近 N 个 Token | 精确控制上下文长度 |
ChatMemory (自定义) | 从数据库加载历史 | 长期对话,需持久化 |
对话记忆工作原理
自定义持久化记忆
通过 chatMemoryProvider 实现从数据库加载历史:
@Beanpublic DataAnalystAgent dataAnalystAgent( StreamingChatLanguageModel model, ChatHistoryService chatHistoryService) { return AiServices.builder(DataAnalystAgent.class) .streamingChatLanguageModel(model) .chatMemoryProvider(memoryId -> { MessageWindowChatMemory memory = MessageWindowChatMemory.withMaxMessages(20);
// 从数据库加载历史消息 List<ChatMessage> history = chatHistoryService.loadRecentMessages( memoryId, 20 );
// 恢复到内存 for (ChatMessage msg : history) { if ("user".equals(msg.getRole())) { memory.add(UserMessage.from(msg.getContent())); } else if ("assistant".equals(msg.getRole())) { memory.add(AiMessage.from(msg.getContent())); } }
return memory; }) .tools(dataQueryTools, analysisTools) .build();}流式响应处理
为什么需要流式响应?
流式响应可以让用户实时看到 AI 的生成过程,类似 ChatGPT 的打字效果,提升用户体验。
实现流式接口
使用 Server-Sent Events (SSE) 实现流式传输:
import org.springframework.http.MediaType;import org.springframework.http.codec.ServerSentEvent;import org.springframework.web.bind.annotation.*;import reactor.core.publisher.Flux;
@RestController@RequestMapping("/api/v1/analyst")@RequiredArgsConstructorpublic class AnalystController {
private final DataAnalystAgent agent; private final ChatHistoryService chatHistoryService;
@PostMapping(value = "/chat-stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux<ServerSentEvent<String>> chatStream( @RequestParam String question, @RequestParam String conversationId ) { return Flux.create(sink -> { try { TokenStream tokenStream = agent.chat(conversationId, question); StringBuilder fullResponse = new StringBuilder();
tokenStream .onNext(token -> { // 实时推送每个 Token fullResponse.append(token); ServerSentEvent<String> event = ServerSentEvent.<String>builder() .event("message") .data(token) .build(); sink.next(event); }) .onToolExecuted(toolExecution -> { // 推送工具调用信息 String toolInfo = String.format( "[工具调用: %s]", toolExecution.request().name() ); ServerSentEvent<String> event = ServerSentEvent.<String>builder() .event("tool") .data(toolInfo) .build(); sink.next(event); }) .onComplete(response -> { // 保存对话历史 chatHistoryService.saveMessage( conversationId, "user", question ); chatHistoryService.saveMessage( conversationId, "assistant", fullResponse.toString() );
// 发送完成事件 ServerSentEvent<String> event = ServerSentEvent.<String>builder() .event("done") .data("") .build(); sink.next(event); sink.complete(); }) .onError(error -> { // 错误处理 ServerSentEvent<String> event = ServerSentEvent.<String>builder() .event("error") .data("服务暂时不可用") .build(); sink.next(event); sink.error(error); }) .start();
} catch (Exception e) { sink.error(e); } }); }}流式事件说明
| 事件类型 | 说明 | 数据内容 |
|---|---|---|
message | AI 生成的文本片段 | 单个 Token 或词组 |
tool | 工具调用通知 | 工具名称 |
done | 流式输出完成 | 空字符串 |
error | 错误发生 | 错误信息 |
高级特性:多工具协作
场景:生成数据分析报告
假设我们需要 AI 完成以下任务:
- 查询最近 7 天的数据
- 分析趋势
- 检测异常
- 生成可视化图表
- 组装完整报告
AI 自动编排工作流程

定义多个工具类
数据查询工具:
@Component@RequiredArgsConstructorpublic class DataQueryTools { @Tool("查询统计数据") public String queryStatistics(String startDate, String endDate) { // 返回统计数据 }}数据分析工具:
@Componentpublic class AnalysisTools { @Tool("分析趋势是上升、下降还是稳定") public String analyzeTrend(String trendData) { // 返回趋势分析结果 }
@Tool("检测异常峰值") public String detectAnomalies(String dailyData) { // 返回异常检测结果 }}报告生成工具:
@Componentpublic class ReportTools { @Tool("生成 Markdown 格式的分析报告") public String generateMarkdownReport( String title, String statistics, String trendAnalysis, String anomalies, String conclusions ) { return String.format(""" # %s
## 📊 统计数据概览 %s
## 📈 趋势分析 %s
## ⚠️ 异常检测 %s
## 💡 结论与建议 %s """, title, statistics, trendAnalysis, anomalies, conclusions ); }
@Tool("生成趋势折线图(Mermaid 格式)") public String generateTrendChart(String trendData) { // 解析数据并生成 Mermaid 图表代码 }}AI 自动编排执行
在 System Message 中指导 AI 的工作流程:
@SystemMessage(""" 你是数据分析助手。当用户要求生成报告时,请按以下流程操作:
1. 调用 queryStatistics 查询原始数据 2. 调用 analyzeTrend 分析趋势 3. 调用 detectAnomalies 检测异常 4. 调用 generateTrendChart 生成图表 5. 调用 generateMarkdownReport 组装报告 6. 将完整报告返回给用户
重要规则: - 必须先查询数据,再进行分析 - 图表数据必须来自查询结果,不要编造 - 报告要包含图表可视化 """)TokenStream chat(@MemoryId String conversationId, @UserMessage String question);用户输入:
生成最近7天的数据分析报告AI 执行流程:
1. [工具调用: queryStatistics] → 获取统计数据2. [工具调用: analyzeTrend] → 分析趋势3. [工具调用: detectAnomalies] → 检测异常4. [工具调用: generateTrendChart] → 生成图表5. [工具调用: generateMarkdownReport] → 组装报告6. 返回完整的 Markdown 报告(含图表)最佳实践
1. System Prompt 设计
✅ 好的 System Prompt:
@SystemMessage(""" 你是数据分析助手。职责: 1. 查询数据: 使用 queryStatistics 工具 2. 分析趋势: 使用 analyzeTrend 工具 3. 生成报告: 使用 generateReport 工具
工作流程: 1. 理解用户问题 2. 依次调用工具 3. 综合分析结果 4. 用专业语言回复
重要规则: - 先查询数据,再分析 - 数字保留2位小数 - 不要编造数据 """)❌ 差的 System Prompt:
@SystemMessage("你是助手,帮用户查询数据") // 太简单,AI 不知道如何操作2. 工具粒度划分
✅ 合理拆分:
queryStatistics: 查询统计数据analyzeTrend: 分析趋势generateReport: 生成报告
❌ 过度耦合:
queryAndAnalyze: 一个方法做所有事情(AI 无法灵活组合)
3. 参数规范设计
✅ 清晰的参数说明:
@Tool("查询统计数据")public String queryStatistics( @P("开始日期,格式 YYYY-MM-DD,例如 2024-01-01") String startDate, @P("结束日期,格式 YYYY-MM-DD,例如 2024-01-07") String endDate)❌ 模糊的参数说明:
@Tool("查询统计数据")public String queryStatistics( @P("开始日期") String startDate, // 格式不明确,AI 可能传错 @P("结束日期") String endDate)4. 错误处理
在工具方法中添加异常处理,返回友好的错误信息:
@Tool("查询统计数据")public String queryStatistics(String startDate, String endDate) { try { LocalDate start = LocalDate.parse(startDate); LocalDate end = LocalDate.parse(endDate);
if (end.isBefore(start)) { return "错误: 结束日期不能早于开始日期"; }
// 执行查询...
} catch (DateTimeParseException e) { return "错误: 日期格式不正确,请使用 YYYY-MM-DD 格式"; } catch (Exception e) { return "错误: 查询失败,请稍后重试"; }}5. 日志记录
在工具方法中添加日志,方便调试:
@Tool("查询统计数据")public String queryStatistics(String startDate, String endDate) { log.info("工具调用: queryStatistics - {} 到 {}", startDate, endDate);
// 执行查询...
log.info("查询完成,返回 {} 条记录", records.size()); return result;}完整系统架构
将所有组件整合在一起,完整的 LangChain4j Agent 系统架构如下:
完整示例:数据分析 Agent
以下是一个完整的 数据分析 Agent 示例,展示所有核心特性的集成:
1. 定义 Agent 接口
public interface DataAnalystAgent { @SystemMessage(""" 你是数据分析助手。职责: 1. 查询数据 → queryStatistics 2. 分析趋势 → analyzeTrend 3. 检测异常 → detectAnomalies 4. 生成报告 → generateReport
工作流程: 1. 理解用户问题 2. 依次调用工具 3. 综合分析结果 4. 用专业语言回复 """) TokenStream chat(@MemoryId String conversationId, @UserMessage String question);}2. 定义工具类
@Component@RequiredArgsConstructorpublic class DataQueryTools { private final DataRepository dataRepository;
@Tool("查询统计数据") public String queryStatistics( @P("开始日期,格式 YYYY-MM-DD") String startDate, @P("结束日期,格式 YYYY-MM-DD") String endDate ) { List<DataRecord> records = dataRepository.findByDateBetween(startDate, endDate); return formatStatistics(records); }}
@Componentpublic class AnalysisTools { @Tool("分析趋势") public String analyzeTrend(@P("趋势数据") String trendData) { // 分析逻辑... }
@Tool("检测异常") public String detectAnomalies(@P("每日数据") String dailyData) { // 异常检测逻辑... }}3. 配置 Agent Bean
@Configuration@RequiredArgsConstructorpublic class LangChain4jConfig { private final DataQueryTools dataQueryTools; private final AnalysisTools analysisTools;
@Bean public DataAnalystAgent dataAnalystAgent(StreamingChatLanguageModel model) { return AiServices.builder(DataAnalystAgent.class) .streamingChatLanguageModel(model) .chatMemoryProvider(memoryId -> MessageWindowChatMemory.withMaxMessages(20) ) .tools(dataQueryTools, analysisTools) .build(); }}4. 实现流式接口
@RestController@RequestMapping("/api/v1/analyst")@RequiredArgsConstructorpublic class AnalystController { private final DataAnalystAgent agent;
@PostMapping(value = "/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux<ServerSentEvent<String>> chat( @RequestParam String question, @RequestParam String conversationId ) { return Flux.create(sink -> { TokenStream stream = agent.chat(conversationId, question);
stream .onNext(token -> sink.next( ServerSentEvent.<String>builder() .event("message") .data(token) .build() )) .onComplete(response -> { sink.next( ServerSentEvent.<String>builder() .event("done") .data("") .build() ); sink.complete(); }) .start(); }); }}常见问题
Q1: 如何切换到其他 LLM?
LangChain4j 支持多种模型,只需更换依赖和配置:
使用 Azure OpenAI:
<dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-azure-open-ai-spring-boot-starter</artifactId></dependency>langchain4j: azure-open-ai: chat-model: endpoint: https://your-resource.openai.azure.com api-key: ${AZURE_OPENAI_API_KEY} deployment-name: gpt-4使用 Google Gemini:
<dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-vertex-ai-gemini-spring-boot-starter</artifactId></dependency>Q2: 如何限制工具调用次数?
在 System Prompt 中明确指示:
@SystemMessage(""" 你是助手。重要规则: - 每次回答最多调用 3 个工具 - 优先使用已有数据,避免重复查询 """)Q3: 如何处理长上下文?
使用 TokenWindowChatMemory 精确控制 Token 数:
.chatMemoryProvider(memoryId -> TokenWindowChatMemory.withMaxTokens(4000, new OpenAiTokenizer()))Q4: 如何实现多租户对话隔离?
通过 @MemoryId 区分不同用户:
String memoryId = userId + ":" + conversationId;agent.chat(memoryId, question);总结
通过本文,我们学习了如何使用 LangChain4j + Spring Boot 构建 AI Agent 应用,核心要点包括:
- ✅ AI Services: 通过接口 + 注解定义 AI 能力
- ✅ Function Calling: 让 AI 自动调用 Java 方法获取数据
- ✅ 对话记忆: 管理上下文,支持持久化
- ✅ 流式响应: 实时推送 AI 生成内容
- ✅ 多工具协作: AI 自动编排多个工具完成复杂任务
LangChain4j 的优势:
- 🎯 类型安全: 编译时检查,避免运行时错误
- 🚀 Spring 集成: 无缝集成 Spring Boot 生态
- 🔧 工具生态: 支持多种 LLM、向量数据库、嵌入模型
- 📚 文档完善: 官方文档 + 丰富示例
下一步建议:
- 📖 阅读 LangChain4j 官方文档
- 🔍 探索 RAG(检索增强生成)能力
- 🎨 集成向量数据库(如 Milvus、Qdrant)
- 🧪 尝试其他 LLM 模型(Claude, Gemini, DeepSeek)
参考资料
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或赞助支持!