Subagent Runtime:多代理编程所需的关键工程基础设施
2026/9/6 21:23:14 网站建设 项目流程

很多人是在真正跑了一次多代理编程之后,才意识到 subagent 不是一个“多问模型几次”的问题,而是一整层工程问题。最近看到有人在 Hacker News 上开源了一个面向 Codex 和 Claude 的 subagent runtime,标题写得很收敛:让 subagent 体验更好。但你真在仓库里拆过任务、让多个代理并行干活,就会明白这件事背后藏着的复杂度,远比“把 prompt 写得更清楚”大。

subagent 直译过来是“子代理”。在一个较大的编码任务里,主代理不会自己从头写到尾,而是把调研、实现、补测试、写文档、代码审查这些环节拆出去,交给一个或一组独立会话去完成。每个子代理可以有不同的目标、不同的工作目录、甚至不同的模型。等它们执行完后,再把结果回收给主代理。这套思路在演示视频里很顺畅,可一旦放到真实代码库上,问题就全冒出来了:谁负责隔离文件权限?谁把子代理的执行过程转成日志?两个子代理同时改同一个文件怎么办?子代理失败后,它写了一半的内容算不算数?

所以我想围绕这个方向展开聊一聊。真正决定 subagent 体验好坏的,往往不是模型能力本身,而是有没有一层足够可靠的 runtime;开源 runtime 的价值,也不是让模型更聪明,而是把这些散落在脚本里的工程细节变成可复用、可观察、可控制的基础设施。

1. subagent 的真正难点:不是模型变强,而是运行时变厚

1.1 从“对话式编码”到“委派式编码”

传统编程助手本质上是“对话式编码”:你和模型坐在同一个工位前,你们共享同一个上下文,所有讨论都留在聊天记录里。遇到问题时,你会顺手让模型读文件、跑测试、改代码,每一步你都看得到。

subagent 模式则不一样,它更接近“委派式编码”。主代理接受到一个高复杂度任务后,不再单线程地完成任务,而是把任务切块,分发给多个下级代理。这些子代理各自拥有独立上下文,执行过程中会产生文件修改、工具调用、中间决策,最后只把一个相对结构化的结果交回主代理手里。

这个变化会立刻引出两个约束:

  • 主代理的上下文窗口有限,它不可能把每个子代理的思考过程都完整读一遍。
  • 多个子代理在同一个仓库里协作,必须有明确的边界,否则改着改着就会互相覆盖。

于是,任务的执行方式从一次长对话,变成了一次短周期、多进程、可横向扩展的分布式作业。你需要有人去分配任务、记录状态、汇总产物、处理错误。这层东西,就是 runtime。

1.2 它和 Tool Call 的本质差异

不少人会这样理解:subagent 本质上就是一种特殊的工具调用,主代理把任务包装成一个函数,然后等待返回值。这个抽象并没有错,但它掩盖了 subagent 和普通工具调用之间巨大的工程差异。

普通 tool call 的生命周期很短,通常一次调用只做一件事,输入输出直接暴露在主上下文里。subagent 则不一样,它内部可能要做多轮推理、多次读写文件、调用各种外部命令,最后还不一定以一段文本结尾,而是产出一个补丁、一份报告、一个测试结果目录。用下面这个表格看会更清晰:

对比项普通 Tool CallSubagent
生命周期通常一次调用包含多轮思考和多次工具调用
上下文关系输入输出都在主上下文里上下文隔离,只回传结构化摘要
典型返回值一段文本或一个 JSON文件、diff、报告、结构化结果
过程可观察性主流程里能看到调用参数需要独立会话日志和事件流
失败后果一次调用失败,主流程兜底可能在仓库里留下半成品修改,恢复复杂

所以,从产品设计角度你可以把 subagent 当作“另类的 tool”,但到了实现层面,它更像一个需要进程管理、状态存储、沙箱边界、结果回收的作业单元。正是因为这种复杂度,runtime 才成为一个独立话题,而不是被随便塞进某个 CLI 里就完事。

2. 为什么官方 CLI 离“subagent 友好”还差一层

2.1 Codex 和 Claude Code 的优势在人机交互

Codex 和 Claude Code 这类终端工具,解决的核心问题是一个人如何更高效地和模型协作。它们把模型能力放进了终端或 IDE,让开发者可以用自然语言指挥模型读代码、写代码、跑命令。从“人”的角度看,它们是很好用的交互层。

但 subagent 场景有一个微妙变化:真正调用 subagent 的,往往不是“坐在终端前的人”,而是另一个程序。这个程序可能是主代理,也可能是一段持续集成脚本。程序不希望从终端拿一段人类可读的文字,它更希望拿到结构化状态、可回放的操作日志、以及可验证的文件产物。

