Agent 工具系统设计六模式:从混乱到有序
问题:当 Agent 有 20+ 工具时
把 20 个工具的 Function Definition 全部塞进 system prompt 会导致:(1) Token 消耗爆炸(每个工具约 300-500 tokens),(2) LLM 选择困难——选项越多越容易选错,(3) 关键工具的上下文被稀释。解决方案是分层设计。
六种设计模式
| 模式 | 核心思路 | 适用场景 |
|---|---|---|
| 1. 工具网关 | 先用便宜模型做意图分类,只注入相关工具子集(≤8个) | 工具数量 20+,多领域 |
| 2. 工具链编排 | DAG 预定义依赖关系 + LLM 自由组合(混合模式) | 复杂多步任务,有明确执行顺序 |
| 3. 描述工程 | name/description/parameters 精心设计,让 LLM 一眼知道"何时用、怎么用" | 所有场景 |
| 4. 并行调用 | 单次返回多个 tool_call,应用层并行执行无依赖的工具 | 需要同时查询多个数据源 |
| 5. 错误处理 | 错误信息结构化:{错误类型 + 可行建议 + 是否可重试},但不暴露内部细节 | 所有生产场景 |
| 6. 安全沙箱 | 权限检查 → 参数白名单 → 限流 → SQL注入防护 → 路径沙箱 → 审计日志 | 生产环境,多租户 |
模式一:工具网关(Tool Gateway)
最实用的模式。意图分类器用便宜的模型(GPT-3.5 / 本地小模型),只负责判断"用户想做什么",然后只注入对应分类的工具子集。
# 两级路由架构
TOOL_GROUPS = {
"database": ["query_db", "list_tables", "describe_schema"],
"file_system": ["read_file", "write_file", "list_dir", "search_files"],
"web": ["web_search", "web_fetch", "browser_snapshot"],
"communication": ["send_email", "send_message"],
}
async def route_tools(user_input: str, all_tools: list):
# 第一步:便宜模型做意图分类
intent = await cheap_model.classify(user_input, list(TOOL_GROUPS.keys()))
# 第二步:只注入对应组的工具
group_names = intent["groups"] # 如 ["database", "web"]
active_tools = []
for g in group_names:
active_tools.extend(TOOL_GROUPS[g])
return [t for t in all_tools if t.name in active_tools]
避坑:意图分类错误会导致注入错误工具子集,任务彻底失败。建议返回 top-2 意图而非单选,增加容错。
模式三:描述工程黄金法则
工具描述的质量直接影响 Agent 的决策准确率。三条铁律:
- description 要比 name 更有信息量——不要写"搜索工具",要写"在已索引的知识库文档中搜索文本,支持关键词和布尔表达式,适用于查找特定主题的详细内容"
- 暗示"何时用"——例如:"当你需要查找具体信息时使用此工具。注意:仅搜索已索引的文档,不包含草稿。"
- 暗示"怎么用"——在 parameters 的 description 中给出示例值格式
{
"name": "search_documents",
"description": "搜索知识库文档。当你需要查找某个主题的具体信息时使用此工具。"
+ "注意:仅搜索已索引的文档,不包含草稿。支持精确匹配和模糊匹配。",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "搜索关键词。支持布尔运算 AND/OR/NOT。"
+ "示例:'RAG AND 混合检索' 或 '向量数据库 NOT Pinecone'"
},
"top_k": {
"type": "integer",
"description": "返回结果数量,默认 5,最大 20。"
+ "数值越大结果越全面但耗时越长"
}
},
"required": ["query"]
}
}
模式五:结构化错误处理
工具返回的错误信息是给 LLM 看的,必须包含:明确错误类型 + 可行建议 + 是否可重试。但不能暴露内部细节(栈追踪、内部路径、数据库结构等)。
# ✅ 正确的错误返回
{
"error": true,
"error_type": "rate_limit",
"message": "API 调用频率过高,请等待 30 秒后重试。",
"retryable": true,
"retry_after_seconds": 30
}
# ❌ 错误的错误返回
{
"error": "InternalError: connection refused at /usr/lib/python3/site-packages/..."
}
总结:从原型到生产的工具系统升级路径
- 原型阶段:直接罗列所有 Function Definition,工具数 < 10
- 增长阶段(10-20 工具):引入描述工程,优化每个工具的 description
- 扩展阶段(20+ 工具):引入工具网关,按领域分组注入
- 生产阶段:加入错误处理标准化 + 安全沙箱 + 审计日志