Appearance
一次 Tool 批次如何安全执行:Parallel Call、Error 与 Timeout
前置:从发现 Tool 到可回灌结果:Search、Execution、Normalization 与 Result Budget
同时读取三个独立文件可以并行;“创建订单”与“基于订单 ID 发货”不能因为模型一次返回两个 call 就并发。支付请求超时但服务端可能已扣款属于 uncertain outcome,应先查交易状态/reconcile,而不是直接 retry。
Parallel Tool Calls
模型一次返回多个 Tool Call,只说明“它同时提出了几个动作”,不等于 Runtime 必须并发执行。真正能并行通常要同时满足:
text
没有数据依赖
没有冲突的资源写入
权限/approval 可以独立判断
下游容量允许
失败后允许部分结果存在Runtime 还要为每个 call 保存独立 attempt/trace,并明确批次是 fail-fast、等待全部结果,还是允许 partial success。
Tool Error Taxonomy
Tool Error Taxonomy 是把一次 Tool 调用失败归一化为 validation、permission、not-found、rate-limit/transient、timeout、semantic/side-effect-uncertain 等可操作类别。分类的目的不是给错误换名字,而是让 Runtime 能决定是否 retry、replan、请求审批或进入 reconciliation。
Timeout
Timeout 是 Tool 单次执行的等待上限,必须区分 connect/read/operation 等层次,并受 Node/Run 的剩余 deadline 约束。超时后的关键不是“抛异常”而是底层 I/O 是否真的被取消,以及副作用是否处于不确定状态。
🔍 源码对照:Stall Observation 不等于 Retry Decision
完整源码与通用分析见 11-01 Timeout / Deadline / Retry。这里不重复代码;这里关注 Tool Executor:stall / timeout 先形成 Observation;是否 retry 由 side-effect semantics 与 Reliability Policy 决定。
源码说明
turn-observation.ts 不只记录最后一个 Tool,还维护 recent activity、pending awaits、async task 类型以及 tool pending/done/failed 状态。这比“await gather() 得到一组字符串”更接近生产 Runtime:并行执行必须持续回答哪些动作仍在运行、哪些已经失败、Turn 是否正在等待,以及这些状态怎样进入 event/trace。
工程边界
观察对象的具体字段和 stall threshold 属于该产品;我们只吸收“并发中的每个 execution 必须有独立 lifecycle 与 identity”这一 invariant。
Shadow Harness 对照
- 并行 ToolCall 每个都有 attempt/execution id,不以数组位置识别。
- batch failure policy 明确区分 fail-fast、collect-all、cancel-siblings。
验证
三个 Tool 并行:一个成功、一个超时、一个被取消;验证每个 Observation 都有独立 terminal state,且 cancellation 不被记录成 generic failure。
哪些 Tool Call 可以并行,哪些不能
一个排查任务同时需要“查最近错误日志”和“读取当前配置”,两者互不依赖,可以并行:
text
┌─ search_logs ─┐
model action ┤ ├─ join observations → next turn
└─ read_config ─┘但“创建工单 → 把工单 ID 写入客户记录”不能并行,因为第二步依赖第一步结果。类似地,两个都会修改同一文件的 Tool 即使数据上没有显式依赖,也可能存在资源冲突,Scheduler 需要额外的 conflict policy。
并行执行时错误也不能只压成一个 failed=true。Runtime 至少要保留每个 call 的 identity 和结果:
text
call A: SUCCEEDED result_ref=artifact://logs/42
call B: TIMED_OUT retryable=true
call C: REJECTED reason=permission下一轮模型看到的应该是规范化 observation,而 Scheduler 则根据程序规则决定 B 是否重试、A 是否保留、C 是否进入 approval;不要让模型用一段自然语言重新解释这些系统事实。
Failure Modes
把有依赖或副作用的 Tool Calls 无脑并行
症状: 两个 Tool 实际存在读写依赖,却因为同一模型响应里出现就同时启动。
为什么危险: 结果出现 race、覆盖或顺序相关副作用。
处理: 仅对明确无依赖 call 并行;写操作通过 graph/dependency/resource key 或串行 policy 约束。
如何验证
| Case | 断言 |
|---|---|
| 把有依赖或副作用的 Tool Calls 无脑并行 | 共享资源的两个 ToolCall 不得同时执行;独立 read-only call 才并发。 |
关联源码
自测
- 两个 read-only search 可以并行,但
apply_patch和依赖其结果的pytest为什么不能无脑并发? - 并行批次中一个 Tool timeout、另一个成功。Runtime 应怎样记录 partial result、cancel 状态和最终 Observation?