从上下文隔离到失败回收:Codex与Claude的Subagent运行时实践
2026/9/23 4:29:43 网站建设 项目流程

从上下文隔离到失败回收:这个开源运行时为什么能让 Codex 和 Claude 的 Subagent 真正好用

我判断这会是一个重要的方向:模型能力已经不再是编程助手的唯一瓶颈,subagent 的“运行时体验”才是。过去半年,多智能体设计里最明显的变化,是主从模式从“研究论文里的概念”变成了“开发工具里的默认选项”,而本质上,subagent 是被当成一种另类的 tool 来调度和执行的。

但很多人在实际使用 Codex、Claude Code 这类工具时,真实体验并没有想象中那么顺滑。问题往往不在大模型能不能理解任务,而在 subagent 执行层:上下文怎么隔离、任务怎么派发、状态怎么同步、工具权限怎么控制、失败之后怎么回收,哪一个环节设计不到位,都会让你觉得“这 Agent 好像有点笨”。

如果你最近在关注 Codex 和 Claude Code 的生态,也看过类似“Show HN: Open-sourced runtime for better Codex and Claude subagent experience”这样的项目,你会发现一个趋势:越来越多的人开始把 subagent 的调度从模型 prompt 里抽离出来,交给一个专门的开源运行时去负责。这篇文章会从为什么需要 runtime、runtime 到底管什么、核心流程怎么设计、实际环境如何配置和排查这几个角度展开,帮你建立一套判断这类项目是否值得使用的框架。

如果读完你只能记住一个结论,我希望是这个:多 Agent 系统的问题,大多数不是“模型不够聪明”,而是“上下文无法持续、执行没有边界”。谁把 runtime 层的上下文管理和失败回收做扎实了,谁才能真正提升 subagent 体验。

1. 这篇文章真正要解决的问题

先说一个让人困惑的地方:Codex 和 Claude Code 本身已经是很强的编程工具了,为什么还需要一个额外的开源环境,也就是 runtime,去优化 subagent 体验?

因为“模型能写代码”和“Agent 能把代码任务稳定执行完”是两件完全不同的事。

在使用 Codex 这样的工具时,很多任务已经不是简单的单轮问答了。你需要它读取项目结构、修改多个文件、运行测试、根据报错继续修复,直到测试通过。这个过程中,Agent 需要调用终端命令,需要读取文件,需要感知代码变化,遇到报错需要回到代码上下文里继续调整,整个过程是一个循环。而 Claude Code 很早就提出了 subagent 的概念,让主 Agent 可以把某个子任务“外包”给一个专用的子代理,比如“让一个安全审查子代理去检查依赖风险”。这种模式的好处很明显,主 Agent 不必把无关的上下文塞进自己的主线程,子代理可以在独立的上下文窗口中专注处理任务,再把结果摘要返回给主 Agent。

但在实际工程化落地的时候,这套机制没有想象中那么简单。

你让一个子代理去修改代码,主代理需要知道它改了什么、改到哪一步、中间有没有产生副作用。子代理跑了一个测试脚本,主代理需要拿到日志,并根据日志决定是重新尝试还是终止任务。子代理之间可能有依赖关系,一个任务的输出是另一个任务的输入。如果只是依靠 prompt 里写“请把结果整理给你父亲”,这套体系很快就会碰到上下文膨胀、状态失真和执行失控的问题。

开源运行时想解决的正是这个夹在模型和实际环境之间的“调度与执行层”。它负责把 subagent 任务实例化,规定子代理能访问哪些工具和目录,把子代理运行过程中的日志和产物持久化下来,让主代理可以随时恢复上下文。换句话说,传统方式里你需要靠提示词来约定子代理的行为边界,而 runtime 方式是用代码和配置文件把这种边界固化下来,让上下文、生命周期和失败回收都有明确的机制。

我在查阅相关讨论时,很多开发者的真实感悟是:不要幻想模型能自动安排好一切,runtime 的价值是把 Agent 的不确定性约束在一个工程可控的范围内。这也是我觉得这个主题值得写的原因,它背后其实是 AI 编程工具从“实验玩具”走向“生产协作工具”的关键一步。

2. Subagent 的核心原理:主从模式与工具化调用

2.1 从“概念上的子代理”到“工程上的执行单元”

要理解 subagent 体验,可以先看一个最常见的误解。

