Agent 工具执行:并行(parallel_tool_calls)和后台(run_in_background)到底有什么区别? (学习笔记)

自研 Agent(学习 Claude Code 实现)过程的一个高频困惑:模型一次调用多个工具是"并行",把工具丢后台是"后台",这两个是一回事吗?CC 两个都有吗?谁来决定?这篇文章一次讲透。

开头:一个常见的直觉误区

刚开始学的时候,我下意识把"并行"和"后台"当成一回事------都是"同时做多件事"嘛。其实它们是两个完全正交的维度,解决的是不同的问题:

  • 并行(parallel_tool_calls) :解决"这一轮怎么跑 "------模型一次返回 N 个工具调用,它们同时执行 ,结果一起在下一次回复里回来。
  • 后台(run_in_background) :解决"结果要不要现在要 "------这个操作不阻塞模型 ,先回个占位符,结果以后以通知注入。

一句话:并行 = 同一轮里 N 个工具同时干活;后台 = 把某个活丢出去,结果晚点再要。 一个是"并发执行",一个是"延迟取结果"。

先打个比方

  • 并行像同时炒三个菜,然后一起吃。你还是守在厨房,只是三个灶台同时开火,总时间从"三道菜依次炒"变成"最慢那道菜的时间"。
  • 后台像点了外卖,然后接着写代码。菜到了(可能十分钟后)再吃,这期间你不等它。

逐个拆解

并行:发生在"工具派发层"

模型在一条回复里返回多个 tool_use(比如同时读 3 个文件、git status + ls 一起来)。CC 把这些并行安全 的工具同时执行,受 CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY 限制(默认 10 个并发)。

关键特征:

  • 结果必然在下一次回复里全部回来------模型一次就能看到 N 个结果
  • agent 循环会等------等待所有并行工具完成,把结果批量喂回给模型。只是等待的墙钟时间从"串行之和"变成"最慢一个"
  • 生命周期活在当前 turn 内,跑完就完了

后台:发生在"任务生命周期层"

模型在某个 bash 调用上带 run_in_background: true。CC 把这个调用从当前 turn 里摘出来,变成一个独立的后台任务 ,回一个占位结果,完成后再通过通知队列(enqueueTaskNotification)注入后续 turn。

关键特征:

  • 结果不一定什么时候回来------可能是下一个 turn,也可能是下下个,甚至你换了话题它才冒出来
  • agent 循环不等------立刻拿到占位符,继续跑
  • 生命周期超出当前 turn ,独立存在。这也是 CC 里 7 种后台任务类型(local_bashlocal_agentremote_agent 等)那一层的事

对比表

维度 并行(parallel_tool_calls) 后台(run_in_background)
解决什么问题 同一轮多个工具同时执行 慢操作不阻塞模型,结果延迟给
结果什么时候到 下一次回复,必定一起到 以后某个 turn 边界,以通知注入
agent 循环等不等 等(所有并行工具完成) 不等(立刻占位)
生命周期 活在当前 turn 内 独立,可超出 turn
控制方式 模型一次返回多个 tool_use 单个调用带 run_in_background 参数
并发上限 有(默认 10) 无硬性限制(独立子进程)

关键问题一:进并行的一定不会进后台吗?

对,单个工具调用是"二选一"的派发------要么前台(可能并行),要么后台,不会两边都进。但一次回复里可以混着两种。

看派发的实际机制。模型一次返回 N 个 tool_use,CC 对每个调用做一次二元派发:

复制代码

模型返回 [bash(npm install, 后台), read_file(a), read_file(b)]

│ │ │

│ └──────┬──────┘

后台路径 前台路径

立刻回占位符 并行执行,等真结果

结果晚点通知 下次回复一起给

  • run_in_background=true 的那个 → 后台路径:立刻回占位符,不再参与"等待结果"这件事
  • 前台的多个调用 → 并行路径:一起执行,下次回复里真结果一起回来

所以"进并行的一定不会进后台"这句话,在单个调用的层面是对的------一个调用派发时只能走其中一条路。后台化的调用已经用占位符"退出"了并行组,并行组等的是那些要真结果的前台调用。

但一个 turn 里可以同时出现两者(上面的例子就是)。所以它不是"整个 turn 二选一",而是"每个调用二选一,turn 可以混合"。

关键问题二:进并行和进后台,都是大模型自主决策吗?

不完全一样。后台是模型直接决定;并行是"模型提议,harness 拍板"。

后台:模型说了算

run_in_background 是 bash 工具 schema 里的一个参数,模型显式决定某个调用进后台。这是模型自己的选择,harness 不干预,也不会把前台工具偷偷挪去后台。

注意:很多教学实现里会有"关键词启发式兜底"(命令里出现 install/build/test 就自动丢后台),这是教学的简化设计,真实 CC 没有------模型不指定,就是前台。

并行:模型提议,harness 执行时决定

