Agentic Coding:从工具到团队的范式跃迁

AI 编程工具的演进,正在经历一次根本性的范式转变:从"补全光标处的代码",到"自主完成一个端到端的工程任务"。这种转变有一个专有名词——Agentic Coding

理解这个转变,需要从三个层面展开:工具层(OpenCode 的能力边界)、框架层(多 Agent 协作编排)、方法论层(如何让 Agent 真正服务于工程流程)。

什么是 Agentic Coding

传统 AI 编程助手的工作模式是响应式的:开发者提问,AI 回答;开发者选中代码,AI 补全。人始终是执行者,AI 是辅助工具。

Agentic Coding 的工作模式是自主式的:开发者描述目标,Agent 自主规划步骤、调用工具、执行操作、验证结果,直到任务完成。人退出执行循环,成为目标定义者和结果审查者。

这不是量变,是质变。一个能够自主编码的 Agent,需要具备:

  • 代码理解能力:不只是文本匹配,而是理解代码的语义结构、类型关系、调用链路
  • 工具调用能力:读写文件、执行命令、调用外部 API
  • 规划与反馈能力:将大任务分解为步骤,根据执行结果调整计划
  • 上下文管理能力:在有限的上下文窗口内,按需加载相关信息

其中,代码理解能力是基础,也是工具层最关键的差异点。

OpenCode:LSP 原生集成与代码语义理解

从文本替换到语义理解

早期的 AI 编程工具,本质上是在做文本替换:把代码当作字符串,在字符串层面做补全、修改、搜索。这种方式有一个根本缺陷——它不理解代码的结构。

一段 Java 代码里,UserService 是一个类,findById 是它的方法,返回类型是 Optional<User>。文本替换工具看到的只是这些字符;而一个真正理解代码的工具,能够知道:

  • findById 的参数类型是 Long,不是 String
  • 调用这个方法的地方有 12 处,分布在 5 个文件里
  • 如果修改了方法签名,哪些调用点会编译失败

这种理解能力,来自 LSP(Language Server Protocol)

LSP 是什么

LSP 是微软在 2016 年提出的协议(Language Server Protocol 官方规范),目的是把"语言智能"从编辑器中解耦出来。

在 LSP 出现之前,每个编辑器都要为每种语言单独实现代码补全、跳转定义、查找引用等功能。VS Code 要实现一套,Vim 要实现一套,Emacs 要实现一套——重复劳动,且质量参差不齐。

LSP 的设计是:语言相关的智能由**语言服务器(Language Server)**提供,编辑器只需实现 LSP 客户端协议,就能获得所有语言的完整智能支持。