有人说,subagent 不就是“让一个 GPT 去指挥另一个 GPT”吗?如果这样理解,很容易把所有精力都花在提示词上,写非常复杂的指令去约束子代理。但真正在多 Agent 框架里实践过之后,你会发现一切的做法,其实是把 subagent 当成一种更加高级的 tool 进行调用。

什么叫把 subagent 当成 tool?传统的 tool 是指 Agent 可以调用的一个函数或者一个接口。Agent 的判断是:我需要获取天气,所以调用 weather API;我需要执行一段代码,所以调用 Python 执行器。Tool 的核心特征是:它有明确的输入输出 schema、它有明确的执行边界、它在调用失败后可以被 Agent 感知并决定下一步。而 subagent 也是这样,主代理的决策逻辑是:“我需要完成代码审查,我可以调用一个通用代码审查 tool,也可以调用一个专门的审查子代理”。不管底层执行的是工具函数还是一个完整模型,对主代理来说,它服务的本质都类似:一个输入任务,返回结果的执行器。

我们把 subagent 工具化之后,就会立刻意识到一个问题:这个执行器不能只是一个模型对话。它必须有运行时行为,比如接收参数、创建独立的会话窗口、在指定目录下执行操作、调用白名单工具、限制执行时间、把 stdout 和文件变更记录下来、最后把结构化的结果返回给调用方。

2.2 主从模式为什么是当前最稳妥的选择?

主从模式并不是所有多 Agent 架构的名字,但它目前在这些编程工具里成为主流设计,是因为工程上够稳妥:

  • 主 Agent 保存全局目标和用户上下文。
  • 子 Agent 负责一个高内聚的子任务。
  • 子 Agent 不直接面向用户,它面向主 Agent 的单项需求。
  • 主 Agent 收集各子 Agent 结果并决定继续调度或交付。

这个模式跟“多个 Agent 平级协作、互相讨论”的模式相比,主要优点是责任边界清晰。主 Agent 是唯一需要对用户负责的角色,子 Agent 是工具化执行单元,即使某个子 Agent 跑偏了,主 Agent 的全局上下文也大概率不会失控。

当然,主从模式也会引入新问题。如果每个子 Agent 的启动和销毁都非常昂贵,频繁调度会带来很大的延迟和成本。如果主子上下文之间没有良好的输出摘要机制,主 Agent 一样会被冗余信息淹没。这就是为什么 subagent 的运行时体验如此重要:它需要高效地管理生命周期,精确地传递信息。

2.3 为什么运行时是优化 subagent 体验的关键?

可以从一个类比来理解 runtime 的含义。很多桌面应用或开发工具在启动时会报错“could not find the WebView2 runtime”,或者报“无法定位 Codex CLI 二进制文件”。这说明底层运行引擎缺失,上层应用就无从谈起。对 subagent 来说,它的运行引擎就是一套完成“上下文初始化、工具注册、任务循环、结果持久化”的代码,也就是 runtime。

没有 runtime 的时候,subagent 的执行方式大致是:

  • 开发者在 prompt 里写清“你是资深后端工程师,请帮我修复这样一个 bug”。
  • 子模型开始对话,读文件,试错。
  • 因为会话窗口有限,子模型可能丢失初始任务目标。
  • 主模型侧只收到一个可能很长的回复,无法判断哪些输出是可信的。
  • 一旦执行中断,没有状态可以恢复,整个子任务要从头再来。

有了 runtime 之后,执行方式会变化:

  • 主代理通过统一 API 发起一个 subagent 执行请求。
  • runtime 根据任务类型选择一个配置好的执行策略。
  • runtime 为这次执行创建独立的会话隔离区和工作目录。
  • 子代理的所有操作都会生成结构化事件流。
  • 如果某个环节失败,runtime 返回错误类型和日志片段;主代理无需阅读全部日志也能决策。
  • 如果执行成功,runtime 返回可验证的产物路径。

所以这个开源项目标题里说的“experience”,并不是 UI 层面的美观,而是工程上的可控。可维护的 subagent 体验,依赖可观测、可恢复、可终止的运行时设计。

3. 现代编程 Agent 的上下文困境与隔离方案

3.1 上下文为什么是 Agent 的核心资源?