关键在于:模型并没有一个"run_in_parallel"参数。 模型"决定并行"的方式是间接的------它选择一次回复里请求多个工具(tool_use 数量是模型定的)。但真正是否并发执行,是 CC 的执行引擎决定的:

  • 判断每个工具是否"并行安全"(concurrency-safe)------有些工具会改动共享状态,必须串行
  • 受并发上限 CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY(默认 10)约束
  • 安全且没超限的,才真正并发跑;否则退化成串行

所以拆开是两层:

决策 谁决定 怎么决定
一次要几个工具 模型 一次返回 N 个 tool_use
后台不后台 模型 调用时带 run_in_background 参数
实际并发不并发 harness 判断并行安全 + 并发上限

一句话:模型决定"请求什么、要不要后台";harness 决定"能不能真的并行跑"。

顺带:Anthropic API 和 OpenAI 协议的一个差异

我用的是 OpenAI 兼容协议(DeepSeek),API 里有个显式的 parallel_tool_calls=True 参数------这是 OpenAI 风格的显式开关。而 Anthropic Messages API 没有这个参数 ,模型返回多个 tool_use 就隐含"可以并行",CC 的执行引擎负责决定怎么跑。

如果从零写 Agent,很容易在这个地方踩坑:API 参数开了并行,不代表执行层真并行。

回到自研实现:两个机制都处于"半成品"状态

很多人从零手写 Agent,两个机制往往都没真正落地:

并行:开关开了,执行是串行的。 比如我自己的代码,虽然给 API 传了 parallel_tool_calls=True,但工具执行循环是逐个 for 循环跑的------模型确实一次返回了多个工具,实际却是一个一个执行,墙钟时间退化成了串行之和。要做真并行,得把执行循环改成"并行安全的工具分组、线程池执行"。

后台:管理类实例化了,主循环没接。 BackgroundManager 写好了(background_tasks 字典、锁、daemon 线程、通知收集),但主循环的工具执行里根本没调用它------所有工具还是同步阻塞。

两个机制的改造方向是独立的两块工作,互不依赖:

  1. 把工具执行循环改成 ThreadPoolExecutor 并发执行,但只对无冲突的只读工具并发 (读文件、bash 查询等);会改动共享状态的工具(todowrite_file、建任务这类)保持串行,否则有顺序/竞态问题。
  2. BackgroundManager 接入工具执行:让 run_in_background 参数真正生效,慢操作走 daemon 线程 + 占位结果 + 通知注入的完整链路。

总结

把这次学习钉死的几个认知:

  1. 并行和后台是两个正交维度,不是一回事:并行管"同一轮怎么跑",后台管"结果要不要现在要"。
  2. 单个调用二选一:要么前台(可能并行),要么后台;但一个 turn 可以同时混两者。
  3. 决策权不同:后台模型说了算(显式参数);并行是"模型提议(返回多个 tool_use)+ harness 拍板(并行安全 + 上限 10)"。
  4. API 开关 ≠ 执行层并行 :parallel_tool_calls=True 只是让模型可以返回多个工具,真正并发与否取决于执行引擎。
  5. 并行安全是关键约束:不是所有工具都能并行,改共享状态的必须串行。

如果你也想弄懂 Claude Code 这类 Coding Agent 到底是怎么工作的,这个仓库也许能帮你少走一些弯路。目前我的github的项目(OpenAI SDK 版),我学习的课程为learn-claude-code的v2版本课程(感谢原作者),大家一起学习,共同进步。如果对你有帮助,请为我点一个Star。

项目地址:https://github.com/peijiping/learn-claude-code-langchain

相关推荐
Oll Correct1 小时前
Adobe illustrator 案例四:吃豆人 (Pac-Man)图标绘制
笔记·ui·adobe·illustrator
何事误红尘1 小时前
KF32A学习笔记(二):IDE基本使用、srec和hex格式、FreeRTOS移植
学习
LuminousCPP1 小时前
单链表专题(四)-刷题复盘篇-LeetCode 138 随机链表复制|原地拷贝法突破复杂指针操作
数据结构·笔记·算法·leetcode·链表
萌新小白YXY1 小时前
SAE J1587/SAE J1708 协议笔记
笔记·单片机·嵌入式硬件
IT古董1 小时前
【MES学习笔记系列】MES 推荐书籍与资源
笔记·学习
迪丽热爱1 小时前
每日英语-11
学习
一米阳光86612 小时前
软考(中级)软件设计师核心笔记(9)算法——时间复杂度与空间复杂度、查找算法、排序算法
笔记·算法·职场发展·软考·软件设计师·中级职称
米饭不加菜2 小时前
常用基本求导公式与法则(超详细推导版——上)
经验分享·笔记
新知图书2 小时前
4.2 北京欢迎您:基于Anthropic的京韵导览Agent实战(智能体工程)
人工智能·agent·ai agent·智能体·智能体工程