OpenCode 循环工程实现

今天我想谈谈我如何在OpenCode中构建了一个代理编码循环。人们称之为循环工程。

OpenCode 循环工程实现
AI模型价格对比 | AI工具导航 | ONNX模型库 | Vibe Coding教程 | PLC在线仿真器 | Tripo 3D | Meshy AI | ElevenLabs | KlingAI | ArtSpace | Phot.AI | InVideo

今天我想谈谈我如何在OpenCode中构建了一个代理编码循环。人们称之为循环工程。

为了展示这个编码循环的健壮性,我在本文的每个示例中都使用了 DeepSeek-V4-ProDeepSeek-V4-Flash。事实证明,通过正确的设计,DeepSeek模型可以以非常低的成本实现高质量的编码循环。

本文的所有源代码都在文章末尾提供。让我们开始吧。

1、简介

如果你最近一直在关注AI代理领域,你可能听过循环工程这个术语。Claude Code和OpenClaw都提到了它。

但没有人真正解释它的含义。

直到Andrew Ng发布了 一篇关于循环工程实际是什么的清晰解读。 这篇文章给了我需要的方向,在OpenCode中构建它。

2、Andrew Ng关于编码循环的观点

Andrew Ng的解释以这张图表为中心:

3个关键的产品开发循环。
3个关键的产品开发循环。

简单来说,三个循环:

  • 第一个循环是代码代理的实现循环。你给代理一个产品规格和一个可衡量的目标。代理开始自己构建功能,运行测试,并不断迭代,直到满足规格中的每个要求。
  • 第二个循环是工程师反馈循环。在这里,工程师充当自己产品的QA。他们测试编码代理构建的内容,并检查是否符合他们的愿景。如果有问题,他们编写新的规格并启动第一轮循环。
  • 第三个循环是外部反馈循环。一旦工程师对产品满意,它就会进入开源社区或交给产品团队。真实的用户反馈随之而来。工程师定期收集这些反馈,将其反馈到工程师反馈循环中,然后再回到代码实现循环。

所有三个循环持续运行。随着AI的加入,它们推动产品前进,直到达到需要的位置。

3、我对编码循环的看法

在我看来,这三个循环对应Claude或Codex中的两个命令:/goal/loop

/goal 涵盖第一和第二个循环。一旦用户编写了产品需求文档或规格,他们通过 /goal 命令将任务传递给代理。代理自己迭代,运行自己的测试,并打开拉取请求。

然后工程师审查代码并手动测试。如果一切看起来不错,他们合并PR并发布。

接下来是外部反馈循环。你可以使用 /loop 命令设置定时任务,定期从GitHub或Jira拉取问题。代理将这些问题转化为需求文档,然后 /goal 接手。

使用  创建新任务,使用  定时运行。
使用 /goal 创建新任务,使用 /loop 定时运行。

这里传统的理解有一个差距。当用户调用 /goal 时,他们只是传递他们想要完成的事情。如何完成,以及退出条件是什么,通常由像Claude Opus或GPT 5.5这样的强大推理模型来弄清楚。

但在一个适当的编码循环中,你需要给代理一个产品规格和一个可衡量的完成目标,这样它才知道何时退出。像这样:

/goal 使用我编写的规格构建这个国际象棋游戏。
使用Playwright MCP进行端到端测试。
验证游戏支持王车易位、兵升变、将死、逼和和等级分计算。
修复测试中发现的任何错误并重新运行。循环不超过20次。

这是编码循环的一个坚实的起始指令。它需要一个目标、一个验证方法和一个最大迭代次数。而且你必须每次都写类似的东西,要么在 /goal 命令之后,要么在规格本身内部。

在我的OpenCode版本中,我不走这条路。我只想告诉 /goal 我想要什么。代理处理其他所有事情。

本文的其余部分将向你展示我如何构建这个增强的 /goal 循环。(/loop 命令是一个单独的主题,我将在未来的文章中介绍。)

4、先看最终结果

在开始实现之前,让我先展示一下 /goal 命令在几个场景中的实际作用,从简单到复杂。

4.1 编写斐波那契脚本

这个测试检查代理是否选择了最佳算法。提示是:

/goal 编写一个具有最佳性能的斐波那契计算脚本。
很酷的是DeepSeek选择了快速加倍算法,性能非常出色。
很酷的是DeepSeek选择了快速加倍算法,性能非常出色。

4.2 构建汉诺塔网页游戏

每个人都知道这个游戏。你完全可以直接提示LLM来构建它。但这种可预测性正是它可用于测试编码循环每一步是否正常工作的原因。

提示是:

/goal 构建一个可玩的汉诺塔网页游戏。
使用  命令构建的汉诺塔游戏内置了AI求解器。
使用 /goal 命令构建的汉诺塔游戏内置了AI求解器。

