ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

从上下文隔离到失败回收:Codex与Claude的Subagent运行时实践

从上下文隔离到失败回收:Codex与Claude的Subagent运行时实践 从上下文隔离到失败回收这个开源运行时为什么能让 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_factorylist) 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_factorydict) dataclass class SubagentResult: task_id: str status: SubagentStatus summary: str output_paths: list error_message: Optional[str] None raw_trace: list field(default_factorylist)这个模型解决的问题是把 subagent 执行需要的所有信息和策略显式表达出来。task_id 用于追踪parent_context_id 用于关联主 Agenttool_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_idtask.task_id, statusSubagentStatus.SUCCEEDED, summaryf[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, encodingutf-8) as f: return f.read() def run(self, command: list[str], cwd: str) - dict: self._check_workdir(cwd) proc subprocess.run( command, cwdcwd, capture_outputTrue, textTrue, timeout30, ) 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_idtask_demo_001, parent_context_idmain_001, instruction请检查 src/auth.py 中是否存在越权访问风险并给出修改建议。, workdir/workspace/app, model_backendclaude, ) 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 traceAgent 出 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 系统时才有可能真正稳定地掌控复杂度而不只是在等待模型某一次“灵光一现”。
返回列表