搜索文章

输入关键词开始搜索

Vibe Coding近期经验总结

项目管理#Agent

Vibe Coding近期经验总结

最近我在用 Vibe Coding 的方式开发叙事可视化工作站。项目目前只完成了一部分功能,还在持续开发,但是这段时间遇到的问题已经非常多了。

一开始我以为,只要模型足够强、Prompt 写得足够详细,AI 就能把开发效率提升很多。后来发现模型能力只是一部分,决定最终结果的是需求、任务拆解、上下文、验收标准、Agent 分工和代码集成。Vibe Coding 表面上是让 AI 写代码,实际上是在管理一组会写代码的 Agent。

这里先把目前的经验记下来,项目还在进行中,后面还会调整和补充。

需求必须细到自己能够判断对错

这次最直接的一个教训,就是需求必须由我自己先搞清楚。

如果我自己都不知道要做什么,只是给 AI 一个很模糊的方向,比如“基于 OpenCode 做一个叙事视频客户端”,AI 很可能自己补全缺失的信息,补出来的方向未必是我想要的。

这次项目早期就出现过这样的情况。我的真实需求是:

  • 基于 OpenCode 已有客户端继续扩展;
  • 保留 OpenCode 原有的模型切换、会话、Provider 和设置能力;
  • 尽量通过 Skill、MCP 和配置扩展 Narrative 能力;
  • 后续还是能够比较方便地跟随 OpenCode 官方版本升级;
  • 本地客户端负责创作者交互,无人值守生产还是由服务端承担。

但是这些约束一开始没有全部冻结下来。结果做出来的东西更接近重新写了一个独立客户端。它虽然也能启动,但是 OpenCode 原来的很多能力都没有了,点一些功能还会提示连接失败。

站在产品需求的角度,它从一开始就走错了。

因此需求不能只写到“要做一个什么东西”,要细到我能够判断:

  • 用户点进去之后看到什么;
  • 哪些原有功能必须保留;
  • 哪些能力运行在客户端;
  • 哪些能力必须运行在服务端;
  • 第一个可运行版本包含什么;
  • 哪些内容明确不做;
  • 出现什么结果算正确;
  • 出现什么结果说明方向错了。

我现在对需求粒度的判断标准是:

如果一个需求描述完之后,我还是无法判断 AI 做出来的结果是对还是错,说明这个需求还不够细。

需求不用手工逐字输入。我现在经常先用语音把想法、犹豫和边界全部说出来,再让 AI 整理成 Requirement、用户流程、非目标和验收条件。产品方向最后还是我来定。

不要一把梭,任务必须拆成可以独立检查的小块

需求明确之后,不能把整个需求一次性丢给一个 Agent。

之前有些任务的范围太大,一个 Agent 同时做客户端入口、运行时、视频生成、结果展示、错误恢复和测试。最后即使它返回“任务完成”,我也很难判断到底是哪一部分完成了,哪一部分只是写了一个壳。

更麻烦的是,只要前面的架构理解错了,后面的代码就会沿着错误方向继续扩张。代码越多,返工成本越高。

更合适的方式是把需求拆成一个个可以独立观察、独立验证的纵切。比如:

  • OpenCode 能不能发现一个 Narrative Skill;
  • Skill 能不能调用一个本地 Tool;
  • Tool 能不能生成确定性的 MP4 和 Manifest;
  • 客户端能不能展示生成结果;
  • 用户能不能只重新生成其中一张图片;
  • 任务失败之后能不能从上一个阶段恢复;
  • 结果能不能安全导出到用户选择的目录。

每完成一块,就马上检查一块,确认正确,后面的依赖任务才继续。

这里的“独立”除了代码文件不重叠,还包括:

  • 有独立的用户可观察结果;
  • 有明确的输入和输出;
  • 有自己的验收标准;
  • 失败时能够定位到这一块;
  • 可以单独提交和回滚。

这和传统软件工程其实没有区别,AI 把编码速度提高了,模块边界、接口设计和依赖管理还是要做。而且 AI 写代码太快,任务边界没拆好,它能更快地制造一大批互相纠缠的代码。

先定义怎么验收,再让 Agent 开始编码

这次还有一个很明显的问题:有时候任务已经开始执行了,我们才开始讨论怎么判断它是否完成。

结果是 Agent 自己选了最容易证明的成功标准。

