多调用、并行与依赖
本节目标
- 区分同一回合多 call 与可安全并行;
- 用依赖图而非模型输出顺序决定调度;
- 定义 all、best effort、first success 等汇合语义;
- 处理部分成功、并发冲突、补偿和审批。
多个 Call 不等于并行许可
模型在一轮中返回多个调用,只说明它提出了多个动作。执行前为每个 call 标注:
- 读取/写入的资源;
- 输入依赖;
- 是否需要前一步输出;
- tenant/权限与审批;
- 幂等和并发控制;
- 失败对其他动作的影响;
- 是否可取消/补偿。
只有独立、无资源竞争、已分别授权、失败可安全汇合且并行不改变业务语义时才并发。
建立 DAG
案例:“为客户下单并发确认邮件”:
lookup_customer ─┐
├→ create_order → send_confirmation
check_inventory ─┘lookup_customer与check_inventory可并行;create_order依赖两者;send_confirmation需要新 order ID,必须后置;- 若创建订单成功而邮件失败,订单是否保留由业务策略决定。
模型的 call 数组顺序不能代替这张依赖图。若依赖只能在运行时发现,应拆回下一模型回合或让确定性 workflow 编排。
三种汇合策略
| 策略 | 何时用 | 输出要求 |
|---|---|---|
| all | 所有结果缺一不可 | 任一失败则不进入下游 |
| best effort | 独立搜索/采集 | 保留成功项和明确缺失项 |
| first success | 等价来源竞速 | 取消/忽略其余并记录赢家 |
| quorum | 多来源一致性 | 预先定义数量与冲突处理 |
每个结果仍按 call ID 独立封装,不能把结果拼成一段让模型猜对应关系。
汇合时也不能“按数组位置 zip”。本库的 validate_result_set 先按 (provider response ID, call ID) 建立唯一映射,再对每项重算 operation、主体、工具合同和 call binding;结果列表调换顺序可以接受,缺失、重复、未知身份或交换审计身份必须失败。这个检查解决关联完整性,不代表各 handler 已经可以安全并行。
并发限制与尾延迟
并行可以降低总时长,也会:
- 放大下游瞬时负载;
- 触发限流;
- 增加部分失败;
- 产生队头阻塞;
- 让重试风暴更严重。
使用最大并发、每依赖连接池、总 deadline、取消和熔断。观测单 call 与 fan-out 整体的 p95/p99,而不是只看平均。
写操作与竞争
两个 call 同时修改同一订单可能出现丢失更新。常见控制:
- 数据库事务;
- 乐观版本号/
If-Match; - compare-and-set;
- 资源级串行队列;
- 唯一约束;
- 幂等键;
- 业务状态机。
“模型认为可并行”不是并发控制。
审批应覆盖完整预览
多个写调用可先生成一张计划:
1. 创建订单:商品 A × 2,¥200
2. 使用优惠券 C10,-¥10
3. 发送确认到 user@example.com批准应绑定每项参数和组合版本。执行中参数或计划变化时重新批准。不要先批准“下单”,后续让模型自由增加收件人或金额。
部分成功与补偿
跨服务通常没有单一 ACID 事务。需要明确:
- 继续:邮件失败但订单有效,进入
PARTIAL_SUCCESS并重试邮件; - 补偿:订单创建后库存预留失败,取消订单;
- 人工修复:补偿也失败,生成诊断与工单;
- 不可逆:消息已发送,不能靠删除记录“撤销”。
补偿不是 rollback 的同义词,它本身也可能失败且需要幂等。
Provider 并行能力
截至 2026-07-19:
- OpenAI 文档说明模型可在一轮提出多个 function call,也可用
parallel_tool_calls=false限制为零或一个;当前使用内置工具时不能进行 parallel function calling,fine-tuned model 在一轮调用多个函数时 strict 也会被关闭; - Gemini 文档描述 parallel 与 compositional function calling;
- Anthropic 客户端 tool use 可以返回多个
tool_useblock。
这些能力只影响调用表达。应用仍需决定调度、依赖、并发、权限和汇合。能力不足时安全串行化,并用端到端测试证明语义不变。
动手实践
给定:
- 查客户;
- 查库存;
- 创建订单;
- 扣款;
- 发送确认;
- 写审计记录。
完成:
- 画 DAG;
- 标出读/写资源;
- 选择每个 fan-out 的汇合策略;
- 定义创建成功、扣款失败的最终状态;
- 为重试分配幂等键;
- 说明哪些 call 需要统一预览审批;
- 写出补偿失败后的人工路径。
常见错误
- Provider 返回多个 call 就全部并行;
- 用数组位置而不是 call ID 关联结果;
- “邮件失败”让整个订单显示为未发生;
- 多写操作共享一个含糊审批;
- 并发写没有版本或唯一约束;
- 补偿操作没有幂等与监控;
- 并发失败后所有分支同步无限重试。
自测
- 判断两个 call 可并行需要哪些条件?
- All 与 best effort 的用户可见语义有何不同?
- 为什么补偿不等于数据库 rollback?
- Provider parallel tool calls 与应用并发调度有何区别?
- 多写操作的审批为什么要绑定完整计划?
下一步:结果、错误与不可信数据。
参考资料
来源获取日期:2026-07-19。并行/内置工具兼容规则应在目标 API 与模型版本上复核。