我们知道大模型对话都有一个上下文窗口限制。在单 Agent 编程场景下,如果项目代码量很大,模型需要反复读取相关文件,聊天历史越长,可用空间越少,效果就越差。你可能会发现 Claude Code 或 Codex 在多轮修改后开始“忘记”前面的要求,主要原因不一定是模型不够聪明,而是上下文太挤了,信息被覆盖或忽略了。

Subagent 的一个重要存在意义就是优化上下文资源。主 Agent 把一个大任务拆成子任务后,子 Agent 只需要读取跟子任务相关的代码目录,不需要把整个项目的上下文都带在主会话里。通过这种隔离方式,每个 Agent 都能在自己有限的上下文窗口里做更聚焦的事情。

但 Subagent 又会带来另一个问题:大量子 Agent 并行运行后,如果它们的中间日志、产物、执行状态全部回流到主会话,主会话会再一次被撑爆。所以主 Agent 和子 Agent 之间,理想情况应该是一个“高压缩比的信息协议”,而不是把所有细节都原样拷贝。

3.2 上下文隔离不等于上下文丢弃

很多刚接触 subagent 的人会有一种错误理解,既然要隔离上下文,那就让子 Agent 完全独立。可是完全独立就意味完全失控。一个代码修改任务,如果子 Agent 不知道主 Agent 采用了什么技术栈,不知道项目里已有的命名规范,它修出来的代码只是“看似正确”。因此,隔离方案需要遵循一条原则:公共信息按需注入,私有上下文严格隔离,结果信息结构化返回。

公共信息包括:项目根目录、语言版本、构建命令、依赖管理方式、测试命令。这些是子 Agent 执行的“外部环境设定”,应该由 runtime 统一注入。子 Agent 私有上下文包括:它自己读取到的文件内容、它的思考过程、它执行的命令返回结果。这些内容不应自动共享给其他 Agent。返回给主 Agent 的应该是结果摘要,而结果摘要可以由 runtime 在子 Agent 输出之上做处理,比如截取关键 diff 和测试结果。

一句话总结:subagent 体验优化,是合理调度上下文资源,而不是去堆更多的上下文。

4. 开源运行时应该具备哪几个核心模块?

我不打算把某个具体作者项目的 API 说得极其确定,因为开源项目迭代速度很快。但从这一类 runtime 的设计需求来看,模块结构通常具有很强的共性。你拿到任何一个新的 runtime 项目,首先可以把它拆成四个模块去分析判断:任务抽象层、工具执行层、生命周期管理、观测与产物层。

4.1 任务抽象层

运行时需要屏蔽底层模型实现差异,这样将来想换成 Codex、Claude Code 或者其他模型,才不用重写整个系统。任务抽象层做的事情通常包括:

  • 接收统一的 subagent 任务定义,例如任务描述、需要输入的文件、可用的工具列表、任务超时时间。
  • 将任务编译成特定 Agent 可以理解的配置格式,例如对应 Codex 的任务配置或 Claude Code 的 subagent 定义。
  • 校验参数合法性。

通过抽象层,业务代码不需要关心底层用的是 Codex 还是 Claude。这种设计跟我们在现代后端开发中用接口解耦依赖是一个道理,模型会变,scheme 相对稳定。

4.2 工具执行层

子 Agent 在开发场景里需要执行哪些工具?至少包括文件读取与编辑、终端命令执行、代码搜索、测试运行器。但问题在于,不是每个子任务都应该拥有全部工具。比如一个专门做代码安全审查的子 Agent,可以让它只读代码,不需要给它文件写入权限。一个负责修复 bug 的子 Agent,可能需要终端命令权限,但应该限制它只能操作白名单目录,避免误删项目外部文件。

工具执行层同时要处理 Agent 调用工具的协议转换。如果底层是 Claude Code,那么工具调用可能遵循 Anthropic 工具调用格式;如果底层是 OpenAI Codex,可能是另一种函数调用格式。Runtime 把统一协议和厂商协议之间的转换封装好之后,上层开发者可以定义一种自己的工具白名单,让不同模型都能复用同一套工具逻辑。

4.3 生命周期管理

Subagent 从创建到结束,生命周期应该有明确的阶段划分:pending、running、completed、failed、cancelled。如果没有生命周期管理,主 Agent 就像一个不知道有几个实习生、也不知道实习生任务进展的负责人,协作必然混乱。