4.3 构建国际象棋网页游戏

也许你对汉诺塔示例印象不深,因为直接提示任何前沿模型都可以在没有编码循环的情况下完成同样的事情。公平地说,国际象棋游戏实验是你应该亲自尝试的。

提示是:

/goal 构建一个可玩的国际象棋网页游戏。
包含简单、中等和困难难度级别。
不需要在线多人游戏。
使用Python后端作为AI引擎。
一个完整的全栈国际象棋游戏,包含前端和后端,使用  命令构建。
一个完整的全栈国际象棋游戏,包含前端和后端,使用 /goal 命令构建。

在这个实验中,OpenCode在接收任务后首先与用户进行快速需求检查。

它沿途提供建议,这样你只需点击下一步。一旦完整的需求列表确认,它就进入自主模式。

  命令将你的目标分解为需求列表,然后逐一实现。
/goal 命令将你的目标分解为需求列表,然后逐一实现。

它处理架构设计,构建每个功能模块,运行单元测试、边缘情况测试和端到端测试。只有当所有测试通过时,它才将结果交还给用户。

很酷,对吧?想知道它是如何工作的吗?我们继续。

5、构建编码循环

5.1 整体设计

OpenCode更新非常快。几乎每个版本都会破坏一些东西或引入小错误。所以我没有构建另一个OpenCode插件,因为插件在更新后很容易损坏。

好消息是OpenCode允许你使用纯Markdown文件定义命令和代理。写几行提示,将文件保存为Markdown,并放到正确的目录中。这个机制是在低成本上构建强大编码循环的基础。

让我带你了解整个循环的交互流程。

当用户运行 /goal <某个任务> 来开始新的编码任务时,OpenCode将该任务发送给我称为协调器的代理。在这个设置中,该代理是 goal-orch

协调器的工作是与用户交谈并审查完成的工作。当它收到任务时,它不会立即开始编码。它首先与用户进行简短对话以澄清细节,然后将任务分解为原子需求列表。

这与OpenCode内置的 Plan 代理不同。/goal 协调器不会问开放式问题。它对用户想要什么做出最佳猜测,并要求用户确认这些子需求是否正确。

当用户不是软件工程师时,这效果更好。这就像一个能干的助手为经理分解任务,而不会让经理感到迷茫。

一旦需求列表确认,协调器将其保存为 reqs-manifest.md 文件。此文件跟踪需求状态,并在整个循环中作为验收记录。

之后,协调器进入自主模式。它启动一个内部循环,调用名为 goal-worker 的工作代理,并将每个需求发送给它。

goal-worker 处理代码实现。在编写任何代码之前,它首先进行架构规划。如果涉及技术选择,它会提出问题。但它不询问用户。它询问 goal-orch。一旦 goal-orch 回答,goal-worker 继续。

架构规划完成后,goal-worker 进入循环并开始实现每个需求。

每个需求包括功能代码、边缘情况处理和单元测试代码。当所有这些完成后,goal-worker 将实现报告发送回 goal-orch

协调器根据需求描述检查报告,确认完成,并更新需求列表中的状态。

在循环内部,goal-orch 还从完整的需求列表构建DAG以映射依赖关系。彼此之间没有依赖关系的需求将与多个 goal-worker 实例并行执行,这显著加快了速度。

一旦所有需求完成,goal-orch 对列表运行验收测试,检查单元测试覆盖率,对于涉及前端工作的任务,它使用 browser use 启动端到端测试以确认一切正常。

当所有测试通过时,协调器编写实现报告并通知用户任务完成。然后等待下一个任务。

执行顺序如下:

  命令运行的序列图。
/goal 命令运行的序列图。

现在,让我逐步介绍每个部分的构建。

5.2 实现 /goal 命令

由于我们希望 /goal 成为编码循环的入口点,就像Claude Code一样,这是在OpenCode中构建的第一件事。

值得庆幸的是,在OpenCode中创建命令非常简单。只需将Markdown命令定义文件放到 .opencode/commands/ 目录中。

编写Markdown命令文件时需要注意两点:

  1. frontmatter 中,通过 agent 参数配置一个单独的代理。没有专用代理,OpenCode会将命令直接发送给默认代理。默认代理没有循环工程提示,因此命令会失败。对于 /goal,我设置了一个名为 goal-orch 的协调器代理,我将在接下来介绍。
  2. 在命令正文中,使用 $ARGUMENTS 占位符表示用户调用命令时传递的任务。当命令将消息发送给协调器时,此占位符将替换为用户输入的内容,完整组装的消息将发送给协调器。

5.3 实现 goal-orch 代理

现在让我们构建 goal-orch 代理,它充当协调器。它处理用户通信、需求澄清、启动开发循环、调用 goal-worker 并验证工作是否完成。