比如,产品目标是“用户可以在官方 OpenCode Desktop 里调用 Narrative 能力并看到视频结果”,但是 Agent 最后证明的可能只是:

  • 某个 Python 脚本可以运行;
  • Fixture 返回了预期数据;
  • 测试文件通过了;
  • 某个原型目录里生成了 MP4。

这些证据有价值,但是替代不了最终产品结果。

这次就出现过三个 Agent 写出了不少可以验证的原型,代码主要落在 rebaseline 目录里,测试和报告也做了很多,但是代码没有真正进入 OpenCode 的正式扩展路径。结果就是局部测试可以通过,客户端里却没有一个可以直接体验的完整版本。

因此现在每个任务都应该在编码之前先确定:

  • Requirement 是什么;
  • Acceptance Criterion 是什么;
  • 用什么 Test Oracle 判断;
  • 运行哪条命令;
  • 用户最终能观察到什么;
  • 证据保存在哪里;
  • 哪些测试只是 Fixture;
  • 哪些测试才是真实 Desktop 或真实服务验证;
  • 到什么程度可以停止。

测试不是越多越好,要看它证明的是不是正确的问题。

之前我还发现,有些 Agent 会花大量时间反复跑完整 Gate。测试跑了很久,报告越来越多,但是用户功能没有增加。后面我们专门增加了 Gate Budget:开发过程中只跑目标测试,全量 Gate 在阶段收口时再跑。

不然测试本身也会变成局部最优。

一定要多模型交叉审核,但是要审核关键决策

单个模型很容易在某一个假设上持续走偏。

假设一个十步任务中,每一步独立做对的概率都是 80%,那么十步全部正确的概率只有:

0.8^10 ≈ 10.7%

真实的开发各步骤不是完全独立的,但是长链任务只靠一个 Agent 自己规划、自己实现、自己测试、自己宣布完成,风险很高。

因此我现在会尽量做两种审核。

第一种是多模型交叉审核。同一份架构方案、任务拆解或者验收结果,让不同模型分别检查,看它们是否能发现不同的问题。

第二种是对抗式审核,审核 Agent 不帮实现者证明它是对的,主动去找:

  • 它依赖了哪些没有验证的假设;
  • 有没有写错仓库或目录;
  • 有没有把 Fixture 当成真实产品;
  • 有没有遗漏原有功能;
  • 证据和当前代码是不是同一个版本;
  • 测试通过是否真的对应用户结果;
  • 失败之后能不能回滚;
  • 多个分支是否真的可以合并。

这次预验收中就发现过一个比较典型的问题:某个任务的报告声称上游依赖已经通过,但是实际读取对应报告时,上游任务还是失败状态。还有一条支线的代码已经可以正常运行,但是它提交的 Artifact 还是早期失败版本。

只看“有没有报告”,这两个任务都有证据,交叉检查之后才发现,证据和代码不一致。

多模型审核也不用让多个模型把所有内容从头看一遍,优先放在这些高风险位置:

  • 产品方向;
  • 架构边界;
  • 任务依赖;
  • 公开扩展面;
  • 数据和接口合同;
  • 合并方案;
  • 阶段验收。

每个小改动都做三轮全量审核,开发很快就会被审核成本拖死。

需要一个强模型作为总指挥

我目前比较认可的方式,是设置一个强模型作为总指挥。

比如这次我会让 GPT-5.6 Sol Extra High 承担总控,再把具体任务分给 GLM、Kimi 和其他 Codex 会话。

总指挥主要负责:

  • 保存完整项目上下文;
  • 理解最终产品目标;
  • 维护当前规格和架构红线;
  • 把需求拆成任务图;
  • 判断哪些任务可以并行;
  • 为子 Agent 生成 Prompt;
  • 审核子 Agent 的计划;
  • 分析各分支之间的依赖和冲突;
  • 制定合并和阶段收口方案。

总指挥最好不要同时陷入某一个局部实现,一边管理全局、一边连续修改某个模块,很容易被局部上下文占满,失去全局视角。

子 Agent 拿到 Prompt 后,也不要马上写代码,我先让它生成 Plan。比如一个任务准备让 Kimi 执行,我会先让它用更适合规划的模型生成执行计划,再把计划回传给总指挥审核。

