【Agent合集-01】《Java AI Agent实战:基于LangChain4j + GPT/DeepSeek构建智能体(工具/记忆/流式/多模态)》
目录
7.2 配合 Spring Boot WebFlux 实现 SSE
9.2 MCP(Model Context Protocol)标准化工具访问
一、AI Agent 的核心概念与架构
在 Java 中开发 AI Agent,本质上就是利用大语言模型(LLM)来构建一个能够自主执行任务、调用外部工具、记住对话上下文并做出决策的应用程序。一个生产级的 Agent 通常包含以下核心组件:
| 组件 | 职责说明 |
|---|---|
| 大脑(LLM) | 理解用户意图、生成自然语言回复、决定何时调用哪些工具 |
| 工具(Tools) | 通过 @Tool 注解将 Java 方法暴露给 LLM,让 Agent 能查询天气、读写数据库、调用 API 等- |
| 记忆(Memory) | 保存对话历史,实现多轮上下文感知;生产环境需持久化到 Redis/MySQL-49 |
| 规划(Planner) | 面对复杂任务时自动拆解成多步计划,按顺序调用工具执行 |
| Skills | LangChain4j 1.12.1+ 引入的能力,类似“技能包”,需要时才激活,避免 Prompt 过长 |
为什么选择 Java 而不是 Python?
相比 Python 的 LangChain 生态,Java 在以下方面具有独特优势:
-
强类型系统:编译期就能发现类型错误,降低运行时异常风险
-
生态无缝集成:Agent 可直接调用企业内部 Java 微服务,无需经过 HTTP/JSON 转换
-
可观测性:OpenTelemetry 原生支持,可追踪 LLM 调用和工具执行全过程
-
高性能启动:Quarkus + GraalVM 可实现亚秒级冷启动,内存占用仅 50-150 MB
当前 Java AI Agent 生态两大主流框架是:
-
LangChain4j:LangChain 的 Java 移植版,功能全面,对 Agent 支持更底层、更灵活
-
Spring AI:Spring 官方出品的 AI 抽象层,与 Spring Boot 生态无缝集成
本文以 LangChain4j 为主线,同时兼顾 Spring AI 的差异点。
二、开发环境搭建
2.1 最低环境要求
| 组件 | 版本要求 | 说明 |
|---|---|---|
| JDK | 21+(推荐 Corretto 21) | LangChain4j 0.35+ 需要 Java 21 |
| Maven | 3.9+ | 项目构建工具 |
| Spring Boot(可选) | 3.3.0+ | 如需整合 Spring 生态 |
| DeepSeek/OpenAI API | - | 注册获取 API Key |
2.2 Maven 核心依赖配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>java-ai-agent-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- LangChain4j 版本(2026年最新稳定版) -->
<langchain4j.version>0.35.0</langchain4j.version>
</properties>
<dependencies>
<!-- LangChain4j 核心模块 -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<!-- OpenAI 兼容客户端(支持 DeepSeek、OpenAI、智谱等) -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<!-- [可选] Skills 技能包支持(LangChain4j 1.12.1+) -->
<!-- <dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-skills</artifactId>
<version>1.12.1</version>
</dependency> -->
<!-- [可选] Spring Boot 集成 -->
<!-- <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.3.0</version>
</dependency> -->
<!-- 日志(推荐使用 SLF4J + Logback) -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.16</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>21</source>
<target>21</target>
<!-- 保留参数名,便于 LLM 理解工具参数 -->
<parameters>true</parameters>
</configuration>
</plugin>
</plugins>
</build>
</project>
版本提示(2026年) :LangChain4j 当前稳定版本为 0.35.0(2026年6月)。如需要使用 Agent Skills 新特性,需引入
1.12.1及以上版本,但该版本仍处于快速迭代阶段。两种方式的 API 差异较大,建议根据项目需求选择统一版本。
三、第一个 Agent:基础对话实现
3.1 最简版 Agent(无工具)
package com.example.agent.basic;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.service.AiServices;
/**
* 最简单的 AI Agent 示例
* 功能:具备对话记忆能力的 AI 助理
*/
public class SimpleChatAgent {
/**
* 定义 AI 服务接口
* Agent 会自动实现此接口的方法
*/
interface Assistant {
/**
* 对话方法,Agent 自动处理记忆与回复
* @param userMessage 用户输入的消息
* @return Agent 的回复文本
*/
String chat(String userMessage);
}
public static void main(String[] args) {
// 1. 初始化 LLM 模型(使用 OpenAI 兼容接口)
// 注意:将 "your-api-key" 替换为真实的 API Key
// 建议通过 System.getenv("OPENAI_API_KEY") 从环境变量读取
ChatLanguageModel model = OpenAiChatModel.builder()
.apiKey("your-api-key") // API 密钥
.modelName("gpt-4o-mini") // 模型名称(也可用 "deepseek-chat")
.temperature(0.7) // 温度参数(0~1,越高越随机)
.maxTokens(2048) // 最大输出 Token 数
.logRequests(true) // [调试] 打印请求日志
.logResponses(true) // [调试] 打印响应日志
.build();
// 2. 配置对话记忆(保留最近 10 条消息)
// MessageWindowChatMemory 采用滑动窗口机制,自动淘汰最早的消息
ChatMemory chatMemory = MessageWindowChatMemory.withMaxMessages(10);
// 3. 使用 AiServices 构建 Agent 实例
// AiServices 是 LangChain4j 的核心构建器,会自动实现接口并注入模型和记忆
Assistant assistant = AiServices.builder(Assistant.class)
.chatLanguageModel(model) // 注入 LLM 模型
.chatMemory(chatMemory) // 注入对话记忆
.build();
// 4. 测试对话
System.out.println("用户: 我叫张三");
String firstResponse = assistant.chat("我叫张三");
System.out.println("Agent: " + firstResponse);
System.out.println("\n用户: 我叫什么名字?");
String secondResponse = assistant.chat("我叫什么名字?");
System.out.println("Agent: " + secondResponse);
// 预期输出:Agent 能记住用户叫「张三」
}
}
3.2 Spring AI 版本对比
如果使用 Spring Boot + Spring AI(1.1.x 版本),实现方式如下:
<!-- Spring AI 需使用 BOM 统一版本管理 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>1.1.8</version> <!-- 2026年6月最新稳定版 -->
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
</dependencies>
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.stereotype.Service;
@Service
public class SpringAIAgent {
private final ChatClient chatClient;
public SpringAIAgent(ChatClient.Builder builder) {
// 配置带记忆的 ChatClient
this.chatClient = builder
.withDefaultChatMemory(MessageWindowChatMemory.withMaxMessages(10))
.build();
}
public String chat(String userMessage) {
return chatClient.prompt()
.user(userMessage)
.call()
.content(); // 同步调用,返回完整回复
}
}
四、赋予 Agent 工具(Tools)能力
工具(Tools)是 Agent 的核心能力,它让 LLM 能够调用外部 Java 方法来执行实际操作(查询天气、读写数据库、调用 API 等)。
4.1 定义工具类(使用 @Tool 注解)
package com.example.agent.tools;
import dev.langchain4j.agent.tool.Tool;
import dev.langchain4j.agent.tool.P;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.Map;
/**
* Agent 可调用的工具集
* 通过 @Tool 注解将 Java 方法暴露给 LLM
*/
public class AgentTools {
// 模拟天气数据库
private static final Map<String, String> WEATHER_DATA = new HashMap<>();
static {
WEATHER_DATA.put("北京", "晴,25°C,湿度 45%");
WEATHER_DATA.put("上海", "多云,28°C,湿度 65%");
WEATHER_DATA.put("广州", "雷阵雨,32°C,湿度 85%");
}
/**
* 计算两个整数的和(基础数学工具)
* @Tool 注解的 description 非常重要,LLM 根据它判断何时调用此工具
*
* @param a 第一个加数
* @param b 第二个加数
* @return 两数之和
*/
@Tool("计算两个整数的和")
public int add(@P("第一个加数") int a, @P("第二个加数") int b) {
System.out.println("[Tool] add(" + a + ", " + b + ") 被调用");
return a + b;
}
/**
* 获取指定城市的天气信息
* @P 注解用于描述参数,帮助 LLM 正确地提取参数值
*
* @param city 城市名称(如:北京、上海)
* @return 天气描述字符串
*/
@Tool("获取指定城市的实时天气信息")
public String getWeather(
@P("城市名称,例如:北京、上海") String city) {
System.out.println("[Tool] getWeather(" + city + ") 被调用");
if (city == null || city.trim().isEmpty()) {
return "错误:城市名称不能为空";
}
String weather = WEATHER_DATA.get(city);
if (weather == null) {
return "抱歉,未找到「" + city + "」的天气信息,目前支持:北京、上海、广州";
}
return city + "的天气:" + weather;
}
/**
* 获取当前日期
*
* @return 当前日期字符串(yyyy-MM-dd 格式)
*/
@Tool("返回今天的日期")
public String getToday() {
System.out.println("[Tool] getToday() 被调用");
return LocalDate.now().toString();
}
/**
* 发送电子邮件(示例:模拟发送,实际需配置 SMTP)
*
* @param to 收件人邮箱
* @param subject 邮件主题
* @param body 邮件正文
* @return 发送结果
*/
@Tool("向指定邮箱发送邮件")
public String sendEmail(
@P("收件人邮箱地址") String to,
@P("邮件主题") String subject,
@P("邮件正文内容") String body) {
System.out.println("[Tool] sendEmail(" + to + ", " + subject + ") 被调用");
// 实际项目中此处调用 SMTP 服务或邮件 API
// 本示例仅模拟发送
return "邮件已发送至 " + to;
}
}
@Tool 注解的核心要点:
description 必须填写:LLM 根据描述判断何时调用该工具
@P 注解(可选但推荐):为参数提供描述,帮助 LLM 正确解析参数值
返回值类型:
void→ 返回字符串"Success"
String→ 原样返回其他类型 → 自动序列化为 JSON 字符串
工具执行可能抛异常:应捕获并返回友好的错误信息,便于 LLM 理解
4.2 将工具注入 Agent
package com.example.agent.tools;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.service.AiServices;
/**
* 带工具调用能力的 Agent 示例
* Agent 会自动判断何时调用 @Tool 注解的方法
*/
public class ToolAgentDemo {
/**
* AI 服务接口
* Agent 会自动实现接口,并根据用户问题决定调用哪个工具
*/
interface SmartAssistant {
/**
* 智能对话方法
* @param userMessage 用户输入(例如:"35 加 47 等于多少?")
* @return Agent 回复(可能包含工具调用结果)
*/
String chat(String userMessage);
}
public static void main(String[] args) {
// 1. 初始化 LLM 模型(需要支持 Function Calling 的模型)
// GPT-4、GPT-4o-mini、DeepSeek-Chat、Claude 3 等均支持
ChatLanguageModel model = OpenAiChatModel.builder()
.apiKey("your-api-key")
.modelName("gpt-4o-mini") // 支持 Function Calling
.temperature(0.3) // 工具调用场景建议较低温度
.maxTokens(4096)
.logRequests(true)
.logResponses(true)
.build();
// 2. 配置记忆(保留最近 20 条消息,因为工具调用会增加消息数)
ChatMemory chatMemory = MessageWindowChatMemory.withMaxMessages(20);
// 3. 构建带有工具的 Agent
AgentTools tools = new AgentTools(); // 创建工具类实例
SmartAssistant assistant = AiServices.builder(SmartAssistant.class)
.chatLanguageModel(model)
.chatMemory(chatMemory)
.tools(tools) // 👈 关键:注册工具
.build();
// 4. 测试各类场景
// 场景1:数学计算(触发 add 工具)
System.out.println("用户: 35 加 47 等于多少?");
String result1 = assistant.chat("35 加 47 等于多少?");
System.out.println("Agent: " + result1);
// 预期输出:35 + 47 = 82
System.out.println("\n--- 分割线 ---\n");
// 场景2:天气查询(触发 getWeather 工具)
System.out.println("用户: 北京今天的天气怎么样?");
String result2 = assistant.chat("北京今天的天气怎么样?");
System.out.println("Agent: " + result2);
// 预期输出:北京的天气:晴,25°C,湿度 45%
System.out.println("\n--- 分割线 ---\n");
// 场景3:不支持的场景(自然语言回复)
System.out.println("用户: 你好,请介绍一下你自己");
String result3 = assistant.chat("你好,请介绍一下你自己");
System.out.println("Agent: " + result3);
}
}
4.3 多工具编排执行原理
当用户问“北京今天多少度?请同时计算 12 乘 5”时,Agent 的执行流程如下:

这个过程中,LangChain4j 自动处理工具调用的编排、参数解析和结果返回,开发者只需专注实现 @Tool 方法。
五、Agent 记忆管理
5.1 基础记忆策略
LangChain4j 内置了多种记忆策略:
| 记忆策略 | 适用场景 | 特点 |
|---|---|---|
MessageWindowChatMemory |
短期对话(客服、闲聊) | 滑动窗口,自动淘汰旧消息 |
TokenWindowChatMemory |
Token 限制严格的场景 | 按 Token 数量滑动窗口 |
PersistentChatMemory |
需要跨会话保存记忆的场景 | 持久化到数据库/Redis |
自定义 Memory + ChatMemoryStore |
特殊需求(加密、多租户、自定义淘汰策略) | 完全自主控制 |
package com.example.agent.memory;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.memory.chat.TokenWindowChatMemory;
import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.store.memory.chat.InMemoryChatMemoryStore;
import dev.langchain4j.store.memory.chat.ChatMemoryStore;
/**
* Agent 记忆配置示例
*/
public class MemoryConfigExample {
/**
* 方式一:滑动窗口记忆(按消息条数)
* 适用于:对话轮次可控的场景
*/
public static ChatMemory windowByMessageCount() {
// 保留最近 10 条消息,超出则淘汰最早的
return MessageWindowChatMemory.withMaxMessages(10);
}
/**
* 方式二:滑动窗口记忆(按 Token 数量)
* 适用于:严格控制成本、模型 Token 上限较小的场景
*/
public static ChatMemory windowByToken() {
// 保留最近 4000 个 Token 的消息
return TokenWindowChatMemory.withMaxTokens(4000);
}
/**
* 方式三:持久化记忆(跨会话)
* 适用于:需要保存用户偏好的长期记忆场景
*/
public static ChatMemory persistentMemory() {
// 使用内存存储(实际生产可替换为 RedisChatMemoryStore 或 JdbcChatMemoryStore)
ChatMemoryStore store = new InMemoryChatMemoryStore();
return MessageWindowChatMemory.builder()
.maxMessages(50)
.chatMemoryStore(store) // 注入存储介质
.id("user-session-id") // 会话标识
.build();
}
}
5.2 生产环境持久化记忆(Redis + MySQL)
在实际生产环境中,对话记忆必须持久化存储,否则服务重启后所有对话将丢失。
Redis 存储示例
package com.example.agent.memory;
import dev.langchain4j.store.memory.chat.ChatMemoryStore;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Jedis;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.List;
/**
* Redis 实现的 ChatMemoryStore
* 支持分布式部署和跨会话记忆
*/
public class RedisChatMemoryStore implements ChatMemoryStore {
private final JedisPool jedisPool;
private final ObjectMapper objectMapper = new ObjectMapper();
public RedisChatMemoryStore(String host, int port) {
this.jedisPool = new JedisPool(host, port);
}
@Override
public List<dev.langchain4j.data.message.ChatMessage> getMessages(Object memoryId) {
try (Jedis jedis = jedisPool.getResource()) {
String key = "chat_memory:" + memoryId.toString();
String json = jedis.get(key);
if (json == null) {
return List.of();
}
// 反序列化 JSON 为消息列表
return objectMapper.readValue(json,
objectMapper.getTypeFactory().constructCollectionType(List.class,
dev.langchain4j.data.message.ChatMessage.class));
} catch (Exception e) {
throw new RuntimeException("Failed to load chat memory", e);
}
}
@Override
public void updateMessages(Object memoryId, List<dev.langchain4j.data.message.ChatMessage> messages) {
try (Jedis jedis = jedisPool.getResource()) {
String key = "chat_memory:" + memoryId.toString();
String json = objectMapper.writeValueAsString(messages);
// 设置 TTL(例如 7 天过期)
jedis.setex(key, 7 * 24 * 3600, json);
} catch (Exception e) {
throw new RuntimeException("Failed to save chat memory", e);
}
}
@Override
public void deleteMessages(Object memoryId) {
try (Jedis jedis = jedisPool.getResource()) {
String key = "chat_memory:" + memoryId.toString();
jedis.del(key);
}
}
}
5.3 长期记忆 vs 短期记忆
对于需要跨会话记住用户偏好的场景,建议采用 双记忆架构:

实现思路:
-
每次对话同时查询长期记忆区,将核心偏好注入 System Prompt
-
对话结束后,LLM 自动提取关键偏好并存储到长期记忆区
-
为用户记忆配置 TTL(如 7 天),定期清理无效数据
六、复杂任务规划(多步任务自动拆解)
当 Agent 面对复合任务(如“帮我订一张从北京到上海的机票,并提醒我明天带伞”)时,需要自动拆解为多步计划并依次执行。
6.1 计划-执行模式(手动实现)
package com.example.agent.planning;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.model.chat.ChatLanguageModel;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.List;
import java.util.ArrayList;
/**
* Agent 规划器示例
* 将复合任务自动拆解为可执行步骤
*/
public class AgentPlanner {
/**
* 规划步骤的数据结构
*/
static class PlanStep {
public String tool; // 要调用的工具名
public String input; // 工具参数
public String description; // 步骤描述
}
public static void main(String[] args) {
ChatLanguageModel model = OpenAiChatModel.builder()
.apiKey("your-api-key")
.modelName("gpt-4o-mini")
.build();
// 用户目标
String userGoal = "我想知道北京现在几点,并计算 123 乘以 456 的结果";
// 构造规划 Prompt
String planningPrompt = String.format("""
你是一个任务规划者。用户的目标是:%s
请将这个目标分解为一系列步骤,每个步骤包含:
1. 步骤描述
2. 需要调用的工具名称
3. 调用参数
可用工具列表:
- getTime(city: String): 获取指定城市的当前时间
- multiply(a: int, b: int): 计算两个整数的乘积
请以 JSON 数组格式输出,例如:
[
{"description": "获取纽约时间", "tool": "getTime", "input": "纽约"},
{"description": "计算乘积", "tool": "multiply", "input": "123,456"}
]
只输出 JSON 数组,不要有其他文字。
""", userGoal);
// 生成计划
String planJson = model.generate(planningPrompt);
System.out.println("规划结果:\n" + planJson);
// 实际项目中,此处需解析 JSON 并依次执行每个步骤
// 可通过反射或工具注册表动态调用对应的 Java 方法
}
}
6.2 LangChain4j 原生规划器
LangChain4j 提供了 AgentExecutor 和相关规划器接口,支持更复杂的链式处理。对于生产场景,建议采用框架原生的 Chain 模式(详见官方文档)。
6.3 非 AI 智能体(Non-AI Agent)
并非所有环节都需要 LLM 参与。对于计算平均分、状态转换等确定性操作,可以用非 AI 智能体(普通 Java 方法)来替代,以节省大模型调用成本。
/**
* 非 AI 智能体示例
* 纯 Java 代码实现,无需 LLM 参与
*/
public class NonAIAgent {
/**
* 聚合多个评审结果为综合评分
* 演示了普通 Java 操作符如何作为一等智能体用于工作流
*
* @param hrReview HR 评审结果
* @param managerReview 经理评审结果
* @param teamReview 团队评审结果
* @return 综合评审结果
*/
public CvReview aggregateScores(
CvReview hrReview,
CvReview managerReview,
CvReview teamReview) {
double avgScore = (hrReview.score + managerReview.score + teamReview.score) / 3.0;
String combinedFeedback = String.join("\n\n",
"HR评审: " + hrReview.feedback,
"经理评审: " + managerReview.feedback,
"团队评审: " + teamReview.feedback);
return new CvReview(avgScore, combinedFeedback);
}
/**
* 根据评分更新申请状态(确定性规则)
*/
public String updateStatus(double score) {
if (score >= 8.0) {
return "已邀请面试";
} else if (score >= 6.0) {
return "待定,需进一步评估";
} else {
return "已拒绝";
}
}
static class CvReview {
double score;
String feedback;
CvReview(double score, String feedback) {
this.score = score;
this.feedback = feedback;
}
}
}
Non-AI Agent = 用普通 Java 代码(计算、if-else、循环、字符串处理)实现确定性的业务逻辑,不调用任何大模型。
它和普通 Java 方法的唯一区别是:在 Agent 架构里,它被当作一个独立的、可替换的“决策单元”来使用,而不是散落在各处的零散代码。
在多智能体系统里,只要一个东西能接收输入、根据规则做决定、输出结果,就可以被称为“智能体”(Agent)。
-
aggregateScores:接收三个评审,输出综合结果 → 它是一个智能体 -
updateStatus:接收分数,输出状态字符串 → 它也是一个智能体
但它们不调用大模型,只靠 Java 的基本运算和 if 判断,所以叫做 Non-AI Agent(非 AI 智能体)。
你可以把它理解为:一个非常“死板”但绝对可靠的机器人,只会按你写的规则执行。
这样的设计将 AI 决策(理解简历、给出评语)与 确定性规则(计算平均分、状态转换)分离,既保证灵活性,又控制成本。
七、流式响应(Streaming)提升用户体验
7.1 什么是流式响应?
大模型生成文本是“一个一个词”蹦出来的,流式响应让前端能实时收到这些词,而不是等全部生成完再一次性返回,从而实现“打字机”效果。
package com.example.agent.streaming;
import dev.langchain4j.model.chat.StreamingChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiStreamingChatModel;
import dev.langchain4j.model.chat.response.StreamingChatResponseHandler;
import dev.langchain4j.model.chat.response.ChatResponse;
/**
* 流式响应 Agent 示例
* 实时逐字输出,提升用户体验
*/
public class StreamingAgentDemo {
public static void main(String[] args) {
// 1. 使用 StreamingChatLanguageModel 替代普通的 ChatLanguageModel
StreamingChatLanguageModel streamingModel = OpenAiStreamingChatModel.builder()
.apiKey("your-api-key")
.modelName("gpt-4o-mini")
.temperature(0.7)
.logRequests(true)
.logResponses(true)
.build();
System.out.println("Agent 正在思考并实时输出:\n");
// 2. 调用流式生成
streamingModel.generate("请写一首关于春天的五言绝句",
new StreamingChatResponseHandler() {
/**
* 每生成一个 Token 时回调
* @param token 最新生成的文本片段
*/
@Override
public void onNext(String token) {
// 实时输出,不加换行,实现逐字打印效果
System.out.print(token);
}
/**
* 全部生成完成时回调
* @param response 完整的 ChatResponse 对象
*/
@Override
public void onComplete(ChatResponse response) {
System.out.println("\n\n✅ 生成完成");
}
/**
* 出错时回调
* @param error 异常信息
*/
@Override
public void onError(Throwable error) {
System.err.println("\n❌ 生成出错:" + error.getMessage());
error.printStackTrace();
}
});
// 注意:主线程需要等待生成完成,否则程序会提前退出
// 实际项目中可用 CountDownLatch 或 CompletableFuture 来控制
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
7.2 配合 Spring Boot WebFlux 实现 SSE
// Spring Boot Controller 示例
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import dev.langchain4j.model.openai.OpenAiStreamingChatModel;
@RestController
public class StreamingController {
private final StreamingChatLanguageModel streamingModel;
public StreamingController() {
this.streamingModel = OpenAiStreamingChatModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.modelName("gpt-4o-mini")
.build();
}
@GetMapping(value = "/chat/stream", produces = "text/event-stream")
public Flux<String> streamChat(@RequestParam String message) {
// 使用 Flux.create 将回调转换为响应式流
return Flux.create(sink -> {
streamingModel.generate(message, new StreamingChatResponseHandler() {
@Override
public void onNext(String token) {
sink.next(token); // 每次收到 Token 就发送给客户端
}
@Override
public void onComplete(ChatResponse response) {
sink.complete(); // 完成时关闭流
}
@Override
public void onError(Throwable error) {
sink.error(error);
}
});
});
}
}
八、多模态 Agent(图像理解)
package com.example.agent.multimodal;
import dev.langchain4j.data.message.ImageContent;
import dev.langchain4j.data.message.TextContent;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
/**
* 多模态 Agent 示例
* 支持图像识别和理解
* 注意:需使用支持多模态的模型,如 GPT-4o、GPT-4o-mini、Claude 3 等
*/
public class MultimodalAgent {
public static void main(String[] args) {
// 必须使用支持多模态的模型
ChatLanguageModel model = OpenAiChatModel.builder()
.apiKey("your-api-key")
.modelName("gpt-4o") // gpt-4o 或 gpt-4o-mini 均支持多模态
.build();
// 构造包含图像的用户消息
UserMessage message = UserMessage.from(
TextContent.from("请描述这张图片中的内容,包括物体、颜色和可能的场景"), // 文本指令
ImageContent.from("https://example.com/image.jpg") // 图像 URL
// 也可以使用本地图片: ImageContent.from(Path.of("/path/to/image.jpg"))
);
String response = model.generate(message);
System.out.println("Agent 识别结果:" + response);
}
}
九、高级特性预览(2026 年)
9.1 Agent Skills(技能包)
LangChain4j 1.12.1 版本正式引入 Agent Skills 特性,允许将 Skill 定义在独立的 Markdown 文件中,实现渐进式披露(需要时才加载详细指令),相比传统 System Prompt 模式更高效。
import dev.langchain4j.skill.FileSystemSkillLoader;
import dev.langchain4j.skill.Skills;
// 加载 Skills 目录下的所有技能包
List<FileSystemSkill> skillList = FileSystemSkillLoader.loadSkills(Path.of("skills/"));
Skills skills = Skills.from(skillList);
9.2 MCP(Model Context Protocol)标准化工具访问
MCP 是 Anthropic 推出的标准化协议,用于将工具、文件、数据库以统一的方式暴露给 AI Agent。
Spring AI 2.0-M6 已原生支持 MCP 注解 @McpTool、@McpToolParam,开发者无需处理底层 JSON-RPC 协议。
9.3 SubAgent 子代理协作
多 Agent 协作模式支持:流水线(Chain)、扇出(Fan-out,并行执行)、循环优化(Loop until satisfied)和路由分发(Route to specialist)四种基础模式。
十、避坑指南
10.1 API Key 安全管理
❌ 错误做法:将 API Key 硬编码在代码中
✅ 正确做法:
String apiKey = System.getenv("OPENAI_API_KEY");
// 或使用 Spring 的 @Value("${openai.api.key}")
10.2 Token 消耗控制
每次调用工具都会额外产生多次 LLM 请求(包含历史消息和工具返回结果),建议:
-
控制
MessageWindowChatMemory的窗口大小(通常 5-10 轮即可) -
工具返回值保持简洁,避免返回大量 JSON 数据
-
使用
TokenWindowChatMemory精确控制成本
10.3 工具调用的错误处理
@Tool("获取实时股票价格")
public String getStockPrice(@P("股票代码") String code) {
try {
// 调用外部 API
return fetchFromExternalApi(code);
} catch (Exception e) {
// 返回友好错误信息,便于 LLM 理解并告知用户
return "获取股票「" + code + "」价格失败:" + e.getMessage();
}
}
10.4 版本兼容性(2026 年)
| 框架 | 当前稳定版 | 注意 |
|---|---|---|
| LangChain4j | 0.35.0 / 1.12.1 | 0.35 与 1.x 的 API 有较大差异,请统一版本 |
| Spring AI | 1.1.8 / 2.0-M6 | 1.x 与 2.0 API 不兼容,2.0 GA 预计 2026 年下半年发布 |
| Spring Boot | 3.5.15 | Spring AI 2.0 需要 Spring Boot 4.0 |
十一、完整项目结构建议
my-java-agent/
├── pom.xml
├── src/main/java/com/example/agent/
│ ├── AgentApplication.java # 主入口(可选 Spring Boot)
│ ├── basic/
│ │ └── SimpleChatAgent.java # 基础对话 Agent
│ ├── tools/
│ │ ├── AgentTools.java # 工具定义类
│ │ └── ToolAgentDemo.java # 带工具的 Agent 演示
│ ├── memory/
│ │ ├── MemoryConfigExample.java # 记忆配置
│ │ └── RedisChatMemoryStore.java # Redis 记忆存储
│ ├── streaming/
│ │ └── StreamingAgentDemo.java # 流式响应
│ ├── planning/
│ │ └── AgentPlanner.java # 任务规划
│ └── multimodal/
│ └── MultimodalAgent.java # 多模态示例
├── skills/ # Agent Skills 目录(可选)
│ └── explain-code/
│ └── SKILL.md
└── README.md
十二、学习路径
-
入门:掌握基础对话记忆 → 为 Agent 添加 1-2 个简单工具(计算器、查时间)
-
进阶:实现多工具编排 → 学习持久化记忆(Redis)→ 流式响应
-
高级:多 Agent 协作(SubAgent、MCP)→ Agent Skills 技能包 → 全链路可观测性(OpenTelemetry)
最后,如有改进之处欢迎指正,觉得有帮助的话不妨点赞收藏支持一下,感谢!
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐
所有评论(0)