由于我们在之前的文章中多次构建OpenCode代理,我不会在这里详细介绍每个细节。只有一些值得注意的事项:

  • 模型选择。goal-orch 处理整体工作流程协调,因此需要强大的推理能力。我是DeepSeek-V4系列的粉丝,所以我选择了 deepseek-v4-pro
  • 系统提示。提示需要涵盖工作流程协调和代理自身的任务,因此篇幅较长。但没关系。当你使用 /goal 发送任务时,goal-orch 系统提示会自动替换OpenCode的默认提示,因此无需担心过多的令牌使用。
  • goal-orch 必须是主代理。OpenCode有两种代理类型:主代理和子代理。主要区别在于主代理可以调用子代理来委派工作,但子代理不能。由于 goal-orch 需要在循环中调用 goal-worker,因此它必须是主代理。唯一的缺点是它会出现在OpenCode界面底部的代理列表中,但你会习惯的。
  • 主代理和子代理之间的交互机制。在循环期间,当 goal-worker 遇到棘手的问题或需要做出技术选择时,它不会询问用户。它通过会话返回将问题返回给 goal-orch。这需要 goal-orch 回答问题,然后继续之前的子会话。OpenCode使用 task 工具向子代理发送消息。此工具接受 task_id 参数。第一次调用 task 工具会打开一个新的子代理会话,返回值包含 task_id。在 goal-orch 回答 goal-worker 的问题后,它将答案和之前的 task_id 传回 task 工具。这会恢复原始子会话中的任务并保留上下文。
  • 简单来说,它就像一个工头和一个工人。工头派工人去做一项工作。工人给工头一个参考号。如果工人遇到问题,他们回来问工头。工头解决问题,带着参考号和答案回到工人那里,工人从他们离开的地方继续。无需重新开始。
OpenCode使用  跟踪子会话中的上下文。
OpenCode使用 task_id 跟踪子会话中的上下文。
  • 并行任务执行。即使我们构建了一个全自动编码循环,协调器仍然可以为彼此之间没有依赖关系的需求并行运行多个 goal-worker 实例。这显著加快了整体任务速度。在 goal-orch 与用户确认需求列表后,它不会直接跳入编码循环。它首先将需求之间的依赖关系映射到DAG中。当它发现彼此之间没有依赖关系的需求时,它会启动并行执行以更快地完成任务。
需求根据其依赖关系重新计算为DAG,然后并发执行。
需求根据其依赖关系重新计算为DAG,然后并发执行。
  • 每个完成的任务都有文档记录。编码循环一次处理大量需求,此过程可能运行数小时。随着任务的持续进行,上下文越来越长,代理遵循提示的能力越来越弱。在这一点上,我们不能仅依靠会话消息来跟踪每个需求的状态。协调器将开始错过工作流程中的关键步骤。因此,在设计 goal-orch 时,我在提示中包含了一个要求:子代理不仅必须在每一步之后更新 reqs-manifest.md 中的需求状态,还必须为每个完成的需求生成文档说明。这样,一旦编码循环结束,goal-orch 可以审查这些文档,查看哪些任务顺利完成,哪些遇到了需要人工关注的阻碍。
  • 使用 browser use 进行端到端测试。既然我们要完全自动化,为什么不彻底呢?当 goal-orch 检测到任务涉及前端页面时,它在最终审查阶段调用 agent-browser 技能或 @playwright-mcp 来运行端到端测试,并捕获屏幕截图作为功能正常工作的证明。由于我使用的是 deepseek-v4 模型,我在需要时还调用 @observer 代理进行图像读取。我在之前的文章中介绍了 @observer 代理的实现。

这涵盖了 goal-orch 背后的值得注意的设计决策。我不会在这里粘贴完整的提示,因为一旦你理解了原则,提示很容易用LLM生成。请在文章末尾获取完整的源代码。

现在让我们看看 goal-worker

5.4 实现 goal-worker 代理

goal-orch 相比,goal-worker 设计上要简单得多。它只是做工作。它的指令越简单,性能越好。话虽如此,我在这个编码循环中确实为它设定了几个期望:

  1. 模型选择。对于不需要深度推理的任务,deepseek-v4-flash 诚实地说比 pro 更出色。根据我的经验,在涉及函数调用和技能加载的情况下,flashpro 更准确,成本也低得多。因此,对于专注于执行的 goal-workerdeepseek-v4-flash 是正确的选择。
  2. 行动前询问。即使它是一个子代理,我也赋予了 goal-worker 提问的能力。无论是在开始之前还是在任务中途,每当遇到技术问题时,goal-worker 都会停下来询问 goal-orch 的意见。这充分利用了链中更强大的推理模型。
  3. 先计划,后行动。就像由 goal-orch 驱动的外层循环一样,goal-worker 遵循相同的规则:先计划再执行。在实现任何新需求之前,goal-worker 会编写一个计划,涵盖技术栈、它打算更改的内容以及如何处理单元测试和边缘情况。该计划提交给 goal-orch 审查。只有在 goal-orch 签字后,goal-worker 才开始编码。此机制最大限度地提高了成功实现的可能性。
  4. 使用现代包管理器。这并不是严格要求的,但在实践中我注意到DeepSeek倾向于默认使用传统工具如 pipnpm 进行全局依赖安装。作为开发人员,这是我无法忍受的。因此,我明确要求 goal-worker 使用现代包管理器如 uvpnpm。当编码循环为你构建东西时,这也能保持你的环境整洁。