这就使得官方 CLI 在很多编排场景里显得不够“服务化”。CLI 更多是在完成人与模型的会话,而不是开放一个可组合、可注入、可拦截的运行单元。

2.2 缺失 runtime 时,你只能自己造轮子

我见过不少团队尝试自己搭一个多代理协作流程。一开始大家觉得,只要把 Codex 和 Claude 的 CLI 像 shell 命令一样循环调用就行。结果跑了几次后发现,真正工作量的重心,早就从“写 prompt”转移到了这些地方:

  • 工作目录隔离:主代理和子代理应该共享哪些目录?子代理能不能越界读取生产配置?
  • 环境变量与密钥管理:不能把.env~/.ssh、云厂商密钥直接暴露给一个行为不可完全预知的代理。
  • 二进制和运行库依赖:Codex CLI、Claude Code 本身的安装依赖、系统级运行库、Node/Python 环境,不同机器可能完全不同。
  • 日志与会话恢复:子代理执行到一半退出,已经做的步骤能不能保留?下一条记录从哪里继续?
  • 文件冲突处理:两个子代理同时修改同一个文件时,是覆盖、报错还是做合并?

这些问题哪一个单拎出来都不难,但数量一多,就会变成一大片无人维护的胶水代码。开源 runtime 想做的,就是把这层胶水固化下来。

2.3 很多安装报错,其实都在提醒你 runtime 的重要性

另一个容易被忽略的现象是,在真实使用 Codex、Claude Code 这类工具时,用户经常连第一步“把工具跑起来”都会卡住。热搜里最常见的几个问题,例如 WebView2 runtime not found、unable to locate the codex cli binary、OCI runtime create failed、.NET runtime无效,本质上都和“环境里缺少某个运行单元”有关。

这类报错看起来像是工具坏了,实际是本地环境缺少了某个系统级运行库、桌面组件运行时,或者二进制路径没有被正确配置。真正要在生产环境维护一个 subagent runtime 时,你必须把语言运行时、系统运行库、模型 CLI 二进制、权限目录都纳入管理,否则换一台机器,整套流程就会断掉。

这正好说明了一件事:当多代理编排成为主流程时,运行环境不再是你“装一次就忘掉”的东西,而是要像依赖锁文件一样被显式记录和校验。

3. 一个 subagent runtime 真正要处理的设计问题

既然要做一个开源 runtime,它到底该关心什么?因为没有实际使用过这个项目,我这里只从通用工程视角拆几个绕不开的设计问题,所有配置都只是示意结构,不是某个项目的官方格式。

3.1 任务描述怎么标准化

如果一个 runtime 要向 Codex、Claude 或其他模型分发子任务,首先得定义一套任务描述格式。任务描述不能只是几句自然语言,它至少要包含角色、目标、约束、上下文入口、期望输出位置。这样 runtime 才能把任务变成可调度、可审计的单元。

一个常见的任务描述可能是这样:

{ "role": "code_reviewer", "goal": "review the theme switch implementation in ./frontend", "constraints": [ "read-only; do not modify source files", "ignore node_modules and dist", "output a report.md, not just a chat summary" ], "context": { "include": ["./frontend/src/styles", "./frontend/src/hooks"], "exclude": ["./frontend/.git"] }, "artifacts": { "report": "./output/review/result.md" } }

任务描述标准化之后,后面的事件日志、失败重试、并行调度才有稳定的对象。否则每个任务都长成“一段 prompt”,你很难回答“这个任务到底让子代理访问了哪些文件、产出了什么”。

3.2 上下文怎么隔离,又怎么回收

这是整个 runtime 里最容易踩坑的地方。

子代理不应该自动继承主代理的全部上下文。它只需要看到和当前子任务相关的文件、约束和历史记录。否则,主代理的上下文限制解决不了,反而多出数倍 token 开销。

设计上通常采用两段式处理:

  • 输入侧:runtime 按任务描述裁剪上下文,把指定目录、相关文件、git diff 注入给子代理。
  • 输出侧:runtime 不把子代理的完整思考过程拼回主代理,而是要求它把“最终修改”写成补丁或文件,把“决策摘要”写进报告,再按结构化摘要回收。

这种方式相当于让每个子代理在独立工作区里完成自己的活,最后只交回一份“结案摘要”和若干产物文件。真正需要看细节时,再去查阅对应目录里的日志和报告,而不是让主代理硬吞几百 KB 对话记录。

3.3 文件系统权限怎么收敛

当多个代理在同一个仓库里协作,权限控制就变成了安全问题。一个负责“读代码并输出分析”的子代理,完全没有必要获得写入权限;一个负责“实现新功能”的子代理,也应该只能在自己的工作区或指定目录里写文件。

一个示意性的权限配置可能长这样:

workspace: root: ./case-001 allow: - ${workspace}/src - ${workspace}/output read_only: - ${workspace}/config deny: - ${workspace}/.git - ${workspace}/.env

这种做法不是限制模型能力,而是在保护整个仓库。代理的行为本身有不确定性,尤其是当它看到一条权限不足的命令时,可能会有各种尝试绕过的倾向。runtime 需要从一开始就限制文件系统能力,而不是等它真改了不该改的文件后再去恢复。

3.4 事件和数据怎么流转

subagent 运行过程充满异步调用:创建任务、读取文件、执行命令、写入结果、失败重试。如果 runtime 只在最后返回一个结果,那所有中间状态对用户和管理者都是黑盒。

比较推荐的模式是让 runtime 把内部事件以结构化日志的方式暴露到一条统一事件流上。每条事件可能是这样:

{"type": "task.started", "task_id": "task_001", "agent": "claude", "ts": "2025-01-01T00:00:00Z"} {"type": "tool.called", "task_id": "task_001", "tool": "filesystem.write", "path": "./output/report.md", "ts": "2025-01-01T00:00:01Z"} {"type": "task.completed", "task_id": "task_001", "result": "./output/report.md", "ts": "2025-01-01T00:02:00Z"}

这种设计让我想起一个类比:runtime 像一根总线,IDE、CLI、持续集成脚本都只是总线上的接收面板。真正的运行细节不散落在某一个终端里,而是集中在可检索的日志流里。出现问题时,你可以沿着事件流追出“子代理在什么时候、调用了什么工具、写了哪个文件”。

3.5 要不要兼容 Codex 和 Claude 两层模型

开源 runtime 选择同时支持 Codex 和 Claude,大概率是因为实践中很少只有一个模型在干活。不同模型在某些环节各有优势:有的擅长架构梳理,有的擅长生成测试用例,有的大段文档输出速度更快。如果 runtime 能把它们封装成统一的“子代理会话接口”,那上层主代理就无所谓底层跑的是 Codex 还是 Claude。

比较理想的状态是只暴露下面这种概念接口:

SubAgentSession.run(task: TaskSpec, event_handler) -> RunResult

至于底层是调 Codex 的 API,还是启动 Claude Code 的进程,都由适配器负责。这样换模型时,上层任务编排不用改,主要成本落在适配层。

3.6 失败恢复和预算控制

subagent 一旦并行跑起来,成本和失败概率都会放大。一个子代理可能会在几十秒内连续调用很多次工具,token 消耗肉眼可见地增加。因此 runtime 一定要给每个任务设置边界,比如最大步数、最大 token、超时时间。

对失败任务,比较稳妥的做法是:先把子代理已经产生的中间文件保留下来,再决定是重试还是换一个提示词继续。

读操作型任务往往可以直接重试,但写操作型任务要格外小心。同一个补丁如果因为超时被重复应用,会让仓库进入冲突状态。所以在设计时要尽量减少“子代理自己写文件”和“runtime 统一帮你打补丁”的混用。一旦确定用哪套机制,就保持一致,否则后续排查会非常困难。

4. 落地边界:哪些场景值得用,哪些先别上

4.1 适合与不适合的场景

subagent runtime 听起来很有潜力,但它不是银弹。在实际落地前,最好先做一个判断:

典型场景是否值得上 subagent runtime
单次问答、查资料、解释一段代码不需要,直接用主代理聊就行
小仓库的单功能重构可以先手动拆两到三个子任务
多模块改造,需要并行梳理、补测试、写文档值得,重点观察文件冲突和上下文隔离
每周都会重复的代码审查、测试生成很值得,把流程沉淀成可复用任务
只跑一次的一次性脚本不一定,编排治理成本大于收益

关键不是“能不能用”,而是“用了之后维护成本高不高”。如果任务本身只出现一次,花大量时间定义任务规范、配置权限、调试事件流,反而得不偿失。

4.2 runtime 不负责任务分解,只负责把任务执行好

一句话需要说透:runtime 能保证任务被执行、被记录、被隔离,但它不能保证任务拆得合理。如果主代理把任务拆成互相依赖的碎片,子代理之间再等到做完才发现需求冲突,runtime 也很难自动修复。

因此,真正的核心能力还是主代理对任务结构的理解,以及人对整个流程的监督。runtime 更像是一条保险丝加一根总线:它防止单个子代理越界,也把整个过程暴露给你看,但它不会替你判断“这个仓库到底应该怎么改”。

4.3 先解决本地运行环境的稳定性