生命周期管理的具体职责包括:

  • 启动时分配 workdir 和 context id。
  • 运行中健康检查,例如心跳或日志进度条。
  • 超时自动终止。
  • 任务是无法继续时,捕获错误状态。
  • 任务完成后清理临时资源,仅保留产物和摘要。

4.4 观测与产物层

这个模块决定了 runtime 是否适合生产使用。设计良好时,开发者应该可以随时查看:

  • 每个 subagent 的输入参数。
  • 运行过程中调用的工具列表。
  • 关键文件变更记录。
  • 运行日志。
  • 任务结果和产物文件位置。
  • 成本 Token 消耗。

没有这些观测数据,我们很难判断 Agent 为什么表现不好。当你发现 Agent 在执行时偏离目标,如果没有 trace,你只能猜测;有了 trace,你可以定位到是哪一步工具调用出了问题。

5. 从零搭一个最小 Subagent Runtime 核心流程

这一节我们采用代码演示的方式,理解 runtime 的核心流程。我不会依赖某个特定开源项目,而是整理出一套带有普遍性的最小抽象,你可以照着这个结构去阅读任意一个开源 runtime 的源码,也会更容易抓住它的主干。

5.1 定义数据模型

我们需要先定义任务数据模型,后面在运行 subagent 时,运行时才能把一个请求转换成可执行操作。

# src/example_runtime/models.py from dataclasses import dataclass, field from enum import Enum from typing import Any, Optional class SubagentStatus(str, Enum): PENDING = "pending" RUNNING = "running" SUCCEEDED = "succeeded" FAILED = "failed" CANCELLED = "cancelled" @dataclass class ToolPolicy: """描述一个 subagent 可以使用哪些工具。""" allow_read: bool = True allow_write: bool = False allow_terminal: bool = False allowed_directories: list = field(default_factory=list) @dataclass class SubagentTask: """主代理派发给子代理的任务定义。""" task_id: str parent_context_id: str instruction: str workdir: str model_backend: str = "claude" # claude / codex / local tool_policy: Optional[ToolPolicy] = None timeout_seconds: float = 120 extra_params: dict = field(default_factory=dict) @dataclass class SubagentResult: task_id: str status: SubagentStatus summary: str output_paths: list error_message: Optional[str] = None raw_trace: list = field(default_factory=list)

这个模型解决的问题是:把 subagent 执行需要的所有信息和策略显式表达出来。task_id 用于追踪,parent_context_id 用于关联主 Agent,tool_policy 限制能力边界。在真实的开源 runtime 中,这些字段只会更丰富,而不会缺少。

5.2 设计 Executor 与 Provider 解耦

运行时我们不可能只适配一个模型厂商,所以需要一个 Executor 层和 Provider 解耦。

# src/example_runtime/executor.py import time from abc import ABC, abstractmethod from .models import SubagentResult, SubagentStatus, SubagentTask class BackendProvider(ABC): """屏蔽不同 Agent 客户端差异的抽象接口。 真实实现中: - ClaudeProvider 会调用 Claude Code / Agent SDK 完成一次 subagent 会话。 - CodexProvider 会调用 Codex CLI 的任务执行入口。 - MockProvider 便于集成测试,不真实调用外部模型。 """ @abstractmethod def execute(self, task: SubagentTask) -> SubagentResult: pass class MockProvider(BackendProvider): """本地 mock 实现,避免集成环境没安装客户端时无法演示。""" def execute(self, task: SubagentTask) -> SubagentResult: time.sleep(0.2) return SubagentResult( task_id=task.task_id, status=SubagentStatus.SUCCEEDED, summary=f"[mock] 已完成任务: {task.instruction[:20]}", output_paths=[task.workdir + "/result.txt"], ) class SubagentRuntime: """面向主 Agent 的运行时入口。""" def __init__(self, provider: BackendProvider): self._provider = provider def run_subagent(self, task: SubagentTask) -> SubagentResult: # 在实际 runtime 中,这里会执行策略检查、目录隔离、 # 生命周期注册和日志持久化。 return self._provider.execute(task)

你可能觉得这段代码太简单,但真实框架的核心出口也就是这样。关键在于 runtime 向上层主 Agent 提供的接口是统一的,不让主 Agent 去关心当前 run 的是 Codex 还是 Claude。这样当你从 Claude 切到 Codex 时,并不需要改动主 Agent 的编排逻辑。

