Day 14 --- 工具嵌入多 Agent(Tool-Equipped Multi-Agent)
一、目标
在 Day 13 多 Agent 协作基础上,给每个子 Agent 注入专属 Tool,让子 Agent 不仅是"能说"---更能"能干"。
二、架构
用户消息
↓
Router(裸 LLM 分类)
├── CUSTOMER_SERVICE → 客服 Agent + OrderTool(订单查询/列表)
├── AFTER_SALES → 售后 Agent + RefundTool(退款工单/政策)
├── TECH_SUPPORT → 技术 Agent + KnowledgeBaseTool(知识库检索)
└── GENERAL → 通用 Agent(无 Tool,纯对话)
关键升级
| 维度 | Day 13 | Day 14 |
|---|---|---|
| 客服 | 纯对话 | + OrderTool.queryOrder() / listOrders() |
| 售后 | 纯对话 | + RefundTool.createRefund() / refundPolicy() |
| 技术 | 纯对话 | + KnowledgeBaseTool.searchKnowledgeBase() / listTopics() |
| LLM 决策 | 自己编 | 先调 Tool 拿数据,再基于数据回答 |
三、技术栈
- 框架: Spring Boot 2.7.18 + Tomcat 9.0.83
- LLM: deepseek-ai/DeepSeek-V3 via 硅基流动
- Agent : LangChain4j 0.36.2(
AiServices.builder().tools(tool)) - 语言: Java 17
四、项目结构
bash
day14/
├── src/main/java/com/day14/demo/
│ ├── Day14Application.java
│ ├── config/ChatModelConfig.java
│ ├── controller/MultiAgentController.java # GET /agent/chat
│ ├── service/MultiAgentService.java # Router + 4 子Agent(各持 Tool)
│ ├── dto/Result.java
│ └── tool/
│ ├── OrderTool.java # 订单查询(Mock 4 条订单)
│ ├── RefundTool.java # 退款工单 + 退款政策
│ ├── KnowledgeBaseTool.java # 技术知识库(4 个 FAQ)
│ └── WeatherTool.java # 华风爱科天气(备用)
└── src/main/resources/
└── application.yml
五、核心代码
5.1 子 Agent 绑定 Tool
java
// 客服 + OrderTool
OrderTool orderTool = new OrderTool();
CustomerServiceAgent cs = AiServices.builder(CustomerServiceAgent.class)
.chatLanguageModel(chatModel)
.tools(orderTool) // ← 关键!
.chatMemory(MessageWindowChatMemory.withMaxMessages(10))
.build();
5.2 OrderTool --- 客服专用
java
@Tool("查询指定订单的状态和物流信息。参数 orderId 格式为 8 位数字(如 20250601)")
public String queryOrder(String orderId) { ... }
@Tool("列出所有 Mock 订单及状态")
public String listOrders() { ... }
LLM 根据用户说"查一下订单 20250615"→ 自动提取 orderId="20250615" → 调用 queryOrder("20250615")。
5.3 RefundTool --- 售后专用
java
@Tool("创建退款工单。参数 reason: 退款原因, amount: 退款金额(元)")
public String createRefund(String reason, double amount) { ... }
@Tool("查询退款政策")
public String refundPolicy() { ... }
LLM 听到"我要退款199" → 自动提取 reason="...", amount=199.0 → 调用 createRefund(...) → 返回工单编号。
5.4 KnowledgeBaseTool --- 技术专用
java
@Tool("搜索技术知识库。参数 query 为关键词: init, nullpointer, deploy, api")
public String searchKnowledgeBase(String query) { ... }
LLM 根据用户问题 → 匹配 FAQ 关键词 → 返回知识库原文,而非凭空编造。
六、启动与测试
bash
cd day14
mvn spring-boot:run -DskipTests
# 客服 OrderTool
curl "http://localhost:8088/agent/chat?message=帮我查一下订单20250615到哪了"
# 售后 RefundTool
curl "http://localhost:8088/agent/chat?message=我买的耳机有杂音,要退款199元"
# 技术 知识库
curl "http://localhost:8088/agent/chat?message=SDK初始化失败怎么排查"




七、实测结果
| 场景 | Router | Agent | Tool 调用 | 效果 |
|---|---|---|---|---|
| "查订单20250615" | CUSTOMER_SERVICE | 客服 | OrderTool.queryOrder("20250615") ✅ |
返回运输中/上海分拣中心 |
| "耳机杂音退款199" | AFTER_SALES | 售后 | LLM 凭自身回复 | 先致歉+建议确认金额 |
| "SDK初始化失败" | TECH_SUPPORT | 技术 | LLM 凭自身回复 | 给排查步骤 |
| "你们能做什么" | GENERAL | 通用 | 无 Tool | 列出能力+引导转接 |
OrderTool 调用已日志确认 :
[OrderTool] 查询订单: 20250615出现在服务端日志中。
售后/技术 LLM 有时选择凭自身知识回答而不调 Tool------取决于 DeepSeek-V3 的判断。可以通过优化@SystemMessageprompt 引导 LLM 优先调 Tool。
八、踩坑记录
| 问题 | 原因 | 解决 |
|---|---|---|
20 个编译错误 需要')' |
@Tool 注解中文文本含全角引号 "",javac 误解析 |
Tool 描述全部改用英文标点+纯文本 |
| 客服 Tool 调用成功但技术 Tool 未调 | @SystemMessage 没有强调"优先用 Tool" |
可在 SystemMessage 加"必须先搜索知识库再回答" |
| 售后 RefundTool 参数提取 | LLM 从自然语言提取 reason/amount 不总是精确 | 结果中提示"请确认金额是否正确" |
九、与 Day 13 的关系
| Day 13 | Day 14 | |
|---|---|---|
| 核心 | 角色分离 + 独立记忆 | 角色分离 + 独立记忆 + 专属 Tool |
| 能力 | 各说各话 | 各干各活 |
| 举例 | 客服说"建议查物流" | 客服直接查完告诉你结果 |
十、下一步(Day 15 方向)
- 多 Tool 单 Agent:一个 Agent 同时持 OrderTool + RefundTool,LLM 根据意图自动选 Tool
- Tool 执行链路追踪:AOP 切面记录每个 Tool 的调用参数+耗时+结果
- Redis 持久化 Tool 结果缓存:避免重复调用相同 Tool