跳转到主要内容

LLM Agent 中的并行工具调用:你可能尚未意识到的耦合测试

阅读需 1 分钟Tian PanTian Pan

大多数工程师之所以选择并行工具调用,是因为他们希望自己的 Agent 运行得更快。工具执行占 Agent 总延迟的 35–60%,具体取决于工作负载——编码任务处于高端,深度研究任务则处于中端。同时运行独立的调用是显而易见的优化方案。但接下来的情况却让大多数团队感到意外。

一旦你启用了并行执行,工具设计中隐藏的每一个假设都会变得显而易见。在顺序执行时可靠工作的工具,在并发运行时可能会悄无声息地失效。原本稳定的行为变得不可预测,而且失败往往不会产生错误——只是在充满自信地返回一个错误的答案。

并行工具调用主要不是一项性能特性。它是一次非自愿的架构审计。

并行工具执行的实际工作原理

在深入探讨失败模式之前,有必要精确了解其机制。并行工具执行是模型做出的决定,而不是你的编排层做出的决定。当模型在单次响应中发出多个 tool_use 块时,你的运行器(runner)应当调用所有这些工具,并在下一步推理之前统一返回它们的结果。模型看不到中间结果——它会一次性看到所有内容。

大多数框架都会提供一个标志来抑制这种行为。OpenAI 的 API 包含 parallel_tool_calls,默认值为 true。Anthropic 没有提供直接的标志——相反,Claude 会根据请求的工具是否看起来独立来做出决定。这种行为在不同模型系列中也不一致:OpenAI 的推理模型(o3、o4-mini)要么忽略,要么完全拒绝 parallel_tool_calls 参数,如果你尝试显式设置它,会返回 400 错误。

这种不一致性在生产环境中至关重要。如果你在多个提供商之间进行路由,或者在模型版本之间进行升级,你不能假设并行行为是稳定的。无论你是否请求过,你的编排层都需要处理多工具响应。

执行模式本身非常直接:当模型在单轮中发出 N 个工具调用时,你的运行器会同时分派所有 N 个调用,等待所有调用完成,并在继续推理之前返回整批结果。延迟的降低完全来自于墙上时钟时间(wall-clock time)的重叠——一批三个独立的 200 ms 工具调用只需 200 ms,而不是 600 ms。

耦合隐藏时的三种失败模式

顺序执行是宽容的。如果工具 A 对工具 B 有隐性依赖,顺序执行会自动强制执行该依赖。你通常甚至不知道这种依赖关系的存在,因为代码一直以相同的顺序运行。并行执行则取消了这种宽容。

上下文依赖(Context dependency):工具 A 悄悄地从一个共享上下文变量中读取数据,而该变量本应由工具 B 填充。在顺序执行中,B 总是运行在 A 之前。在并行执行中,A 在 B 填充上下文之前运行,读取了陈旧或空的数据,并返回了一个看起来有效但基于错误输入计算的结果。没有抛出异常。Agent 带着错误答案继续运行。

共享状态变更(Shared state mutation):两个工具根据在写入完成前读取的状态,向同一个资源(文件、数据库行、缓存值)写入数据。这是经典的“读取-修改-写入”竞态条件。工具 A 读取当前值 (100),计算增量 (+10),并写回 110。工具 B 读取相同的初始值 (100),计算不同的增量 (+20),并写回 120。最终值是 120,但预期的值应该是 130。两个工具都没有报错。这种不一致性是无声的。

执行时序依赖(Execution timing dependency):这是最微妙的失败。一个工具中的逻辑隐式地假设另一个工具已经运行——不是因为它读取了输出,而是因为第一个工具的副作用是第二个工具的前提条件。例如,一个工具创建数据库记录,另一个工具写入相关记录;一个工具初始化会话,另一个工具向该会话添加数据;或者一个工具获取资源锁,另一个工具在锁定的资源上操作。在顺序执行中,前提条件总是能得到满足。在并行执行中则不然。

这些失败都有一个共同点:它们不是崩溃。Agent 循环继续运行,模型处理结果,下一步在损坏的状态下进行。当错误的输出显现时,执行轨迹已经向前推进了好几步,与原始并行调用的因果联系已变得不可见。

幂等性测试:在并行化之前对工具进行分类

最简单且最可靠的分类方法是在决定是否并发运行每个工具之前,问三个问题。

它是原子的吗(Is it atomic)? 工具是否只做一件事,没有其他并发工具可以观察到的中间状态?搜索查询是原子的——它读取并返回,没有其他事情发生。文件重命名在大多数文件系统中不是原子的——存在一个旧名称已消失而新名称尚未显示的窗口。

它是幂等的吗(Is it idempotent)? 如果这个工具对相同的输入运行两次,最终世界的状态是否相同?GET 请求是幂等的。除非你显式处理去重,否则创建记录的 POST 请求不是幂等的。每次调用都发送通知邮件的工具不是幂等的。

会员专享

余下内容仅对会员开放。

会员可读完整内容 —— 每一个公开发布的观点背后,那些框架、决策与推理的全貌。

  • 完整文章,包含未公开存档的部分
  • 可落地的工作框架,附带权衡与决策依据
  • 新文章抢先看,先于公开发布

随时取消 · 一次订阅,畅读全部

参考资料

保持联系,关注我获取更多内容

阅读需 10 分钟

你的 LLM 抄不准的那个账号

LLM 是 token 预测器,不是字符串复印机。当两个相似的账号出现在同一段上下文里,智能体会换错数字、把退款打给错的客户,留下一条干净得看不出问题的 trace。修复方式是把『标识符保真』从模型的工作描述里剔除出去。

insider
llm-agents
阅读需 10 分钟

流式工具结果破坏了请求-响应式智能体规划器

“缓冲并移交”式的集成会将流式工具转变为撑爆上下文、吞噬延迟的隐形故障点。一个由四个部分组成的规划器契约 —— 流式标志、运行摘要、consume_until 和预算中止 —— 能让智能体在执行轨迹而非具体数值上进行推理。

insider
ai-agents
阅读需 10 分钟

智能体规划模块:隐藏的架构缝隙

在 LLM 智能体中将任务拆解与执行分离,是大多数团队都会忽略的架构决策——直到他们的智能体在面对超过五个步骤的任务时开始崩溃。

insider
agent-architecture
阅读需 11 分钟

你的网关在 LLM 调用与工具执行之间丢失的 traceparent 请求头

生产环境中的 LLM 智能体技术栈经常在模型调用与工具执行之间丢失 W3C traceparent 请求头,导致原本连贯的用户交互逻辑碎裂成一堆“孤儿追踪”森林 —— 本文将揭示泄漏发生的环节以及如何修复它。

insider
observability
阅读需 9 分钟

原本运行良好的工具,直到两个智能体同时调用它

智能体工具通过了单调用者测试,但在第二个智能体出现的那天崩溃了。本文将探讨为什么并发漏洞在结构上对串行评估是不可见的,以及幂等性、锁定和负载测试如何修复这些问题。

insider
ai-agents