总指挥重点检查:

  • 计划有没有改变原始需求;
  • 是否触碰禁止修改的路径;
  • 是否复用了正确的已有能力;
  • 是否遗漏依赖;
  • 验收方法是否匹配用户结果;
  • 是否和其他并行任务发生文件冲突。

计划确认之后,再让执行 Agent 编码。

这样多了一步,但是能避免很多返工,修改一份 Plan 的成本远低于修改一个已经写了几千行代码的分支。

计划审核通常一到两轮就够。如果反复修改计划还是不能执行,是需求或架构还没有搞清楚,继续润色 Prompt 没用。

Vibe Coding 是一个管理问题

做到这里,我越来越觉得 Vibe Coding 是管理问题,和会不会写 Prompt 关系不大。

要管理的有:

  • 需求;
  • 任务;
  • 优先级;
  • 依赖关系;
  • Agent 分工;
  • 文件所有权;
  • 上下文;
  • 代码分支;
  • 测试预算;
  • 验收证据;
  • 合并顺序;
  • 阶段停止条件。

这和管理一个开发团队很像。总指挥 Agent 相当于技术负责人,执行 Agent 相当于开发人员,Reviewer 相当于独立审核者,而 Requirement、接口合同和验收标准相当于团队共同遵守的工程规则。

好的管理者更容易用这套机制产出质量更好的代码,因为他知道怎么把模糊目标变成明确任务,怎么分配负责人,怎么检查结果,什么时候该停止扩张。

同时指挥的 Agent 越多,效率不一定越高:

Agent 数量只有在独立任务、接口合同、审核能力和集成能力同时增加时,才会变成有效产出。

只有三个可以独立执行的任务,同时启动一百个 Agent,只会产生大量重复实现、冲突分支和审核负担。要锻炼的是:

  • 能不能把工作拆成足够多、又互相独立的任务;
  • 能不能让每个 Agent 拿到刚好够用的上下文;
  • 能不能自动判断依赖是否满足;
  • 能不能快速发现跑偏;
  • 能不能把产出稳定地集成为一个可运行版本。

一百个 Agent 的瓶颈可能不是模型调用速度,是管理者的集成带宽。

串行、并行和任务图

要最大化 Vibe Coding 的效率,得区分哪些任务串行,哪些任务并行。

适合并行的任务通常满足:

  • 从同一个固定代码基线开始;
  • 输入和输出合同已经确定;
  • 修改的文件范围不重叠;
  • 不需要等待另一个任务决定产品方向;
  • 可以独立测试;
  • 失败不会破坏其他任务。

必须串行的任务通常包括:

  • 产品范围还没冻结;
  • 公共接口还没确定;
  • 后续任务依赖前一个任务产生的数据结构;
  • 多个任务会修改同一个核心文件;
  • 必须先完成基础能力,才能判断后面的方案是否可行。

这次我们后来把接入工作拆成了 A、B、C 三部分。A 先确定正式扩展载体和共同接口;A 冻结之后,B 和 C 才能分别开发 Runtime 和 Artifact 能力。

如果 A 没完成就同时启动 B、C,它们很可能各自发明一套接口,三个 Agent 都在干活,后面重新对齐花的时间更多。

因此我用的是任务图,不用任务列表:

需求和架构冻结
        ↓
共同合同 A
      ↙   ↘
 Runtime B   Artifact C
      ↘   ↙
    集成与真实验收
        ↓
    阶段版本

任务图中的节点是可交付任务,边表示依赖,上游节点满足完成条件之后,才启动下游任务。

如果能进一步自动化,总指挥 Agent 就可以根据任务图自动选择空闲 Agent、生成 Prompt、分配 Worktree、收集结果,再触发审核和集成。我感觉这比单纯增加一个聊天客户端更有价值。

Worktree 是并行开发的隔离机制

这次项目里大量使用了 Git Worktree,很适合多 Agent 并行开发,也踩了不少坑。

一个 Git 仓库可以建立多个 Worktree。每个 Worktree 有自己的工作目录、分支和 HEAD,但是共享同一个 Git 对象库。

对多 Agent 开发来说,不同 Agent 不用在同一个目录里反复切换分支,也不用共享一份正在变化的工作区。

我用的约定是:

  • 一个 Agent 对应一个任务;
  • 一个任务对应一个分支;
  • 一个分支对应一个 Worktree;
  • 所有并行任务从同一个固定 Commit 创建;
  • 每个任务声明允许修改的路径;
  • Agent 不能修改其他任务拥有的文件;
  • 完成后提交到自己的分支;
  • 由单独的集成任务决定如何合并。