5.3 增加统一的工具执行环境

为什么必须把工具执行环境做成独立模块?因为如果每个模型 Provider 都自己实现一套终端和文件编辑,就会产生不一致行为和安全漏洞。正确做法是让厂商客户端“只做模型对话”,而具体的文件、命令操作统一通过 runtime 提供受控接口来完成。

以下是一个最小工具执行器,只提供两个方法:read_file 和 run_terminal_command。真实实现会进一步封装交互式终端、命令超时、输出截断和敏感信息脱敏。

# src/example_runtime/tools.py import subprocess class SandboxedToolbox: """实际项目中请用更严格的文件系统访问控制。 这里只演示工具执行层的边界思想。 """ def __init__(self, allowed_directories): self._allowed_dirs = allowed_directories def _check_workdir(self, path: str): # 简化示例:仅做字符串前缀判断,生产环境应使用 # Path.resolve() 防止符号链接逃逸。 for d in self._allowed_dirs: if path.startswith(d): return raise PermissionError(f"路径不在白名单内: {path}") def read_file(self, path: str) -> str: self._check_workdir(path) with open(path, "r", encoding="utf-8") as f: return f.read() def run(self, command: list[str], cwd: str) -> dict: self._check_workdir(cwd) proc = subprocess.run( command, cwd=cwd, capture_output=True, text=True, timeout=30, ) return { "returncode": proc.returncode, "stdout": proc.stdout[-2000:], "stderr": proc.stderr[-2000:], }

如果用户在实际项目中照抄,请不要真的只依赖 startswith 做路径校验,因为符号链接可能会绕过这道防线。生产环境应该基于 Path.resolve() 做解析。但这个例子已经足够说明:runtime 不能把工具能力直接裸露给 Agent,而要通过 Toolbox 限定 Agent 看到什么、能改什么、能执行什么。

5.4 注册表:从 Agent 能力到工具策略

我们还可以再加一个 agent 注册表,用于声明不同的 subagent 的默认配置。比如 test-runner、code-reviewer、refactor-helper,每个角色对应不同的工具策略。这样主 Agent 不需要在每次派发任务时都重新声明权限矩阵,只要按 ID 选择一个 subagent profile 即可。

{ "agent_profiles": { "code-reviewer": { "description": "只读代码并输出审查意见", "allow_read": true, "allow_write": false, "allow_terminal": false, "allow_directories": ["/workspace/app/src", "/workspace/app/tests"] }, "bug-fixer": { "description": "可读取和修改指定模块代码,可运行测试", "allow_read": true, "allow_write": true, "allow_terminal": true, "allow_directories": ["/workspace/app"] } } }

将这个 JSON 注册到一个运行时,运行时在派发 subagent 之前就从 config 中加载对应的权限包。这个设计在工程上是一个很实用的最佳实践:权限策略跟随 agent profile,而不是由主 Agent 的动态上下文决定。正因为运行时控制了这个权限包,子代理才不能随便把执行触角伸到项目之外的敏感目录。

5.5 派发一个真实的 Subagent 主流程

把上面模块组合起来,主流程可以这样写:

# scripts/demo_runtime.py from example_runtime.executor import MockProvider, SubagentRuntime from example_runtime.models import SubagentTask provider = MockProvider() runtime = SubagentRuntime(provider) task = SubagentTask( task_id="task_demo_001", parent_context_id="main_001", instruction="请检查 src/auth.py 中是否存在越权访问风险,并给出修改建议。", workdir="/workspace/app", model_backend="claude", ) result = runtime.run_subagent(task) print(result.status) print(result.summary)

在真实环境中,provider 的位置是一个调用 Claude Code 或 Codex CLI 的 HTTPServer 或本地子进程管理器。但这个最小流程展示的意义在于:不管 subagent 内部调度如何复杂,对外暴露的接口就像一个同步的 API 调用:传任务、得结果、状态可查。

6. 在本地环境接入 Codex 与 Claude Code 的通用步骤

虽然你最后可能选择某个开源 runtime 来管理 subagent,但 runtime 通常是跑在模型客户端之上的,所以环境里最基本的前提是本地已经能正常使用 Codex 和 Claude Code。这里整理几条通用经验和验证方法,具体安装命令请以官方仓库为准,因为工具更新很快。

