基于OpenCode的多Agent代码开发工作流:演进与优化

基于OpenCode的多Agent代码开发工作流:演进与优化

这是系列第三篇。第一篇《用 opencode 搭一套多 Agent 开发工作流:设计与搭建》讲架构、机制与九轮修订,第二篇《用 opencode 跑完一个完整项目:多 Agent 开发工作流实践与效果》讲 pulse-pet V1 的完整复盘。这一篇讲 V1 交付之后的事:工作流自己作为产品继续演进——补多模态能力、换浏览器自动化工具链、踩嵌套委派的坑、以及一次从”主角降为备胎”的角色再定位。核心命题只有一个:一套配置即代码的工作流,怎么在不停机干活的前提下进化自己。

相关地址:实验仓库 yq3/lab | 设计文档全文(44 条决策记录):.opencode/README.md | 全部检查点存档:.opencode/workflows/

1. V1 之后:编排骨架冻结,演进全部发生在挂件层

第二篇结尾留了三个”下一步”:skill 化拆分、SDK 固化、迁移全局配置。诚实对照:这三个都还没动。实际发生的是另一件事——pulse-pet 进了 V2(Claude Code 双 agent 接入、设计系统、Token 看板、定时任务、多 agent 抢镜……08-24 到 08-29 连跑 9 个检查点),而工作流本身在 V2 干活的同时完成了第二轮演进(决策记录 D38-D44):

条目 日期 一句话
D38 Vision subagent 08-22 给纯文本工作流装上眼睛
D39 playwright-cli skill 08-22 DOM 断言层做实,浏览器自动化弃 MCP 走 CLI
D40 双闸门修复 08-22 subagent 委派 subagent 的平台机制补课
D41 双设计 skill 08-22 治”AI 设计三大俗”
D42 Reviewer 角色 08-22 方案文档审查角色化
D43 图像选型修订 08-28 原生读图优先,Vision 降备胎
D44 depth-2 零 ask 08-30 嵌套委派权限挂死的根因修复

先把不变的钉死:编排者、主流程状态机、检查点协议、意见传递协议、质量门禁三层——零改动。所有演进都是”挂件”级:加 subagent、加 skill、改权限矩阵、换模型。这个分层是刻意维持的:V1 验证过的骨架不动,新能力全部先挂在外围观察。后面 §5 的翻车会证明这个决定的价值——挂件烧起来的时候,主线只受擦伤。

2. 给纯文本工作流装上眼睛:Vision subagent(D38)

V1 留下的最大能力缺口:四个角色全是纯文本模型。GUI 验证链只有 screencapture → OCR——字符提取尚可,”弹窗有没有正确遮挡””烟花渲染得对不对”这类语义判断无能为力。第二篇 M1 的透明窗口假阴性,本质就是这个缺口的第一次显形。

08-22 的补法是新增第五个 agent vision.md,设计上有四条硬约束:

  • 纯只读:edit/bash 全禁,只用 read 读图(png/jpg/PDF 原生支持);
  • 无状态单次调用:不进检查点协议、无会话续接,结果即弃——它是”工具化的眼睛”,不是队友;
  • 结构化输出契约:5 小节(图片概况 / 文本提取原文照抄+区域 / 视觉元素 / 针对问题的结论 / 低置信度标注),禁止编造;
  • 调用方式:Task 传图片绝对路径 + 具体问题——文本模型调用方自己读图没有意义。

模型选 glm-4.6v(订阅套餐内视觉模型,128K ctx,按 token 计费 0.3/0.9 每百万;备选 glm-5v-turbo 零成本,frontmatter 一行可切)。

验证结果超预期:128×128 小图标的文本提取正确;5MB retina 桌面截屏的中文 UI 全量提取准确——窗口标题、标签页、提醒规则文案、按钮勾选态,连桌面上其他窗口的文件名都逐个识别。

最有价值的发现是一次定向提问对比实验:同一张烟花截图,泛问”描述截图”只得到一句”中央有彩色烟花效果”;定向问”烟花位置/形态/是壁纸还是叠加特效”,得到完整分析——中央偏上、放射状、数百粒子+拖尾、判断为实时叠加特效,并附层次/动态感/设置项三重依据。结论写进了三个调用方的 prompt:第 4 小节(针对问题的结论)才是 Vision 的核心价值,问题质量决定输出深度

已知限制也如实记录:macOS TCC 拦桌面目录(Operation not permitted,且 Glob 会表象成”空目录”——连错误形态都有迷惑性),需要系统授权或把图拷到已放行目录。

