工具批量调用出错,七种 Agent 框架如何处理
测试将有效工具调用与未知工具、参数格式错误或缺少必填参数的调用放在同一批次,检查模型能否收到成功结果和错误信息。不同框架会出现错误静默消失、成功结果被丢弃或直接抛异常等行为。
AI 深度解读
模型一次返回多个工具调用,其中一个参数坏了,另一个执行成功,框架会把什么交回模型?agentic-arena 的这组测试关注两个问题:成功结果有没有保住,失败调用有没有被交代。最隐蔽的情况,是流程继续运行,模型却不知道自己漏了一部分证据。
这篇原文的价值,在于提醒我们:单次调用能正确报错,不代表放进批次后仍然可靠。不过,它测的是固定脚本下的错误处理行为,不能据此给七个框架的回答质量排名。
批量调用出错,不能只看流程有没有跑完
测试把一个有效调用分别与三种错误调用放在同一批次:工具名不存在、参数格式错误、缺少必填参数。然后检查框架发给模型的下一次请求。
原文用「both」表示成功结果和错误信息都到达了模型。这让模型既能利用已经拿到的信息,也能决定如何补救失败的调用。
测试发现了三种不同的失败方式。
第一种是静默丢失部分调用。错误调用消失,没有任何提示,流程继续回答。模型拿到的证据不完整,却不知道缺了什么。对于使用工具查询资料的 Agent,这种缺口很难从最终回答里察觉。
第二种是报了错,却把成功结果一起丢掉。原文中的 smolagents 会把错误写进一个重新组织的任务,而不是作为对话记录中的一轮反馈;与此同时,历史和成功结果也被丢弃。在这次脚本测试里,模型随后再次发出了完全相同的一批调用。
第三种是直接抛异常。它会中断流程,但故障清楚可见。测试仓库在这三种失败方式中更接受这种结果,因为它不会让流程悄悄带着缺失信息继续运行。
一次批量调用是否可靠,要同时检查成功结果是否保留、失败信息是否可见。
为什么单次调用测试通过,批量调用仍可能出问题
langgraph 的案例揭示了一个容易漏测的变化:同一个参数格式错误,单独调用时没有生成工具消息,图执行随之停止,故障能够被看见。
但当它和一个成功调用放在同一批次时,图继续运行,那个没有生成消息的错误调用就悄悄消失了。
因此,仓库放弃了「批量执行不会改变行为」这个假设,改用另一条检查规则:批量执行可以帮助流程从故障中恢复,但不能让原本可见的故障变得更隐蔽。
测试工具本身也踩了坑。初版探针通过统计返回消息里的「observation」判断反馈数量,结果资料中描述 Tokyo Tower 的一句话恰好包含这个词,把一批 2 个调用计成了 3 个。
修正后,探针改为匹配各个结果自身的文本,并增加测试,确保这些标记不会出现在资料语料中。总体发现没有改变,但「模型完全没有收到错误通知」这一说法需要撤回:smolagents 确实通知了模型,只是通知方式会丢掉其他上下文。
原文给出的测试命令是:
python -m pytest tests/test_parallel_tool_calls.py -q
要关注命令中的 tests/test_parallel_tool_calls.py:它验证的是这组批量工具调用行为。完整说明位于仓库的 docs/findings.md 第 2b 节和配套指南中。
我的判断
这组测试选对了观察位置:检查发给模型的下一次请求,比只看工具执行日志更接近问题所在。日志显示某个工具成功执行,并不能证明模型最终看到了它的结果。
但结论有明确边界。所有测试都在 mock 模式下运行,各框架接收的模型轮次经过脚本编排,字节完全一致。这样能够控制模型输出的差异,集中观察框架如何处理错误;它无法证明真实模型收到反馈后会怎样修复调用,也不能证明某个框架最终回答得更好。
原文标题提到七个框架,提供的正文却没有完整结果表,也没给出框架版本。因此,我们只能讨论这里明确描述的 langgraph、smolagents 行为,不能补出其余框架的排名,更不能直接套用到其他版本。
相比「遇错就整体重试」,保留成功结果并反馈具体错误,通常更有利于继续完成任务。但哪些错误值得重试、真实运行中能节省多少调用,原文没有给出对照数据。仓库偏好显式抛错,也是一项可理解的工程取舍,并非回答质量实验得出的胜负结论。
能拿来做什么
- 给现有 Agent 增加三组混合批次测试:有效调用分别搭配未知工具名、格式错误参数和缺失必填参数,直接检查下一次模型请求里是否同时包含成功结果与错误反馈。
- 维护 Node 工具封装时,把单次执行和批量执行放在一起验证,尤其检查单次会中断的错误,放进批次后是否变成了静默丢失。
- 排查 AI 编程流程反复调用同一批工具的问题时,检查框架有没有在错误恢复时重写任务、清空历史,或者丢弃已经成功的结果。
- 编写测试探针时,避免用资料中可能出现的普通单词计数,并增加标记与语料不冲突的检查。