6.1 安装后的首件事不是运行,而是检查版本和 CLI 路径

很多同学遇到的问题不来自 Agent 本身的模型调用,而是本机的 CLI 没有正确暴露。比如一个很常见的报错是“unable to locate the Codex CLI binary”,字面意思是上层应用无法找到 codex 的可执行文件,或者本机只安装了 Codex 的桌面应用,没有把 codex 命令暴露到 PATH。另一个常见问题是“claude 无法将项识别为 cmdlet、函数、脚本文件或可运行程序的名称”,这意味着 Windows 环境下 Claude Code 的安装目录不在 PATH 中。

排查这一类常规问题,最重要的思路是逐层确认:

  • 命令是否真的存在。
  • 可执行文件目录是否在 PATH。
  • 通过配置文件或界面设置,明确告诉上层工具 CLI 的实际路径,而不是让工具去猜。
# 推荐逐步验证 which codex codex --version which claude claude --version

如果你使用的是桌面端应用或 IDE 插件来管理 Codex,但外面找不到 codex 命令,可以在应用的设置界面里指定 codex cli path,而不是重新安装一遍。这种配置思路也适用于其他 Agent 工具的使用,比如通过环境变量或配置指向自定义模型服务地址时,很多人也会遇到“本地代理不可用导致 endpoint 报错”的问题,这时应该先检查相关服务是否在线,再看网络策略和鉴权配置,而不是怀疑模型本身。

6.2 在不同终端配置模型服务

有些 runtime 为了帮助国内用户解决模型服务访问的问题,会支持配置第三方兼容模型服务。这个方向本身说明,Agent 工具和 IDE 与传统 API 一样,已经开始支持把模型底座替换为你自己的接入方式。配置模型供应商时,需要关注三个信息源:模型的接入 Base URL、API Key、模型名称。不同版本对这三个字段的要求会不一样。建议先用命令行小范围验证,确认模型服务响应正常后,再把这个配置写进 runtime 的配置文件里。

6.3 从最小任务开始验证 subagent 能力

不要在安装之后立刻把一个大型仓库交给 subagent 处理。无论你用的是 Codex 还是 Claude Code,都建议从一个只有几个文件的临时目录开始,测试你的 subagent 能不能完成精确修改。

最小验证任务可以是:创建一个临时项目,里面有一个 Python 文件的函数返回结果不正确,让 subagent 修复它,并运行测试。如果这个流程能够稳定完成,再放开到真实仓库。这个思路同样适用于评测开源 runtime:如果你想让一个 runtime 来管理 subagent,先让它跑通最简单的主代理派发子任务流程,接下来再引入复杂工具和较长上下文。

6.4 将 Subagent 嵌入自动化流水线

使用 runtime 的最终目的往往不只是手工交互,而是在 CI/CD 里做自动代码审查或自动补丁生成。我们可以写一个通用的批处理脚本,用来调用运行时接口并读取结构化结果。

# scripts/run_review.sh # 将代码审查任务交给某个已配置好 subagent profile 的运行入口执行 RUNTIME_URL="${RUNTIME_URL:-http://127.0.0.1:8080}" curl -s -X POST "$RUNTIME_URL/subagents/reviews" \ -H "Content-Type: application/json" \ -d '{ "profile": "code-reviewer", "repository": "/workspace/app", "branch": "feature/order-service", "notify_on_failure": true }'

如果 runtime 支持 HTTP API,那么把它接入 CI 会非常自然。你可以等它返回一个 review id,然后在后续步骤轮询状态,而不是同步阻塞整个流水线。如果 runtime 不支持 HTTP API,只支持本地进程调用,那也可以写成命令行工具之后再包装。

7. Subagent Runtime 的配置建议与参数调优

7.1 超时时间

子代理既然是一个工具调用,就应该有超时。以前在纯 prompt 模式下,你可能会等待大模型自己“说完”,但工程执行不能让 Agent 一直空转。超时建议区分任务类型:代码修改类任务可以给更长的时间;只读审查类任务可以更短。如果发现子代理频繁超时,可以看是否是任务拆分太粗,而不是盲目调大超时,否则你会掩盖真正的问题。

7.2 结果摘要的长度限制