3. 工具链换血:浏览器自动化弃 MCP 走 CLI+Skill(D39)

D38 的选型优先级表里,顶层是”DOM/accessibility 断言”——但当时没有任何工具支撑,悬空。补齐这一层时评估了两条路线:

Playwright MCP playwright-cli + Skill(选定)
token 开销 工具 schema 常驻每个 agent 的 context 无 schema;快照是精简 YAML,find 只返回匹配节点
接入成本 要写 opencode.json 的 mcp 配置 零配置:走 bash 命令,coder/tester 的 bash 权限天然放行

微软官方 README 明示 coding agent 场景用 CLI+Skill 更合适,但对我们决定性的论据是 subagent 架构本身:Coder/Tester 每次 Task 都是全新 context,MCP 的 schema 常驻是每会话重复税;CLI 调用零常驻成本。这个论证反过来也成立——如果是单 agent 长会话场景,MCP 的账要重新算。

落地:@playwright/cli 全局安装(复用系统 Chrome,附带 FFmpeg 供录屏),skill 装到 .agents/skills/——这是 Agent Skills 开放标准的中立路径,跨工具可发现(Codex 源码实锤从 cwd 向上扫这个目录)。验证用 TodoMVC 有头演示跑通全链:中文输入、regex 定位、勾选、截图。

一个值得记的细节:装完 skill 不代表会被用。Tester 的任务框架是”用例转测试”,不点破连接,它大概率继续走截屏 OCR 老路——所以在 coder/tester prompt 的图像识别选型里各加了一条首位 bullet 指路。skill 发现靠一行 description 是概率触发,关键路径要 prompt 显式接线。

4. 意料之外的坑:subagent 调 subagent 没那么当然(D40)

Vision 落地当天实跑就翻车:tester 报告没有 task 工具,”三个 subagent 自动委派 Vision”的设计直接落空。探测确认自定义 Tester 和内置 explore 都没有——平台级限制,与权限配置无关。

翻 v1.18.19 源码,结论是 subagent 用 task 工具要过两道闸

  1. 挂载闸:subagent 配置里没有任何显式 task 权限规则时,自动注入 task: deny * 并把工具从列表移除——检查只看”规则存在”,不看动作是什么;
  2. 执行闸:调用时 depth >= subagent_depth(默认 1)直接抛错——只拦执行,不影响挂载。

复盘第一篇的 D23:当时只验证了”权限默认开放”,漏了”工具挂载默认收紧”这层。权限能调 ≠ 工具在手上,平台机制要分层验证。

修复缺一不可:.opencode/opencode.jsonsubagent_depth: 2(主→Coder/Tester/Committer 第 1 层→Vision 第 2 层);三个 subagent 显式声明 task: {"*": deny, "Vision": allow}(既过挂载闸,又把委派面收窄到 Vision,互不可调);vision.md 刻意不加 task 规则——Vision 天然无嵌套,不可能再孵 Vision。

验证方法本身也留了个附带发现:用 OPENCODE_CONFIG_CONTENT 环境变量注入配置做 A/B 对比很顺手,但它不走严格校验——typo 键不报错。判断一个配置键是否被当前版本支持,必须写进真配置文件让 opencode 亲自拒绝一次。

这次的附带发现里还埋着一颗雷:”Vision 读工作区外图片触发 external_directory ask:TUI 下用户可批准,无头模式挂死。”当时的处理是规避——“截图放仓库内或已放行目录”。没修根因,§6 爆。

5. 实战翻车:Vision 的三时代沉浮(v2-m5 事故 + D43)

Vision 转正当主力的日子并不长。B 时代的账单:单次延迟 37.6s、5.1k token/次(无状态单次调用的代价——每次都带全量上下文)、1 次幻觉需要交叉核验、2 次流卡死。

压垮它的是 v2-m5 的事故,检查点留了完整时间线:

  • 08-27 10:33:tester 调 Vision 做截图目验,首次卡死;
  • 11:25:续接恢复后再调,同症状卡死,用户取消本次调用;
  • 重试派工词一行字:”禁用 Vision 子代理”——截图类目验降级为 DOM/CSS 断言(getComputedStyle/class 命中/boundingBox),63 张真实截图留档供人工复核;
  • R2 全绿:cargo 301+3i、npm 386,报告专门注明”全程未调用 Vision”。

这就是挂件层演进的好处:熔断开关是运行时可执行的——派工词一行字,流程立刻绕开故障通道,主线零改动。

