Agentic Coding 深度解析:从架构原理到多 Agent 协作
AI 编程工具的演进,正在经历一次根本性的范式转变:从"补全光标处的代码",到"自主完成端到端工程任务"。这种转变有一个专有名词——Agentic Coding。
围绕 Coding Agent 的讨论,常见两种极端:将其神化为自主智能体,或将其贬为"不过是提示词工程"。两种判断都失之简单。理解这个转变,需要从三个层面展开:工具层(OpenCode 的能力边界)、框架层(多 Agent 协作编排)、方法论层(如何让 Agent 真正服务于工程流程)。本文从真实的架构出发,拆解 Claude Code、OpenCode 等工具的实现模式,厘清各自的设计取舍,深入探讨子 Agent 的本质与多 Agent 协作的核心问题。
什么是 Agentic Coding
传统 AI 编程助手的工作模式是响应式的:开发者提问,AI 回答;开发者选中代码,AI 补全。人始终是执行者,AI 是辅助工具。
Agentic Coding 的工作模式是自主式的:开发者描述目标,Agent 自主规划步骤、调用工具、执行操作、验证结果,直到任务完成。人退出执行循环,成为目标定义者和结果审查者。
这不是量变,是质变。一个能够自主编码的 Agent,需要具备:
- 代码理解能力:不只是文本匹配,而是理解代码的语义结构、类型关系、调用链路
- 工具调用能力:读写文件、执行命令、调用外部 API
- 规划与反馈能力:将大任务分解为步骤,根据执行结果调整计划
- 上下文管理能力:在有限的上下文窗口内,按需加载相关信息
其中,代码理解能力是基础,也是工具层最关键的差异点。关于代码理解能力的核心——LSP(语言服务协议),已在独立文章 LSP:语言服务协议与AI编程助手的代码理解能力 中详细阐述。
从单 Agent 到 Agent 团队
OpenCode 解决了单个 Agent 的代码理解问题。但工程任务的复杂度,往往超出单个 Agent 的能力边界。
理解这个边界在哪里,是理解为什么需要多 Agent 的前提。一个单独的 Agent,即便配备了 LSP 和完整的工具权限,仍然面临三个结构性限制:上下文窗口有限(无法同时持有整个大型项目的全貌)、角色混淆(规划者和执行者是同一个 Agent,容易在"想清楚"和"动手做"之间反复横跳)、无法真正并行(单线程的问答流水线,无法同时搜索文档和修改代码)。
这些限制不是模型能力的问题,而是单 Agent 架构的天花板。突破它,需要引入外部编排层——把规划、执行、验证拆给不同的角色,让它们并行工作、相互制衡。
编程 Agent 的本质
在讨论任何具体的 Agent 工具或框架之前,有必要先把"编程 Agent 到底是什么"这个问题说清楚。理解了本质,才能理解为什么各种框架要做它们做的事。
一个编程 Agent,剥去所有包装,本质上是四个要素的组合:
while loop:Agent 不是一次性的问答,而是一个持续运行的循环。每一轮循环,Agent 观察当前状态、决定下一步行动、执行行动、再观察新状态。循环在何时退出,取决于完成信号的检测——可以是文件中的特定标记(如 DONE),可以是测试通过,也可以是外部脚本的判断。
system prompt:Agent 的"人格"和"职责"由 system prompt 定义。它告诉 Agent:你是谁、你的目标是什么、你能用哪些工具、你应该遵守哪些约束。system prompt 是 Agent 行为的根本来源——同一个底层模型,配上不同的 system prompt,就变成了完全不同的 Agent。这也是为什么多 Agent 框架的核心工作,往往是精心设计每个角色的 system prompt,而非替换底层模型。
tool calling:Agent 通过工具与外部世界交互。读文件、写文件、执行 Shell 命令、调用 API——这些都是工具。工具调用是 Agent 从"思考"到"行动"的桥梁。没有工具,Agent 只能输出文本;有了工具,Agent 才能真正改变世界的状态。
persistent state(文件系统):Agent 的记忆不在上下文里,而在文件系统中。代码文件、任务列表、中间结果——这些都是持久化的状态。文件系统是 Agent 跨轮次、跨会话保持连贯性的基础。这也是为什么 Agent 框架普遍依赖文件来传递状态:task.md、boulder.json、.sisyphus/plans/——本质上都是在用文件系统弥补上下文窗口的有限性。
1 | |
一个循环统治一切
先说结论:所有 Coding Agent 的核心,都是一个 while(tool_use) 循环。
通过对 Claude Code 实际 API 流量的追踪分析,其核心逻辑可以用伪代码描述如下:
1 | |
没有复杂的状态机,没有多 Agent 协调框架,没有专门的"停止决策模块"。模型自己决定什么时候停——当它不再调用工具,循环就自然结束。
这个设计有一个被低估的优雅之处:模型可以通过"输出纯文本而不调用工具"来向用户提问或汇报进度,不需要任何额外的机制。
messages 数组:唯一的状态载体
上述伪代码中的 context,在所有主流 LLM API 里的实际形态是一个 messages 数组。没有其他格式——Agent 的全部状态,包括历史、推理过程、工具调用结果,都存储在这个数组里。
每条消息有四种角色,工具调用的插入位置是固定的:
1 | |
每一轮循环的操作模式是:模型输出 assistant 消息(含 tool_calls)→ 框架执行工具 → 把结果以 tool 角色追加 → 再次调用模型。Agent 框架在做的核心事情,就是决定往这个数组里追加什么、以什么顺序追加、以及何时停止追加。
这个数组的增长方式,取决于框架策略:
| 策略 | 描述 | 适用场景 |
|---|---|---|
| 无限叠加 | 保留所有消息,数组持续增长 | 短任务、大 context 窗口 |
| 工具结果清除 | 保留工具调用记录但丢弃返回内容,减少冗余 | 工具结果可重新获取的场景 |
| 压缩摘要 | 用 LLM 总结历史,用摘要替换原始消息数组 | 超长任务(Claude Code 的 compaction 机制) |
| 滑动窗口 | 丢弃旧消息,保留最近 N 条 | 长对话、有限 context 窗口 |
这四种策略的激进程度递增,但本质上都在做同一件事:改写 messages 数组,用一个更短的数组替代原来的数组,然后基于这个更短的数组继续推理。这就是上下文压缩的全部秘密——没有魔法,只有对数组的精确操纵。
终止条件的最简实现:不需要专门的 stop 工具或终止正则,让模型的"不调用工具"行为本身成为停止信号,是最低耦合的设计。
Claude Code 的真实架构
工具集:精简而非全能
Claude Code(截至 2025 年中,基于 system prompt 追踪分析)共有 14 个工具,分为四类:
| 类别 | 工具 | 设计意图 |
|---|---|---|
| 命令行 | bash、glob、grep、ls |
bash 需要用户审批,其余不需要 |
| 文件操作 | read、write、edit、multi_edit、notebook_read、notebook_edit |
Jupyter 单独处理,因为原始格式极长 |
| 网络 | web_search、web_fetch |
基础信息获取 |
| 控制流 | todo_write、task |
计划管理与子 Agent 调度 |
没有 critic 模式,没有角色扮演,没有复杂的记忆数据库。简单是刻意的选择,不是能力不足。
TODO 列表:外化的计划
Claude Code 的第一个工具调用几乎总是 TodoWrite,创建一个结构化的任务列表:
1 | |
这个设计解决了一个关键问题:模型在执行数百步操作后会"忘记"自己在做什么。TODO 列表是外化的工作记忆,不依赖模型的上下文记忆能力。
更聪明的是,工具调用的返回结果里会附带提醒文字,要求模型继续使用 TODO 列表跟踪进度。指令在工具结果里重复出现,比只放在 system prompt 里遵从率高得多。
计划外化原则:把计划写成可被工具读写的结构化文件(TODO 列表、plan.md),比依赖模型"内化"计划更确定、更可控。内化的计划会随着上下文增长而衰减,外化的计划不会。
System Reminder:动态注入的上下文
Claude Code 会在每次用户消息后附加 <system-reminder> 块,内容随状态动态变化:
- 会话开始:注入基本行为约束(不要主动创建文件、不要做多余的事)
- TODO 列表为空时:提醒模型考虑是否需要创建计划
- TODO 列表更新后:把最新的任务状态注入上下文
这不是"提示词工程",而是程序化的上下文管理——根据 Agent 的运行状态,精确控制每一步模型能看到什么信息。
子 Agent:上下文隔离与并行
当任务复杂到单个上下文窗口装不下,Claude Code 会通过 task 工具派发子 Agent。子 Agent 是一个完整的 Claude Code 实例,接收相同的 system prompt,但有自己独立的上下文窗口。
关键设计决策:子 Agent 不接收主 Agent 的上下文历史,且在设计上被约束为不能再派发子 Agent(防止无限递归)。子 Agent 的 system prompt 中包含对其行为边界的约束,但其上下文窗口是全新的、干净的——这正是上下文隔离的核心价值。这一设计保证了行为的可预测性。值得注意的是,这个约束只针对 Agent 实例的创建——Skill(通过 SKILL.md 注入的行为扩展)则可以无限递归调用,因为 Skill 是上下文内的提示词注入,不涉及新 Agent 实例的创建。
关于子 Agent 的本质,还有一个常被误解的问题:"子 Agent"是关系描述,不是能力描述。子 Agent 可以拥有与主 Agent 完全相同甚至更强的能力,它的核心价值在于上下文隔离,而非能力弱化。详细分析见后文"子 Agent 的本质"章节。
子 Agent 的两个用途:
- 上下文管理:把大任务拆成小任务,每个子任务有干净的上下文
- 并行加速:多个独立子任务可以同时执行
安全检查:用小模型做守门员
一个鲜为人知的细节:Claude Code 在执行 bash 命令前,会把命令发给 Claude Haiku(最小最快的模型)做安全检查,判断命令是否读取或修改了敏感文件。
这个设计体现了一个重要的工程权衡:用便宜的小模型做确定性判断,不让安全检查拖慢主循环。Haiku 的输出是结构化的 XML,不是自然语言,降低了解析的不确定性。
异构模型协作:主循环用强模型做复杂推理,安全/分类等确定性任务用小模型,是成本与能力的最优分配。
Claude Code 的核心竞争力:上下文工程
上文所描述的每一个机制——system reminder 的动态注入、TODO 列表的外化记忆、子 Agent 的上下文隔离、messages 数组的增长策略——本质上都在做同一件事:精确控制每一步模型能看到什么信息。这不是"改改 prompt 就能做到的事",而是对模型行为的系统性工程,需要对模型的注意力机制、上下文衰减、工具调用模式有深刻理解。
Anthropic 在其工程博客中给出了精确定义:Context Engineering(上下文工程)是在 LLM 推理期间策划和维护最优 token 集合的策略集合。它与 Prompt Engineering 的区别不在于程度,而在于维度——Prompt Engineering 关注"如何写好一段提示词",Context Engineering 关注"在每一次推理调用中,什么样的 token 配置最可能产生期望行为"。后者是一个迭代过程,涵盖 system prompt、工具定义、messages 历史、外部数据的全部组合。
一个有力的佐证:Claude Code 的 system prompt 和工具集在每次版本更新时都会变化,这些变化直接影响模型行为。这说明 Anthropic 在持续做的是 Context Engineering,而不是一次性的提示词设计。
操纵 messages 数组的艺术
前文提到 messages 数组是 Agent 的唯一状态载体。但"操纵 messages 数组"远不止"快满了就压缩"这一件事。Agent 框架对 messages 数组的操纵,至少包含五个维度:注入、定位、保护、清理、重复。 压缩只是清理维度的一个子集。
维度一:注入(Injection)——往数组里放什么
messages 数组中有四种角色的消息,每种角色的语义和注意力权重截然不同:
| 角色 | 语义 | 注意力权重 | 是否被压缩 |
|---|---|---|---|
| system | 全局行为指令,定义模型身份和约束 | 最高——位于数组开头,享有首因效应(primacy bias) | ❌ 永远不会被压缩 |
| user | 用户输入,包含实际请求和上下文 | 高——最新的 user message 享有近因效应(recency bias) | ✅ 历史 user message 会被压缩 |
| assistant | 模型响应,包含思考过程和工具调用 | 中——随对话增长被推向中间位置 | ✅ 会被压缩 |
| tool | 工具执行结果,返回给模型 | 中——与 assistant 的工具调用配对出现 | ✅ 会被压缩或清除 |
Claude Code 的注入策略是分层的,不同类型的信息被注入到不同角色的消息中:
第一层:system prompt(不可变层)。 核心身份定义、基础行为规则、工具使用指南、安全声明。这些内容约 16,000-23,000 tokens,对所有用户共享,永远不会被压缩。Claude Code 的 system prompt 有一个精妙的设计:安全声明在 prompt 的开头和结尾都出现——利用 U 形注意力曲线的两个峰值,确保安全约束在任何上下文长度下都不会被忽略。
第二层:system prompt 动态扩展(半不可变层)。 Output Style(如 software-architect 风格指令)被追加到 system prompt 数组中。这些内容随用户配置变化,但在单次会话内保持稳定,同样不会被压缩。
第三层:<system-reminder> 注入(可变层)。 这是 Claude Code 最独特的机制。CLAUDE.md 的内容、skill 元数据、当前日期、Git 仓库状态等信息,被包裹在 <system-reminder> 标签中,作为 user message 注入到对话历史中:
1 | |
这个设计有一个关键的工程权衡:CLAUDE.md 的内容虽然用 <system-reminder> 标签标记为"系统级",但它的实际角色是 user message。这意味着它享有 user message 的注意力权重,但也承受 user message 的命运——会被压缩。这个设计选择是为了兼容 prompt caching(后文详述),但也埋下了 skill 遗忘问题的种子。
第四层:工具调用与结果(动态层)。 每一轮循环产生的 assistant tool_call 和 tool result 消息。这些是数组增长最快的部分,也是压缩的主要目标。
维度二:定位(Positioning)——放在数组的哪个位置
Stanford 的 Lost in the Middle 论文(arXiv:2307.03172,引用 3700+)揭示了一个关键发现:LLM 对 messages 数组中不同位置信息的注意力呈 U 形分布——开头和结尾的信息获得最高注意力,中间位置的信息最容易被忽略。
1 | |
Claude Code 的定位策略充分利用了这个特性:
- 开头位置(primacy bias):system prompt 固定在数组最前面,核心规则前置,身份定义优先
- 结尾位置(recency bias):最新的 user message 和最近的工具调用结果自然位于数组末尾
- 中间位置(注意力低谷):历史对话、早期的工具调用结果——这些是压缩的首选目标,因为即使不压缩,模型对它们的注意力也已经很低了
这解释了一个反直觉的现象:为什么 Claude Code 的 system prompt 长达 16,000+ tokens 却不会显著影响性能。因为 system prompt 位于数组开头,享有最高的注意力权重;而且它通过 prompt caching 被缓存为不可变前缀,不会随对话增长而被"推"到中间位置。
维度三:保护(Protection)——哪些内容不能丢
并非 messages 数组中的所有内容都是平等的。Claude Code 建立了一个隐式的信息保护层级:
| 保护级别 | 内容 | 保护机制 |
|---|---|---|
| 永久保护 | system prompt、工具定义 | 位于 API 调用的顶层参数,不在 messages 数组中,永远不会被压缩 |
| 缓存保护 | system prompt + Output Style | 通过 prompt caching 创建不可变前缀,缓存后的内容不会被修改 |
| 摘要保留 | 架构决策、未解决的 bug、最近 5 个文件 | compaction 时被明确要求保留 |
| 无保护 | 历史工具调用结果、早期对话、CLAUDE.md 内容、skill 内容 | 压缩时可能被摘要化或丢弃 |
Prompt Caching 的保护作用值得单独说明。Claude API 的 prompt caching 通过前缀匹配工作:tools → system → messages 按此顺序构成缓存前缀。前缀中的任何变化都会使缓存失效。Claude Code 围绕这个机制做了一个关键的架构决策:所有用户共享相同的 system prompt。这使得 system prompt 成为一个稳定的、可缓存的前缀,减少 90% 的输入 token 成本和 85% 的延迟。
但这也意味着,任何需要个性化的内容(CLAUDE.md、skill、项目规则)都不能放在 system prompt 中——否则会破坏缓存共享。这就是为什么这些内容被降级为 user message 注入,也是它们在压缩时容易丢失的根本原因。这不是一个 bug,而是一个成本与持久性之间的工程权衡。
维度四:清理(Pruning)——从数组中移除什么
这是大多数人理解的"上下文压缩",但它实际上包含三个递进的层次:
第一层:工具结果清除(Tool Result Clearing)。 最轻量的清理形式。Agent 保留"我调用了 read_file 读取了 config.yaml“这个记录,但丢弃实际返回的文件内容。Anthropic 已将此作为 Claude Developer Platform 的正式功能发布(clear_tool_uses)。这是"最安全的轻触式压缩”——不丢失任何决策上下文,只丢弃可重新获取的原始数据。
第二层:上下文摘要压缩(Compaction)。 最核心也最复杂的清理形式。其操作可以用一句话概括:把整个 messages 数组传给 LLM,让它生成一个高保真摘要,然后用这个摘要替换原始数组,开始一个新的上下文窗口。
1 | |
压缩的艺术在于选择保留什么、丢弃什么——过于激进的压缩会丢失微妙但关键的上下文。Anthropic 在其工程博客中给出了调优建议:先最大化召回率(确保压缩 prompt 捕获了 trace 中的每一条相关信息),再迭代提升精确率(消除多余内容)。
第三层:结构化笔记(Structured Note-taking)。 不是对 messages 数组的直接操作,而是一种补偿机制:Agent 在运行过程中主动将关键信息写入外部存储(TODO 列表、memory 文件),使得即使上下文被压缩甚至完全清空,关键状态也不会丢失。
维度五:重复(Repetition)——关键指令的多点锚定
这是最容易被忽视、却可能是最重要的维度。Claude Code 的一个核心设计哲学是:关键指令不能只出现一次,必须在 messages 数组的多个位置重复出现。
具体实现包括:
- system prompt 首尾重复:安全声明在 system prompt 的开头和结尾都出现,利用 U 形注意力的两个峰值
- tool result 中嵌入提醒:每次
todo_write工具调用的返回结果中,都会附带固定文字提醒模型"keep using the TODO list to keep track"。这意味着只要模型在使用 TODO 列表,每次工具调用都会重新强化这条指令 <system-reminder>的每轮注入:CLAUDE.md 的内容不是只在会话开始时注入一次,而是在每个 user turn 中都重新注入。这确保了即使中间的 CLAUDE.md 内容被注意力衰减影响,最新一轮的注入仍然位于数组末尾的高注意力区域
为什么重复比单次注入更有效?原因有三:
- 对抗注意力衰减:单次注入的信息会随着对话增长被推到中间位置(注意力低谷),重复注入确保关键信息始终出现在高注意力区域
- 提供容错冗余:即使某一次注入被模型忽略,其他位置的重复仍然有效
- 压缩后恢复:即使历史中的注入被压缩掉,最新一轮的注入仍然完整保留
指令在工具结果里重复出现,比只放在 system prompt 里遵从率高得多——这不是经验之谈,而是 Claude Code 团队通过大量 A/B 测试验证的工程结论。
五个维度的协同:一个完整的例子
以 Claude Code 处理一个复杂编码任务为例,观察五个维度如何协同工作:
1 | |
这个例子展示了一个关键洞察:messages 数组的操纵不是某个单一时刻的操作,而是贯穿 Agent 整个生命周期的持续性工程。每一条消息的注入位置、每一次清理的时机、每一条指令的重复频率,都是精心设计的。
裸 OpenCode 的能力边界
OpenCode 是一个开源的终端 AI 编程 Agent,支持 GPT-4/5 系列、Claude 等多种模型(通过界面切换模型),内置四个角色:
| Agent | 类型 | 能力 |
|---|---|---|
| Build | 主 Agent | 全工具权限,默认开发模式 |
| Plan | 主 Agent | 只读分析,禁止文件修改 |
| General | 子 Agent | 通用研究与多步骤任务 |
| Explore | 子 Agent | 只读代码库探索,快速搜索 |
值得注意的是,表格中 General 和 Explore 被标注为"子 Agent",但这只是描述它们在 OpenCode 默认工作流中的调用关系,而非能力限制。它们本身是完整的 Agent,拥有独立的上下文和工具权限,完全可以作为主 Agent 直接使用。"子 Agent"是关系描述,不是能力描述——关于这一点的深入分析,见后文"子 Agent 的本质"章节。
Plan 与 Build:模式切换,而非 Agent 切换
在 OpenCode 的终端界面中,按 Tab 键可以在 Plan 模式和 Build 模式之间切换。切换的是同一个 Agent 的工具权限集,而不是切换到另一个独立的 Agent。底层调用的是同一个 LLM,区别仅在于工具白名单:
- Plan 模式:只读权限。Agent 可以读文件、搜索代码库、分析调用链,但禁止写文件和执行命令。这一限制强迫 Agent 只思考、不动手,输出分析报告和行动计划。
- Build 模式:全工具权限。Agent 可以读写文件、执行 Shell 命令、调用外部 API。
分离两种模式的核心原因是防止 Agent 在理解不充分时就开始修改代码。Plan 模式提供了一个只读沙箱,让 Agent 先把问题想清楚。一个实用的工作流是:先用 Plan 模式分析代码库、理解依赖关系、输出修改方案;人类确认方案合理后,再切换到 Build 模式执行。
OpenCode 的 Skills 机制(SKILL.md 文件)实现了"渐进式披露"的上下文管理——Agent 只在需要时才加载技能的完整内容,而不是一次性把所有知识塞进上下文。这与 AI Agent 领域的上下文最小化原则高度吻合:
“The model should only know what it needs to know to make the next immediate decision.”
裸 OpenCode 的天花板
裸 OpenCode 有比较明确的能力边界:
- 并不以内置并发编排为核心体验:子 Agent 可以被调用,但原生形态下并没有像外部编排框架那样,把并行调度作为主工作流来强调
- 无角色分工体系:Build 和 Plan 是模式切换,而非职责分明的团队角色
- 无跨会话状态持久化:每次会话独立,无法在多天的复杂项目中保持进度
- 无业务域知识:工具是通用的,不理解特定团队的技术栈、部署流程、业务规则
裸 OpenCode 是一把锋利的瑞士军刀,但尚未构成一支完整的工程团队。突破这些限制,需要在 OpenCode 之上引入外部编排层。
命令与配置:从单工具到可编排工作流
如果只把 OpenCode 当作一个终端里的编码助手,那么 /init、/undo、/redo、/share 这些内置命令,更多是在提升单个会话的可用性。但当工作流开始延伸到 OMO 这种多 Agent 编排层时,这些命令的意义就变了:它们不再只是“方便操作”,而是在为后续的自动化协作准备上下文、状态和回退能力。
其中最值得关注的是两类能力:
- 项目知识初始化:例如
/init与/init-deep,负责把代码库的结构、规范和目录知识沉淀成可供 Agent 读取的配置文件; - 会话控制与工作流命令:例如
/undo、/redo、/share,以及 OMO 扩展出的/ralph-loop、/refactor、/start-work,负责把“单次回答”变成“可持续推进、可回退、可验证的工程过程”。
先看 OpenCode 自带的基础命令:
| 命令 | 功能 | 使用场景 |
|---|---|---|
/init |
生成项目 AGENTS.md | 新项目初始化 |
/undo |
撤销上一条消息和文件变更 | AI 改错了,想回退 |
/redo |
重做已撤销的操作 | 撤销后想恢复 |
/share |
生成会话分享链接 | 需要分享对话给他人 |
/help |
显示帮助信息 | 忘记命令用法 |
/undo 与 /redo:安全的迭代探索
这两个命令构成了 OpenCode 的"时间旅行"机制。
工作原理(以下 ASCII 图为摘要,展示三步操作的状态变化):
1 | |
注意事项:
/undo和/redo依赖 OpenCode 内部的会话状态追踪,在 Git 仓库中效果最佳- 文件变更会被完整恢复(包括删除的文件)
- 可以连续执行多次
/undo回退多步
/share:会话分享
1 | |
分享链接包含完整的对话历史和代码变更,适合:
- 向同事展示解决方案
- 提交 Bug 报告时附上复现步骤
- 记录学习过程
OMO 内置命令详解
OMO(Oh My OpenAgent,原名 Oh My OpenCode)在 OpenCode 基础上扩展了一组更偏"工作流模板"的斜杠命令。它们的价值不只在于省输入,而在于把原本需要人手动维持的节奏——规划、循环、重构、收尾——固定成可重复执行的流程。
| 命令 | 功能 | 复杂度 |
|---|---|---|
/init |
生成根目录 AGENTS.md(OpenCode 原生,OMO 继承) | 低 |
/init-deep |
生成层级化 AGENTS.md 知识库 | 中 |
/ralph-loop |
自引用开发循环,持续工作直到完成 | 高 |
/ulw-loop |
Ultrawork 版本的 ralph-loop | 高 |
/cancel-ralph |
取消活跃的 Ralph Loop | 低 |
/refactor |
智能重构,完整工具链验证 | 高 |
/start-work |
从 Prometheus 计划开始工作 | 中 |
/init:OpenCode 原生的项目引导
/init 是 OpenCode 的内置命令,用于为项目创建 AGENTS.md 配置文件。
解决的问题:Agent 需要理解项目结构、技术栈、编码规范才能高效工作。每次新项目都要从零开始学习,效率低下。
工作原理(以下 ASCII 图为摘要,展示扫描→生成的主干流程;各分支的详细说明见下方文字):
1 | |
使用方式:
1 | |
关键特性:
- 只生成根目录文件:
/init只在项目根目录生成一个AGENTS.md - 增量更新:如果文件已存在,会保留原有内容并补充新信息
- Git 友好:生成的文件应该提交到版本控制,供团队共享
/init-deep:层级化知识库
/init-deep 是 OMO 扩展的命令,在 /init 的基础上实现了层级化的知识库生成。
解决的问题:大型项目结构复杂,单一根目录的 AGENTS.md 无法承载所有模块的细节。Agent 在处理特定模块时,需要该模块级别的上下文。
工作原理(以下 ASCII 图为摘要,展示并行分析→层级生成的主干流程):
1 | |
使用方式:
1 | |
层级化知识库的价值:
| 层级 | 作用 | 示例内容 |
|---|---|---|
根目录 AGENTS.md |
项目全局视图 | 技术栈、整体架构、部署流程 |
模块级 AGENTS.md |
模块专属知识 | 该模块的 API、依赖关系、设计模式 |
子模块级 AGENTS.md |
细节实现 | 具体函数的用法、边界情况处理 |
与 /init 的对比:
| 维度 | /init(OpenCode 原生) |
/init-deep(Oh My OpenAgent) |
|---|---|---|
| 生成范围 | 仅根目录 | 根目录 + 所有关键子目录 |
| 知识粒度 | 项目级 | 项目级 + 模块级 + 子模块级 |
| 上下文精度 | 粗粒度 | 细粒度,按需加载 |
| 适用场景 | 小型项目、单模块项目 | 大型项目、多模块项目 |
| Token 消耗 | 低 | 中等(但按需加载,不一次性全部读入) |
最佳实践:
- 新项目首次使用:先用
/init-deep建立完整知识库 - 定期更新:当项目结构有重大变化时重新运行
- Git 提交:将所有
AGENTS.md文件提交到版本控制 - 增量更新:默认模式会保留已有内容,避免覆盖人工补充的知识
/ralph-loop:持续工作直到完成
这是 OMO 中最有代表性的命令之一,实现了"自引用开发循环"。
核心机制(以下 ASCII 图为摘要,展示循环的主干结构;循环与 OMO 多 Agent 模式的关系见后续"能力层 vs 循环层"小节):
1 | |
使用方式:
1 | |
关键参数:
| 参数 | 默认值 | 说明 |
|---|---|---|
--completion-promise |
DONE |
Agent 输出该标记表示任务完成 |
--max-iterations |
100 |
最大迭代次数,防止无限循环 |
适用场景:
- 复杂的多步骤任务(重构大型模块)
- 需要多次迭代才能完成的功能开发
- Bug 修复(可能需要多次尝试不同方案)
设计哲学:能力层 vs 循环层
一个常见的困惑是:既然界面已经选择了 Sisyphus (Ultraworker) 模式,Agent 已经可以自行多步操作,为什么还需要 /ralph-loop 和 /ulw-loop?
答案在于两者解决的是不同层面的问题:
| 概念 | 解决的问题 | 行为特点 |
|---|---|---|
| Sisyphus (Ultraworker) | “代理能力” | 多代理编排、能多步执行、能并行探索 |
/ralph-loop /ulw-loop |
“代理纪律” | 强制循环验证、防止假完成、必须满足停止条件 |
能力层(Sisyphus/Ultraworker) 解决的是"Agent 能不能做这件事"——它提供多代理编排、并行调度、工具调用等能力。但有能力不代表有纪律。一个有能力执行多步的 Agent,仍可能在第一次响应时就声称"我完成了",或者跳过验证环节直接结束。
循环层(ralph-loop/ulw-loop) 解决的是"Agent 会不会假完成"——它通过自引用循环机制强制 Agent:
- 执行 → 自检 → 发现问题 → 继续执行 → 再自检
- 直到满足明确的
--completion-promise条件 - 防止 Agent 在第一轮就声称完成
用一个比喻:
- Sisyphus (Ultraworker) 像一个全能的工程师:能写代码、能调试、能查文档、能并行处理多个任务
/ralph-loop像一个严格的质检流程:不信任工程师的"我做完了",必须通过验证才能结束
两者是正交互补的关系,而非替代关系。
使用建议:
| 任务类型 | 推荐组合 |
|---|---|
| 日常小改动 | 普通提示,无需特殊命令 |
| 中等功能开发 | ulw: 前缀(激活 Ultraworker) |
| 复杂多步骤任务 | ulw + 分阶段提示 |
| 追求极致/大重构 | ulw + /ralph-loop |
/ulw-loop:Ultrawork 版本的循环
/ulw-loop 是 /ralph-loop 的增强版,专为 Ultraworker 模式优化。它在标准 Ralph Loop 的基础上增加了更严格的验证机制和更智能的任务分解能力。
与 /ralph-loop 的区别:
| 特性 | /ralph-loop |
/ulw-loop |
|---|---|---|
| 验证强度 | 基础自检 | 多重验证(编译、测试、Lint) |
| 任务分解 | 简单分步 | 智能拆解为子任务 |
| 错误恢复 | 重试当前步 | 自动回退并调整策略 |
| 适用场景 | 一般复杂任务 | 高可靠性要求的重构 |
使用方式:
1 | |
/cancel-ralph:取消活跃的循环
当 Ralph Loop 陷入死循环或需要中断时,使用此命令。
1 | |
注意事项:
- 会立即终止当前循环
- 保留已完成的中间状态
- 适合在发现方向错误时及时止损
/refactor:智能重构
/refactor 是一个专门用于代码重构的命令,它集成了完整的工具链验证。
工作流程:
- 分析阶段:识别需要重构的代码块及其依赖
- 规划阶段:生成重构计划,包括目标结构和迁移步骤
- 执行阶段:逐步执行重构,每步后进行验证
- 验证阶段:运行测试、Lint、编译检查
使用方式:
1 | |
关键特性:
- 原子性保证:每一步重构都是原子的,可随时回退
- 依赖追踪:自动更新所有引用点
- 回归测试:重构后自动运行相关测试用例
/start-work:从 Prometheus 计划开始工作
/start-work 用于从已有的 Prometheus 计划文件中恢复工作状态。
使用场景:
- 中断的工作需要继续
- 多人协作时接手他人的计划
- 从长期规划中提取具体任务
使用方式:
1 | |
命令速查表
| 命令 | 用途 | 适用场景 |
|---|---|---|
/init |
生成项目知识库 | 新项目初始化 |
/init-deep |
生成层级化知识库 | 大型项目 |
/ralph-loop |
自引用开发循环 | 复杂多步骤任务 |
/ulw-loop |
Ultrawork 循环 | 高可靠性重构 |
/cancel-ralph |
取消循环 | 中断死循环 |
/refactor |
智能重构 | 代码结构优化 |
/start-work |
从计划恢复 | 继续中断工作 |
/undo |
撤销操作 | 回退错误变更 |
/redo |
重做操作 | 恢复撤销的变更 |
/share |
分享会话 | 协作与复盘 |
模式速查表
| 模式 | 特点 | 适用场景 |
|---|---|---|
| Plan 模式 | 只读分析,禁止修改 | 代码审查、方案设计 |
| Build 模式 | 全工具权限 | 日常开发、功能实现 |
| General Agent | 通用研究能力 | 多步骤调研、文档查阅 |
| Explore Agent | 快速代码探索 | 定位代码、理解结构 |
| Sisyphus (Ultraworker) | 多代理并行编排 | 复杂任务并行处理 |
| Ralph Loop | 自引用循环验证 | 防止假完成、强制迭代 |
大型重构工作流:持续数周的项目实战
在实际工程中,最考验 Agent 编排能力的不是写一个新功能,而是对一个运行多年的大型项目进行持续数周的重构。这类任务的特点是:
- 规模大:涉及数百个文件、数千处引用
- 周期长:需要多天甚至数周的持续工作
- 风险高:任何一步出错都可能导致系统不可用
- 上下文深:需要理解历史债务、业务约束、技术演进路径
下面以一个真实的"单体服务拆分"项目为例,展示如何设计一个可持续数周的大型重构工作流。
四阶段工作流设计
我们将整个重构分为四个阶段,每个阶段有明确的目标、交付物和退出条件:
阶段一:分析与规划(第 1-3 天)
目标:全面理解现有系统,制定详细的拆分方案。
关键动作:
- 代码库扫描:使用
/init-deep生成层级化知识库 - 依赖分析:识别模块间的调用关系、数据流向
- 边界划定:确定拆分后的服务边界、接口契约
- 风险评估:识别高风险区域,制定回滚预案
交付物:
plans/refactoring-plan.md:详细的重构计划diagrams/dependency-graph.mmd:依赖关系图risks/risk-register.md:风险登记册
退出条件:
- 计划经过人工评审并通过
- 所有高风险项都有对应的缓解措施
- 测试环境准备就绪
阶段二:基础设施准备(第 4-7 天)
目标:搭建新服务的基础设施,确保可以独立运行。
关键动作:
- 脚手架生成:创建新服务的项目结构
- CI/CD 配置:配置自动化构建、测试、部署流水线
- 监控接入:集成日志、指标、链路追踪
- 数据迁移脚本:编写数据库迁移脚本
交付物:
- 新服务的基础代码仓库
- 可运行的 Hello World 服务
- 完整的 CI/CD 流水线
退出条件:
- 新服务可以独立部署和运行
- 监控指标正常上报
- 数据迁移脚本在测试环境验证通过
阶段三:渐进式迁移(第 8-20 天)
目标:将功能从单体服务逐步迁移到新服务,保持系统始终可用。
关键动作:
- 流量灰度:通过网关将少量流量路由到新服务
- 双写验证:关键数据同时写入新旧存储,比对一致性
- 功能开关:使用 Feature Flag 控制新旧逻辑切换
- 每日回归:每天运行核心测试用例,确保无回归
交付物:
- 每日迁移进度报告
- 双写一致性验证报告
- 性能对比数据
退出条件:
- 100% 流量已切换到新服务
- 双写验证连续 7 天无差异
- 性能指标不低于原系统
阶段四:清理与收尾(第 21-25 天)
目标:移除旧代码,完成最终收尾。
关键动作:
- 旧代码删除:移除单体服务中的已迁移代码
- 依赖清理:移除不再需要的依赖包
- 文档更新:更新架构文档、API 文档
- 经验总结:记录本次重构的经验教训
交付物:
- 清理后的代码仓库
- 更新后的架构文档
- 重构总结报告
退出条件:
- 旧代码完全移除,系统正常运行
- 所有文档已更新
- 团队完成知识传递
每日工作节奏
在长达数周的重构过程中,保持稳定的每日工作节奏至关重要。我们采用以下节奏:
上午(9:00-12:00):执行阶段
- 运行
/ralph-loop执行当天的迁移任务 - 监控实时指标,发现异常立即暂停
- 记录遇到的问题和解决方案
下午(14:00-17:00):验证与调整阶段
- 运行回归测试,验证上午的变更
- 分析测试结果,修复发现的问题
- 更新第二天的工作计划
傍晚(17:00-18:00):同步与复盘
- 向团队同步当日进度
- 记录当日学到的新知识到
AGENTS.md - 规划第二天的具体任务
关键实践
在整个重构过程中,以下实践被证明是关键成功因素:
- 每日提交:每天的变更都提交到 Git,保持进度可追溯
- 自动化验证:所有验证步骤都自动化,减少人为疏漏
- 渐进式暴露:每次只迁移一个小模块,控制风险范围
- 双向同步:新旧系统之间的数据保持双向同步,确保可随时回退
- 知识沉淀:每天将学到的领域知识写入
AGENTS.md,避免重复探索
完整工作流图
1 | |
Ralph Loop:上下文重置驱动的迭代工程模式
在讨论完具体的命令和工作流之后,我们需要深入理解支撑这些实践的核心理念:Ralph Loop。它不仅是一个命令,更是一种应对"上下文腐化"(Context Rot)的工程模式。
源头视角:Geoffrey Huntley
Ralph Loop 的概念最早由 Geoffrey Huntley 提出。他在维护大规模开源项目时发现,AI Agent 在长对话中会逐渐"迷失"——上下文窗口被大量中间状态填满,Agent 开始重复犯错、忽略之前的约束、甚至产生幻觉。
他的解决方案非常朴素:不让 Agent 在同一个上下文中运行太久。每一轮迭代完成后,强制开启一个新的会话,只保留必要的状态文件,丢弃所有中间对话历史。
这就是 Ralph Loop 的核心思想:用进程级的上下文重置,换取长期的稳定性。
核心理念:Context Rot
Context Rot(上下文腐化) 是指随着对话轮次增加,Agent 的上下文窗口逐渐被无关信息污染,导致性能下降的现象。具体表现包括:
- 注意力分散:Agent 开始关注无关细节,忽略核心任务
- 约束遗忘:之前设定的规则被逐渐忽略
- 重复劳动:Agent 重复执行已经做过的操作
- 幻觉增加:由于上下文混乱,Agent 开始编造不存在的信息
传统的解决方法是增加上下文窗口大小,但这只是治标不治本。更大的窗口意味着更多的噪声,Agent 的注意力机制仍然会在海量信息中迷失。
Ralph Loop 的思路相反:不追求更大的窗口,而追求更干净的窗口。通过定期重置上下文,确保 Agent 每一轮都从一个清晰的状态开始。
例一:open-ralph-wiggum
open-ralph-wiggum 是 Ralph Loop 的一个参考实现。它的核心逻辑非常简单:
1 | |
关键点:
- 每一轮都启动新的
opencode run进程 - 只通过文件系统(
state.md、output.md)传递状态 - 不保留任何对话历史
例二:OMO 实现
OMO 在 open-ralph-wiggum 的基础上做了增强,主要改进包括:
- Hook 机制:在每轮迭代前后注入自定义逻辑(如运行测试、更新知识库)
- 状态管理:使用结构化的
boulder.json替代简单的文本文件 - 错误恢复:检测到失败时自动回退到上一个稳定状态
- 并行验证:在 Agent 执行下一轮的同时,后台运行验证脚本
OMO 的 Ralph Loop 流程:
1 | |
两种实现的本质差异
| 维度 | open-ralph-wiggum | OMO |
|---|---|---|
| 状态传递 | 简单文本文件 | 结构化 JSON |
| 扩展性 | 硬编码逻辑 | Hook 机制可扩展 |
| 错误处理 | 简单重试 | 智能回退 |
| 验证机制 | 无 | 并行验证 |
| 适用场景 | 个人小项目 | 团队大型项目 |
本质上,open-ralph-wiggum 证明了 Ralph Loop 理念的可行性,而 OMO 将其工程化为一个可用的生产工具。
两种循环的信号检测视角
从信号检测的角度看,Ralph Loop 和传统长对话的本质差异在于噪声累积的控制:
传统长对话:
1 | |
Ralph Loop:
1 | |
通过进程级重置,Ralph Loop 确保每一轮的噪声不会带入下一轮,从而保持长期的稳定性。
深挖三种模式
在实际使用中,Ralph Loop 有三种常见模式:
模式一:严格 Ralph Loop
特点:每轮完全重置,只保留最少量的状态文件。
适用场景:
- 任务可以清晰分解为独立步骤
- 每步的输出可以作为下一步的输入
- 对上下文依赖较低
示例:
1 | |
模式二:混合 Ralph Loop
特点:部分状态持久化,保留关键的中间结果。
适用场景:
- 任务有一定的上下文依赖
- 需要保留部分历史信息
- 平衡稳定性和连续性
示例:
1 | |
模式三:Ultrawork Ralph Loop
特点:结合 Ultraworker 的多代理能力,在每轮中进行并行验证。
适用场景:
- 高可靠性要求的重构
- 需要多维度验证的任务
- 团队级的大型项目
示例:
1 | |
本质:短跑选手的接力赛
Ralph Loop 的本质可以用一个比喻来概括:
传统长对话像一个马拉松选手,试图一口气跑完全程。但随着距离增加,体力下降、注意力分散、错误增多。
Ralph Loop像一群短跑选手的接力赛。每个选手只跑一小段,保持最佳状态,然后通过接力棒(文件系统)将状态传递给下一个选手。
这个比喻揭示了 Ralph Loop 的核心优势:
- 每轮都是最佳状态:每个"短跑选手"都从清晰的上下文开始
- 状态传递标准化:接力棒(文件系统)是标准化的状态载体
- 容错性强:一个选手失误,不影响下一个选手从头开始
- 可观测性好:每轮的结果都可以独立检查和审计
理解了这一点,就能理解为什么 Ralph Loop 成为大型重构的标准模式——它不是简单地"多跑几轮",而是通过架构级的上下文管理,解决了单 Agent 长对话的根本缺陷。
子 Agent 的本质:上下文隔离与专门化
"子 Agent"这个词在多 Agent 系统的讨论中频繁出现,却鲜有人把它说清楚。它是一个能力弱化的 Agent,类似一个 Agent 化的工具?还是一个拥有更小上下文的原始 Agent,像从主 Agent fork 出来的进程?还是一个在指挥体系里听从领导 Agent、但拥有更强资源和能力的 Agent?
这三种直觉都不完全准确。本文从 Anthropic、LangChain、Claude Code 等权威来源出发,厘清子 Agent 的真实本质,并探讨一个更深层的问题:"子 Agent"究竟是能力描述,还是关系描述?
三种直觉,三种误解
在深入定义之前,先把三种常见直觉逐一检验。
误解一:子 Agent 是能力弱化的 Agent
这种直觉来自于"子"字的字面含义——子集、子系统、子进程,往往意味着更小、更弱。但 LangChain 官方文档明确指出:
“An interesting aspect of this approach is that sub-agents may have the exact same capabilities as the main agent.”
子 Agent 可以拥有与主 Agent 完全相同的能力。它不是弱化版,不是受限版,更不是"工具的高级包装"。
误解二:子 Agent 是拥有更小上下文的 fork
这种直觉来自操作系统的进程模型——子进程从父进程 fork,继承部分状态,但资源受限。这个类比有一定道理,但关键词不是"更小",而是"独立且干净"。
Anthropic 官方工程博客描述其多 Agent 研究系统时写道:
“Subagents facilitate compression by operating in parallel with their own context windows, exploring different aspects of the question simultaneously before condensing the most important tokens for the lead research agent.”
子 Agent 拥有独立的上下文窗口(own context windows),而不是主 Agent 上下文的子集。这个上下文窗口是全新的、干净的,不是"更小的"。
误解三:子 Agent 是听从指挥但能力更强的下属
这种直觉来自军事或企业的层级模型——将领指挥士兵,但士兵在具体战术上可能比将领更专业。这个类比在某些场景下成立,但它把"子 Agent"理解成了一种永久的身份,而非一种临时的关系。
真正的问题在于:一个 Agent 是否是"子 Agent",取决于它在当前任务中的角色,而非它的固有属性。
子 Agent 的真实本质
综合 Anthropic、Claude Code、LangChain 的权威定义,子 Agent 的本质可以用一句话概括:
子 Agent 是一个完整的、专门化的 Agent 实例,运行在独立的上下文窗口中,由主 Agent 通过工具调用方式协调,其核心价值在于上下文隔离,而非能力弱化。
五个核心特征
1. 上下文隔离
这是子 Agent 最核心的价值。LangChain 的表述最为精辟:
“This provides context isolation: each subagent invocation works in a clean context window, preventing context bloat in the main conversation.”
每次调用子 Agent,都是在一个干净的上下文窗口里开始工作。主 Agent 的历史对话、工具调用记录、中间推理过程,都不会污染子 Agent 的上下文。这防止了主 Agent 的上下文膨胀(context bloat)。
2. 完整的 Agent 能力
子 Agent 不是工具(Tool)。工具是单一功能的函数,被动执行,没有决策能力,没有 Agent Loop。子 Agent 是完整的 Agent 实例,拥有:
- 独立的推理-行动循环(Agent Loop)
- 自主规划和决策能力
- 多步骤任务执行能力
- 执行期间的短期记忆
3. 无状态执行
子 Agent 是无状态的(stateless)——它不保留跨调用的记忆。每次被主 Agent 调用,都是一次全新的执行。所有跨步骤的状态,由主 Agent 维护。
4. 专门化任务处理
子 Agent 通过自定义 system prompt 定义专门职责,可以针对特定领域优化。这种专门化不是能力的限制,而是能力的聚焦。
5. 不能递归派发子 Agent
Claude Code 官方文档明确指出:
“Subagents cannot spawn other subagents, so Agent(agent_type) has no effect in subagent definitions.”
子 Agent 不能再派发子 Agent。这是一个刻意的设计约束,防止无限递归和控制流混乱,保证行为的可预测性。
一个重要的附加结论:Skill 可以无限递归
子 Agent 不能递归派发,但 Skill 可以。
这里需要区分两个概念:
| 概念 | 本质 | 递归能力 |
|---|---|---|
| 子 Agent | 完整的 Agent 实例,独立上下文窗口 | ❌ 不能递归派发 |
| Skill | System prompt 的动态注入,上下文内的行为扩展 | ✅ 可以无限递归 |
Skill(如 Claude Code 中的 SKILL.md 机制)本质上是提示词注入,而非 Agent 实例的创建。当一个 Skill 被触发时,它的内容被注入到当前 Agent 的上下文中,Agent 按照 Skill 的指令行动。这个过程发生在同一个上下文窗口内,不涉及新 Agent 实例的创建。
因此,Skill A 可以触发 Skill B,Skill B 可以触发 Skill C,形成任意深度的调用链——这是纯粹的上下文内行为扩展,不存在"无限递归创建 Agent 实例"的风险。
这个区别揭示了一个深层设计哲学:Agent 实例的创建是重量级操作(需要独立上下文窗口),应该被约束;而上下文内的行为扩展是轻量级操作,可以自由组合。
"子 Agent"是关系描述,不是能力描述
这是本文最重要的洞见。
当我们说某个 Agent 是"子 Agent"时,我们描述的是它在当前任务中与其他 Agent 的关系,而不是它的固有属性或能力等级。
以 OMO(Oh My OpenAgent)的 Agent 团队为例:
1 | |
在这个架构图里,Prometheus、Oracle、Librarian 看起来是 Sisyphus 的"子 Agent"。但这个判断是错误的,或者说是不完整的。
Prometheus、Oracle、Librarian 都可以独立运行。
- 用户可以直接对话 Prometheus,让它制定战略规划,完全不经过 Sisyphus
- 用户可以直接调用 Oracle 进行架构咨询
- Librarian 可以作为独立的文档研究 Agent 被任何工作流调用
它们之所以在某些场景下表现为 Sisyphus 的"子 Agent",仅仅是因为 Sisyphus 在那个特定的任务中扮演了编排者的角色,通过工具调用的方式协调了它们。一旦任务结束,这种"主-子"关系就消失了。
这与传统软件工程中的"子系统"概念截然不同。子系统是静态的架构关系,一旦被设计为子系统,就永远是子系统。而 Agent 的"主-子"关系是动态的、任务级别的。
类比:项目中的角色 vs 职位
一个更直观的类比:
在一个软件项目中,张三是"项目经理",李四是"开发工程师"。但在另一个项目中,李四可能是项目经理,张三是开发工程师。他们的职位(固有属性)没有变,但他们在不同项目中的角色(关系描述)是不同的。
Agent 的"主-子"关系正是如此。Prometheus 的固有属性是"战略规划专家",但它在不同的任务中可以是:
- 独立运行的规划 Agent(直接与用户对话)
- Sisyphus 的子 Agent(被 Sisyphus 通过工具调用协调)
- 某个更高层编排器的子 Agent(在更复杂的多层架构中)
子 Agent vs Tool:本质区别
既然子 Agent 不是弱化的 Agent,那它和 Tool 的区别是什么?
| 维度 | Tool | 子 Agent |
|---|---|---|
| 本质 | 单一功能的函数/方法 | 完整的 Agent 实例 |
| 上下文 | 无独立上下文 | 拥有独立上下文窗口 |
| 决策能力 | 无,被动执行 | 有,可自主规划 |
| 循环能力 | 无 | 拥有 Agent Loop(推理-行动循环) |
| 记忆 | 无 | 执行期间有短期记忆 |
| 复杂度 | 单步操作 | 多步骤复杂任务 |
| 状态 | 无状态 | 执行期间有状态,调用间无状态 |
何时用 Tool,何时用子 Agent?
- Tool:任务是单步的、确定性的、不需要推理的(读文件、执行命令、调用 API)
- 子 Agent:任务需要多步骤推理、需要上下文隔离、需要专门化处理
实践含义
理解子 Agent 的本质,对实际的多 Agent 系统设计有直接影响:
1. 不要把"子 Agent"设计成永久的层级关系
如果你的系统里有一个 Agent 永远只能被另一个 Agent 调用,永远不能独立运行,这往往是过度设计的信号。好的 Agent 应该是可以独立运行的,"主-子"关系是任务级别的协调,而非架构级别的约束。
2. 上下文隔离是选择子 Agent 的核心理由
当你考虑是否要用子 Agent 时,最重要的问题不是"这个任务需要多强的能力",而是"这个任务需要独立的上下文吗?"如果任务足够简单,一个 Tool 就够了;如果任务需要多步骤推理但上下文不需要隔离,在主 Agent 内处理就够了;只有当任务需要多步骤推理且需要上下文隔离时,才需要子 Agent。
3. Skill 是上下文内的行为扩展,子 Agent 是上下文外的任务委托
这两种机制解决的是不同层面的问题。Skill 扩展的是当前 Agent 的行为能力,子 Agent 委托的是独立的任务执行。前者是"让我学会新技能",后者是"把这个任务交给专家去做"。
4. 协调者 Agent 应该"不写代码"
在多 Agent 团队的设计中,一个关键原则是:协调者 Agent 应当专注于调度与决策,而不直接参与执行细节。
这个设计有两层深意:
第一,保护协调者的全局视野。 执行细节(如代码实现、文件操作、调试过程)会迅速填满上下文窗口。如果协调者亲自下场执行,它会在技术细节中逐渐丢失对整体任务目标、约束条件和进度安排的掌控。就像一个项目经理如果整天埋头写代码,就会忘记关注项目风险、资源协调和交付时间线。
第二,确保执行者的上下文纯净。 当协调者将任务派发给子 Agent 时,子 Agent 只接收到最小化的任务描述——它需要做什么、遵循什么约束、返回什么格式。子 Agent 的上下文窗口不会被协调者的历史对话、中间推理、或其他无关任务污染。这种"干净"的上下文让子 Agent 能够高度专注地完成单一任务。
这正是 Divide and Conquer(分治) 思想在 Agent 系统中的体现:
| 层级 | 职责 | 上下文特征 |
|---|---|---|
| 协调者(Orchestrator) | 任务分解、进度追踪、质量把控、异常处理 | 保留全局任务图、约束条件、各子任务状态 |
| 执行者(Executor) | 具体实现、细节处理、单任务完成 | 仅包含当前子任务的输入、工具、输出规范 |
执行层往往是"重"的——涉及大量代码、多轮工具调用、错误重试。调度层必须是"轻"的——保持敏捷,随时准备调整策略。如果让协调者同时承担执行,这两层会互相干扰:执行细节膨胀会挤压全局规划的上下文空间,而频繁的全局状态查询又会打断执行的连贯性。
因此,"协调者不写代码"不是能力的限制,而是架构的自觉——通过严格的角色分离,让系统获得更好的可预测性和可维护性。
5. 上下文消耗的恶性循环与"就改一行"陷阱
如果这篇文章你只记住一件事,记这个:中等复杂度以上的任务,协调者绝不写代码。
为什么?因为 LLM 的上下文窗口是有限的。Agent 执行长任务时,窗口里慢慢堆起来的是代码 diff、编译错误、测试输出、lint 报告、重试记录……到第 40 次 tool call,早期的关键信息已经被压缩或丢弃了。Agent 开始"忘记"最初的架构决策,做出跟前面矛盾的改动。
这是一个恶性循环:
1 | |
一旦进入这个循环,就很难出来。到第 60 次 tool call,Agent 可能已经忘了最初的任务目标是什么了。你让它加个用户认证功能,它却在那儿纠结一个完全不相关的 import 路径问题。
解法是把 Agent 拆成两层。 协调者(Coordinator)只管规划、委派、汇总,一行代码都不碰;执行者(子 Agent)每次从干净的上下文开始,拿到精确的 prompt,干完就释放。子 Agent 不知道之前发生了什么,但它拿到的 prompt 里包含了它需要知道的一切。任务完成后,详细上下文被丢掉,协调者只保留一段摘要。信息经过了压缩和筛选,而不是无差别地堆在上下文里。
破坏这个原则最常见的方式是"只是快速改一下"。 协调者发现一个小问题,心想"这么简单的东西不用启子代理,我直接改了"。一次编辑变成了五次(因为牵扯出其他地方),五次变成二十次,上下文就被消耗殆尽了。
这个陷阱看起来很合理——“就改一行而已嘛”——但你低估了代码的牵连性。如果你发现协调者正在用 Edit 或 Write 工具修改源代码,立刻停下来,启动子代理。没有例外。
复杂度分层决策框架
不同复杂度的任务,执行方式也不同:
| 复杂度 | 判断标准 | 执行方式 | 示例 |
|---|---|---|---|
| 简单 | 能用一句话描述,且不包含"和"字 | 协调者直接执行 | 改 typo、加行日志 |
| 中等 | 需要清单来跟踪改了哪些地方 | 委派给子 Agent | 多文件一致性修改 |
| 复杂 | 需要做设计决策和权衡 | 委派 + Git Worktree 隔离 | 重构、新模块开发 |
Git Worktree 隔离相当于仓库的临时副本,子 Agent 在独立工作区执行结构性变更,成功了合并,失败了丢掉,不污染主分支。
模型选型的经济账
委派子 Agent 时还有一个容易被忽略的杠杆:不是所有任务都需要用最强的模型。
一个"重命名变量"的任务和一个"重构认证模块"的任务,对模型能力的要求完全不同。前者要的是快和便宜,后者要的是深度推理。如果所有子代理都用同一个顶级模型,既浪费钱又浪费时间。
协调者在委派时可以根据任务性质指定模型:
| 任务类型 | 推荐模型 | 理由 |
|---|---|---|
| 快速执行类(改 typo、简单重命名) | Claude Haiku | 响应快、成本低 |
| 深度推理类(复杂重构、架构级变更) | GPT-5.3 Codex / Claude Opus | 质量远比速度重要 |
| 代码检索类(大型代码库中定位文件) | Gemini 3 Flash | 速度第一 |
这种分层模型策略让系统在保证质量的同时,显著降低运行成本。
OMO:Prompt Engineering 构建的虚拟团队
OMO(Oh My OpenAgent,原名 Oh My OpenCode)通过精心设计的 system prompt 和 Hook 机制,在 OpenCode 内部构建了一支由 11 个专业 Agent 组成的虚拟团队。这不是简单的工具集合,而是一个基于 Prompt Engineering 的组织架构。
三层架构:规划层、执行层、工作者层
OMO 的 Agent 团队分为三个层次,各司其职:
1 | |
规划层负责将用户需求转化为结构化的执行计划。执行层负责任务的编排和调度。工作者层负责具体的执行工作。
多轨主 Agent:四个入口的选择逻辑
OMO 提供了四个用户可直接选择的主 Agent 入口,对应不同的工作模式:
| 入口 | 适用场景 | 核心特点 |
|---|---|---|
| Prometheus | 需求不明确,需要先规划 | 只做计划,不写代码 |
| Atlas | 已有计划,需要执行 | 按 Todo 列表波次执行 |
| Hephaestus | 需要深度自主执行 | 单 Agent、单上下文,禁止委托 |
| Sisyphus | 日常多 Agent 协作 | 委派优先,多上下文隔离 |
这四条路径彼此独立、互不委托。路由决策权保留给人类用户——Agent 不具备自主判断"当前任务更适合另一条路径"并切换的能力。
Sisyphus vs Hephaestus:委派优先 vs 深度自主
四个主 Agent 中,Sisyphus 和 Hephaestus 的对比最能体现"多轨"设计的核心张力:
| 维度 | Sisyphus | Hephaestus |
|---|---|---|
| 核心哲学 | 委派优先、并行默认、证据驱动 | 禁止询问、不中途停下、100% 完成 |
| 底层模型 | Claude Opus(编排能力优先) | GPT-5.3 Codex(推理能力优先) |
| Todo 列表 | ✅ 使用 boulder.json 管理 |
❌ 没有 Todo 列表 |
| 子 Agent 委托 | ✅ 可委托多种子 Agent | ❌ 禁止委托子 Agent |
| 上下文模式 | 多上下文:主 Agent 持续存在,子 Agent 每次重建 | 单上下文:全程一个 Agent |
| 探索方式 | 按 Todo 顺序,Atlas 调度时探索 | 写代码前强制并行探索(2-5 个 Explore Agent) |
| 中途交互 | 可通过 Todo 状态观察进度 | 不中途停下,直到 100% 完成 |
Hephaestus 是 OMO 中唯一一个"单 Agent、单上下文"的主 Agent。 它的核心设计哲学是:给目标,不给菜谱——用户只需描述最终目标,Hephaestus 自主决定如何达成,中途不停下来询问。
Sisyphus 是 OMO 的核心主编排器,代表"委派优先"的执行哲学。 它的核心设计哲学是:能委派就不自己做——Sisyphus 把任务拆解成结构化的 Todo 列表,然后委派给最合适的子 Agent 去执行。
两者的互斥性,恰恰反映了广度优先和深度优先在执行策略上的根本不兼容——你不能同时既并行委派又深度自主。
OMO Agent 角色规格表
OMO 完整的 11 个 Agent 各有明确的模型选型和职责边界:
| Agent | 默认模型 | 温度 | 模式 | 核心职责 |
|---|---|---|---|---|
| Sisyphus | claude-opus-4-6 | 0.1 | primary | 主编排器,接收用户请求后进行意图分类、委派任务、验证结果 |
| Hephaestus | gpt-5.3-codex | 0.1 | primary | 自主深度执行器,端到端完成复杂任务,不中途停下 |
| Prometheus | claude-opus-4-6 | 0.1 | all | 战略规划师,只做计划不写代码,输出 .sisyphus/plans/*.md |
| Atlas | claude-sonnet-4-6 | 0.1 | primary | Todo 列表编排器,按波次并行调度任务执行 |
| Oracle | gpt-5.2 | 0.1 | subagent | 只读高智商顾问,用于架构决策和疑难调试 |
| Metis | claude-opus-4-6 | 0.3 | subagent | 规划前顾问,在 Prometheus 生成计划前做 gap 分析 |
| Momus | gpt-5.2 | 0.1 | subagent | 计划审查员,验证计划的可执行性和引用正确性 |
| Librarian | glm-4.7 | 0.1 | subagent | 外部文档/代码搜索,克隆仓库、查官方文档、搜 GitHub |
| Explore | grok-code-fast-1 | 0.1 | subagent | 内部代码库搜索,回答"X 在哪里"类问题 |
| Multimodal Looker | gemini-3-flash | 0.1 | subagent | 多模态文件分析,处理 PDF/图片/图表 |
| Sisyphus-Junior | claude-sonnet-4-6 | 0.1 | all | 分类任务执行器,由 category 系统派生,不能再委派 task() |
温度差异值得注意:大多数 Agent 使用 temperature: 0.1(确定性输出),但 Metis 使用 0.3——作为"前置分析师",它需要更多创造性来发现潜在问题和盲点。
协作拓扑形成了清晰的分层结构:
1 | |
OMO 的一次循环:从请求到代码落地
以一个具体例子拆解 OMO 内部的执行过程。
场景:在 OpenCode 终端输入:
1 | |
第一步:Hook 拦截,识别 ulw 魔法词
OMO 通过 OpenCode 的 UserPromptSubmit Hook 拦截输入。检测到 ulw(ultrawork 的缩写)后,Hook 在提示词前注入系统级指令,激活完整的多 Agent 协作流程。这一注入对用户透明——Sisyphus 收到的实际提示词已包含"启动并行子 Agent、强制完成 Todo、使用 LSP 重构"等完整指令。
架构洞察:中间件/拦截器模式
从实现角度看,OMO 是一个典型的中间件/拦截器模式。它不直接实现 AI 对话逻辑,而是通过 OpenCode 提供的各个生命周期钩子点(UserPromptSubmit、PostToolUse 等)注入自己的逻辑。整个插件本质上是一个巨大的"拦截器集合"——每个钩子点对应一个拦截层,OMO 在这些层上叠加规划、调度、验证等能力,而 OpenCode 的核心对话引擎完全不感知这些注入的存在。
第二步:Prometheus 规划(规划层)
Sisyphus 框架首先调用 Prometheus(规划师),将需求拆解为结构化的 Todo 列表:
1 | |
Todo 列表是 OMO 的核心状态——写入 boulder.json(或 .sisyphus/ 目录下的状态文件),而非对话历史。这使得 OMO 能跨会话恢复:即使中途关闭终端,Todo 列表仍保存在文件中。
第三步:并行子 Agent 执行(工作者层)
Atlas(指挥官) 读取 Todo 列表,识别无依赖关系的任务并行执行。Todo 1(扫描调用方)和 Todo 2(查文档)互相独立,Atlas 同时启动两个子 Agent:
1 | |
两个 Agent 并发工作,各自完成后将结果汇报给 Atlas。这是"并行"的真实含义——多个 AI 进程同时运行,而非顺序问答。
第四步:Sisyphus-Junior 执行核心编码
Atlas 将 Explore 和 Librarian 的结果(调用方列表 + API 文档)传给 Sisyphus-Junior(主力执行者),开始重构:
1 | |
LSP 的介入是关键:Sisyphus-Junior 通过 LSP 的 publishDiagnostics 接口获得编译级别的反馈,确保重构不破坏任何引用,而非依赖人工跑测试验证。
第五步:Todo 执行器强制收尾
OMO 内置 Todo 执行器(Todo Enforcer):通过 PostToolUse Hook,每次工具调用结束后检查 Todo 列表,若有未完成项,则将"继续完成剩余 Todo"的指令注入到下一轮提示词。这一机制确保 Agent 持续工作直到任务完成,而非依赖模型的自律性。
流程 ASCII 图:多轨主 Agent 入口
OMO 有四个用户可直接选择的主 Agent 入口,对应不同的工作模式。以下展示核心路径的完整流程。
路径一:Sisyphus ulw 路径(委派优先,Todo 驱动)
1 | |
路径二:Hephaestus 路径(自主深度执行,推理优先)
Hephaestus 是与 Sisyphus 并列的第二个主 Agent,使用 GPT-5.3 Codex 模型,专为深度架构工作和复杂调试设计。它的核心哲学是"给目标,不给菜谱"——用户只需描述最终目标,Hephaestus 自主决定如何达成,中途不停下来询问。
1 | |
boulder 机制:对抗 Context Rot 的注意力刷新
**Context Rot(上下文腐化)**是 Transformer 架构的数学属性:随着上下文增长,模型对中间位置信息的注意力最弱(Lost-in-the-Middle 效应),每个 Token 分到的注意力权重趋近于零(注意力稀释),语义相似但无关的内容会主动误导模型(干扰项叠加)。
研究表明,每个 AI Agent 的成功率在 35 分钟后都会下降,任务时长翻倍,失败率翻四倍。这是因为 35 分钟后,Agent 通常已经读取了 15-30 个文件,上下文中有效信号的占比已经低到临界点。
boulder 机制的应对策略非常直接:通过 PostToolUse Hook,在每次工具调用结束后,将"继续完成剩余 Todo"的指令重新注入到提示词的尾部。这意味着:
- 无论上下文已经积累了多少历史,当前任务目标始终出现在上下文的最后一条消息
- 模型在每次推理时,都能以最高注意力感知到"我还有什么没做完"
- Todo 列表本身存储在
boulder.json文件中(持久化状态),而非依赖上下文记忆
这是一个精妙的设计:用文件系统承载状态,用尾部注入保持注意力。boulder 机制没有试图解决 Context Rot(那需要改变 Transformer 架构),而是绕过了它——通过持续将任务目标"刷新"到注意力最强的位置,让 Context Rot 的影响无法积累到足以干扰任务执行的程度。
多维度委派:像造房子一样同时发展
问题:往不同维度委派不同的 tuned 过的 Agent 工程师团队,是不是像造房子一样,长宽高同时发展的最优模式?
答案:这个类比非常准确,但需要补充一个关键约束条件。
传统软件开发的瓶颈之一是串行依赖:前端等后端 API,后端等数据库 Schema,测试等功能完成。这种串行性不是因为工程师不够聪明,而是因为人类工程师的注意力是单线程的——同一时间只能深度专注于一件事。
多 Agent 架构打破了这个约束。OMO 的 11 个 Agent 按职责维度分工:
- 规划维度(Prometheus):负责任务分解,不参与执行
- 执行维度(Sisyphus-Junior):负责代码实现,不主导规划
- 搜索维度(Librarian):负责文档查询,不干扰编码
- 审查维度(Atlas):负责代码审查,不参与生成
这确实像造房子:地基、框架、水电、装修可以在不同维度同时推进,只要接口约定清晰(墙的位置、管道走向),各工种互不干扰。
但"造房子"类比也揭示了一个关键约束:并行的前提是接口的提前约定。如果前端和后端同时开发,必须先约定好 API 契约;如果多个 Agent 并行执行,必须先约定好文件边界和状态格式。OMO 的 .sisyphus/plans/ 目录和 boulder.json 正是扮演这个"建筑图纸"的角色——它们定义了各 Agent 的工作边界,使并行成为可能。
所以更精确的表述是:多维度委派是最优模式,但前提是有一个强规划层(Prometheus)先把"图纸"画好。没有图纸的并行,不是造房子,是各自为战。
计划-委派-执行-测试-审查:瀑布流的复活?
问题:当前的计划→委派→执行→测试→审查模式,是不是重新复现了当年瀑布流的工程项目管理模式?
答案:形似瀑布,但本质不同——关键差异在于迭代速度和反馈机制。
表面上看,Agentic Coding 的工作流确实与瀑布模型高度相似:
| 瀑布模型 | Agentic Coding |
|---|---|
| 需求分析 | Prometheus 规划,生成 Todo 列表 |
| 系统设计 | 技术方案 Agent 输出架构文档 |
| 编码实现 | Sisyphus-Junior 并行执行 |
| 测试验证 | 测试 Agent 部署到测试环境验证 |
| 部署上线 | 部署 Agent 执行发布流程 |
但瀑布模型的核心问题不是"有没有阶段",而是阶段之间的反馈延迟:需求分析完成后,要等几个月才能看到测试结果,发现问题时已经积累了大量错误的实现。
Agentic Coding 的关键差异在于:
- 迭代速度:一个完整的"计划→执行→测试"循环可以在分钟级完成,而不是月级。这使得"发现问题→修正方向"的成本极低。
- 并行反馈:测试 Agent 不需要等所有功能完成才开始工作,可以在执行 Agent 完成部分功能后立即介入验证。
- 动态规划:Prometheus 的规划不是一次性的,而是可以根据执行结果动态调整——这是瀑布模型最根本的缺陷所在(需求冻结)。
更准确的类比是:Agentic Coding 更像极速迭代的敏捷开发,只是把"Sprint"的时间单位从两周压缩到了几分钟,把"团队成员"从人类工程师替换为了专职 Agent。它保留了敏捷的核心——快速反馈、持续验证——而不是瀑布的核心——阶段冻结、线性推进。
当然,有一个场景确实更接近瀑布:当任务足够大、规划足够复杂时,Prometheus 的初始规划会变得非常重要,一旦规划方向错误,后续所有 Agent 的执行都会偏离。这是 Agentic Coding 目前最需要人类介入的环节——不是执行,而是规划的正确性验证。这也是为什么 Human-in-the-Loop 在企业级框架中被显式设计为"需求澄清"阶段:让人类在规划阶段介入,而不是在执行阶段救火。
两种循环的检验对象:它们到底在检验谁?
问题:外部 ralph CLI 和 OMO 内部 /ralph-loop 这两种循环,检验的是西西弗斯的完成状态,还是西西弗斯的子 Agent 的完成状态?
这个问题触及了 Agentic Coding 中一个常被忽视的结构性盲点。要回答它,需要先厘清一个前提:在 OMO 的多 Agent 架构中,实际执行任务的是子 Agent,而不是西西弗斯本身。西西弗斯是编排者,它把具体工作委派给 Sisyphus-Junior、Explore、Librarian 等子 Agent 去完成。
那么,当任务未完成时,未完成的是谁?是子 Agent——是 Sisyphus-Junior 没有真正重构完 formatDate,是 Explore 没有找到所有调用方。西西弗斯自己只是一个调度层,它感知不到子 Agent 是否真正完成了任务,只能看到子 Agent 的文字报告和文件变更。
这就引出了两种循环的检验对象问题。
外部 ralph CLI(open-ralph-wiggum)检验的是西西弗斯 session 的输出。
外部 ralph 是 Shell 层面的进程级循环脚本。每次迭代,它启动一个全新的西西弗斯 session,等待该 session 结束,然后检查 session 的 stdout 输出中是否包含完成标记(默认是 <promise>COMPLETE</promise>):
1 | |
关键在于:外部 ralph 看不到子 Agent 的 session。子 Agent 在西西弗斯内部运行,它们的输出被西西弗斯消化后,只有西西弗斯的最终输出才暴露给外部 ralph。完成标记 <promise>COMPLETE</promise> 是由西西弗斯输出的,不是子 Agent 输出的。
OMO 内部 /ralph-loop 检验的也是西西弗斯 session 的输出。
/ralph-loop 是 OMO 通过 Stop Hook 实现的内部循环机制。当西西弗斯 session 尝试退出时,Stop Hook 拦截这个退出信号,检查 session 输出中是否包含完成标记(如 <promise>DONE</promise>):
1 | |
与外部 ralph 一样,Stop Hook 监听的是整个西西弗斯 session 的输出,而不是任何子 Agent session 的输出。子 Agent 的 session 在西西弗斯内部是隔离的,Stop Hook 无法直接感知它们的状态。
两种循环的本质共同点:都只能检验西西弗斯层面。
| 维度 | 外部 ralph CLI | OMO /ralph-loop |
|---|---|---|
| 实现位置 | Shell 进程层(外部) | OpenCode Stop Hook(内部) |
| 检验对象 | 西西弗斯 session 的 stdout | 西西弗斯 session 的输出 |
| 完成标记输出者 | 西西弗斯(主 Agent) | 西西弗斯(主 Agent) |
| 子 Agent 可见性 | 不可见 | 不可见 |
| 会话管理 | 每次迭代启动全新 session | 同一 session 内循环 |
这揭示了一个深层的结构性问题:两种循环都依赖西西弗斯的"自我报告"。西西弗斯说"完成了"(输出完成标记),循环就退出;西西弗斯没说完成,循环就继续。但西西弗斯自己对子 Agent 的感知,也只是子 Agent 的文字报告——这是一个信任传递链:
1 | |
链条上的每一环都是"荣誉系统"(honor system):没有机制能自动验证子 Agent 是否真正完成了任务,也没有机制能验证西西弗斯是否正确评估了子 Agent 的工作。如果子 Agent 伪完成(声称完成但实际未完成),西西弗斯可能会被误导,进而输出完成标记,导致循环提前退出。
这就是为什么 Human-in-the-Loop 在 Agentic Coding 中不可或缺——不是因为 Agent 不够聪明,而是因为完成状态的验证链条本质上是软约束,最终需要人类的眼睛来做最后一道确认。
Agentic Coding 的人机分工
Agentic Coding 改变的不只是工具,而是人在研发流程中的角色定位。
在传统开发模式下,开发者是执行者:写代码、调试、部署、验证。在 Agentic Coding 模式下,开发者是架构师和审查者:
- 定义目标:描述要解决的问题,而不是描述解决步骤
- 设定约束:告诉 Agent 不能做什么(如不能修改某个核心模块)
- 审查结果:在 Agent 完成任务后,判断结果是否符合预期
- 介入纠偏:当结果偏离预期时,提供更精确的指导
这种分工有一个关键前提:人类的"品味"。品味不是审美,而是决策力——在众多可行方案中判断"哪个是对的选择",尤其体现为"选择不做"。AI 擅长执行与优化,但缺乏责任意识与经验直觉;人类凭借实践经验积累、业务理解与后果承担能力,把控质量边界与必要性判断。
多工具生态融合:配置文件如何协同
从单工具到多 Agent 团队,这条演进路径的终点并不是"选一个最好的工具",而是让多个工具协同工作——这正是"从工具到团队"这个命题的自然延伸:当 Agent 本身已经开始组队,工具之间的配置知识也需要统一管理,否则团队协作的收益会被配置漂移抵消掉。
一个现实的问题是:团队可能同时使用 Claude Code、Cursor 和 OpenCode(配合 OMO)。每个工具都有自己的配置体系——Claude Code 用 CLAUDE.md,Cursor 用 .cursorrules,OMO 用 AGENTS.md 和 SKILL.md。真正的挑战不是"配置写在哪",而是如何避免同一份项目知识在多个文件里重复、漂移和失真。
更稳妥的做法是把它理解为一个分层配置体系:
- 项目全局知识放在
AGENTS.md,作为跨工具共享的主入口; - 工具专用规则放在
CLAUDE.md、.cursorrules之类的轻量文件里,只保留该工具独有的行为约束; - 领域技能放在
SKILL.md中,按需加载; - 任务计划与进度放在
.sisyphus/plans/等工作目录中,负责跨会话延续执行。
换句话说,多工具协作的关键不是"每个工具都配一遍",而是建立单一真相源 + 工具侧薄包装的结构:共识写一次,工具按需引用。这样,Agentic Coding 才不会从"工程协作系统"退化成"配置文件迷宫"。
如果只用 OpenCode,如何继承 Cursor 和 Claude Code 的 Rule 遗产?
如果你只用 OpenCode,但项目里已经有了 .cursorrules 和 CLAUDE.md,不必推倒重来。可以按以下步骤渐进迁移:
第一步:分类审计现有规则
把 .cursorrules 和 CLAUDE.md 里的内容按"通用性"分类:
| 类型 | 特征 | 示例 |
|---|---|---|
| 项目共识 | 与工具无关,描述业务、架构、约定 | "所有 API 返回格式为 { code, data, message }" |
| 工具行为约束 | 特定工具的交互模式 | “Cursor 的 Tab 补全触发条件” |
| 编码规范 | 语言/框架层面的风格 | “TypeScript 项目使用 4 空格缩进” |
第二步:迁移项目共识到 AGENTS.md
把"项目共识"类内容提取出来,写入 AGENTS.md。这是跨工具共享的主入口,格式建议:
1 | |
第三步:保留工具专用规则
.cursorrules 和 CLAUDE.md 不要删除,但只保留该工具独有的行为约束。例如:
1 | |
第四步:建立引用关系
在工具专用规则文件里,显式引用 AGENTS.md:
1 | |
第五步:用 SKILL.md 承载领域技能
如果项目有特定领域的复杂规则(如 React 组件开发规范、API 设计指南),可以拆分为独立的 SKILL.md,放在 skills/ 目录下。OpenCode 的 SKILL 机制支持按需加载,避免 AGENTS.md 臃肿。
1 | |
迁移后的结构对比:
| 迁移前 | 迁移后 |
|---|---|
.cursorrules 包含所有规则(重复) |
.cursorrules 只保留 Cursor 特有约束(薄包装) |
CLAUDE.md 包含所有规则(重复) |
CLAUDE.md 只保留 Claude Code 特有约束(薄包装) |
无 AGENTS.md |
AGENTS.md 作为单一真相源(项目共识) |
| 无 SKILL 机制 | skills/*/SKILL.md 按需加载(渐进披露) |
关键原则:
- 不要删除原文件:保留
.cursorrules和CLAUDE.md,但只保留工具特有的内容 - 先审计再迁移:理解每条规则的目的,避免无脑搬运
- 渐进式迁移:可以先迁移高频使用的规则,低频规则后续再处理
- 测试验证:迁移后让 Agent 执行几个典型任务,验证规则是否生效
这样,你既继承了 Cursor 和 Claude Code 的规则遗产,又避免了多工具协作时的配置漂移问题。
小结:Agentic Coding 真正改变的是什么?
回过头看,Agentic Coding 真正带来的变化,不只是"AI 能写更多代码",而是软件工程的组织方式开始被重新包装为可调用、可验证、可并行的流程。
从裸 OpenCode 到 Ralph Loop,再到 OMO 和更偏企业化的 Agent 框架,演进路径其实很清晰:
- 第一阶段解决"单个 Agent 能不能理解并修改代码";
- 第二阶段解决"任务能不能在验证约束下持续推进";
- 第三阶段解决"多个角色、多个上下文、多个知识源能不能像团队一样协作"。
这也是为什么我更愿意把 Agentic Coding 看成一次从工具到组织的迁移。代码生成当然重要,但更重要的是:规划、委派、验证、知识沉淀这些原本分散在人类团队中的动作,正在被重新抽象为一套可执行的协作系统。
结合前文对子 Agent 本质的分析,我们可以得出几个关键结论:
- 子 Agent 是完整的 Agent,可以拥有与主 Agent 相同甚至更强的能力,其核心价值在于上下文隔离而非能力弱化
- "子 Agent"是关系描述,不是能力描述——Prometheus、Oracle、Librarian 这样的 Agent 可以独立运行,也可以在特定任务中作为子 Agent 被协调
- 主-子关系是动态的、任务级别的,不是静态的架构约束,好的 Agent 设计应该让每个 Agent 都能独立运行
- 协调者不写代码是架构的自觉,通过严格的角色分离让系统获得更好的可预测性和可维护性
- 上下文隔离是选择子 Agent 的核心理由,中等复杂度以上的任务,协调者绝不写代码,以避免上下文消耗的恶性循环
理解了这些,你就能更清晰地设计多 Agent 系统:让每个 Agent 都能独立运行,让"主-子"关系服务于任务,而不是被架构固化。
参考资料
核心概念
- Context Rot 研究:Long Context is Not All You Need: Diagnosing and Mitigating the Performance Degradation of Long-Context LLMs(Chroma,2025)——测试了 18 个前沿模型,发现所有模型都会随上下文增长而性能下降,提出了"35 分钟墙"和 Lost-in-the-Middle 效应的量化数据。
- Everything is a Ralph Loop:ghuntley.com/loop/(Geoffrey Huntley,2026)——Ralph Loop 设计哲学的源头文章,提出"软件开发是陶轮上的黏土"和"编程循环而非砌砖"的核心论断。
- 子 Agent 的本质:本文第三部分深入分析了子 Agent 的上下文隔离特性、关系描述本质以及与 Skill 的区别。
工具与框架
- OpenCode:opencode.ai / GitHub: opencode-ai/opencode(原仓库
sst/opencode已迁移至此)——开源终端 AI 编程 Agent,本文讨论的工具层基础。 - open-ralph-wiggum:GitHub: Th0rgal/open-ralph-wiggum——Ralph Loop 的标准外部 CLI 实现,每次迭代启动全新 OpenCode 进程,实现进程级上下文重置。
- Oh My OpenAgent(OMO):GitHub: code-yeongyu/oh-my-openagent——通过配置文件和 Prompt Engineering 在 OpenCode 内部构建多 Agent 虚拟团队,包含 Sisyphus、Prometheus、Atlas 等 11 个角色。
- Anthropic Engineering Blog:How we built our multi-agent research system(2025)——Anthropic 官方对多 Agent 研究系统的工程实现详解。
- Claude Code 官方文档:Create custom subagents——Claude Code 关于子 Agent 创建的官方文档。
- LangChain 官方文档:Subagents——LangChain 对子 Agent 概念的官方定义和使用指南。
- LangChain Blog:Benchmarking Multi-Agent Architectures——LangChain 对多 Agent 架构的性能基准测试。
延伸阅读
- LSP 与 AI 编程助手:LSP:语言服务协议与AI编程助手的代码理解能力——本文的姊妹篇,详细阐述代码理解能力的底层机制。
- Multi-Agent Performance Research:Anthropic 的研究表明,多 Agent 架构可将性能提升 90.2%(参见 Anthropic 博客:Building effective agents),核心原因是主 Agent 的上下文保持干净,而非子 Agent 更聪明。