主 Agent 上下文是贵的。runtime 在把结果回传给主 Agent 时,需要控制摘要长度。通常的原则是:如果主 Agent 后续只需要知道“这个任务完成了、改动了哪些文件、测试结果如何”,那就不需要把子 Agent 的完整思考过程带回。推荐摘要里包含结论、关键证据和可验证路径,然后再附一份更长的 trace 连接,供需要时人工查看。

7.3 历史日志保留

在开发环境,可以考虑保留所有 subagent 的完整执行日志,方便分析模型行为。但在生产环境,日志可能包含敏感代码片段和客户数据,所以要对日志做抽象、脱敏。如果 runtime 支持结构化日志,尽量使用 JSON 格式,后端接 Elasticsearch 或 Loki 会更为顺畅。

7.4 模型切换的灰度策略

如果你想从 Claude 切换到 Codex,不要一次性把全部工作负载切过去。可以按子任务类型灰度,先让 10% 的代码审查任务由 Codex 执行,然后对比结果摘要质量、Token 消耗和失败率,再把占比调高。Runtime 的多 Provider 抽象,正是为了让你可以有这种灰度切换的机会。

7.5 错误分类

错误分类是 runtime 设计里容易被低估的点。不是所有错误都一样,网络超时、Agent 返回格式错误、测试用例失败、权限拒绝,这些都可能发生。如果 runtime 能把错误分类再返回,主 Agent 就能采取不同策略。网络超时可以考虑重试,语法错误应该反馈给模型重新生成,测试用例失败说明功能仍然不对,权限拒绝需要人工介入。如果把所有错误都混在一起,主 Agent 就只能统一“再试一次”,这种体验自然不好。

8. 常见问题与排查方法

在搭建和使用 Codex、Claude Code 以及它们所对接的开源 runtime 时,下面的问题出现频率相对较高。整理成表格,方便你在遇到类似场景时快速定位。

问题现象可能原因排查方式解决方案
运行 Codex 时报“could not find the Codex CLI binary”电脑上只安装了桌面端,或 codex 命令不在 PATH 中在终端运行 which codex,确认可执行文件路径在应用/插件设置中指定 codex cli path,或重新安装命令行版本
Claude 命令在终端无法识别Claude Code 可执行文件目录不在 PATH运行 where claude 或查看安装日志把安装目录加入系统 PATH,重启终端
subagent 执行超时任务拆分过粗或某些命令阻塞等待输入查看 subagent trace,找到长时间未返回的工具调用重新拆分任务;给终端命令加 timeout 参数
子代理修改了不应修改的文件工具策略没有限制写目录检查 runtime 配置中的 allow_write 和 allowed_directories按 agent profile 收紧写权限,必要时使用独立 workdir
主代理上下文被冲爆子代理结果摘要太长,或没有启用摘要压缩查看日志返回主上下文的字节数配置结果摘要最大长度;只回传结论和 diff 路径
Agent 反复执行相同操作但失败子代理无法从错误日志中获得足够信号检查 provider 是否把 stderr 传给模型在工具层返回额外日志字段,如 exit code 和最近日志片段
换模型后工具行为不一致不同模型对工具 schema 的兼容度不同用同一任务分别在不同 Provider 上回放对模型差异做抽象,尽量走统一工具协议并对底层做适配
Firefox 或 IDE 组件提示找不到 WebView2 Runtime桌面工具依赖 Edge WebView2 这类系统运行库查看应用启动日志,确认缺失哪个运行库安装对应系统运行库或更新框架版本

如果你的 runtime 已经能查 trace,那么绝大多数问题都可以通过 trace 定位。我特别想强调的是,代码 Agent 的排查方式与传统程序排错差别很大。传统程序出 bug,你可以直接看 stack trace;Agent 出 bug,必须看它是如何理解任务、如何调用工具的,因此 trace 是比“最终代码 diff”更重要的排查依据。

9. 最佳实践与工程建议

9.1 从业务目标反推任务粒度

很多 subagent 效果差,是因为任务拆分得太大。比如让一个子 Agent “从零实现用户登录模块”,这个任务仍然很复杂,涉及数据库、前端表单、后端接口、Token 签发、安全策略。更合理的拆分是让不同子 Agent 分别负责“设计用户表结构并生成 migration”“实现登录接口”“实现前端登录表单”“检查安全漏洞”。只有当每个子 Agent 的职责足够专一,它的上下文窗口才装得下必要信息,结果也才更可控。