Worktree 只隔离工作目录,解决不了架构冲突。三个 Agent 在三个 Worktree 中工作,如果都修改同一批入口文件,或者各自设计了一套不同的接口,最后还是会冲突,只是冲突晚一点出现。

这次还有几个具体的教训。

第一个,Worktree 的物理路径不代表它属于哪个 Git 项目。

我们曾经看到一个 Worktree 放在 narrative-vision/.worktrees/ 下面,下意识以为代码写进了 narrative-vision。后来通过 .git 指向和 git worktree list 才确认,它实际上属于 narrative-code,只是物理目录放在了另一个项目下面。

因此判断 Worktree 归属要运行下面这些命令,光看文件夹名称不行:

git rev-parse --show-toplevel
git branch --show-current
git rev-parse HEAD
git status --short
git worktree list

第二个,未跟踪文件不会自动进入分支历史。

这次主工作区里有一批未跟踪但有价值的正式扩展代码。因为没有 Commit,只检查分支 Diff 很容易得出“这里没有实现”的错误结论,这时直接清理 Worktree,或者从干净基线重新开发,就可能把已有实现删掉或者重复写一遍。

因此在迁移、合并和清理之前,除了 tracked diff,还要检查:

  • modified 文件;
  • untracked 文件;
  • ignored 文件;
  • 生成产物;
  • 文件校验值;
  • 是否已经存在仓库外备份。

第三个,Worktree 完成不等于功能已经集成。

某个 Agent 在自己的 Worktree 里测试通过,说明这个分支在自己的环境里达标了,没有证明:

  • 能和其他分支一起工作;
  • 没有重复实现;
  • 没有覆盖别人的能力;
  • 能从共同基线稳定合并;
  • 最终客户端真的可以启动;
  • 用户能够走完完整流程。

因此合并之前要检查分支祖先、路径重叠和功能包含关系,三个 Agent 都完成了,也不要把三个分支全部 Merge。有些后续分支已经包含了前一个分支的实现,再合并只会重复;有些分支文件不冲突,接口语义已经分叉,也不能直接拼接。

上下文分层,不全塞进 Prompt

多 Agent 调度中最麻烦的,是给每个 Agent 传递合适的上下文。上下文太少,Agent 会自己补全需求;太多,又会把大量时间花在阅读和复述历史材料上,甚至被过期文档误导。

这次后来把上下文分成了几层:

  • 共同规格源:保存当前产品目标、架构和 Requirement;
  • 项目规则:保存仓库边界、禁止修改路径和开发规范;
  • 原子任务包:只描述当前任务的输入、输出、依赖和验收;
  • 代码事实:以固定 Commit 和真实文件为准;
  • 历史复盘:只用来解释为什么有这些规则,不直接充当当前需求。

还要避免两个都声称自己是“共同事实源”的文档目录,不然不同 Agent 读到不同版本,各自都认为自己是按文档实现的。

Prompt 不要复制整个项目历史,引用固定版本的规格,再补上当前任务需要的上下文就行。

现在的流程还靠人工

现在我需要在多个工具之间复制 Prompt、Plan、审核意见、Commit 和测试结果,过程比较枯燥,也很容易漏信息。

我试过 Multica、T3 Code 一类的工具,目前还没有找到特别顺手的。后面可能要自己做一个总控工具,把任务图、上下文、模型选择、Worktree、审核和集成连接起来,先解决管理问题,不一定要替 Agent 写代码:

  • 当前有哪些任务;
  • 哪些任务可以开始;
  • 哪些 Agent 空闲;
  • 每个 Agent 应该拿到什么上下文;
  • 哪个 Plan 等待审核;
  • 哪个分支等待集成;
  • 哪份证据已经过期;
  • 当前是否形成了可运行版本。

后续

后面开发中还会遇到新的问题,比如:

  • 多 Agent 的最佳并发数量;
  • 任务图如何自动生成;
  • 如何自动选择不同模型;
  • 如何减少计划和审核成本;
  • 如何判断两个分支是冲突、重复还是可以组合;
  • 如何让 Agent 自动完成阶段收口;
  • 如何避免上下文在多轮调度中逐渐失真。

后面我会继续把实际遇到的问题补进来。