SpringAI系列|第9篇:AI-Agent开发
Spring AI 实战系列 | 第 9 篇:AI Agent 开发
📄 约 9000 字 | ⏱️ 阅读约 22 分钟
系列说明:本文是《Spring AI 实战系列》第 9 篇,系统讲解 AI Agent 的核心概念、ReAct 模式、Spring AI Agent 框架实战(智能客服/代码助手/数据分析)、多 Agent 协作,以及评估与优化策略。
前置知识:已完成第 6-8 篇,掌握 Tool Calling、Advisor 和 MCP 基础。
文章目录
前言
ChatGPT 能回答问题,但让它"帮我订一张明天去上海的机票,查一下酒店,再安排一下行程",它就无能为力了。
AI Agent 正是为了解决此问题而生。 它不只是"回答问题",而是能自主感知、规划决策、调用工具、执行行动——从"聊天机器人"进化为"智能助理"。
若将前面的 RAG 比作给 AI 装上"眼睛",Tool Calling 给 AI 装上"双手",那 Agent 就是给 AI 装上"大脑"。
本文从概念到实战,将 AI Agent 论述透彻。
一、什么是 AI Agent
1.1 核心定义
AI Agent 是一个能自主感知环境 → 推理规划 → 执行行动 → 获取反馈的智能系统。(其核心循环机制详见 2.2 ReAct 执行流程)
1.2 与传统 AI 的本质区别
| 维度 | 传统 AI(Chatbot) | AI Agent |
|---|---|---|
| 交互方式 | 一问一答,被动响应 | 自主执行多步骤任务 |
| 能力边界 | 只能生成文本 | 能调用工具、操作环境 |
| 决策能力 | 无,完全依赖用户引导 | 自主规划和决策 |
| 记忆能力 | 仅当前对话上下文 | 长期记忆 + 学习积累 |
| 典型场景 | 客服问答、闲聊 | 订票、写代码、数据分析 |
一句话:Chatbot 是"回答问题",Agent 是"完成任务"。
1.3 Agent 的技术栈
AI Agent = LLM(大模型大脑)
+ Tool Calling(动手能力)
+ RAG(知识检索)
+ Memory(长期记忆)
+ Planning(任务规划)
+ Reflection(自我反思)
前面几篇学到的技术在此汇合:
| 已学技术 | 在 Agent 中的角色 |
|---|---|
| ChatClient | Agent 的基础交互层 |
| Tool Calling | Agent 的"手",执行具体操作 |
| RAG | Agent 的"知识库",提供背景信息 |
| Advisor | Agent 的"技能插件"(记忆、安全等) |
| MCP | Agent 的"工具市场",标准化工具接入 |
1.4 什么时候该用 Agent
不是所有场景都需要 Agent。选型原则:
| 复杂度 | 场景 | 推荐方案 |
|---|---|---|
| 简单 | “北京天气怎么样?” | ChatClient |
| 中等 | “帮我查下订单状态” | ChatClient + Tool Calling |
| 中高 | “分析这份销售数据” | ChatClient + RAG + Tool Calling |
| 复杂 | “帮我策划一次团建活动:查天气、比价、预订、通知所有人” | Agent |
判断标准:任务是否需要多步推理 + 多工具协作 + 自主决策?若是,则采用 Agent。
二、ReAct 模式:Agent 的核心思维框架
2.1 什么是 ReAct
ReAct = Reasoning(推理)+ Acting(行动)
这是目前最主流的 Agent 思维模式。核心思想:让 AI 一步一步思考,每步思考后决定是继续推理还是调用工具。
2.2 ReAct 执行流程
ReAct 的核心是一个思考 → 行动 → 观察的循环:

下面通过一个完整的例子来看 ReAct 是如何逐步执行的:

2.3 ReAct 的 Prompt 模板
Spring AI 内部使用类似以下的 Prompt 结构驱动 ReAct 循环:
你可以使用以下工具完成用户任务:
{tool_definitions}
请按以下格式思考和行动:
思考:[你需要做什么,为什么]
行动:[工具名称]
输入:[工具参数]
观察:[工具返回结果]
...(重复思考→行动→观察循环,直到获得足够信息)
最终回答:[基于所有信息给出的最终答案]
2.4 ReAct vs 其他模式
| 模式 | 特点 | 适用场景 |
|---|---|---|
| ReAct | 思考-行动交替,逐步推进 | 大多数通用场景 |
| Plan-and-Execute | 先制定完整计划,再逐步执行 | 复杂多步任务 |
| Act-only | 不思考直接行动 | 简单工具调用 |
Spring AI 默认使用 ReAct 模式,对大多数场景已够用。
三、Spring AI Agent 开发实战
3.1 最简 Agent
从最简单的开始——一个带工具的 Agent:
@Service
public class SimpleAgent {
private final ChatClient chatClient;
public SimpleAgent(ChatClient.Builder builder, WeatherService weatherService) {
this.chatClient = builder
.defaultTools(weatherService)
.build();
}
public String execute(String task) {
return chatClient.prompt()
.system("你是一位智能助手。请利用可用工具完成用户的任务。")
.user(task)
.call()
.content();
}
}
就这么简单。Spring AI 的 defaultTools() + ChatModel 本身支持的多轮 Tool Calling,就已经构成了一个基础的 Agent。
3.2 自主规划 Agent —— 任务分解
对于复杂任务,Agent 需要先分解再逐个击破:
@Service
public class PlanningAgent {
private final ChatClient chatClient;
public PlanningAgent(ChatClient.Builder builder, List<ToolCallback> tools) {
this.chatClient = builder.defaultTools(tools).build();
}
public String execute(String task) {
// Phase 1: 任务分解
List<String> steps = decomposeTask(task);
log.info("任务分解为 {} 个步骤", steps.size());
// Phase 2: 逐步执行
StringBuilder executionLog = new StringBuilder();
for (int i = 0; i < steps.size(); i++) {
log.info("执行步骤 {}/{}: {}", i + 1, steps.size(), steps.get(i));
String stepResult = executeStep(steps.get(i));
executionLog.append(String.format("**步骤 %d**: %s\n\n", i + 1, stepResult));
}
// Phase 3: 汇总结果
return summarize(task, executionLog.toString());
}
/**
* 让 AI 把复杂任务拆解为可执行的子步骤
*/
private List<String> decomposeTask(String task) {
String plan = chatClient.prompt()
.system("""
你是任务规划专家。将用户任务分解为具体的、可执行的步骤。
要求:
- 每个步骤应该是原子操作
- 步骤之间有逻辑依赖关系
- 输出格式:每行一个步骤,以数字编号开头
""")
.user("请分解以下任务:" + task)
.call()
.content();
return Arrays.stream(plan.split("\n"))
.map(String::trim)
.filter(s -> !s.isEmpty() && s.matches("\\d+\\.?.*"))
.collect(Collectors.toList());
}
private String executeStep(String step) {
return chatClient.prompt()
.system("你正在执行一个复杂任务的某个步骤。专注完成这个步骤。")
.user(step)
.call()
.content();
}
private String summarize(String task, String executionLog) {
return chatClient.prompt()
.system("基于以下执行记录,生成简洁的任务总结报告。")
.user("原始任务:" + task + "\n\n执行记录:\n" + executionLog)
.call()
.content();
}
}
效果示例:
String result = planningAgent.execute(
"帮我们团队安排一次团建活动:查一下下周六北京的天气," +
"找几个适合户外活动的场地推荐,估算人均预算"
);
// Agent 会自动分解为:
// 1. 查询下周六北京天气预报
// 2. 根据天气搜索合适的团建场地
// 3. 估算各场地的费用和人均预算
// 4. 汇总推荐方案
3.3 多工具编排 Agent
实际项目的 Agent 通常需要同时使用多种工具:
@Service
public class SmartOfficeAgent {
private final ChatClient chatClient;
public SmartOfficeAgent(
ChatClient.Builder builder,
WeatherService weatherService,
CalendarService calendarService,
OrderService orderService,
DatabaseToolService dbService) {
this.chatClient = builder
.defaultTools(weatherService, calendarService, orderService, dbService)
.build();
}
public String handle(String request) {
return chatClient.prompt()
.system("""
你是一位智能办公助手。你可以:
- 查询天气(规划出行时很有用)
- 查询日历(安排会议前先看空闲时间)
- 查询订单(处理客户问题)
- 查询数据库(获取业务数据)
请根据用户需求选择合适的工具,必要时组合使用多个工具。
如果需要的信息不足,主动询问用户。
""")
.user(request)
.call()
.content();
}
}
3.4 有状态的 Agent —— 对话记忆
Agent 亦需记住上下文:
@Component
public class StatefulAgent {
private final ChatClient chatClient;
private final Map<String, AgentSession> sessions = new ConcurrentHashMap<>();
public StatefulAgent(ChatClient.Builder builder) {
this.chatClient = builder.build();
}
public String execute(String sessionId, String task) {
AgentSession session = sessions.computeIfAbsent(sessionId, AgentSession::new);
// 构建包含历史的消息列表
List<Message> messages = new ArrayList<>(session.getHistory());
messages.add(new UserMessage(task));
// 执行
String result = chatClient.prompt()
.messages(messages)
.call()
.content();
// 更新会话状态
session.addInteraction(task, result);
return result;
}
public void clearSession(String sessionId) {
sessions.remove(sessionId);
}
/** Agent 会话状态 */
private static class AgentSession {
private final List<Message> history = new ArrayList<>();
private final LocalDateTime createdAt = LocalDateTime.now();
public List<Message> getHistory() { return Collections.unmodifiableList(history); }
public void addInteraction(String userMsg, String assistantMsg) {
history.add(new UserMessage(userMsg));
history.add(new AssistantMessage(assistantMsg));
// 限制历史长度,防止 Token 超限
if (history.size() > 40) {
history.subList(0, 10).clear(); // 移除最早的消息
}
}
}
}
3.5 自我反思 Agent
高级 Agent 能自我评估并改进:
@Service
public class ReflectiveAgent {
private final ChatClient chatClient;
private static final int MAX_REFLECTIONS = 2;
public ReflectiveAgent(ChatClient.Builder builder) {
this.chatClient = builder.build();
}
public String executeWithReflection(String task) {
String currentResult = null;
String reflection = null;
for (int round = 0; round <= MAX_REFLECTIONS; round++) {
if (round == 0) {
// 第一轮:直接执行
currentResult = execute(task);
} else {
// 后续轮:根据反思改进后重新执行
String improvedPrompt = task + "\n\n【改进要求】\n" + reflection;
currentResult = execute(improvedPrompt);
log.info("第 {} 轮反思后重新执行完成", round);
}
// 自我反思
reflection = reflect(task, currentResult);
// 如果质量达标,提前结束
if (isQualityAcceptable(reflection)) {
log.info("经过 {} 轮迭代,结果已达标", round + 1);
break;
}
}
return currentResult;
}
private String execute(String task) {
return chatClient.prompt().user(task).call().content();
}
private String reflect(String task, String result) {
return chatClient.prompt()
.system("""
你是一个严格的质量评审专家。请评估以下任务完成质量。
评估维度:
1. 是否完整回答了用户的问题?
2. 信息是否准确?
3. 回答是否清晰有条理?
4. 是否有遗漏或错误?
如果质量不达标,请明确指出需要改进的地方。
如果质量达标,回复"QUALITY_OK"。
""")
.user("任务:" + task + "\n\n回答:" + result)
.call()
.content();
}
private boolean isQualityAcceptable(String reflection) {
return reflection.contains("QUALITY_OK");
}
}
四、三大实战案例
4.1 智能客服 Agent
结合 RAG + Tool Calling + 对话记忆的完整客服方案:
@Service
public class CustomerServiceAgent {
private final ChatClient chatClient;
public CustomerServiceAgent(
ChatClient.Builder builder,
VectorStore vectorStore,
OrderToolService orderTool,
ChatMemory chatMemory) {
this.chatClient = builder
.defaultTools(orderTool)
.build();
this.vectorStore = vectorStore;
this.chatMemory = chatMemory;
}
public String handle(String sessionId, String userMessage) {
return chatClient.prompt()
.system("""
你是某电商平台的智能客服助手。你的能力范围:
1. 产品咨询 → 使用知识库(RAG)回答产品相关问题
2. 订单查询 → 调用订单工具查询物流和状态
3. 退换货处理 → 调用退款工具处理申请
4. 投诉建议 → 共情倾听,必要时转人工
规则:
- 基于真实数据回答,不要编造
- 语气友好专业
- 涉及金钱操作时二次确认
- 无法解决的问题建议转人工客服
""")
.user(userMessage)
.advisors(
new QuestionAnswerAdvisor(vectorStore), // RAG 知识库
new MessageChatMemoryAdvisor(chatMemory, sessionId, 10), // 对话记忆
new SafeGuardAdvisor(), // 安全过滤
new LoggingAdvisor() // 日志审计
)
.call()
.content();
}
}
配套的工具服务:
@Service
public class OrderToolService {
@Tool(name = "queryOrderStatus",
description = "查询订单状态和物流进度。当用户询问订单、物流、发货时使用")
public OrderStatus queryOrderStatus(
@ToolParam(description = "订单号") String orderId) {
Order order = orderRepository.findById(orderId)
.orElseThrow(() -> new RuntimeException("订单不存在:" + orderId));
return new OrderStatus(order.getId(), order.getStatus(),
order.getTrackingNumber(), order.getEstimatedDelivery());
}
@Tool(name = "applyRefund",
description = "申请订单退款。需要订单号和退款原因")
public RefundResult applyRefund(
@ToolParam(description = "订单号") String orderId,
@ToolParam(description = "退款原因:质量问题/不想要了/发错货/其他") String reason) {
Order order = orderRepository.findById(orderId).orElse(null);
if (order == null || !order.canRefund()) {
return new RefundResult(false, "该订单当前不支持退款");
}
refundService.createRefund(orderId, reason);
return new RefundResult(true, "退款申请已提交,预计 3-5 个工作日到账");
}
public record OrderStatus(String orderId, String status,
String trackingNo, String estimatedDelivery) {}
public record RefundResult(boolean success, String message) {}
}
4.2 代码助手 Agent
@Service
public class CodeAssistantAgent {
private final ChatClient chatClient;
public CodeAssistantAgent(ChatClient.Builder builder) {
this.chatClient = builder.build();
}
/** 代码生成 */
public String generateCode(String requirement) {
return chatClient.prompt()
.system("""
你是一位资深 Java/Spring Boot 开发工程师。
代码规范要求:
1. 遵循阿里巴巴 Java 开发手册
2. 类和方法要有清晰的 Javadoc 注释
3. 合理使用设计模式
4. 必须处理异常和边界条件
5. 使用现代 Java 特性(record、var、Stream 等)
6. 提供完整可运行的代码,不要省略
""")
.user("需求:" + requirement)
.call()
.content();
}
/** 代码审查 */
public String reviewCode(String code) {
return chatClient.prompt()
.system("""
你是一位严格的代码审查专家(Senior Code Reviewer)。
审查维度(按优先级排序):
1. 🔴 严重:潜在的 Bug、空指针风险、并发安全问题
2. 🟡 警告:性能问题、资源泄漏风险
3. 🔵 建议:代码风格、命名规范、设计模式优化
输出格式:按严重程度分类列出问题,每个问题给出:
- 位置(行号/方法名)
- 问题描述
- 修改建议(给出代码片段)
""")
.user(code)
.call()
.content();
}
/** 单元测试生成 */
public String generateTests(String sourceCode) {
return chatClient.prompt()
.system("""
你是一位测试工程师。为以下代码生成 JUnit 5 单元测试。
要求:
1. 使用 Mockito mock 外部依赖
2. 覆盖正常流程和异常流程
3. 测试方法命名采用 should_ExpectedBehavior_When_State 格式
4. 使用 AssertJ 断言库
5. 关键测试添加注释说明测试意图
""")
.user(sourceCode)
.call()
.content();
}
}
4.3 数据分析 Agent
Text-to-SQL + 数据分析的完整链路:
@Service
public class DataAnalysisAgent {
private final ChatClient chatClient;
private final JdbcTemplate jdbcTemplate;
public DataAnalysisAgent(ChatClient.Builder builder, DataSource dataSource) {
this.chatClient = builder.build();
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
public String analyze(String question) {
// Step 1: Text → SQL
String sql = generateSql(question);
log.info("生成的 SQL: {}", sql);
// 安全检查
if (!isSqlSafe(sql)) {
return "抱歉,无法执行该查询。";
}
// Step 2: 执行 SQL
List<Map<String, Object>> data = executeQuery(sql);
// Step 3: 数据分析
return analyzeData(question, data);
}
private String generateSql(String question) {
String schema = getDatabaseSchema();
return chatClient.prompt()
.system("""
你是 SQL 专家。根据表结构生成 PostgreSQL 查询语句。
规则:
- 只使用 SELECT 查询,禁止 DDL/DML 操作
- LIMIT 100 条防止数据量过大
- 只输出 SQL 语句,不要解释
- 表名和字段名必须与 schema 一致
""")
.user("数据库表结构:\n" + schema + "\n\n问题:" + question)
.call()
.content()
.replace("```sql", "").replace("```", "").trim();
}
private List<Map<String, Object>> executeQuery(String sql) {
try {
return jdbcTemplate.queryForList(sql);
} catch (Exception e) {
log.error("SQL 执行失败: {}", sql, e);
throw new RuntimeException("查询执行失败:" + e.getMessage());
}
}
private String analyzeData(String question, List<Map<String, Object>> data) {
if (data.isEmpty()) {
return "查询结果为空,没有找到相关数据。";
}
String dataStr = formatDataForLLM(data, 50); // 限制条数
return chatClient.prompt()
.system("""
你是数据分析专家。基于查询结果进行分析。
分析要求:
1. 用通俗语言解释数据含义
2. 发现关键趋势和异常点
3. 给出可行的业务建议
4. 适当使用数据支撑结论
""")
.user("问题:" + question + "\n\n查询结果:\n" + dataStr)
.call()
.content();
}
/** SQL 安全检查 */
private boolean isSqlSafe(String sql) {
String upperSql = sql.toUpperCase();
List<String> dangerousKeywords = List.of(
"DROP", "DELETE", "INSERT", "UPDATE", "ALTER", "CREATE",
"TRUNCATE", "EXEC", "EXECUTE"
);
return dangerousKeywords.stream().noneMatch(upperSql::contains);
}
private String getDatabaseSchema() {
// 返回数据库表结构描述
return """
-- 订单表
orders(id BIGINT PK, user_id VARCHAR, total_amount DECIMAL(10,2),
status VARCHAR, create_time TIMESTAMP)
-- 用户表
users(id VARCHAR PK, name VARCHAR, email VARCHAR,
register_date TIMESTAMP)
-- 商品表
products(id BIGINT PK, name VARCHAR, category VARCHAR,
price DECIMAL(10,2), stock INT)
""";
}
}
五、多 Agent 协作
复杂场景需要多个专业 Agent 分工协作:
5.1 Agent 路由器
@Service
public class MultiAgentOrchestrator {
private final CustomerServiceAgent customerAgent; // 客服 Agent
private final CodeAssistantAgent codeAgent; // 代码 Agent
private final DataAnalysisAgent dataAgent; // 数据 Agent
private final ChatClient router; // 路由器
public MultiAgentOrchestrator(
CustomerServiceAgent customerAgent,
CodeAssistantAgent codeAgent,
DataAnalysisAgent dataAgent,
ChatClient.Builder builder) {
this.customerAgent = customerAgent;
this.codeAgent = codeAgent;
this.dataAgent = dataAgent;
this.router = builder.build();
}
public String dispatch(String sessionId, String userMessage) {
// Step 1: 意图识别,路由到对应 Agent
String agentType = routeToAgent(userMessage);
log.info("消息路由到 {} Agent", agentType);
// Step 2: 委托给对应的 Agent 处理
return switch (agentType) {
case "customer_service" -> customerAgent.handle(sessionId, userMessage);
case "code_assistant" -> codeAgent.generateCode(userMessage);
case "data_analysis" -> dataAgent.analyze(userMessage);
default -> handleGeneralQuery(userMessage);
};
}
private String routeToAgent(String message) {
return router.prompt()
.system("""
判断用户问题的类型,只返回以下之一:
- customer_service(客服类:订单、售后、产品咨询)
- code_assistant(代码类:写代码、review、测试)
- data_analysis(数据分析类:查询数据、报表、统计)
- general(其他一般性问题)
""")
.user(message)
.call()
.content()
.trim()
.toLowerCase();
}
private String handleGeneralQuery(String message) {
return router.prompt()
.system("你是一个通用助手。回答用户的一般性问题。")
.user(message)
.call()
.content();
}
}
5.2 Agent 协作架构

六、Agent 评估与优化
Agent 上线后,评估和优化是持续的工作。
6.1 评估指标体系
| 指标 | 说明 | 目标值 |
|---|---|---|
| 任务完成率 | Agent 是否完成了用户要求的任务 | ≥ 85% |
| 工具调用准确率 | 是否选择了正确的工具 | ≥ 90% |
| 平均执行步数 | 完成任务平均需要多少步 | 越少越好 |
| 首轮成功率 | 第一次就完成任务的比例 | ≥ 70% |
| 响应时间 (P99) | 99% 请求的响应时间 | < 30s |
| Token 消耗 | 平均每次任务消耗的 Token | 控制成本 |
6.2 自动化评估框架
@Service
public class AgentEvaluator {
private static final Logger log = LoggerFactory.getLogger(AgentEvaluator.class);
public EvaluationReport evaluate(Agent agent, List<TestCase> testCases) {
int passed = 0, failed = 0;
List<FailureDetail> failures = new ArrayList<>();
long totalLatency = 0;
for (TestCase tc : testCases) {
long start = System.currentTimeMillis();
try {
String result = agent.execute(tc.task());
long latency = System.currentTimeMillis() - start;
totalLatency += latency;
boolean success = verifyResult(result, tc.expectedKeywords());
if (success) {
passed++;
} else {
failed++;
failures.add(new FailureDetail(tc, result, "关键词匹配失败"));
}
} catch (Exception e) {
failed++;
failures.add(new FailureDetail(tc, null, e.getMessage()));
}
}
return new EvaluationReport(testCases.size(), passed, failed, failures, totalLatency);
}
/** 验证结果是否包含预期的关键字 */
private boolean verifyResult(String result, List<String> expectedKeywords) {
if (result == null) return false;
return expectedKeywords.stream().allMatch(result::contains);
}
public record EvaluationReport(int total, int passed, int failed,
List<FailureDetail> failures, long totalLatency) {
public double passRate() { return (double) passed / total; }
public double avgLatency() { return (double) totalLatency / total; }
}
public record TestCase(String task, List<String> expectedKeywords) {}
public record FailureDetail(TestCase testCase, String actualResult, String reason) {}
}
6.3 测试用例集
public class AgentTestSuite {
public static List<TestCase> customerServiceCases() {
return List.of(
new TestCase("我的订单 12345 发货了吗?", List.of("订单", "发货")),
new TestCase("我想退货,订单号 67890", List.of("退款", "申请")),
new TestCase("你们的产品有什么保修政策?", List.of("保修")),
new TestCase("查一个不存在的订单 99999", List.of("不存在", "找不到"))
);
}
public static List<TestCase> dataAnalysisCases() {
return List.of(
new TestCase("上个月销售额最高的产品是什么?", List.of("销售", "最高")),
new TestCase("最近一周有多少新用户注册?", List.of("新用户", "注册")),
new TestCase("各个品类的销售占比是多少?", List.of("品类", "占比"))
);
}
}
6.4 优化策略
策略一:Prompt 优化
根据失败案例针对性改进 System Prompt:
// 失败案例分析
List<FailureDetail> recentFailures = evaluator.evaluate(agent, testCases).failures();
// 用 AI 自动优化 Prompt
String optimizedPrompt = chatClient.prompt()
.system("你是 Prompt 工程专家。根据失败案例优化系统提示词。")
.user("""
当前 Prompt:
{currentPrompt}
近期失败案例:
{failures}
请给出优化后的 Prompt。
""".replace("{currentPrompt}", currentPrompt)
.replace("{failures}", formatFailures(recentFailures)))
.call()
.content();
策略二:工具描述优化
// ❌ 优化前:太模糊
@Tool(name = "getOrder", description = "获取订单")
// ✅ 优化后:明确触发条件
@Tool(name = "queryOrderStatus",
description = "查询订单当前状态和物流信息。" +
"当用户询问订单进度、物流跟踪、发货状态时使用此工具。" +
"需要用户提供订单号。")
策略三:Few-Shot 示例
在 System Prompt 中加入成功案例作为参考:
String systemPrompt = """
你是智能客服助手。
【参考示例】
用户:我的东西发了吗?
→ 调用 queryOrderStatus,参数 orderId 从对话历史获取
用户:不想要了要退款
→ 先调用 queryOrderStatus 确认订单状态,再调用 applyRefund
请参考以上示例的风格和方式来处理用户请求。
""";
6.5 生产监控
@Component
public class AgentMonitor {
private final MeterRegistry meterRegistry;
/** 记录每次 Agent 执行 */
public void recordExecution(String agentType, boolean success,
int toolCalls, long latencyMs, int tokens) {
meterRegistry.counter("agent.execution",
"type", agentType, "status", success ? "success" : "failure").increment();
meterRegistry.timer("agent.latency", "type", agentType)
.record(latencyMs, TimeUnit.MILLISECONDS);
meterRegistry.counter("agent.tokens", "type", agentType).increment(tokens);
meterRegistry.counter("agent.tool_calls", "type", agentType).increment(toolCalls);
}
/** 告警规则建议 */
// - 失败率 > 15% 持续 5 分钟 → 告警
// - P99 延迟 > 60s → 告警
// - 平均 Token > 10000 → 成本告警
}
七、常见问题
Q1:Agent 循环次数太多怎么办?
- 设置最大迭代次数(
maxIterations) - 优化工具描述,减少误调
- 在 Prompt 中提示"尽量少的步骤完成任务"
Q2:Agent 调用了错误的工具?
这是最常见的问题。解决思路:
- 优化工具描述:让每个工具的边界更清晰
- 减少工具数量:合并相似工具
- 增加 Few-Shot 示例:展示正确的调用方式
- 使用更强的模型:GPT-4o 比 GPT-4o-mini 工具调用更准
Q3:Agent 结果不稳定怎么办?
- 同样的输入可能产生不同的输出(LLM 的随机性)
- 解决方案:设置
temperature=0提高确定性 - 对于关键业务逻辑,加人工审核环节
Q4:Agent 成本太高?
- 用小模型做简单任务(路由、格式化)
- 用大模型做复杂推理
- 缓存常见问题的答案
- 限制最大迭代次数和 Token 数
写在总结
AI Agent 是 Spring AI 所有技术的集大成者。回顾一下技术演进路径:
第 1-2 篇:学会让 AI "说话"(ChatClient + 多模型)
第 3 篇: 学会让 AI "理解"(结构化输出 + 多模态)
第 4-5 篇:学会给 AI "喂知识"(Embedding + RAG)
第 6 篇: 学会让 AI "动手"(Tool Calling)
第 7 篇: 学会给 AI "装插件"(Advisor)
第 8 篇: 学会让 AI "接外部世界"(MCP)
第 9 篇: ★ 学会让 AI "自主思考"(Agent)★
| 要点 | 核心内容 |
|---|---|
| 核心理念 | 从"回答问题"到"完成任务" |
| 思维模式 | ReAct:思考 → 行动 → 观察 → 循环 |
| 开发方式 | ChatClient + defaultTools 即可构建基础 Agent |
| 进阶能力 | 任务分解、自我反思、多 Agent 协作 |
| 关键实践 | 评估指标、测试集、持续优化 |
下一篇也是本系列的最后一篇——企业级应用与最佳实践,把前面所有知识点整合到一起,讲怎么在生产环境中落地。
系列目录:
- 第一篇-SpringAI概述与快速上手
- 第二篇-模型集成与对话基础
- 第三篇-结构化输出与多模态
- 第四篇-Embedding与向量数据库
- 第五篇-RAG检索增强生成
- 第六篇-Tool-Calling工具调用
- 第七篇-Advisor机制与对话管理
- 第八篇-MCP模型上下文协议
- 第九篇-AI-Agent开发 ✅(本文)
- 第十篇-企业级应用与最佳实践
若本文对您有所帮助,欢迎点赞、收藏与关注,系列持续更新中!
更多推荐


所有评论(0)