9.2 Prompt 里必须固定验证标准

让 subagent 修改代码,只写“请修改登录逻辑”不够。更好的方式是说明“修改后运行 pytest tests/test_login.py,确保全部通过,并把通过结果作为输出证据”。工程上需要把这种验证标准变成一个约定。如果每个 subagent 任务描述都自带“成功标准”,runtime 就能在运行时自动判断是否完成,而不是只等待模型说“我完成啦”。

9.3 尽量不把密钥和敏感信息交给 subagent

你可以合理地让子 Agent 查看 .env 文件结构的 key 名,但不要让子 Agent 把真实的密钥文件内容打印到 trace 或日志中。尤其当多个子 Agent 共享同一个日志服务时,密钥泄露风险会成倍上升。在生产环境,建议对终端输出做脱敏过滤,比如识别常见的 API Key 格式并打码。

9.4 对文件目录使用白名单而不是黑名单

工具权限设计更推荐白名单:声明哪些目录可以访问,其余默认拒绝。而不是试图枚举“哪些不能访问”,因为你永远可能漏掉一个奇怪的系统路径。runtime 的默认配置应该越收越紧。需要放开权限时,基于当前任务的子目录加白,而不是对整个用户主目录放行。

9.5 在 CI 中把 Agent 当异步任务而不是同步等待

如果你的 CI 准备引入 Agent 作为代码审查或自动修复工具,推荐以异步形式调用并保留任务 ID,这样即使 Agent 执行时间超过 CI 最大时长,也可以从外部继续查询进度。发布前的自动修改任务更是要设置严格分支保护,让 Agent 只在你预期的 feature 分支上推送,不直接推主分支。因为代码 Agent 虽然能写逻辑,但它无法理解公司内部发布规范,这些边界必须由工程体系兜底。

9.6 保留与回滚

如果 runtime 以真实仓库代码作为 workdir,一定谨慎操作。生产环境改动前必须有备份、标签和可回滚的提交记录。subagent 修改代码时,要让它先基于当前分支 checkout 出一个子分支或局部补丁,再由人工审查合并,而不是让 Agent 直接对共享分支做 force push。要牢记一点:Agent 会犯错,它的高效是建立在工程体系能快速回滚之上的,而不是建立在模型不会犯错这个假设之上。

9.7 给人类保留决策入口

再好的 subagent 运行时也不能把代码审查的最终决策权完全交给模型。实际项目里,可以设计运行时在任务结束时输出一个“审查报告摘要 + 风险等级建议”,并自动邀请维护者进行 review。这个设计意味着代码 Agent 仍然是协作流的一部分,而不是发布流水线的唯一决策者。对大型仓库来说,这种克制尤其重要。

10. 总结与后续学习方向

通过这篇文章,我想说明白一个核心判断:真正决定 Codex 和 Claude subagent 体验的,不是某一次 prompt 的质量,而是 runtime 层的任务抽象、上下文隔离、工具权限、失败回收和观测能力。这也是“开源 runtime”这一类项目开始出现的原因,因为它正在把多 Agent 的能力封装成一个开发者可以理解和控制的基础设施。

如果你正准备把 subagent 接入实际项目,我建议从这几个方面继续深入:

  • 深入阅读你选定的开源 runtime 的源码,重点看 lifecycle 和 tool policy 的实现。
  • 先设计好你这套系统的 agent 目录和角色清单,不要一上来就是抽象“万能助手”。
  • 为你的主 Agent 场景写“成功标准”模板,并测试 runtime 是否能基于这些标准决定停止或重试。
  • 逐步积累错误案例,建立典型失败模式库,这会比换更大的模型模型更有长期价值。

最后提醒一点:无论你用的是 Claude Code、Codex 还是其他模型客户端,subagent 都只是一种工程模式,不是银弹。它在上下文隔离和任务专业化上的优势,必须建立在清晰的权限边界和严格的验证机制上。而任何面向生产环境的 Agent 改造,都要做好备份、回滚和人工审查的关键入口,让模型负责高效生成,让人负责最终决策。这样,你在 build 下一个子Agent 系统时,才有可能真正稳定地掌控复杂度,而不只是在等待模型某一次“灵光一现”。

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

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

立即咨询