之前我写了篇 Codex CLI 与 OpenCode 的对比,那篇文章侧重于 general 场景的横向评测。最近在开发一个 Obsidian 同步插件时,我有了更深的感受——当任务复杂度提升到某个临界点,两者的差距不是线性增长,而是质的分化。
场景:开发一个复杂的插件 链接到标题
这个插件需要:
- 理解 Obsidian 的插件 API 和事件系统
- 实现增量同步的状态机(chunker + diff + merge)
- 与 CouchDB 后端交互,处理冲突解决
- 多文件协同,跨多个模块的状态一致性
用 Codex 跑这个任务,从头到尾大约 20 分钟,人工介入 1 次(最后 review 时改了一个变量名)。
用 OpenCode 跑同一个任务,大约 40 分钟,人工介入 4 次:
- 某个子任务完成后需要确认,才肯继续
- doom loop 检测触发了一次
- 压缩后上下文丢失,一度开始改无关内容
- 最后合并时又需要一次确认
这不是模型的问题——两者用的都是 deepseek v4 flash medium。问题出在架构设计上。
架构分析:单 Agent 循环 vs 多 Subagent 树 链接到标题
OpenCode 的单 Agent 循环 链接到标题
OpenCode 的核心执行逻辑在 SessionProcessor.process(),是一个 while(true) 的单线程循环:
// OpenCode - 单 Agent 循环示意
while (true) {
const stream = await LLM.stream(input)
for await (const value of stream.fullStream) {
switch (value.type) {
case 'tool-call':
const result = await executeTool(value.toolName, value.input)
// 将结果注入下一个 turn
break
case 'finish-step':
if (result === 'tool-calls') continue
return // 任务完成
}
}
// 上下文超限?触发 compaction
if (needsCompaction) await compact()
}
这个模型有几个固有的限制:
-
Doom Loop 检测是双刃剑 当同一个工具被连续调用 3 次且参数相同,OpenCode 会暂停并等待用户确认。这是好的安全设计,但对于某些"正当的重复操作"(比如批量创建 10 个文件),它也会触发中断。
-
上下文压缩是全局的 当对话历史太长,OpenCode 会调用一个专门的 compaction agent 来压缩上下文。压缩后,原先分散在多处的地方变量可能丢失,LLM 的指令跟随会退化。
-
没有任务分解机制 复杂任务只能在一个 Agent 里顺序执行。每个子任务都依赖同一个上下文窗口,任何一个环节出问题都会影响后续。
Codex 的多 Subagent 树 链接到标题
Codex 的核心区别是支持 Subagent Fork——一个任务可以分解为多个独立或半独立的子代理并行执行:
// Codex - Subagent Fork 示意
pub enum SpawnAgentForkMode {
FullHistory, // 复制完整历史
LastNTurns(usize), // 只复制最近 N 轮
}
pub struct SpawnAgentOptions {
pub fork_parent_spawn_call_id: Option<String>,
pub fork_mode: Option<SpawnAgentForkMode>,
pub parent_thread_id: Option<ThreadId>,
pub environments: Option<Vec<TurnEnvironmentSelection>>,
}
这带来了几个关键优势:
-
任务天然分解 复杂插件开发可以分解为:
- Subagent A:实现 chunker 模块
- Subagent B:实现 sync 状态机
- Subagent C:实现 CouchDB 交互层
- 主 Agent:协调各模块,最终合并 每个子代理独立运行在自己的上下文中,互不干扰。
-
RolloutBudget 精细控制 Codex 有 RolloutBudget 机制,可以精确控制每个子任务的 token 预算,避免单任务耗尽整个会话的资源。
-
TurnEnvironmentSelection 多环境并行 Codex 支持在不同的"环境"中并行执行任务,每个环境有独立的文件视图和工具权限。这对于插件开发尤其有用——可以在隔离环境中测试,不污染主分支。
-
压缩是局部的 每个 Subagent 独立压缩自己的历史,不会因为一次全局压缩而丢失其他无关模块的上下文。
两种设计哲学 链接到标题
| 维度 | OpenCode |
|---|---|
| 设计优先级 | 可控性 > 吞吐量 |
| 哲学 | “AI 应当随时可以被干预” |
| 适用场景 | 短任务、需要频繁确认 |
| 安全模型 | per-tool/per-command 细粒度 |
| 上下文管理 | 全局压缩 |
这没有对错之分。OpenCode 的设计更保守,更适合团队场景——每个操作都能被审计和干预。Codex 的设计更激进,适合个人开发者跑长任务,不需要中途停下来"教它怎么做"。
实际感受 链接到标题
Codex 的 20 分钟长跑 链接到标题
我给 Codex 的 prompt 大约是:
“实现一个 Obsidian 同步插件,参考 Obsidian Sync 的 chunk-based 增量同步方案,支持 CouchDB 后端,实现冲突解决…”
Codex 自动分解了子任务,Subagent 并行工作,中途只有一次我手动让它停了一下(因为它想用一个过时的 API)。最后 review 时发现代码质量很高,状态机设计合理,注释也很清晰。
OpenCode 的 4 次介入 链接到标题
同样的 prompt,OpenCode 会在每个"阶段"完成后等待确认:
- chunker 实现完了,等我确认
- sync 模块开始,等我确认
- 突然触发 doom loop 检测(它在尝试用同样的方式读文件),我点了继续
- compaction 后上下文丢失,它开始改无关内容,我赶紧拉回来
- 最后合并,又等确认
单次任务时间反而更长,介入次数更多。
什么时候选哪个 链接到标题
| 任务类型 | 推荐 |
|---|---|
| 复杂插件/SDK 开发 | Codex |
| 快速单文件修改 | OpenCode |
| 需要多模型切换、本地模型 | OpenCode |
| 多日 goal 持久化 | Codex |
| 团队安全审计 | OpenCode |
结论 链接到标题
Codex 之所以在复杂任务上表现更好,不是因为模型更强,而是因为架构设计上允许任务分解和并行执行。OpenCode 的单 Agent 循环 + 全局压缩模型,在短任务上可控性强,但在长任务上会成为瓶颈。
这不是一个工具比另一个工具"更好"的问题,而是不同架构适合不同任务的问题。如果你经常跑 10 分钟以上的复杂开发任务,Codex 的 Subagent 机制会显著提升体验。如果你主要是快速修改、团队协作、需要细粒度权限控制,OpenCode 仍然是更好的选择。
两者的设计哲学恰好代表了这个领域两种路线的分歧:一种是把 AI 当作需要被监督的助手,另一种是把 AI 当作可以独立作业的同事。哪种更合适,取决于你的工作场景。