反 Vibe Coding 范式
首先明确本文所使用的 Vibe Coding 概念的定义。本文中,它指开发者主要通过自然语言向 AI 描述需求、提出修改意见和反馈结果,以驱动 AI Agent 编程;开发者主要负责需求表达和结果评估,注意力从代码转向与 AI 的自然语言交互,具体实现更多交由 AI 自主完成。随着概念流行,出现了将所有 AI 辅助编程都归入 Vibe Coding 的倾向,这会模糊不同 AI 编程模式的边界,也易混淆性质不同的实践。因此,下文所称 Vibe Coding 仅指此义。
在 Vibe Coding 实践中,开发者通常使用 Agent 的 /plan 指令,结合自然语言描述的需求文档,让 AI 生成自然语言的开发计划。开发者审查并改进计划后让 AI 实施。不过,自然语言是一种信息密度非常低、夹杂着噪声且通常存在歧义的人机交互介质。阅读 AI 生成的文档给我带来的心智负担往往是阅读代码数倍。另外,AI 还经常不说“人话”,输出的内容里经常夹带一些不知所云的“术语”,看得人云里雾里。最后往往是按照 AI 的“推荐”选项一路“下一步”,先把代码生成出来看看。然后在漫长的等待后,发现 AI 拉了一坨大的。
有些开发者甚至颇为“自豪”地宣称,自从使用了某某 Agent 进行 Vibe Coding 后,他再也没有打开过 IDE。我很怀疑他究竟是在 Coding 还是在堆砌屎山。对于流行框架,AI 生成的代码通常中规中矩,如果是偏门框架或者自建框架,AI 会倾向于模仿同类流行框架设计代码结构,最后写出一堆不伦不类的东西,根本没法看。几轮迭代之后就会生成一滩不可描述之物。
代码会随着不断迭代而老化。如果采用不看生成代码、只管验证执行结果的黑盒式开发模式,会急剧加速代码的老化。或许有人认为,等代码腐烂到一定程度,再让 AI 根据旧代码整体重构,但这忽略了全量重构所带来的巨大时间成本与极其高昂的验证成本。相比之下,保持 Human-in-the-loop 的精细优化与增量重构,可以大幅降低代码老化速度。
我认为,在 AI Coding 中,应该弱化自然语言的比重,让代码作为人机交流的第一语言。这并不仅仅是因为代码的信息密度更高。与自然语言相比,代码还具有结构化、可验证、可比较和可追溯等优势。结构化意味着意图可以通过明确的语法和组织关系表达;可验证意味着代码可以通过编译、类型检查和测试检验其正确性;可比较意味着双方可以通过 diff 精确识别修改内容;可追溯则意味着每一次修改都可以关联到具体的版本和上下文。这些特性使代码不仅是一种实现工具,也是一种更适合人机协作的信息载体。
具体方法如下:
- 让 AI 生成包含注释的代码脚手架,替代自然语言描述的开发计划
- 开发者也可以直接编写代码脚手架和注释,让 AI 据此理解需求并生成或改进实现方案,替代自然语言描述的需求文档
- 开发者通过改动脚手架代码和注释向 AI 进行反馈。可以在每一处代码修改的位置留下注释来解释开发者的意图,以方便 AI 理解
- 和 Agent 约定一套注释交互标签,简化输入,提升效率。比如:
// REVIEW:要求 Agent 审查// ASK:向 Agent 提问,或者 Agent 要求开发者裁决// REMOVED:向 Agent 解释删除此处代码的原因// WHY:解释理由// KEEP:要求 Agent 保留此处代码不得改动
对于一个真正的开发者而言,用编程语言进行人机交互,永远优先于自然语言。实际上,开发者甚至不用了解 AI 生成代码的目标编程语言,而只要掌握一门编程语言即可和 AI 进行高效交流。完全可以用 TypeScript 写脚手架,然后 AI 最终生成 Go 代码。用于表达开发意图的语言,不必与最终实现所使用的语言一致。
这里有一个很大的误区:人们往往认为自然语言是一种低成本的、能精确表达自己真实想法的沟通方式——这些人通常对自己的表达能力有很大的误会——每个人都会说话,但这不意味着每个人都会表达。更重要的是,即使开发者认为自己已经准确表达了意图,也仍然需要额外确认 AI 是否真正理解了这些意图。
即然选择编程语言作为和 AI 的主要交流语言,那么目前 Agent 主流的聊天形式也不太适用了。完全可以用 Git 作为开发者和 AI 进行交流的介质。具体流程如下:
- 为每个 Agent 会话创建一个对应的 git 分支
- 每一轮对话生成一到两个 git commit。commit message 里用
ai:和user:区分是由哪一方创建的 - 开发者和 Agent 通过
git diff跟踪代码变化完成交流 - 通过
git reset和git revert重置或撤回一轮对话 - 将聊天内容写入 commit message
- 通过
git tag标记关键节点 - 一次会话结束,使用 squash 合并到开发分支,酌情保留会话分支
这样做的好处是,Git 不再仅仅承担代码版本管理的职责,还成为开发者与 Agent 之间的上下文管理和交互介质。
首先,Git Commit Hash 可以作为精确的上下文定位符。开发者和 Agent 不必依赖聊天记录中模糊的自然语言描述来引用此前的修改,而是可以直接通过 Hash 指定某次提交、某一阶段的代码状态,甚至限定 Agent 应当关注的代码变更范围。这样既能明确上下文边界,也能避免无关历史信息不断累积造成的上下文膨胀。
其次,Git 的差异比较、分支、回滚和标签等机制,天然提供了一套成熟的协作工具。开发者可以像审查其他开发者提交的代码一样审查 Agent 的工作,也可以精确地接受、拒绝或撤销某一轮修改,而不必在冗长的聊天记录中寻找和还原此前的状态。
最后,只要你的 Git 分支没有被删除,你的会话记录就存在。甚至可以在不同的 Agent 之间切换。
归根结底,反 Vibe Coding 并不是拒绝 AI 自主编程,也不是排斥自然语言,而是试图改变开发者与 AI 之间的协作方式:让开发者重新掌握技术表达和工程协作的主动权,而不是被动适应 Agent 的聊天交互模式。
以上核心思想可以归纳为两条:
- 用代码代替自然语言,作为开发者与 AI 的主要交流媒介。
- 用 Git 代替聊天记录,作为开发者与 AI 的主要交互载体。