2472 字
约 8 分钟
14
S21-A21 · 工具选择:Agent 为什么选错,以及怎么让它选对

一个有 18 个工具的 Agent 老是调错工具:明明要"查订单详情",它调了"查订单列表";明明要"改状态",它调了"查状态"。日志里能看到它连续三次调用同一个错了的工具,每次都得到"参数不符",然后又换参数重试——因为它以为"是参数问题"。

工具选择错误是 Agent 最常见的失败模式,而它有三类成因:描述不清、工具重叠、以及失败反馈不可行动。这个"只对第一类有用"是判断的关键:如果"加提示"两次都没改善,说明问题不在"它不知道",而在"它没法区分"或"它得不到反馈"。
三者修法完全不同,而"加提示"只对第一类有用。


1. 三类"选错"

类型 表现
该用的没找到 选了"看起来像"的另一个
该用的被排除 前置条件不满足(如缺参数)
用对了但用错方式 参数/顺序错

第一项是"描述问题":**两个工具的描述里都有"查订单"**第一项的"机制"是"语义相似度高于差异":在它的视角里,"查订单详情"与"查订单列表"共享大量词,而"详情 vs 列表"这个差异只占一小部分。
,而它们实在的区别(列表 vs 详情)没被写清。

第三项是"接口设计"问题:参数名相似但语义不同(status 与 state),于是它"按字面填"。

2. 描述该怎么写才"可区分"

要素 作用
一句话"做什么" 决定何时调用
"什么时候不该用" 排除相近工具
必需的输入 决定能否调用
返回什么(含失败) 决定下一步

第二项的"原理"是"排除比包含更省判断":它不必"比较两个工具的正面描述",只需"看到否决条件就排除"——于是判断成本下降。
第二项最被忽略:"不要用它来查列表"这类"负向说明"往往比"正向说明"更能区分——因为正向他能从名字猜到,负向只有你说。

// 两个易混工具的"可区分"写法
get_order_detail: 查"单个订单"的完整详情(含商品、金额、状态)。
  不要用它查多个订单——那用 list_orders。
  必需:order_id(字符串,形如 O-123)。
list_orders: 按条件查"订单列表"(分页返回摘要,不含商品明细)。
  不要用它取单个订单详情——那用 get_order_detail。
  必需:user_id 或 status 至少一个。
// 关键:每个都写了"不要用它做什么"

3. "工具重叠"的三种程度

程度 表现
完全重复 两个工具做同一件事
部分重叠 覆盖范围交叉
粒度不同 一个做一步,一个做整链

第三项最容易被"加工具"制造出来:**既有"下单"(含扣库存),又有"扣库存"与"建订单"**第三项的"成因"通常是"渐进添加":先有"下单",后来为"补偿场景"加了"扣库存",再后来为"报表"加了"建订单"——于是三个都存在,而"整链"与"单步"没有标注。
——于是"下单"时它可能选"分两步走",结果漏了一步。

修法不是"删一个",而是"在描述里写清适用层级"("整链" vs "单步")。

4. 失败反馈为什么必须"可行动"

返回 Agent 的行为
"error": "invalid param" 换参数重试
"error": "field=order_id, expected O-xxx" 改格式重试
"error": "该订单不存在,可先用 list_orders 确认" 换工具

第二项(有字段与期望格式)能救一半:它知道"哪个字段错了、应该长什么样",于是"改格式"而不是"换工具"——而这两者的成功率差很多。
第一项会让它"猜",而"猜"的表现就是"连续三次同一个工具"——因为它不知道错在"工具选错"还是"参数写错"。

第三项是"最好的反馈":它直接指向"下一步该做什么"。第三项的"额外"是"它顺便教了工具选择":一句"可先用 list_orders 确认 ID"让 Agent 学到"这两件事的先后关系",于是在下一轮更可能选对。

// 可行动的错误返回(四个字段)
{"ok": false,
 "code": "NOT_FOUND",
 "field": "order_id",
 "hint": "该订单不存在;可先用 list_orders 确认 ID",
 "retryable": false}

"选错率"可以量化,否则"改描述"只能靠感觉:

// 三个可算的数(按任务类型分)
1 选对率 = 第一次就选对工具的次数 / 任务总数
2 重试率 = 同一任务里"重复调用同一工具"的次数 / 工具调用总数
3 切换率 = 换了工具后成功的比例(低 → 换工具也没用)
// 判据:选对率 < 80% → 描述/分层有问题;重试率高 → 反馈不行动

5. 让"选对"变简单的三个手段

手段 效果
减少工具数(分层暴露) 最有效
工具名带"动作 + 对象" 提高可区分
提示里给"任务 → 工具"的示例 补上下文

第一项的"代价"要说清:分层意味着"多一轮交互"(先要工具,再调用),而它换来的是"选择准确率"——所以只在"选错代价高"时值得。
第一项是"结构"解法:18 个工具全暴露,选择空间就大。分层(先给"订单相关"5 个,需要时再给其它)能把"选错概率"降一个量级。

第二项很便宜:get_order_detail 比 order_query 清楚得多第二项的"命名规则"可以固定为"动词_对象_限定":get_order_detail、list_orders_by_status——而"限定"部分正是最容易缺的。
——因为后者无法区分"查一个"还是"查一堆"。

// 分层暴露(按任务阶段给工具子集)
stage_collect:   [list_orders, get_order_detail, get_user]
stage_mutate:    [update_order_status, cancel_order]
stage_notify:    [send_message]
// 收益:每阶段只看到 2–3 个工具,选择空间小

"工具清单"应当做成一张"可区分矩阵",一眼看出重叠:

// 工具矩阵(行=工具,列=关键维度)
工具               对象   数量  是否变更  粒度
get_order_detail   订单   单个  否        整条
list_orders        订单   多个  否        摘要
update_order_status订单   单个  是        单字段
cancel_order       订单   单个  是        整链(含退款)
// 冲突:update 与 cancel 都能"改状态" → 描述需写"cancel 才做退款"

6. 排错:五种"工具选错"

现象 成因 处理方向
反复调同一个错工具 错误反馈无信息 加 hint/field
两个工具混用 描述不可区分 加"不要用它做什么"
选"分步工具"漏步骤 粒度重叠 描述标"整链/单步"
换了模型就好了 兼容性差异 不改描述,标注模型差异
只在长任务里错 上下文稀释 缩短上下文/分层

第四项的"排查方式"是"同一描述、两个模型各跑 20 次任务":差异显著 → 模型差异;都错 → 描述问题。这个实验半小时能做完。
第四项很重要:"换模型就好"说明是"模型差异"而不是"描述问题"——此时改描述没用,要么换模型,要么给出更强的结构化约束。

最后一个"验收"方式:用任务集回归,而不是看单次对话。

// 工具选择回归集(10 条,覆盖三类易混)
"查订单 O-123 的详情"        → 期望 get_order_detail
"看看我最近 5 个订单"        → 期望 list_orders
"把这单取消掉并退款"          → 期望 cancel_order(不是 update_status)
// 断言:第一次调用的工具名 + 参数键集合;每周跑一次,看选对率

7. 边界:什么情况不必优化工具选择

场景 为什么 做法
工具很少(≤ 3) 选择空间小 不优化
任务单一(每次同一流程) 几乎不需选择 写死流程
有人工确认每一步 错了会被拦 不优化
失败代价低(可重试) 试错便宜 允许试错

判断口径一句话:"工具数 × 任务类型数"是否小到"它能记住"。最后一条与"演进"有关的边界:工具数增长会让"选错率"非线性上升。所以"加工具"应当与"分层 + 描述复核"一起做——只加不治,很快会到"怎么改描述都没用"的状态。
小(3 个工具 1 种任务),不必优化;大(18 个工具 10 种任务),必须靠"描述 + 分层 + 可行动反馈"来控制。


8. 自测

  1. 三类"选错"分别对应什么成因?为什么"加提示"只对第一类有用?
  2. 描述里"什么时候不该用"为什么比"做什么"更能区分?
  3. "粒度不同"的重叠是怎么被制造出来的?修法该写什么?
  4. 为什么 "invalid param" 会让 Agent 反复重试同一个工具?
  5. "分层暴露"为什么能降低选错概率?它牺牲了什么?
  6. 判断"是否需要优化工具选择"的那个问题是什么?
S21-A21 · 工具选择:Agent 为什么选错,以及怎么让它选对
https://www.clxhxhhr.top/posts/6601/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。