事故之后是 D43 的数据考古(对 opencode.db 做只读 SQL 查询审计 Tester 会话行为):换 glm-5.3-flash(原生多模态)之后的三个 Tester 会话,原生读图 0 次、Vision 调用 0 次——多模态通道全程闲置;同期 v2 里程碑之间,图像类 bash 命令从 m4 的 403 次跌到 m6 的 17 次——DOM/OCR 确定性通道成熟后,图像验证需求本身在萎缩。

三时代定性:

时代 图像验证主力 特征
A(v1 前期) 纯脚本管线 环境敏感,v1-M1 无头假阴性损失 2 轮 + 人工介入
B(v2 前中期) Vision 主力 有语义价值,但延迟/成本/稳定性三高,2 次卡死
C(v2 后期) DOM/OCR 确定性通道 快、便宜、可断言;语义判断退回 tester 原生读图

修订(D43):语义判断优先 tester 用 read 直接读截图自判(结论须写明依据,高风险断言与 OCR/DOM 双通道互证);Vision 降为备胎——当前模型读不出图时才委派。选型优先级链固化:DOM/accessibility 断言 > 测试钩子 > OCR > 直接读图 > Vision。

两个防止复发的细节:指引文案不硬编码模型名,写”若当前模型支持图片输入”——下次换模型不再产生提示词滞后(第一篇 D31 的教训直接复用);"Vision": allow 和 vision.md 本体保留——备胎不是删除。

6. 根因修复:depth-2 零 ask 不变量(D44)

08-30,§4 埋的雷爆了:委派 Vision 读其他工作区的图片,流程永久挂死。

根因链完整拆开是这样:vision.md 没有 external_directory 规则 → 工作区外 read 触发默认 askdepth-2 子会话的权限申请不冒泡到 TUI,用户根本看不见 → Task 无限等待。depth-1 没这个问题(coder 的 git push* ask 全程依赖冒泡弹确认),坑特定于 depth-2。v2-m5 的两次”流卡死”事后看大概率就是它——同一条根因的两种表象。

修复顺手把这类问题一次关死,确立一条不变量:depth-2 agent 零 ask、零用户交互,潜在阻塞一律 fail-fast

  • external_directory: {"*": allow}:Vision 纯只读(edit/bash 全禁、task 挂载闸天然拦截),最坏是读了不该读的文件——威胁模型是”防误操作、非防对抗”(第一篇 D37 同款哲学);
  • question / webfetch / websearch 全 deny:杜绝其余可能在深嵌套里等待用户的工具,触发即报错,绝不静默挂死。

验证三条,全部 headless 实测:depth-1 链路读工作区外图片正常返回;depth-2 生产等价链路(Committer→Vision,deepseek 无多模态必须委派——正是曾经的挂死组合)无阻塞;委派 Vision 自报工具清单只剩 glob, grep, read, skill——deny 真实生效,顺带排除了”frontmatter 未知字段被静默吞掉”的假阳性。

收益直接兑现:D40 时代”截图放仓库内或已放行目录”的规避条款作废,委派时路径随便给。

这条的经验可以抽象一层:与其指望模型在深嵌套里表现良好,不如让配置保证深嵌套里不可能发生需要人的事。确定性机制兜底,模型只管判断层——P6 原则在权限层的应用。

7. 品味层与新角色(D41 / D42)

V2 的 UI 开发暴露了另一类问题:coder 生成的界面有模板味,总结为AI 设计三大俗——奶油底衬线陶土色 / 近黑底荧光绿 / 报纸风零圆角。补法是双 skill 并存:

frontend-design(Anthropic) impeccable
形态 8KB 纯 SKILL.md 设计哲学 skill + 23 命令 + 59 条确定性检测 + live 浏览器迭代
作用方式 被动:生成新 UI 时自动加载,管”下限” 主动/impeccable critique/polish/bolder 定向迭代,管”上限”

分流靠 description 天然完成(”building new UI” vs “user wants to improve”),残余重叠最坏是双加载,内容互补无冲突。踩坑三条都实测过:非交互 shell 里 npx 首次下载的确认会挂死(须 -y);安装器的 --help 不是只读命令(走交互流程真装了,多装还误装了 Codex 构建);同名 skill 的 opencode 构建与 Codex 构建不可互换不可并存(/ 前缀 vs $ 前缀、脚本路径各指自家目录),误装清了一次。