在评估 subagent runtime 之前,很多人连第一步都会被卡住。你可能已经在网上见过类似报错:代码工具在启动时提示缺少某个 runtime,Windows 下会报 WebView2 runtime not found,Linux 容器环境里可能报 OCI runtime create failed,还有各种“找不到 cli”的问题。它们表面上是不同工具的毛病,本质却都是同一件事:本地运行环境没有被打理干净。

如果要用这类工具做正经的 subagent 流程,最好先养成一套排查顺序:

  1. 先确认报错来自哪个二进制:是模型 CLI,还是 IDE 插件,还是容器运行时。
  2. 再检查它依赖的系统运行库、桌面组件是否安装,版本是否匹配。
  3. 然后检查 CLI 路径是否正确,有没有安装多个版本导致调用到旧路径。
  4. 接着检查当前工作目录的权限、目录可写性。
  5. 最后才去怀疑模型接口或子代理逻辑本身。

这几个步骤看起来基础,但在日常使用中,绝大多数“工具打不开”“启动后闪退”问题,答案都出在这一层。

4.4 成本、人工审批和可追溯性

并行 subagent 会让执行速度变快,也会让 token 消耗和工具调用次数同步上升。更麻烦的是,某个子代理一旦跑偏,它可能在一个错误的方向上重复调用工具很久,直到预算耗尽。

行之有效的方法有三个:

  • 先只并行两个子代理,观察整体 token 量和耗时,再慢慢加并发。
  • 对高风险操作设置人工审批,例如删除文件、覆盖线上配置、执行外部命令。
  • 每次任务结束后保留任务描述、事件日志、最终产物,确保同一任务能被复盘和回放。

这些措施不复杂,却是 runtime 进入生产环境前必须补齐的工程能力。

5. 给想试的人一条最小落地路径

5.1 不要从复杂框架开始

如果你想认真体验 subagent 协作,我建议先不要急着搭一套完整 runtime。大多数团队现在最缺的,其实是对“任务拆解和产物回收”的真实感受。

可以按下面这个顺序来:

project/ runs/ 001_login-refactor/ tasks/ research/ input.md result.md implementation/ patch.diff review/ issues.md manifest.yaml

第一步,准备一个干净目录,把任务拆成研究、实现、审查三个子任务。

第二步,手动把其中一个子任务交给 Codex 或 Claude 执行,要求它把产出写到指定文件,而不是只在聊天框里回复。

第三步,看执行结果是否完整:它读了哪些文件?产出了什么?有没有把不必要的内容写进工作区?

第四步,再加一个子任务,让两个子代理并行执行,观察是否会互相覆盖文件。

第五步,如果重复多次仍然稳定,再考虑引入 runtime 或自定义 harness 去把它固化下来。

这个过程的意义在于,它会强迫你提前思考“任务边界”和“产物格式”。即使最终你没有用到任何开源 runtime,这些经验也会让后续落地顺畅很多。

5.2 判断该不该引入 runtime 的三个信号

当下面几个问题的答案多数为“是”时,就值得认真看一下 runtime 方向:

  • 同一类任务是不是会周期性出现,比如每个迭代都要生成测试、做代码审查、更新文档。
  • 是不是需要多个代理并行处理不同模块,而不是一个代理单线程跑完整件事。
  • 是不是需要把执行过程变成团队可复用的配置,而不是每次都在终端里临时口头交代。
  • 是不是需要结果可追溯、可回滚,甚至连失败现场都能还原。

如果一个都不满足,直接用官方 CLI 可能更舒服;如果满足了两个或以上,那 runtime 带来的治理能力会逐渐超过它的配置成本。

5.3 验收时不要只看“任务完成”

最后提醒一个容易被忽略的点:当子代理跑完,你验收的绝对不只是“它说自己完成了”。你还要验证:

  • 修改文件没有越过权限范围。
  • 产物文件真实存在,且内容格式正确。
  • 执行过程在日志里可回放,能回答“哪个代理、在什么时候、改了什么文件、为什么这么改”。
  • 失败之后能恢复,而不是每次都要从头重跑。

在 subagent 场景里,输出不等于生成一段文本。输出是改到磁盘上的文件、写进日志里的决策、沉淀在报告里的结论。一个真正好用的 runtime,本质上就是在帮你保证这些输出可以被确认、被追溯、被复用。

所以回到最开始那个判断:Codex 和 Claude 的模型能力已经足够让人看到 subagent 的潜力,但潜力要变成生产力,还需要一层可靠的运行时来承接。这个方向被开源出来,值得关注的价值不在某个具体命令或界面,而在于它提醒了我们:复杂的多代理协作,终究不是靠几段聪明 prompt 就能稳定运转的。真正让人放心的,是那些把执行过程管住、把失败边界收住、把每一步都记录下来的基础设施。对想尝试的人来说,下一步可以先别求多,用最小流程跑两个子任务,亲自感受一下断点会出现在哪里。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询