这就是我的OpenCode编码循环的完整实现计划。我没有将源代码粘贴到文章正文中,因为所有代码都在末尾。请去那里获取。

我还试图清楚地解释这个编码循环背后的思考过程以及如何构建它,以便你可以直接将本文放入OpenCode,让它为你重建一个工作的 /goal 命令。从那里,随心所欲地调整它,构建你自己的循环工程版本。在AI时代,还有什么真正不可能的呢?

在结束之前,让我快速介绍如何实际使用这个编码循环。

6、如何使用此编码循环

首先,转到本文末尾,打开我分享的GitHub链接。然后回到这里继续阅读。

编码循环的源代码位于其自己的git仓库中。你唯一需要关心的目录是 .opencode/。要在所有OpenCode项目中使用此编码循环,请将该文件夹中的 agentscommands 目录复制到 ~/.config/opencode/,然后重新启动OpenCode。

如果你只想在一个特定项目中尝试它,只需将 .opencode/ 目录复制到项目根目录并重新启动OpenCode。

如果你只想快速试用,请在本地克隆仓库,创建一个新分支,并从该分支运行 opencode 以启动环境。

之后,在OpenCode中输入 /goal 命令,以及你希望编码循环处理的任何任务。例如,如果你想构建Andrew Ng在他的文章中提到的打字练习游戏,只需输入:

/goal 我想为孩子们构建一个打字练习网络应用。
屏幕底部是9个代表10个手指位置的键,拇指共享一个更宽的空格键,占据两个位置。
在这9个键上方是一个渐变透明的矩形。
字母从顶部向下落向该矩形,与它们匹配的键位置对齐。
当字母进入区域时按下正确的键,算作命中,触发命中效果。
连续正确的命中会建立越来越戏剧性的效果。
下落速度逐渐增加。
屏幕顶部是一个计分板,每命中一次加1分,并带有弹出动画。
整个过程应该感觉令人兴奋并触发多巴胺,提供大量的视觉鼓励。
使用  命令创建的打字小游戏。
使用 /goal 命令创建的打字小游戏。

你可以随心所欲地详细或模糊。无论哪种方式,一旦你按下回车键,编码循环就开始运行。goal-orch 将与你展开对话以澄清需求。

你可以在对话发展中填写更多细节,或者对所有内容选择 recommend,然后去给自己泡杯咖啡,让它完成工作。

6、结束语

这就是我如何在OpenCode中构建这个编码循环的故事。在结束之前,让我回答几个你可能有的问题。

1. 开源模型能支持这个编码循环吗?

是的,我认为可以。在本文中,我使用 deepseek-v4-pro 作为 goal-orchdeepseek-v4-flash 作为 goal-worker,两者都运行良好。在循环工作流程的严格约束下,它们可以自动处理你的大多数任务。

此外,DeepSeek将在七月中旬发布DeepSeek-V4的官方版本。它几乎肯定会带来训练后的改进,我期望它能带来更好的结果。

2. 我应该期望什么结果?

编码循环将花费数小时来完成你的任务,但不要对单次 /goal 运行能产生的结果期望过高。即使使用最强大的Claude或GPT模型也是如此。

正如Andrew Ng所说,代码实现循环只是三个循环中的第一个。你需要进入第二个循环,即工程师反馈循环。尝试 /goal 产生的结果,找出所有错误和与你愿景不符的地方,将它们组织成新的规格,并启动另一个编码循环。不断迭代。这就是产品随时间变得更好的方式。

3. 编码循环能替代像OpenSpec这样的SDD框架吗?

不能。它们服务于不同的场景。

编码循环非常适合产品经理或团队负责人,他们希望从市场洞察或自己的想法快速启动最小可行产品。它优先考虑速度和自动化。它适用于想要交接并让代理自己运行的人。

但如果你的产品要投入生产,如果你对代码质量和实现细节有高标准,如果你有详细的产品规格,并且你是一位经验丰富的软件工程师,确切地知道产品应该是什么样子,那么OpenSpec或其他SDD插件是正确的工具。从坚实的基础开始,逐步构建你的完整产品。


原文链接: No Plugins Needed, I Built a Fully Automated Coding Loop in OpenCode

汇智网翻译整理,转载请标明出处