D42 补的是角色空白:方案文档(DESIGN.md、TEST-CASES.md)本身的质量审查此前无人负责——Committer 审代码 diff 和 CASE_BUG 裁定,但”方案自洽吗、可测吗、和仓库现状一致吗”没人管。V2-DESIGN 的多轮评审(仅 §5 一章就两轮 P1×1/P2×6/P3×16/N×7)都是人肉完成的,Reviewer 把这件事角色化了:deepseek-v4-pro + max(与 Committer 同款跨族正交配置),定位在编排工作流之外——不进状态机、不占检查点、不占调用预告,用户在 build/plan 模式直接 @。输出契约对齐 Committer:P1/P2 问题清单 + 需澄清项 + verdict。

8. 演进方法论:这一轮学到的

第二版的七条决策记录,方法论上比内容本身更值钱:

  1. 修订闭环不变,且在加速。每条演进依然是”实跑证据 → 设计文档 → 配置/prompt”的三段闭环(D38-D44 无一例外),但 V1 的九轮修订跨度两周,这一轮从装眼睛到修完根因只用了 8 天——因为骨架稳了,挂件迭代没有心理负担。
  2. 遥测就位,行为可审计。D43 的全部结论来自对 opencode.db 的只读 SQL 考古(Tester 会话读图几次、调 Vision 几次、bash 命令分布),不凭印象评价新能力。模型行为第一次可以被度量。
  3. 不变量思维。D44 不是”教 Vision 小心使用权限”,而是让配置保证 depth-2 不可能 ask。凡是”永远不应当发生”的事,都往配置层沉。
  4. 熔断与降级是一等公民。m5 派工词一行”禁用 Vision”就是运行时熔断开关;降级不是失败,是能力引入流程的正常环节。
  5. 能力引入的正确节奏:新能力先当备胎,拿数据说话再决定转正还是维持备胎。Vision 从”解决语义验证缺口的主角”到”备胎”,不是打脸,是流程在正确地收敛。

9. 教训清单

给想复刻或继续演进这套流程的人排雷:

  1. 平台机制有两层:权限规则和工具挂载。”能不能调某个工具”要分层验证——权限放行 ≠ 工具在列表里(D40)。
  2. 嵌套深度改变权限可见性。depth-1 的 ask 能弹给用户,depth-2 的不会,只会无限等待。嵌套链条上的 agent 必须配置成零 ask(D44)。
  3. 多模态能力的延迟/成本/稳定性要实测。37.6s/次、5.1k token/次、幻觉率,这些是 demo 看不出来、一上量就致命的数字(D43)。
  4. 无状态调用 = 每次全量上下文。单次调用看起来干净,高频场景成本按次数线性砸——高频路径要么改有状态,要么换确定性工具。
  5. 验证配置生效要拿行为证据。让 agent 自报工具清单、用 mock 服务抓请求体;配置不报错 ≠ 生效(D36 与 D44 两次验证同一原则)。
  6. OPENCODE_CONFIG_CONTENT 注入不走严格校验,试验配置键必须用真配置文件(D40)。
  7. MCP 的 schema 常驻在 subagent 架构下是每会话重复税,CLI+Skill 是更贴的形态;但单 agent 长会话场景要重新算账(D39)。
  8. 第三方安装器的 --help 可能不是只读,非交互 shell 里 npx 会挂起——装东西前把退出路径想好(D41)。

10. 结论

盘点这一轮:V2 期间 9 个检查点照常交付,工作流侧 7 条决策记录;编排骨架零改动;唯一一次事故(m5 Vision 卡死)从熔断(08-27 派工词禁用)到降级定位(08-28 备胎化)到根因修复(08-30 零 ask 不变量),3 天闭环。

一句话:V1 证明这套工作流能交付一个完整项目;这一轮证明它能一边干活一边进化自己——而且进化本身也是工程化的:有决策记录、有验证记录、有熔断手段、有不变量,唯独没有”感觉应该”。

真正的变化在能力边界上:V1 的工作流是四个文本模型的状态机;现在它有眼睛(Vision/原生读图)、有手(playwright-cli 的 DOM 断言)、有品味(双设计 skill)、有方案评审(Reviewer)。这些都是挂件——骨架依然是那个”确定性的骨架上挂若干各司其职的模型”。

没动的依然是那三件:自建 skill 拆分(外部 skill 已经装了三个,内部 know-how 还躺在 prompt 里)、SDK 固化进 CI、迁移全局配置。条件在继续成熟——也许会有第四篇。


基于OpenCode的多Agent代码开发工作流:演进与优化
https://yq3.github.io/codelife/2026090101/
作者
yq3
发布于
2026年9月1日
许可协议