基于OpenCode与Ollama的无头双智能体编码循环
如何在使用 Ollama 的 OpenCode 中,通过权限、技能、保密规则、截图以及仅允许人工提交的机制,将规划与审核工作分配给两名代理。
来源: Ollama on Steroids with OpenCode: A Headless Multi Agent Coding Workflow
大多数人工智能编程演示在有人提出一些枯燥的工程问题之前都显得相当出色:究竟发生了什么、谁负责审核、运行了哪些测试,以及明天是否还能重现整个过程?
下面的工作流程试图回答这些问题。它并非通过偶尔生成优质代码补丁的聊天窗口来实现,而是将人工智能编程视为一个小的工程循环:
- 一个智能体负责规划与实现
- 另一个智能体负责审核并确认
- 每个提示都会拥有独立的本地会话文件夹
- 每次运行都会留下日志以及测试已执行的证明
- 由人类而非智能体来决定何时提交或推送代码
- 私密的提示内容及会话输出将保持保密
分工协作:MiniMax负责制定计划和编写代码,GLM负责审核与批准,OpenCode负责推动工作流程,而Ollama则将请求路由到相应模型。这并非什么神奇的自主系统,而是一个可重复的循环,包括计划制定、审核、测试、截图、安全检查,最终由人工进行提交操作。
在工具方面,OpenCode提供了非交互式的opencode run功能、命名代理、模型选择选项、--dir标志,以及将运行任务绑定到无界面opencode serve实例的能力。还可以通过--sanitize选项导出会话记录。Ollama提供了通过ollama launch opencode实现与OpenCode集成的方式,而OpenCode则能够读取项目级别的配置、代理设置、权限信息、技能数据以及MCP服务器相关内容。
该示例配置将 Ollama Cloud 模型命名为 minimax-m3:cloud 和 glm-5.1:cloud,其中 MiniMax 适用于编码与智能体任务,而 GLM 则被视作智能体工程的旗舰模型。这一命名规则并不局限于这些特定模型,只需将模型名称视为示例,在复制前请查看最新的 Ollama 目录。原项目中的原始提示词、会话输出、本地路径、密钥及截图均不会在此分享,仅会提供相应方法。
别再把 AI 编码视为单次对话
单独的编码智能体与处于压力下的独立开发者有同样的弱点:它可能会自我欺骗,以为任务已经完成。再次使用同一个模型并不能解决这个问题,而规范的流程才能做到:
Prompt -> Plan -> Review -> Implement -> Test -> Review -> Fix -> Signoff -> Human commit
布局如下所示:
control-workspace/
AGENTS.md
opencode.json
.opencode/
agents/
minimax-builder.md
glm-reviewer.md
skills/
opencode-ollama-agent-guardrails/
SKILL.md
agent-sessions/
project-slug/
promptNN/
PROMPTNN_CODER.md
PROMPTNN_REVIEWER.md
PROMPTNN_PLAN.md
PROMPTNN_PLAN_REVIEW.md
PROMPTNN_IMPLEMENTATION.md
PROMPTNN_TEST_RESULTS.md
PROMPTNN_IMPLEMENTATION_REVIEW.md
PROMPTNN_SIGNOFF.md
redacted logs
screenshot references
product-repo/
为何要从父控制工作空间开始?仅在产品代码库中,代理可能就无法看到提示文件、会话文件、共享规则或更广泛的工作流程。而绝对路径则可能将特定于机器的详细信息写入日志中。因此有这样一条规则:从父工作空间启动OpenCode,使用相对路径,将产品相关修改保存在产品代码库中,而会话输出则保存在代码库之外。这听起来很枯燥,但正因如此它才有效。
承担不同职责的两个代理
关键的设计考量并非具体的模型,而是职责的分离。
构建器
minimax-builder可以规划、编辑代码、运行命令并撰写实现说明。它的职责包括阅读提示与AGENTS.md、起草计划、应用审核者的反馈、仅实现已获批的范围、运行验证、记录哪些内容被修改以及哪些测试失败,同时在每次提交前等待人工确认。禁止执行的操作包括:提交代码、推送代码、重新基址、强制推送、进入下一个提示、放宽测试要求以及编辑保留给审核者的文件。
审核者
glm-reviewer按设计要求极为严格。它的检查清单包括:计划是否符合提示要求、实现内容是否仍在规定范围内、测试是否有意义、生成的文件是否经过刻意修改、浏览器截图是否能佐证说法、敏感信息处理是否得当,以及构建工具是否夸大了其成果?
它的决策选项被限制得非常少:
APPROVED
CHANGES_REQUESTED
SIGNED_OFF
NOT_SIGNED_OFF
词汇量有限的话,可发挥的空间就很小。“整体看起来不错”并不能算作认可。
OpenCode 配置
配置的结构如下:
{
"$schema": "https://opencode.ai/config.json",
"model": "ollama/minimax-m3:cloud",
"default_agent": "minimax-builder",
"share": "disabled",
"instructions": ["AGENTS.md"],
"enabled_providers": ["ollama"],
"permission": {
"read": {
"*": "allow",
"*.env": "deny",
"*.env.*": "deny",
"*.env.example": "allow"
},
"glob": "allow",
"grep": "allow",
"webfetch": "ask",
"websearch": "ask",
"external_directory": "deny",
"skill": {
"*": "allow"
}
},
"agent": {
"minimax-builder": {
"description": "Main planning and implementation agent.",
"mode": "primary",
"model": "ollama/minimax-m3:cloud",
"temperature": 0.2,
"permission": {
"edit": {
"*": "deny",
"product-repo/**": "allow",
"agent-sessions/project-slug/**": "allow"
},
"bash": {
"*": "ask",
"cd product-repo && *": "ask",
"git status *": "allow",
"git diff *": "allow",
"git log *": "allow",
"git commit *": "deny",
"git push *": "deny",
"git rebase *": "deny",
"rm *": "deny"
}
}
},
"glm-reviewer": {
"description": "Strict reviewer. Must not edit product code.",
"mode": "primary",
"model": "ollama/glm-5.1:cloud",
"temperature": 0.1,
"permission": {
"edit": {
"*": "deny",
"agent-sessions/project-slug/**": "allow"
},
"bash": {
"*": "ask",
"git status *": "allow",
"git diff *": "allow",
"git log *": "allow",
"grep *": "allow",
"rg *": "allow",
"git commit *": "deny",
"git push *": "deny",
"git rebase *": "deny",
"rm *": "deny"
},
"task": "deny"
}
}
}
}
有两个细节值得注意。共享功能默认处于禁用状态,由于OpenCode提供了share选项,将其设置为"disabled"即可避免意外信息泄露。审核者也没有广泛的编辑权限:它可以将审核和确认文件写入会话文件夹,但不应修改生产代码。OpenCode为edit、bash、read、grep、glob、skill等操作设置了精细的权限规则,因此配置本身应能规范工作流程。
请根据您自己的仓库调整路径,原则保持不变:
builder can edit product code;
reviewer can write review notes;
neither agent can commit or push;
external directories are denied;
dangerous shell commands ask or deny.
技能作为可移植的防护栏
最具复用价值的并非配置文件,而是技能本身。OpenCode的技能是存储在项目或全局技能文件夹中的可复用SKILL.md定义文件。标准的项目级存储路径为:
.opencode/skills/<skill-name>/SKILL.md
也存在与 Claude 兼容以及与智能体兼容的技能路径,但针对此工作流,保持简单更为合理。将防护技能放在这里:
.opencode/
skills/
opencode-ollama-agent-guardrails/
SKILL.md
每个 SKILL.md 文件都必须包含前置信息,至少要有 name 和 description 两项。名称需为小写,用连字符分隔,且与文件夹名称一致。防护技能可以向智能体指定诸如以下的规则:
- Do not publish raw prompts.
- Do not publish raw session logs.
- Do not use absolute local paths.
- Do not edit outside the approved product directory.
- Do not claim success without test output.
- Do not weaken tests to make validation pass.
- Do not commit, push, rebase, or force-push.
- Store review notes separately from production code.
- Treat screenshots as sensitive evidence.
- Stop for human approval after signoff.
这些规则看似简单,却能有效避免真正的错误。如果它们仅存在于某个仓库的 AGENTS.md 文件中,就会一直留在那里;而作为技能被打包后,则会随你一同使用。
无头模式确保可重复性
交互式编程适合探索性开发,而无头模式则更利于实现可重复的运行过程。构建器的配置如下:
opencode run \
--model ollama/minimax-m3:cloud \
--agent minimax-builder \
--dir . \
"$(cat agent-sessions/project-slug/promptNN/PROMPTNN_CODER.md)"
审核人已通过:
opencode run \
--model ollama/glm-5.1:cloud \
--agent glm-reviewer \
--dir . \
"$(cat agent-sessions/project-slug/promptNN/PROMPTNN_REVIEWER.md)"
对于使用 MCP 服务器的更复杂的配置,可先启动一个本地的 OpenCode 服务器,后续运行时直接连接到该服务器,从而避免重复的冷启动过程:
opencode serve --hostname 127.0.0.1 --port 4096
opencode run \
--attach http://localhost:4096 \
--agent minimax-builder \
--dir . \
"$(cat agent-sessions/project-slug/promptNN/PROMPTNN_CODER.md)"
将服务器绑定到 127.0.0.1。任何将其暴露给其他机器的人都应该设置 OPENCODE_SERVER_PASSWORD,并像真正的开发服务那样运行它,因为命令行文档是通过该变量来描述 HTTP 基本认证的。模型并没有变得更聪明,只是更难被欺骗了。
防止提示词和输出泄露
将提示词文件和会话输出存储在本地有助于调试智能体的行为,但直接发布原始提示词或原始输出则不可取。智能体的日志中可能包含本地路径、Shell 提示符、分支名称、内部待办事项、实现相关机密、环境名称、截图路径、多余的凭证以及你希望私下重复使用的提示词内容。
规则是:所有内容均需本地存储,仅发布经过脱敏处理的摘要和可重复使用的模板。OpenCode的opencode export [sessionID]命令配合--sanitize参数有助于内部审核,但应将其视为初步处理步骤而非正式发布按钮。任何公开内容都需经过第二次脱敏审核。
对于公开仓库,需提交以下内容:
AGENTS.md
opencode.json
.opencode/agents/*.md
.opencode/skills/*/SKILL.md
templates/*.md
scripts/*.zsh
scripts/redact_sessions.py
docs/publication-redaction-checklist.md
并将这些忽略:
agent-sessions/**
screenshots/**
.env
project.local.env
*.raw.log
*.events.jsonl
opencode-session-*.json
这样就能生成可共享的报告,同时避免仓库信息泄露。
MCP工具的用处
模型只是系统的一部分,工具界面则至关重要。将MCP和内置工具视为专门的感知器官与操作手,是一种有效的理解方式:
| Workflow stage | Useful tool or MCP category | What it helped with |
| ---------------- | ------------------------------------------------------- | -------------------------------------------------- |
| Planning | repo search, docs lookup, issue/context reader | understand current architecture before changing it |
| Coding | filesystem, shell, language server, package manager | edit code, inspect symbols, run targeted commands |
| Review | git diff, grep, test reports, generated artifact reader | catch scope creep and weak tests |
| Unit tests | test runner, coverage | prove the patch did not only compile |
| Browser tests | Playwright/browser automation | validate real UI routes and flows |
| Security tests | secret scan, dependency audit, SAST | catch obvious unsafe output before publish |
| Docs/site checks | static-site build, route checks, smoke tests | catch generated-output drift |
最佳的 MCP 配置并不会启用所有功能。它只为智能体提供所需的少量工具,并要求那些有风险的功能先经过审批。OpenCode 在 opencode.json 文件的 mcp 键下定义 MCP 服务器,同时还提供了用于管理这些服务器的 CLI 命令。应将这些定义视为生产环境中的依赖项:锁定版本、仔细审查,并移除那些未被使用的功能。
为何截图能占据一席之地
浏览器测试只会返回通过或失败的结果,而截图则能提供视觉证据。它们帮助审查人员发现单元测试遗漏的问题:干净构建后的布局错误、路由上的内容错误、生成的页面为空、导航功能出现退化、某些测试未检测到的错误提示,以及静态站点路由存在且能正常渲染的证明。
它们同样存在风险:浏览器配置文件名、私密标签页、localhost路径、问题标题、URL令牌以及开发者工具的输出内容都可能被截取到。相关政策要求仅对localhost界面进行截图,严格裁剪范围,发布前需审核,且绝不能截取认证页面、生产环境控制面板、私密标签页或显示环境参数的终端界面。截图属于证据,按默认规则不视为公开资料。
一个私有维基项目的案例研究
作者将此方法应用于一个私有的LLM维基及静态站点项目,并仅发布了经过处理的成果报告。最终验证记录显示:977个Python测试通过,静态站点重新构建后完成刷新测试、烟雾测试及域名验证,文档构建成功,路由检查通过,还有150个Playwright测试通过。对于已完成的限定功能,作者自身信心颇高,约为8到9分(满分10分),这一评估有可重复运行的测试、生成的站点检查、路由检查以及浏览器验证作为支撑。不过该评分具有主观性,不应推广到其他项目。
薄弱环节并不在于产品代码。有一个无头自动化脚本因代理名称设置错误而失败,它使用的是通用名称:
planner
coder
tester
reviewer
而实际配置的代理为:
minimax-builder
glm-reviewer
这种不匹配导致程序退化为错误的行为模式,因而预期的多代理签名流程未能完成。这次故障其实很有价值,因为它凸显了使用纯文本名称、精确的配置、相对路径以及检查会话文件夹的重要性。修正后的模式如下:
opencode run \
--model ollama/minimax-m3:cloud \
--agent minimax-builder \
--dir . \
"$(cat agent-sessions/project-slug/promptNN/PROMPTNN_CODER.md)"
opencode run \
--model ollama/glm-5.1:cloud \
--agent glm-reviewer \
--dir . \
"$(cat agent-sessions/project-slug/promptNN/PROMPTNN_REVIEWER.md)"
这意味着不能使用绝对路径,不能编造代理名称,也不能在工作范围之外隐藏提示词文件。
与前沿工作流的差距有多大?
这方面很容易夸大其词。在OpenCode和Ollama上使用MiniMax加上GLM的配置,并不等同于直接运行最优秀的前沿编程模型。前沿模型在原始推理能力、长上下文处理能力以及默认指令遵循方面仍更出色,因此直接对比不同模型并不公平。真正重要的比较应是工作流的质量:规划、审查、测试、截图、安全检查以及人工审批。
工作流程具有非常重要的意义。对于有完善测试支撑的限定范围任务,其架构设计几乎可以媲美强大的 Frontier 模型——它通过划分不同的角色、提前规划、在实现过程的两端进行审查、设置强制性的验证环节、利用本地会话内存、截图作为证据、进行安全检查,并由人工控制提交操作。
在处理确定性功能开发、静态站点生成、数据检索与搜索功能、需要大量测试的任务、审查生成结果、防止范围蔓延以及要求相关人员记录故障等方面,这种流程已经非常接近 Frontier 模型的水平。不过在面对架构设计不明确的场景、对测试不足的代码进行深度重构、产品风格与决策判断、长期自我修正、减少重试次数、默认遵循指令以及分析复杂截图等方面,Frontier 模型依然更具优势。
威胁模型
在这种工作流程下,几种常见的 AI 编码风险会得到控制:不实的成功宣称、开发者偏离预定代码库、审核者转而成为实现者、原始提示词被上传到公共代码库、日志泄露路径或机密信息、截图暴露私人标签页或令牌、生成的文件被悄悄修改,以及在其他人查看之前就有代理程序进行提交或推送操作。
人工审核仍然必不可少。目标并非完全的自动化,而是建立一个更紧密的循环,让每一项宣称都有证据支撑,每一项高风险操作都有限制。
优缺点
优点
- 可重复性。提示词会对应特定文件夹,运行过程会留下记录,审批痕迹也可追溯。
- 管理机制。如果审核者在没有验证证据的情况下拒绝批准,开发者就无法擅自跳过测试。
缺点
- 流程更为繁琐。它的使用方式比简单的聊天提示词要复杂,这就是需要付出的代价。
- 强制措施依赖配置。仅靠告知审核人员不要修改生产代码,其约束力远不如通过权限控制和持续集成检查来强制执行。
- 劣质提示词仍会生成劣质结果。虽然循环机制能减少混乱,但无法替代明确的任务范围定义。
- 权限管理需格外谨慎。MCP服务器和shell访问权限极具威力,应将其视为生产环境级别的权限来对待。
- 日志信息敏感。日志内容越详细,保密处理就需要越小心。
站得住脚的论点
这种架构并不会让MiniMax或GLM成为顶级前沿模型。它所做的只是让通过Ollama实现的低成本代理编程更具规范性、可审计性,并更适用于特定范围的工程任务。这是它唯一能够如实提出的论点。
相关阅读
- 实用笔记:Google ADK详解——如何构建多智能体系统 —— 对《实用笔记:Google ADK详解——如何构建多智能体系统》的详细操作指南,包括合同定义、检查机制以及供采用该模式的团队直接使用的代码模板。