Claude 工具调用在 Agent 循环里最容易踩的五个坑
用 tool_use 搭 Agent,前半段通常很顺,真正耗时间的是循环跑起来之后:工具结果回传格式不对、并行调用索引错位、循环停不下来。下面五个点按出现频率排,多数都能在日志里直接看出来。
一、tool_use 和 tool_result 必须严格配对
模型返回的 tool_use block 带 id、name、input,下一轮你必须用一个 user 消息回传 tool_result block,里面的 tool_use_id 要和它一模一样。常见错误是:把 tool_result 塞进 assistant 消息;或者 tool_use_id 复制时多了空格;或者一次 tool_use 只回了一半结果。这些都会触发 400 invalid_request_error,但错误信息往往只提示 “messages 结构不合法”,不容易定位。
排查方法:在回传前把 tool_use_id 打印出来做字符串比对,长度和内容都要一致;确认 tool_result 的 content 是字符串或 block 数组,不要直接塞 dict。
二、并行工具调用要对齐 index
一次响应里可能出现多个 tool_use block,流式下它们会以 content_block_start 的 index 区分。如果解析器只用 name 做键,两个同名工具同时被调用时就会互相覆盖参数,表现为 “工具收到的参数是另一个工具的”。
正确做法是把 index 一并带进内部数据结构,content_block_delta 时按 index 累加 input_json_delta 的片段,拼完再 json.loads。这里还有个细节:input 是分片到达的,不要在第一个 delta 就尝试解析。
三、stop_reason 为 tool_use 不代表结束
stop_reason=tool_use 的意思是 “模型要调工具”,循环要继续;只有 end_turn 且没有新的 tool_use 才是自然结束。很多实现把 stop_reason != end_turn 当成异常直接退出,Agent 就只跑了一轮。
另外必须自己设硬上限:最大轮数(比如 12 轮)、累计 token 上限、单轮耗时上限。模型有可能反复调用同一个工具,靠模型自己收敛不可靠。
四、同一个 tool_use_id 只能回传一次
网络超时后重试,很容易把同一个 tool_use_id 的 tool_result 传两遍,或者传了结果又重发原始请求。前者会让上下文里出现重复 block,后者等于让模型重新决策,既浪费 token 也可能产生重复副作用(比如下了两次单)。
做法是给每个 tool_use_id 建一个幂等表,回传前查一次;工具本身如果是写操作,也在服务端用 tool_use_id 做幂等键。Token5u 的请求日志按 request_id 可回查,出现重复调用时能直接看到同一轮被发了两次,定位比翻应用日志快。
五、跨入口时 schema 描述要收敛
tools 里的 description 太长、required 字段互相矛盾、嵌套对象过深,都会让模型倾向于 “少调” 或者 “乱传参数”。换入口时这类问题会被放大,因为不同实现对 schema 的容忍度不一样。
建议把工具描述压到三行以内,参数只留必要项,枚举值写全;上线前用固定 prompt 跑 10 次,统计工具选择准确率和参数合法率。Token5u 的接口在 tools 字段上是原样透传的,做 A/B 对照时 schema 不用改写,能直接看出差异来自模型还是来自入口封装。
总结
配对规则、index 对齐、循环终止条件、幂等回传、schema 收敛,这五点覆盖了 Agent 循环里绝大多数 “跑不通” 和 “跑不停” 的情况。先把这五处埋点做对,再去调 prompt,效率会高很多。
- 点赞
- 收藏
- 关注作者
评论(0)