1. Vibe Coding 的概念与起源
2025 年 2 月,Andrej Karpathy 在推特上发了一条帖子,大意是:他现在写代码基本靠"感觉",告诉 AI 要什么,看一眼输出,感觉不对就再说,感觉对了就继续——他把这叫做 Vibe Coding。
这个词很快就传开了,因为它说出了很多开发者正在做但没想到要命名的事。
Vibe Coding 的典型操作流程
你:帮我写一个用户登录接口,用 NestJS,JWT 认证
AI:[给出一段代码]
你:运行,报错
你:帮我修一下这个错
AI:[修了]
你:好像可以了,继续下一个功能
这没什么不好。对于原型、个人项目、探索性开发,Vibe Coding 极其高效。Karpathy 自己也说了,这套路"对某些项目完全奏效"。
问题在于:当项目变大、团队变多、需要持续维护的时候,Vibe Coding 的天花板就来了。
2. Vibe Coding 的天花板在哪
用一个真实场景来说明。
场景:做一个用户管理模块
Vibe Coding 的方式
创建一个用户管理的 NestJS 接口,支持增删改查
AI 会给你一份代码,能跑,看起来挺完整。然后你继续做下一个功能:
加一个角色权限控制
用户列表加分页和搜索
密码需要加密存储
每次对话,AI 都不知道前几次发生了什么。它不知道你用的是什么数据库驱动,不知道你的错误格式是什么,不知道你的接口是 REST 还是 GraphQL,不知道你的分页是基于 cursor 还是 page number。
于是:
- 第一次生成用了
class-validator,第三次改成了手写校验 - 有的接口返回
{ data: ... },有的直接返回数组 - 密码加密有的用 bcrypt,有的用 bcryptjs,版本不一致
- 错误处理有的抛
HttpException,有的throw new Error
代码能跑,但质量在悄悄腐烂。这就是 Vibe Coding 的天花板:输出的一致性无法保障,项目越大越难控制。
3. 从 Prompt 到 Production:中间缺了什么
一个 Prompt 和一个上线的功能之间,差的不只是代码。
| 阶段 | Vibe Coding 的状态 |
|---|---|
| 需求 | 模糊的自然语言,凭感觉说 |
| 设计 | 没有,让 AI 自己决定 |
| 数据模型 | 每次对话重新生成,可能不一致 |
| 接口契约 | 没有文档,AI 每次可能给不同结构 |
| 错误处理 | 随机,取决于 AI 当次的"心情" |
| 测试 | 基本没有,或者是事后补的 |
| 一致性 | 依赖开发者肉眼 review |
Spec Coding 要做的事情,就是把"需求"这一层补完整:
在写第一行代码之前,先把"AI 需要知道的所有事情"写成文档
这份文档叫做 spec.md。
4. AI 编程范式的跃迁
把 AI 编程的演进简单分三代:
第一代:补全助手(Copilot 时代)
AI 帮你写下一行、下一个函数。你还是主要的思考者,AI 是打字员。
// 你写:
function getUserById(
// AI 补全:
id: number): Promise<User> {
return this.userRepository.findOne({ where: { id } });
}
第二代:对话式生成(Vibe Coding 时代)
你描述意图,AI 给出完整实现。上下文依赖人脑管理。
你:给我写一个 NestJS 的用户 CRUD 模块
AI:[完整输出 controller + service + module]
第三代:Spec 驱动开发(Spec Coding 时代)
你写规格文档,AI 按规格执行,上下文由文档承载,不靠对话记忆。
你:按照 @spec/user.md 实现用户模块,
遵循 .cursorrules 的代码风格,
参考 @spec/api.md 的接口格式
AI:[严格按规格生成,格式一致、风格统一]
核心区别:Spec Coding 把"上下文"从对话历史转移到了文档。AI 不需要记住你之前说过什么,因为所有约定都在文档里。
5. 开发者的超级能力放大器
有一个比喻很好用:
Vibe Coding 好比你雇了一个手艺不错的工人,但每次干活你都得在旁边盯着,口头告诉他每个细节。
Spec Coding 好比你给了工人一份完整的施工图纸——他按图施工,你去干别的事,回来验收就行。
对于独立开发者,Spec Coding 的意义在于:你可以同时"管理"多个 AI 并行工作。
对于带团队的开发者,意义在于:Spec 文档本身就是团队协作的基础,新人对着 spec 就能上手,而不是靠口口相传。
6. 一个完整的对比示例
❌ Vibe Coding 方式
# 第一次对话
"帮我创建一个用户管理的 NestJS 接口,支持创建用户和查询用户列表"
# 第二次对话(新开)
"帮我加一个更新用户的接口,需要校验邮箱格式"
# 第三次对话(又新开)
"用户查询接口加个分页"
结果:三次对话生成的代码,接口返回格式不同、校验风格不统一、分页参数命名也不一样(一个用 page,一个用 pageNum)。
✅ Spec Coding 方式
先写 spec/user.md:
## 用户模块接口规范
### 统一返回格式
所有接口返回 Result 包装:
{
"code": 0,
"message": "ok",
"data": { ... }
}
### 分页参数约定
- page: number(从 1 开始)
- pageSize: number(默认 20,最大 100)
### 字段校验
- email: 必须符合 RFC 5322,使用 class-validator @IsEmail()
- password: 8-32 位,包含大小写字母和数字
### 接口列表
POST /users 创建用户
GET /users 查询列表(支持分页 + 按 name/email 搜索)
GET /users/:id 查询单个
PATCH /users/:id 更新用户
DELETE /users/:id 软删除(is_deleted 标记)
然后每次对话:
"按照 @spec/user.md 实现用户模块,
使用 Prisma 操作数据库,
遵循 .cursorrules 的项目规范"
每次生成的代码,结构一致、格式统一、命名规范——因为规范在文档里,不在你的脑子里
7. 小结
Vibe Coding 是 AI 编程的起点,它降低了动手的门槛,让"说人话就能生成代码"成为现实。
但它的天花板很明显:没有规格约束的 AI,就像没有图纸的施工队——每个人都在凭感觉干活,最后拼在一起是一团乱。
Spec Coding 不是让你写更多文档、更多规矩。它的核心只有一件事:
把原本藏在你脑子里的、靠每次对话重新交代的上下文,变成可以被 AI 稳定读取的结构化文档
这一步做到,AI 才真正成为你的工程搭档,而不是每次都要重新带入门的实习生。