Vibe Coding近期经验总结

最近我在用 Vibe Coding 的方式开发叙事可视化工作站。项目目前只完成了一部分功能,还在持续开发,但这段时间遇到的问题已经非常多了。
一开始我以为,只要模型足够强、Prompt 写得足够详细,AI 就能把开发效率提升很多。后来才发现,模型能力只是其中一部分。真正决定最终结果的,是需求、任务拆解、上下文、验收标准、Agent 分工和代码集成。
换句话说,Vibe Coding 表面上是在让 AI 写代码,实际上是在管理一组会写代码的 Agent。
这里先把目前的一些经验记录下来。因为项目还在进行中,这些结论后面肯定还会继续调整和补充。
需求必须细到自己能够判断对错
这次最直接的一个教训,就是需求必须由我自己先搞清楚。
如果我自己都不知道要做什么,只是给 AI 一个很模糊的方向,例如“基于 OpenCode 做一个叙事视频客户端”,AI 大概率会自己补全缺失的信息。
问题是,AI 补出来的方向未必是我想要的。
这次项目早期就出现过这样的情况。我的真实需求是:
- 基于 OpenCode 已有客户端继续扩展;
- 保留 OpenCode 原有的模型切换、会话、Provider 和设置能力;
- 尽量通过 Skill、MCP 和配置扩展 Narrative 能力;
- 后续仍然能够比较方便地跟随 OpenCode 官方版本升级;
- 本地客户端负责创作者交互,无人值守生产仍然由服务端承担。
但这些约束一开始没有全部冻结下来。结果做出来的东西更接近重新写了一个独立客户端。它虽然也能启动,但 OpenCode 原来的很多能力都没有了,点一些功能还会提示连接失败。
站在局部实现的角度,它不是完全没有代码;但站在产品需求的角度,它从一开始就走错了。
所以需求不能只写到“要做一个什么东西”。它必须细到我能够判断:
- 用户点进去以后看到什么;
- 哪些原有功能必须保留;
- 哪些能力运行在客户端;
- 哪些能力必须运行在服务端;
- 第一个可运行版本包含什么;
- 哪些内容明确不做;
- 出现什么结果算正确;
- 出现什么结果说明方向错了。
我现在对需求粒度的判断标准是:
如果一个需求描述完以后,我仍然无法判断 AI 做出来的结果是对还是错,说明这个需求还不够细。
需求不一定非要手工逐字输入。我现在经常先通过语音把想法、犹豫和边界全部说出来,再让 AI 帮我整理成 Requirement、用户流程、非目标和验收条件。
但 AI 可以帮助整理需求,不能替我决定产品方向。最后的判断还是要由我来做。
不要一把梭,任务必须拆成可以独立检查的小块
需求明确以后,还不能把整个需求一次性交给一个 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 后,也不应该马上开始写代码。
我现在采用的方式是先让执行 Agent 生成 Plan。例如,一个任务准备交给 Kimi 执行,我会先让它用更适合规划的模型生成执行计划,然后把这份计划回传给总指挥审核。
总指挥重点检查:
- 计划有没有改变原始需求;
- 是否触碰禁止修改的路径;
- 是否复用了正确的已有能力;
- 是否遗漏依赖;
- 验收方法是否匹配用户结果;
- 是否和其他并行任务发生文件冲突。
计划修改确认以后,再让执行 Agent 进入编码阶段。
这个过程看起来多了一步,实际上能避免很多返工。因为修改一份 Plan 的成本,远低于修改一个已经写了几千行代码的分支。
当然,计划审核也要有停止条件。通常一到两轮足够。如果反复修改计划却始终不能执行,说明需求或架构本身还没有搞清楚,而不是应该继续润色 Prompt。
Vibe Coding本质上是一个管理问题
做到这里以后,我越来越觉得,Vibe Coding 本质上不是一个“会不会写 Prompt”的问题,而是一个管理问题。
需要管理的内容包括:
- 需求;
- 任务;
- 优先级;
- 依赖关系;
- Agent 分工;
- 文件所有权;
- 上下文;
- 代码分支;
- 测试预算;
- 验收证据;
- 合并顺序;
- 阶段停止条件。
这和管理一个开发团队很像。总指挥 Agent 相当于技术负责人,执行 Agent 相当于开发人员,Reviewer 相当于独立审核者,而 Requirement、接口合同和验收标准相当于团队共同遵守的工程规则。
所以一个好的管理者,确实更容易通过这一套机制产出质量更好的代码。因为他知道如何把一个模糊目标变成明确任务,如何分配负责人,如何检查结果,以及什么时候应该停止继续扩张。
但“同时指挥越多 Agent,效率就一定越高”也需要加一个前提:
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 让冲突晚一点出现,并不会让冲突消失。
这次还有几个非常具体的教训。
第一个是,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。
有些后续分支已经包含了前一个分支的实现,再次合并只会重复;有些分支虽然文件不冲突,但接口语义已经分叉,也不能直接拼接。
Worktree 是并行开发的基础设施,不是自动集成工具。
上下文应该分层,而不是全部塞进Prompt
多 Agent 调度中最麻烦的一点,是如何给每个 Agent 传递合适的上下文。
上下文太少,Agent 会自行补全需求;上下文太多,它又会把大量时间花在阅读和复述历史材料上,甚至被过期文档误导。
这次我们后来把上下文拆成了几层:
- 共同规格源:保存当前产品目标、架构和 Requirement;
- 项目规则:保存仓库边界、禁止修改路径和开发规范;
- 原子任务包:只描述当前任务的输入、输出、依赖和验收;
- 代码事实:以固定 Commit 和真实文件为准;
- 历史复盘:只用来解释为什么有这些规则,不直接充当当前需求。
这也解决了另一个问题:不能维护两个都声称自己是“共同事实源”的文档目录。否则不同 Agent 可能分别读取不同版本,最后各自都认为自己是按照文档实现的。
Prompt 不应该复制整个项目历史。它应该引用固定版本的规格,再提供当前任务真正需要的上下文。
目前形成的一套执行流程
结合这次的教训,我目前倾向于采用下面这套流程:
- 先通过讨论和语音输入,把需求细化到可以判断对错。
- 冻结目标用户、平台、核心流程、非目标和架构红线。
- 把需求落到唯一的共同规格源。
- 把工作拆成任务图,标注依赖关系和文件所有权。
- 为每个任务先定义验收标准、目标测试和证据。
- 由总指挥 Agent 生成子任务 Prompt。
- 子 Agent 先生成 Plan,不直接编码。
- 总指挥或另一个强模型审核 Plan。
- Plan 确认后,在独立 Worktree 中实现。
- 开发阶段只跑目标测试,不反复运行全量 Gate。
- 实现完成后,由不同模型做交叉审核和对抗式检查。
- 固定 Commit,再做集成、真实客户端验收和回滚检查。
- 达到阶段目标后立即形成一个可启动、可演示的版本。
- 后续功能进入下一轮,不要让当前阶段无限扩张。
这一套流程还比较依赖人工操作。现在我需要在多个工具之间复制 Prompt、Plan、审核意见、Commit 和测试结果,过程比较枯燥,也很容易漏信息。
我试过 Multica、T3 Code 一类的工具,但目前还没有找到特别顺手的方案。后面可能需要自己做一个总控工具,把任务图、上下文、模型选择、Worktree、审核和集成连接起来。
它不一定需要替 Agent 写代码。它首先应该解决的是管理问题:
- 当前有哪些任务;
- 哪些任务可以开始;
- 哪些 Agent 空闲;
- 每个 Agent 应该拿到什么上下文;
- 哪个 Plan 等待审核;
- 哪个分支等待集成;
- 哪份证据已经过期;
- 当前是否形成了可运行版本。
后续
这个项目目前只开发了一部分功能,所以这不是最终总结,只是一个阶段记录。
随着后续继续开发,肯定还会遇到新的问题。例如:
- 多 Agent 的最佳并发数量;
- 任务图如何自动生成;
- 如何自动选择不同模型;
- 如何减少计划和审核成本;
- 如何判断两个分支是冲突、重复还是可以组合;
- 如何让 Agent 自动完成阶段收口;
- 如何避免上下文在多轮调度中逐渐失真。
后面我会继续把实际遇到的问题补进来。
目前最需要记住的一点是:
不要把 Vibe Coding 理解成“把需求发给 AI,然后等代码回来”。它更像是在管理一个由多个 Agent 组成的开发团队。需求、分工、上下文、验收和集成没有管理好,模型越快,项目反而可能跑偏得越快。