1
2
3
编辑器(LSP Client)  ←→  Language Server(LSP Server

理解代码结构、类型、引用关系

语言服务器在后台持续分析代码,维护一个完整的语义模型。当编辑器请求"光标处变量的类型是什么"或"这个函数被哪些地方调用"时,语言服务器能够精确回答。

LSP Server 与 Project SDK:两个不同层面的配置

这是一个容易混淆的概念:IDE 天然带有 SDK 支持,那 LSP Server 和传统的 Project SDK Configuration 有什么区别?

两者解决的是完全不同的问题域

Project SDK Configuration:编译与运行的配置

传统的 Project SDK(如 Java 的 JDK、Python 的 Interpreter)解决的是代码如何被编译和执行的问题:

  • 编译时:用什么版本的编译器?依赖哪些库?
  • 运行时:用什么版本的运行时?类路径(classpath)是什么?
  • 构建时:依赖如何解析?产物如何打包?

这是工具链层面的配置,决定了代码"能不能跑起来"。

LSP Server:编辑器智能的配置

LSP 解决的是代码如何被理解和辅助的问题:

  • 补全:输入 str. 后,弹出 .split().join() 等方法
  • 跳转Ctrl+点击 跳到定义处
  • 诊断:实时显示红线错误(类型不匹配、未定义变量)
  • 重构:重命名变量时,所有引用同步更新

这是编辑体验层面的配置,决定了代码"写起来有多顺"。

以 VS Code 为例:两者如何协同工作

一个 Java 项目在 VS Code 中同时运行着两套独立系统:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
┌─────────────────────────────────────────────────────────────────┐
│ VS Code 架构 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────┐ ┌─────────────────────────────┐ │
│ │ Project SDK 层 │ │ LSP 层 │ │
│ │ │ │ │ │
│ │ • JDK 路径配置 │ │ • Eclipse JDT Language │ │
│ │ • Maven/Gradle 依赖 │ │ Server (jdtls) │ │
│ │ • classpath 设置 │ │ • 语义分析引擎 │ │
│ │ • 运行时参数 │ │ • 实时诊断服务 │ │
│ │ │ │ │ │
│ │ 【解决:编译与运行】 │ │ 【解决:编辑器智能】 │ │
│ └─────────────────────┘ └─────────────────────────────┘ │
│ ↓ ↓ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 共享的语义模型 │ │
│ │ │ │
│ │ LSP Server 需要知道 SDK 配置才能准确分析代码: │ │
│ │ • JDK 版本决定语法支持范围(var 关键字需要 Java 10+) │ │
│ │ • 依赖库决定可用的类和方法 │ │
│ │ • classpath 决定 import 能否解析 │ │
│ └───────────────────────────────────────────────────────��─┘ │
└─────────────────────────────────────────────────────────────────┘

关键洞察:LSP 需要"借用"SDK 信息

LSP Server 要提供准确的智能提示,必须知道:

  1. 用什么版本的语言 → Java 8 的 LSP 不认识 var,Java 17 的认识 record
  2. 依赖了哪些库 → 输入 List 后,能补全 java.util.List 的方法
  3. 项目的模块结构 → 多模块项目里,跨模块的引用能否解析

VS Code 的 Java 扩展会自动读取 Maven/Gradle 配置,把这些信息"喂"给 LSP Server。这就是为什么你改了 pom.xml 后,VS Code 会提示"正在导入项目"——它在同步 SDK 配置到 LSP。

具体对比

维度 Project SDK Configuration LSP Server
配置位置 pom.xml / build.gradle / .sdkmanrc VS Code 设置 + 扩展自动管理
核心作用 决定编译输出、运行时行为 决定编辑器补全、跳转、诊断
是否可见 构建产物(JAR/WAR)直接体现 编辑器内的"智能"体验
能否脱离 可以(用 javac 直接编译) 可以(用记事本写代码)
典型工具 Maven、Gradle、JDK 本身 jdtls、gopls、pyright
VS Code 展示 “JAVA PROJECTS” 面板 编辑器内的红线/补全/跳转

常见问题:两者不同步

1
2
3
4
5
6
7
场景:升级 JDK 从 817
├── pom.xml 改了 ✓(SDK 层面已升级)
├── Maven 构建成功 ✓(编译层面已升级)
└── VS Code 仍标红 record 关键字 ✗(LSP 不知道你升级了)

解决:执行 "Java: Clean Java Language Server Workspace"
→ 强制 LSP 重新加载项目配置

为什么 IDE 会"自带" LSP?

传统 IDE(IntelliJ IDEA、Eclipse)的做法是:SDK 配置和 LSP 深度绑定。你配置好 JDK,IDE 内置的语义分析引擎就自动获得完整的项目理解。

VS Code 采取了解耦策略

  1. 核心编辑器:只是一个文本编辑器,不懂任何语言
  2. 扩展市场:每种语言由独立的扩展提供 LSP 支持
  3. SDK 配置:仍由项目自己的构建工具管理

这种解耦带来灵活性——你可以混合使用多个语言的 LSP(前端项目同时有 TypeScript 和 Python),但也带来复杂性——SDK 和 LSP 的"同步"可能出问题。

总结

概念 本质 类比
Project SDK 编译运行的"原材料" 厨房的食材和灶具
LSP Server 编辑体验的"智能助手" 厨师的菜谱和技巧指导

两者解决的是完全不同的问题域,但 LSP 需要"借用" SDK 的信息才能工作。在 VS Code 这种解耦架构下,两者的同步是通过扩展(如 Java Extension Pack)自动完成的,但当同步出问题时,你需要理解这两个层面才能有效排查。

Claude Code 与 OpenCode 的 LSP 支持对比

这是两种工具在工程能力上的核心差异之一。

Claude Code 的 LSP 支持依赖插件机制,官方仅为三种语言提供了开箱即用的支持:TypeScript、Python、Rust。其他语言需要用户手动配置,且必须自行安装对应的语言服务器二进制文件。对于一个 Java 后端工程师来说,这意味着:需要手动安装 Eclipse JDT Language Server,配置 classpath,处理 Gradle/Maven 的依赖解析——这些配置工作本身就是一道门槛。

OpenCode 采取了不同的策略:内置 30+ 种语言的 LSP 支持,部分语言服务器还能自动下载。更关键的是,OpenCode 实现了项目类型自动检测

检测到的文件 自动启动的 Language Server
package.json TypeScript/JavaScript LSP(tsserver)
go.mod Go LSP(gopls)
Cargo.toml Rust LSP(rust-analyzer)
build.gradle.kts Java/Kotlin LSP(Eclipse JDT / Kotlin LS)
pyproject.toml / setup.py Python LSP(pylsp / pyright)

打开一个项目,OpenCode 扫描根目录,识别项目类型,对应的 Language Server 自动启动。开发者不需要做任何配置。

LSP 集成对 Agent 能力的实质影响

这不只是"配置方便不方便"的问题,而是 Agent 能力边界的根本差异。

有了 LSP 集成,Agent 在修改代码时能够:

精确定位引用:修改一个接口方法签名时,Agent 可以通过 LSP 的 findReferences 请求,获取所有调用点的精确位置,而不是用正则表达式在文件里搜索字符串。正则搜索会漏掉动态调用,会误匹配注释里的同名词,会找不到跨模块的间接调用。

类型感知的修改:Agent 知道一个变量的实际类型,而不是猜测。在重构时,这意味着能够生成类型正确的代码,而不是生成一段"看起来对"但实际上类型不匹配的代码。

实时编译反馈:LSP 提供诊断信息(textDocument/publishDiagnostics),Agent 修改代码后,能够立即获知哪些地方出现了编译错误,并在下一步修复它们。这构成了一个修改→验证→修复的紧密反馈循环。

没有 LSP 的 Agent,只能在文本层面操作代码,相当于一个不会编译的程序员——能写代码,但不知道写的对不对。

从单 Agent 到 Agent 团队

OpenCode 解决了单个 Agent 的代码理解问题。但工程任务的复杂度,往往超出单个 Agent 的能力边界。

Ralph Loop:上下文重置驱动的迭代工程模式

在讨论多 Agent 协作之前,有必要先理解一个更基础的工程模式——Ralph Loop(拉尔夫循环)。它由开发者 Geoffrey Huntley 提出,以《辛普森一家》中那个总是重复同样错误的角色 Ralph Wiggum 命名,带着一丝自嘲:Agent 也会像 Ralph 一样,在积累了太多历史包袱后陷入混乱。

核心理念:上下文是 Agent 的最大敌人

标准 Agent 循环有一个隐蔽的缺陷:上下文累积(Context Accumulation)。每一次失败的尝试、每一条错误信息、每一轮调试输出,都会留在对话历史里。经过几轮迭代后,模型必须在一大堆历史噪音中寻找真正有用的信息——这不仅消耗 Token,更会让模型的注意力被稀释,导致越来越难以聚焦于当前任务。

Ralph Loop 的核心洞察是:每次迭代重置对话上下文(Fresh Context Reset),但通过文件系统持久化任务状态。这样,Agent 每次启动时都是"干净"的,不会被历史噪音干扰;而任务进度、上一轮的反馈、已完成的工作,则通过文件传递给下一轮。

“The conversation history does not persist. The files do.”
——Ralph Loop 的核心设计原则

工作流程

Ralph Loop 的完整流程是一个**工作(Work)→ 审查(Review)→ 决策(SHIP/REVISE)**的迭代循环:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
┌─────────────────────────────────────────────────────┐
│ Ralph Loop │
│ │
│ 任务描述(task.md) │
│ ↓ │
│ ┌─────────────────────────────────────────────┐ │
│ │ Iteration N(全新上下文) │ │
│ │ │ │
│ │ ① WORK PHASE(Worker Model) │ │
│ │ 读取 task.md + review-feedback.txt │ │
│ │ 执行编码工作 │ │
│ │ 写入 work-summary.txt │ │
│ │ │ │
│ │ ② REVIEW PHASE(Reviewer Model,不同模型) │ │
│ │ 读取 task.md + work-summary.txt │ │
│ │ 验证代码是否可运行、功能是否完整 │ │
│ │ 写入 review-result.txt(SHIP/REVISE) │ │
│ │ │ │
│ │ ③ 决策 │ │
│ │ SHIP → 任务完成,退出循环 ✓ │ │
│ │ REVISE → 写入 review-feedback.txt │ │
│ │ 进入下一轮迭代 │ │
│ └─────────────────────────────────────────────┘ │
│ ↑_____________(最多 N 次)_____________↑ │
└─────────────────────────────────────────────────────┘

关键设计:Worker 和 Reviewer 使用不同的模型(如 GPT-4o 做编码,Claude 做审查)。不同模型有不同的盲点,交叉审查能发现单一模型自我审查时容易忽略的问题。

状态文件:跨迭代的记忆载体

Ralph Loop 的状态完全通过文件系统传递,open-ralph-wiggum 将这些状态文件存储在项目根目录的 .ralph/ 目录下,共 5 种数据结构,每轮迭代开始时读取,每轮迭代结束时写入

文件 格式 作用
ralph-loop.state.json JSON 活跃循环状态(当前迭代、提示词、完成条件)
ralph-history.json JSON 迭代历史和指标(每轮耗时、工具调用次数)
ralph-context.md Markdown 人类在循环运行中注入的提示(下一轮消费后清除)
ralph-tasks.md Markdown Tasks Mode 的任务列表([ ]/[/]/[x] 状态)
ralph-questions.json JSON Agent 提出的待回答问题

这些文件由外层的 ralph CLI 管理,OpenCode 进程本身不读写它们——OpenCode 只负责修改业务代码文件。这种设计的精妙之处在于:进程是短暂的,文件是持久的。每一轮迭代都从文件中读取上下文,而不是从对话历史中读取。这使得 Ralph Loop 天然支持跨会话恢复——即使中途中断,下次启动时也能从上次的进度继续。

实际实现:OpenCode + open-ralph-wiggum

这里有一个关键认知需要澄清:OpenCode 本身不是 Ralph Loop 的实现者,而是被调用的对象。Ralph Loop 是一个运行在 OpenCode 之外的外部编排层,它通过循环调用 opencode -p "..." 非交互命令来驱动 OpenCode 工作。

这意味着什么? 如果你平时与 OpenCode 进行长时间的交互式对话,那你并不是在"跑 Ralph Loop"——你只是在使用 OpenCode 的普通会话模式。OpenCode 的普通会话会持续积累上下文,直到触发 autoCompact(默认在上下文达到 95% 时自动压缩并创建新会话)。这与 Ralph Loop 的"主动重置"是两种不同的上下文管理策略:

模式 上下文管理方式 适用场景
OpenCode 普通会话 持续积累,95% 时自动压缩 交互式开发、需要人类频繁介入
Ralph Loop(外部编排) 每轮主动重置,状态通过文件传递 自主任务、有明确完成标准

open-ralph-wiggum 是目前最完整的 OpenCode Ralph Loop 实现,支持 OpenCode、Claude Code、Codex、Copilot CLI 多种 Agent,OpenCode 是其默认 Agent。其本质是一个 TypeScript/Bun 编写的 CLI 工具,核心逻辑极其简单:

1
2
3
4
5
6
# Ralph Loop 的本质:一个 while 循环
while true; do
opencode -p "完成任务 X。当任务完成时输出 <promise>COMPLETE</promise>。"
# 检查输出中是否包含 <promise>COMPLETE</promise>
# 如果是,退出;如果否,继续下一轮
done

每一轮迭代,OpenCode 都是一个全新启动的无状态进程。它不记得上一轮做了什么——但它能看到上一轮修改过的文件和 git 历史。这就是 Ralph Loop 的核心:进程是短暂的,文件是持久的

启动方式:

1
2
3
4
5
6
7
8
9
10
# 安装
npm install -g @th0rgal/ralph-wiggum

# 运行(OpenCode 是默认 Agent)
ralph "Build a REST API for todos with CRUD operations. \
Run tests after each change. Output <promise>COMPLETE</promise> when all tests pass." \
--max-iterations 20

# 也可以传入 PRD 文件
ralph --file ./prd.md --max-iterations 30

四种 Agent 的本质差异:不是微调,而是架构哲学

open-ralph-wiggum 支持四种 Agent,但这四种 Agent 并非"同一类工具的不同版本"——它们在底层模型、架构设计、工具调用机制上存在根本性差异。理解这些差异,有助于在不同场景下选择最合适的 Agent。

首先澄清一个常见误解:这些 Agent 都没有经过专门针对 Ralph Loop 的微调(fine-tuning)。 它们的能力差异不来自后训练,而来自三个维度:底层模型的选择架构实现的哲学工具调用的机制

维度 OpenCode Claude Code Codex CLI GitHub Copilot CLI
底层模型 模型无关(75+ 提供商) Claude 系列(Anthropic) GPT/o 系列(OpenAI) 默认 Claude,可切换
实现语言 TypeScript + Bun TypeScript/Python SDK Rust(性能优先) TypeScript
工具调用核心 多工具并行系统 精简工具集 + JIT 检索 单一 Shell 工具 MCP 驱动
LSP 支持 ✅ 35+ 语言,自动启动 ✅ 10+ 语言,需配置 ❌ 通过 shell 间接实现 ❌ 通过 MCP 间接实现
上下文管理 AGENTS.md 规则文件 Compaction + Memory 工具 Compaction 压缩 组织级配置
开源 ✅ 完全开源 ❌ 闭源 ✅ 开源 ❌ 闭源
认证体系 多提供商 API Key Anthropic API OpenAI API / ChatGPT GitHub Token

OpenCode:通用框架,模型无关

OpenCode 的核心设计理念是框架优先——它本身不绑定任何模型,支持 75+ LLM 提供商。能力差异来自你选择注入哪个模型。OpenCode 的独特优势是原生 LSP 集成:打开项目时自动扫描根目录,识别 package.jsongo.modCargo.tomlbuild.gradle.kts 等文件,对应的 Language Server 自动启动,无需任何配置。这使得 OpenCode 在代码语义理解上有结构性优势——Agent 能通过 LSP 的 findReferencespublishDiagnostics 等接口获得精确的类型信息和编译反馈,而不是在文本层面猜测。

Claude Code:精简工具集 + JIT 检索

Claude Code 使用 Anthropic 的 Claude 系列模型,该模型经过大量代码任务的后训练,但这是通用代码能力的强化,而非针对 Agentic Coding 工作流的专项微调。Claude Code 的架构哲学是精简:核心工具只有 ReadEditWriteBashGrepGlob 六类,但配合 Just-in-Time(JIT)检索策略——Agent 不预加载全部代码库,而是在需要时动态读取相关文件。上下文管理上,Claude Code 有独特的 Compaction 机制:当上下文达到阈值时,自动将历史对话压缩为摘要,保留关键决策而丢弃中间过程噪音。此外,Memory 工具允许 Agent 将重要信息持久化写入文件,跨会话保留。

Codex CLI:Shell-Centric,Rust 实现

Codex CLI 是 OpenAI 出品的终端 Agent,使用 GPT/o 系列模型。它最显著的架构特征是Shell-Centric 设计:不像 OpenCode 和 Claude Code 那样提供多种专用工具(读文件、写文件、搜索……),Codex CLI 的核心工具只有一个统一的 Shell 执行器——所有操作(读文件、写文件、运行测试、搜索代码)都通过 shell 命令完成。这种设计的优点是极度灵活,任何能用命令行完成的事情都能做;缺点是缺乏语义层面的代码理解,无法直接获得 LSP 级别的类型信息。Codex CLI 从 Node.js/TypeScript 重写为 Rust,目标是性能和安全性——更低的内存占用、更快的启动速度、更严格的沙箱隔离。

GitHub Copilot CLI:GitHub 生态深度集成

GitHub Copilot CLI 的差异化不在于模型(默认使用 Claude Sonnet,可切换),而在于生态集成:内置 GitHub MCP Server,预配置了与 GitHub.com 交互的工具集——搜索 issues、分析 PR、管理仓库、读取 Actions 日志。这使得 Copilot CLI 在处理"基于 GitHub 工作流的任务"时有天然优势,比如"分析最近 10 个 PR 的代码风格"或"根据 issue #123 的描述实现功能"。但在纯粹的本地代码编辑任务上,它并不比其他 Agent 有结构性优势。

open-ralph-wiggum 如何统一调用它们

这四种 Agent 的接口各不相同,open-ralph-wiggum 通过适配层将它们统一为相同的调用模式:

1
2
3
4
5
6
7
8
9
10
11
# 调用 OpenCode(默认)
ralph "实现 REST API" --agent opencode --max-iterations 20

# 调用 Claude Code
ralph "实现 REST API" --agent claude-code --max-iterations 20

# 调用 Codex CLI
ralph "实现 REST API" --agent codex --max-iterations 20

# 调用 GitHub Copilot CLI
ralph "实现 REST API" --agent copilot --max-iterations 20

适配层的核心工作是:将 Ralph Loop 的完成信号(<promise>COMPLETE</promise>)注入到每个 Agent 的提示词中,并解析各 Agent 不同格式的输出,判断是否触发退出条件。每个 Agent 的二进制路径可通过环境变量覆盖(RALPH_OPENCODE_BINARYRALPH_CLAUDE_BINARYRALPH_CODEX_BINARYRALPH_COPILOT_BINARY)。

如何选择?

  • 需要最强代码语义理解:选 OpenCode,LSP 原生集成是结构性优势
  • 需要最强推理能力 + 上下文管理:选 Claude Code,Compaction 机制在长任务中表现更稳定
  • 需要最高性能 + 沙箱安全:选 Codex CLI,Rust 实现 + Shell-Centric 设计适合高频迭代
  • 任务强依赖 GitHub 工作流:选 GitHub Copilot CLI,MCP 生态集成是核心优势

一次典型的运行输出如下:

1
2
3
4
5
6
7
8
9
10
11
Iteration 1 / 20
→ ralph 启动 opencode -p "..."(全新进程,干净上下文)
→ OpenCode 读取代码库,创建初始实现,修改文件
→ OpenCode 进程退出,输出中未找到 <promise>COMPLETE</promise>
→ ralph 更新 .ralph/ralph-history.json,进入下一轮

Iteration 2 / 20
→ ralph 再次启动 opencode -p "..."(又一个全新进程)
→ OpenCode 看到上一轮修改的文件,继续推进
→ 测试通过,OpenCode 输出 <promise>COMPLETE</promise>
→ ralph 检测到完成信号,退出循环 ✓

本质:短跑选手的接力赛

用一个比喻来理解 Ralph Loop 的设计哲学:

模型是一个短跑选手,能够奔跑的路程是有限的。 在没有清晰的规范和意图澄清时,它会走各种弯路——尝试错误的方向、被历史噪音干扰、在失败的尝试上反复纠结。我们编写的各种 Spec、工程 Rules、Skill 文档,本质上都是在优化短跑选手的跑道和奔跑模式,让它在一个任务里少走弯路,尽可能笔直地向目标前进。

Ralph Loop 借助外部存储,实现了任务的接力赛。 每一轮迭代都是一个短跑选手从起跑线出发,跑到力竭时把接力棒(.ralph/ 下的状态文件)交给下一个短跑选手。无数个短跑连接起来,看起来就像一场无限长的长跑。

这意味着,如果不考虑 Token 成本,我们可以制造出"无限长任务执行"的体验——无需手工切换上下文,无需担心上下文窗口溢出,Agent 会自动在每一轮重置后继续前进。代价是每一轮都要重新加载必要的上下文(通过文件传递),但换来的是:永远干净的注意力,永远不会被历史噪音拖慢的执行力

Ralph Loop 最适合的场景:

  • 复杂的多步骤任务:需要多轮迭代才能完成的功能开发
  • 有明确完成标准的任务:测试通过、构建成功、功能可验证
  • 需要质量门禁的场景:不允许"差不多能跑"就算完成,必须经过独立审查

不适合的场景:

  • 简单的一次性任务(直接用 Build 模式更快)
  • 探索性、交互式的开发(需要人类频繁介入)
  • 没有可验证完成标准的任务(Reviewer 无法判断 SHIP 还是 REVISE)

Ralph Loop 与 OMO 的关系

Ralph Loop 是一个工程模式,而非特定工具的功能。OMO(Oh My OpenCode)的 Sisyphus 框架在设计上与 Ralph Loop 高度同构:Sisyphus-Junior 是 Worker,Atlas 是 Reviewer 兼编排者,boulder.json 是跨会话的状态文件,.sisyphus/notepads/ 是积累的反馈记录。

两者的核心差异在于:Ralph Loop 是单任务的迭代收敛,OMO 是多任务的层级编排。Ralph Loop 解决"一件事做对"的问题,OMO 解决"多件事并行推进"的问题。在实际工程中,两者可以嵌套使用:OMO 的 Atlas 将大任务分解后,每个子任务由一个 Ralph Loop 驱动执行,直到 SHIP。

裸 OpenCode 的天花板

OpenCode 是一个开源的终端 AI 编程 Agent,内置四个角色:

Agent 类型 能力
Build 主 Agent 全工具权限,默认开发模式
Plan 主 Agent 只读分析,禁止文件修改
General 子 Agent 通用研究与多步骤任务
Explore 子 Agent 只读代码库探索,快速搜索

Plan 与 Build:Tab 切换的是模式,不是 Agent

在 OpenCode 的终端界面中,按 Tab 键可以在 Plan 模式Build 模式之间切换。这是一个高频操作,但它的本质容易被误解——切换的是同一个 Agent 的工具权限集,而不是切换到另一个独立的 Agent。底层调用的是同一个 LLM,同一段系统提示的核心逻辑,只是工具白名单不同:

  • Plan 模式:只读权限。Agent 可以读文件、搜索代码库、分析调用链,但禁止写文件和执行命令。这个限制是刻意的——它强迫 Agent 只思考、不动手,输出的是分析报告和行动计划。
  • Build 模式:全工具权限。Agent 可以读写文件、执行 Shell 命令、调用外部 API,是真正的执行模式。

为什么要分两个模式? 核心原因是防止 Agent 在理解不充分时就开始修改代码。一个没有充分分析就动手的 Agent,很容易在复杂代码库里做出破坏性的修改——改了 A 不知道 B 依赖 A,删了一个方法不知道有 12 处调用。Plan 模式提供了一个"只读沙箱",让 Agent 先把问题想清楚。

什么时候切换? 一个实用的工作流是:

  1. 先用 Plan 模式:描述任务,让 Agent 分析代码库、理解依赖关系、输出修改方案
  2. 审查计划:人类确认方案合理,没有遗漏的影响面
  3. 切换到 Build 模式:让 Agent 按计划执行,写代码、跑命令、验证结果

对于简单的、影响范围明确的任务(如"在这个文件里加一个方法"),可以直接用 Build 模式。对于涉及多模块、跨文件的重构,Plan 先行是降低风险的关键步骤。

OpenCode 的 Skills 机制(SKILL.md 文件)实现了一种"渐进式披露"的上下文管理——Agent 只在需要时才加载技能的完整内容,而不是一次性把所有知识塞进上下文。这与 AI Agent 领域的上下文最小化原则高度吻合:

“The model should only know what it needs to know to make the next immediate decision.”

但裸 OpenCode 有明确的天花板:

  • 无多 Agent 并发编排:子 Agent 可以被调用,但没有内置的并行任务调度机制
  • 无角色分工体系:Build 和 Plan 是模式切换,而非职责分明的团队角色
  • 无跨会话状态持久化:每次会话独立,无法在多天的复杂项目中保持进度
  • 无业务域知识:工具是通用的,不理解特定团队的技术栈、部署流程、业务规则

裸 OpenCode 是一把锋利的瑞士军刀,但还不是一支施工队。

Oh My OpenCode:Prompt Engineering 构建的虚拟团队

Oh My OpenCode(OMO)在 OpenCode 的基础上,通过配置文件和精心设计的 Prompt,构建了一个拥有 11 个角色的虚拟开发团队。这是一个三层架构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
规划层(Planning Layer)
├── Prometheus 战略规划师,像工程师一样面试用户,构建详细计划
├── Metis 缺口分析员,捕捉 Prometheus 遗漏的隐含意图
└── Momus 无情审查员,验证计划的清晰度、可测量性和完整性

执行层(Execution Layer)
└── Atlas 指挥官,读取计划、分发任务、验证结果,但自己不写代码

工作者层(Worker Layer)
├── Sisyphus-Junior 主力代码执行者(Claude Sonnet,可靠优先)
├── Hephaestus 深度架构工匠(GPT-5.3 Codex,推理优先)
├── Oracle 只读架构顾问
├── Explore 快速代码库搜索
└── Librarian 文档与 OSS 搜索

Sisyphus 是 Agent 还是框架?Tab 切换的是什么?

安装 OMO 后,你会在 OpenCode 的 Tab 列表里看到 Sisyphus(西西弗斯)这个新入口,旁边还有 Atlas、Oracle 等名称可以切换。这里有两个容易混淆的概念需要厘清。

Sisyphus 的双重身份:它既是一个具体的 Agent(工作者层的主力代码执行者),也是 OMO 整个多 Agent 框架的代称(“Sisyphus 框架”)。当你说"用 Sisyphus 工作",通常指的是启动整个 OMO 的规划→执行→工作者三层协作流程,而不只是调用那个叫 Sisyphus-Junior 的单一 Agent。

Tab 切换的是不同的 Agent,而不是同一个 Agent 的不同模式。这与裸 OpenCode 的 Plan/Build 切换有本质区别:

切换方式 本质 系统提示 工具权限
OpenCode Tab(Plan↔Build) 同一 Agent 的模式切换 相同核心,工具白名单不同 只读 vs 全权限
OMO Tab(Sisyphus↔Atlas 等) 不同 Agent 的角色切换 完全不同的 Prompt 和职责定义 各自独立配置

切换到 Atlas,你面对的是"指挥官"角色——它读取计划、分发任务、验证结果,自己不写代码。切换到 Sisyphus,你面对的是"执行者"——它接受任务、写代码、跑命令。切换到 Oracle,你面对的是"只读顾问"——只分析,不动手。

什么时候应该切换? 实用原则如下:

  • 日常开发任务:直接用 Sisyphus(主力执行者),它能独立完成大多数编码任务,是你的默认入口
  • 复杂的多模块任务:先切换到 Atlas,让它读取任务描述、制定分发计划,再由它调度 Sisyphus 等工作者并行执行
  • 只想分析、不想动代码:切换到 Oracle 或 Explore,获得只读的架构建议
  • 需要查文档或搜索 OSS:切换到 Librarian

一个关键洞察:你确实可以只依赖 Sisyphus 完成大多数工作。Atlas 的价值在于任务足够复杂、需要并行调度多个工作者时才显现。对于单线程的开发任务,Sisyphus 直接上就够了;只有当你发现任务需要"前后端同时开发"或"多个独立模块并行推进"时,才值得切换到 Atlas 来做编排。

OMO 带来的核心突破:

并行任务执行:无依赖的任务(如前后端开发)可以同时启动多个子 Agent 并发执行,大幅缩短交付时间。

多模型按需调度:不同任务路由到最适合的模型——Claude 做编排,GPT 做深度推理,Gemini 做前端视觉,Haiku 做快速任务。

跨会话状态持久化boulder.json 记录任务进度,会话中断后可以无缝恢复,支持多天的复杂项目。

智慧积累机制:Atlas 在 .sisyphus/notepads/ 中记录每个任务的学习、决策和问题,防止重复犯错。

这与 Agent Swarm 有本质区别。Agent Swarm 通常是平等节点的广播协作——多个 Agent 共享同一个任务池,谁空闲谁接单,适合高度同质化的并行任务(如大规模数据处理)。

OMO 的 Sisyphus 框架是严格层级的委托协作——规划层不执行,工作者层不规划,每一层有明确的职责边界。这更接近真实的软件工程团队组织方式。

一个关键洞察:Claude Code、某 AI 编程助手等工具同样内置了多个 Agent(如 Claude Code 的 subagent 机制),但工作流里 Agent 数量的核心决定因素不是工具,而是工程流程的分工粒度。一个人做全栈需要 1 个 Agent;前后端分离需要 2 个;加上测试、部署、代码审查,自然演化出 5-7 个。Agent 的数量是工程角色的映射,而不是技术上的限制。

企业级 Agent 框架:业务域知识注入

企业级 Agent 框架在 OMO 的基础上,做了一件更关键的事:把通用的 Agent 团队变成了懂业务的研发团队

这在三个维度上做了增强:

业务域知识注入:通用 Agent 不知道内部中间件叫什么、内部 API 怎么调用、部署流程是什么。业务域知识空间把这些知识结构化地注入到 Agent 的上下文中——业务领域知识、可用的 MCP 工具、内部规范——让 Agent 能够基于真实的企业环境做决策。

SDLC 全流程覆盖:从需求澄清(Human-in-the-Loop)到技术方案设计,到前后端并行开发,到部署、测试验证、上线,覆盖完整的软件开发生命周期。专职的测试 Agent 不只是跑单元测试,而是真正把代码部署到测试环境,用浏览器工具、curl 等手段做功能验证。

记忆湖(逆向注释知识库):用强推理能力的 LLM 对现有代码进行"逆向注释",生成覆盖业务知识、架构、技术规范的知识库,以 Markdown 形式存储在 Git 仓库中。Agent 的上下文不再依赖人工维护的文档,而是从代码本身提炼出来的活文档。

三层进化的本质

层次 代表 解决的核心问题 关键机制
工具层 裸 OpenCode 单 Agent 的代码理解与编码能力 LSP 原生集成 + Skills 渐进披露
框架层 Oh My OpenCode 多 Agent 的协作编排 层级委托 + 多模型调度 + 状态持久化
企业层 企业级 Agent 框架 业务域的知识注入 域空间 + 记忆湖 + SDLC 全流程

这三层的演进,印证了一个核心论点:Agent 的价值不在于单点的智能,而在于系统性的协作设计

多 Agent 的本质:同一个大脑,不同的面具

理解 Agentic Coding 的多 Agent 架构,需要回答一个根本问题:为什么要分那么多 Agent?它们的能力差异从何而来?一个 Agent 不够吗?

原生 OpenCode 到底有几个 Agent?

安装任何插件之前,OpenCode 自带的 Agent 数量是:

类型 名称 可见性 作用
主 Agent Build 用户可见,Tab 可切换 全工具权限,默认开发模式
主 Agent Plan 用户可见,Tab 可切换 只读分析,禁止修改
子 Agent General 用户可通过 @ 提及 通用研究,多步骤任务
子 Agent Explore 用户可通过 @ 提及 只读代码库探索
系统 Agent Compaction 隐藏,自动触发 压缩长上下文为摘要
系统 Agent Title 隐藏,自动触发 生成会话标题
系统 Agent Summary 隐藏,自动触发 生成会话总结

用户可感知的 Agent:4 个(Build、Plan、General、Explore)
实际运行的 Agent:7 个(包含 3 个隐藏系统 Agent)

安装 OMO 插件后,通过配置文件定义了 11 个新角色(Prometheus、Metis、Momus、Atlas、Sisyphus-Junior、Hephaestus、Oracle、Explore、Librarian 等)。但这些 Agent 是新增的吗?

不完全是。OMO 的 Agent 是通过 OpenCode 的 Agent 配置机制覆盖或扩展的——本质上是在同一个 Agent 框架上,注入了不同的系统提示(System Prompt)和工具权限配置。

能力差异的来源:Prompt + 权限,而非代码

这是理解多 Agent 架构的关键:所有这些 Agent 调用的底层 LLM 是同一个,执行逻辑是同一套,能力差异完全来自「身份提示词 + 工具权限」的组合

以 OpenCode 的原生配置为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
// opencode.json 中的 Agent 定义示例
{
"agent": {
"build": {
"mode": "primary",
"tools": { "write": true, "edit": true, "bash": true }
},
"plan": {
"mode": "primary",
"tools": { "write": false, "edit": false, "bash": false }
}
}
}

Build 和 Plan 调用的是同一个模型,同一套工具调度逻辑。区别仅在于:

  • Build 的工具白名单write: true, edit: true, bash: true → 可以改文件、跑命令
  • Plan 的工具白名单write: false, edit: false, bash: false → 只能读,不能动

再加上不同的系统提示:

1
2
3
4
5
# Build 的隐含提示
你是开发执行者,全权处理代码修改和命令执行。

# Plan 的隐含提示
你是只读分析师,禁止修改任何文件,输出分析报告和行动计划。

Agent 的"能力"不是代码写出来的,而是 Prompt 和权限配置"约束"出来的。

OMO 的 11 个角色同理。它们不是 11 个独立开发的程序,而是 11 套精心设计的 Prompt + 权限组合:

  • Atlas(指挥官):Prompt 定义"只读计划、分发任务、验证结果",工具权限禁止 write
  • Sisyphus-Junior(执行者):Prompt 定义"主力代码执行",工具权限全开
  • Oracle(顾问):Prompt 定义"只读架构建议",工具权限只读

为什么不能只用一个 Agent?

技术上,一个 Agent 确实可以完成所有工作。但在工程实践中,单一 Agent 面临三个根本问题:

1. 上下文污染(Context Contamination)

一个负责"规划→执行→验证"全流程的 Agent,会在一次会话中累积大量中间产物:分析过程、尝试代码、错误日志、修正记录。这些内容会污染后续决策的上下文——Agent 可能会基于"之前尝试过但已废弃的方案"做出错误判断。

分离 Agent 后,规划 Agent 的上下文只保留分析结论,执行 Agent 从干净的上下文开始,验证 Agent 只看结果不看过程。每个 Agent 在自己的上下文窗口内专注一件事,减少干扰。

2. 职责混淆(Role Confusion)

一个同时负责规划和执行的 Agent,容易在"要不要改代码"的边界上产生混淆。LLM 没有真正的"自我约束"能力——给它写文件的权限,它可能在分析阶段就忍不住动手,导致分析不充分就进入执行。

通过权限配置硬性限制(Plan 不能写,Build 可以写),用机制代替自律,这是多 Agent 分工的核心价值。

3. 并行能力(Parallelism)

单一 Agent 在一个时刻只能做一件事。复杂任务往往包含多个无依赖的子任务(如前端和后端同时开发),单 Agent 只能串行处理。

多 Agent 架构允许启动多个子 Agent 并发执行。OpenCode 的 Agent Teams 机制甚至支持不同模型协作:Claude 做规划,GPT 做深度推理,Gemini 做前端视觉——同一个任务,多个大脑并行思考

先进的多 Agent 设计模式

目前最先进的 Agentic Coding 系统,在多 Agent 设计上呈现三种模式:

模式一:模式切换(Mode Switching)—— OpenCode 原生

  • 特点:同一个 Agent,不同的权限集
  • 适用:简单项目,单人开发
  • 代表:Build ↔ Plan 的 Tab 切换

模式二:层级委托(Hierarchical Delegation)—— OMO Sisyphus 框架

  • 特点:主 Agent 调度子 Agent,层级分工
  • 适用:中等复杂度项目,需要流程化协作
  • 代表:规划层→执行层→工作者层

模式三:平等协作(Peer Collaboration)—— Agent Swarm / OpenCode Agent Teams

  • 特点:多个 Agent 平等对话,共享任务池
  • 适用:大规模并行任务,如安全扫描、数据处理
  • 代表:多个安全扫描 Agent 同时运行,结果汇总

一个关键洞察:Agent 数量的决定因素不是技术限制,而是工程流程的分工粒度。一个人做全栈需要 1 个 Agent;前后端分离需要 2 个;加上测试、部署、代码审查,自然演化出 5-7 个。Agent 的数量是工程角色的映射

配置一个新 Agent 需要什么?

在 OpenCode 中,创建一个新的 Agent 只需要:

  1. 一个 Markdown 文件~/.config/opencode/agents/xxx.md
  2. 一段 YAML 元数据(description、mode、tools、permission)
  3. 一段系统提示(定义 Agent 的职责和行为规范)

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
---
description: 代码安全审计员,识别潜在漏洞
mode: subagent
tools:
write: false
edit: false
bash: false
---

你是安全专家。专注于:
- 输入验证漏洞
- 认证授权缺陷
- 数据泄露风险
- 依赖安全问题

只分析,不修改代码。

这就是全部。不需要写代码,不需要 Agent SDK,只需要用自然语言定义"你是谁、能做什么、该怎么做"

这也是为什么 OMO 能通过纯配置(而非代码)扩展出 11 个角色——Prompt Engineering 本身就是 Agent Engineering

Agentic Coding 的人机分工

Agentic Coding 改变的不只是工具,而是人在研发流程中的角色定位。

在传统开发模式下,开发者是执行者:写代码、调试、部署、验证。在 Agentic Coding 模式下,开发者是架构师和审查者

  • 定义目标:描述要解决的问题,而不是描述解决步骤
  • 设定约束:告诉 Agent 不能做什么(如不能修改某个核心模块)
  • 审查结果:在 Agent 完成任务后,判断结果是否符合预期
  • 介入纠偏:当结果偏离预期时,提供更精确的指导

这种分工有一个关键前提:人类的"品味"。品味不是审美,而是决策力——在众多可行方案中判断"哪个是对的选择",尤其体现为"选择不做"。AI 擅长执行与优化,但缺乏责任意识与经验直觉;人类凭借踩坑记忆、业务理解与后果承担能力,守住质量、边界与必要性底线。

Agent 数量的核心决定因素不是工具,而是工程流程的分工粒度:一个人做全栈需要 1 个 Agent;前后端分离需要 2 个;加上测试、部署、代码审查,自然演化出 5-7 个。Agent 的数量是工程角色的映射,而不是技术上的限制。

模式速查表

场景 推荐模式 关键机制
单语言项目快速开发 裸 OpenCode + LSP 自动检测项目类型,Language Server 自动启动
多模块并行开发 OMO Sisyphus 框架 规划层→执行层→工作者层,无依赖任务并发
企业存量项目改造 企业级 Agent 框架 记忆湖逆向注释 + 业务域知识注入
新项目端到端交付 Quest 模式 Spec → 编码 → 部署 → 验证,人类仅审查结果
存量生产项目小改动 Editor 模式 高频人机协同,逐步确认与修正