Skip to content
概述
Vibe coding(共鸣编程)是 Andrej Karpathy 在 2025 年提出的术语,描述一种以自然语言表达意图、由大型语言模型生成代码,并通过观察运行行为进行迭代的编程方式。它将开发者的注意力从“如何实现”转移到“想要什么”以及“结果是否正确”,使认知负荷从实现细节重新分配到意图表达和结果验证上。
基本概念
Vibe coding 的核心不是“用 AI 写代码更快”,而是改变了编程过程中的认知分工:人负责定义需求、给出约束、审查行为;模型负责生成代码。在这一模式下,开发者可能并不完全理解生成的每一行代码,正确性主要通过对运行结果的验证、自动化测试和类型检查来保证。
与传统 AI 辅助编程的区别
以下光谱展示了不同编程方式的特征:
传统编程 AI 辅助编程 Vibe Coding 全自主 AI
│ │ │ │
手写每一行 AI 补全代码 描述意图→AI生成 AI 自主决策
完全理解实现 理解实现 可能不理解实现 完全黑盒
调试=读代码 调试=读代码+AI帮助 调试=描述问题+AI修复 调试=AI自主修复- 传统编程:开发者手写每行代码,并完全理解实现细节。
- AI 辅助编程(如 GitHub Copilot):AI 在开发过程中提供补全建议,开发者仍需理解并确认每处逻辑。
- Vibe coding:开发者用自然语言描述功能需求,AI 生成完整代码片段甚至整个文件。开发者通过运行代码、自动化测试来验证,遇到问题后用自然语言反馈差异让 AI 修正。部分实现细节可以不必逐行阅读。
- 全自主 AI:AI 自行读取需求、规划、实现并提交结果,开发者仅看到最终产物。
Vibe coding 位于第三阶段——它不要求开发者对所有生成代码拥有完全的理解,但要求开发者有能力判断代码的行为是否符合预期。
工作原理
技术前提
Vibe coding 能够成立,依赖于三个条件的同时满足:
- 模型能力:当前的大型语言模型(如 Claude、GPT-4 系列)已能在常见编程任务中生成可通过简单验证的代码——虽不完美,但可用。
- 迭代成本:交互方式从“重写 prompt、等待数分钟”下降到接近口语对话的水平。开发者可以在对话中连续纠正“这里不对,改成用 A 而不是 B”,交互成本接近与人结对编程。
- 验证手段:TypeScript 的类型系统、自动化测试、lint 工具、热重载等基础设施,让“不读代码也能验证行为”成为可能。如果每次生成后都必须逐行 review 才能确认正确性,验证成本会超过编写成本,vibe coding 便无法落地。
工作循环
一次典型的 vibe coding 迭代包含以下步骤:
- 描述意图:用自然语言给出功能需求、输入输出以及明确的约束。
- 生成代码:AI 模型根据 prompt 输出代码文件或代码块。
- 自动验证:运行类型检查、lint、单元测试等自动化门禁。
- 行为验证:启动应用或脚本,观察行为是否符合预期。
- 反馈修正:若不符合,用自然语言描述差异(包括错误信息、异常行为),让模型生成修正版本;重复直至通过所有验证。
验证是这一循环的中心环节。因为开发者可能未逐行理解代码,自动化验证与行为观察成为质量兜底的手段。
基本用法
工具要求
Vibe coding 最自然的载体是 Agent 模式的工具,这类工具能够读取项目文件(获取上下文)、写入代码(生成实现)、执行命令(运行测试、类型检查)。常用的 Agent 工具包括 Claude Code、Cursor Agent、Windsurf 等。普通的代码补全工具或独立的对话面板难以形成完整闭环,因为需要手动复制代码并切换上下文。
编写 Prompt
Vibe coding 的质量高度依赖 prompt 的质量。一份清晰的 prompt 应包含:
- 上下文:当前技术栈、相关模块、已有的类型或接口。
- 输入/输出:功能接收什么、返回什么。
- 约束:性能要求、错误处理策略、边界情况处理。
- 反例:明确说明“不要做什么”,例如“不要引入新的依赖”“不要使用全局状态”“错误应向上抛出,不得内部吞掉”。
Prompt 不是临时对话,它实际上是功能的规格说明,应当纳入版本控制,便于后续追溯设计意图。
验证门
所有 AI 生成的代码在合并前必须通过以下硬性验证:
- 类型检查(TypeScript strict mode,零错误)
- Lint 检查
- 自动化测试(至少覆盖正常路径与一个错误路径)
- 手动行为验证(在本地或 staging 环境中实际运行观察)
如果代码未能通过上述任何一项,应将报错信息直接反馈给模型,让其修正。
简单示例(Node.js)
需求:编写一个 Node.js 脚本,读取当前目录下的 data.txt 文件,文件中每行一个数字,计算这些数字的平均值并输出,保留两位小数。若文件不存在,输出错误信息。不使用第三方库。
Prompt:
text
用 Node.js 写一个脚本,读取 data.txt,每行一个数字,计算平均值并打印,保留两位小数。
如果文件不存在,输出错误信息。不要使用第三方库。AI 生成的初始代码:
javascript
const fs = require('fs');
const path = require('path');
const filePath = path.resolve('data.txt');
fs.readFile(filePath, 'utf8', (err, data) => {
if (err) {
console.error('Error reading file:', err.message);
return;
}
const lines = data.trim().split('\n');
const numbers = lines.map(Number);
const valid = numbers.filter(n => !isNaN(n));
if (valid.length === 0) {
console.log('No valid numbers found.');
return;
}
const sum = valid.reduce((acc, n) => acc + n, 0);
const avg = sum / valid.length;
console.log(avg.toFixed(2));
});检查行为:通过 node script.js 执行,验证几个典型文件(包含正常数据、空行、非数字行),确认输出正确。若发现边界情况处理不当(例如文件仅包含空行时输出“无有效数字”),可反馈给 AI 修正:“当没有有效数字时,不输出任何结果并返回非零退出码”。模型会更新代码,再重新验证。
工具
不同工具对 vibe coding 的适用性差异很大,核心差别在于上下文范围与交互模式:
| 工具类型 | 代表产品 | 交互方式 | 适用程度 |
|---|---|---|---|
| 行内补全 | GitHub Copilot, Supermaven | 在编辑器中逐行补全 | 低——只能加快单行书写,无法生成完整功能或自主迭代 |
| 对话面板 | Copilot Chat, Claude.ai | 对话中生成代码块,手动复制 | 中——可生成功能片段,但上下文割裂,需人工整合 |
| Agent 模式 | Claude Code, Cursor Agent, Windsurf | 直接读写文件、执行命令 | 高——可围绕整个项目迭代,交互成本最低 |
| 全自主 Agent | Devin, Factory | 独立完成整个 issue,过程不完全透明 | 功能最强,但可控性与可验证性较低 |
Agent 模式因其能直接操作文件系统并运行验证命令,是 vibe coding 最有效的载体。使用 Agent 模式时需注意,AI 可能同时修改多个文件,应在版本控制下工作,并辅以前述的自动化验证门,以防止引入跨模块的不一致。
示例:构建带搜索与分页的 Node.js 数据服务
以下展示一个更完整的工作流:使用 vibe coding 在 Node.js + Express + TypeScript 项目中实现一个内存数据存储的查询接口。
第一轮:生成基础实现
Prompt:
text
项目使用 Node.js + Express + TypeScript。
需要实现一个 /api/items 端点,支持 GET 请求,查询参数包括:
- q (搜索关键词,匹配 item.name 中的子串,忽略大小写)
- page (页码,默认 1)
- pageSize (每页条数,默认 20)
数据源是一个内存中的 Item 数组:
interface Item {
id: string;
name: string;
category: string;
}
返回值格式:
{
items: Item[],
total: number,
page: number,
pageSize: number
}
约束:
- 使用 Express 路由,不要引入额外的 ORM 或数据库库
- 所有类型必须有完整的 TypeScript 类型
- 分页页码从 1 开始,page 和 pageSize 参数非正整数时应回退到默认值
- 查询时先过滤再分页AI 生成 itemRoutes.ts:
typescript
import { Router, Request, Response } from 'express';
interface Item {
id: string;
name: string;
category: string;
}
const items: Item[] = [
{ id: '1', name: 'Alpha', category: 'A' },
{ id: '2', name: 'Beta', category: 'B' },
// ... 更多数据
];
const router = Router();
router.get('/api/items', (req: Request, res: Response) => {
const q = (req.query.q as string) || '';
const page = Math.max(1, parseInt(req.query.page as string) || 1);
const pageSize = Math.max(1, parseInt(req.query.pageSize as string) || 20);
const filtered = items.filter(item =>
item.name.toLowerCase().includes(q.toLowerCase())
);
const total = filtered.length;
const start = (page - 1) * pageSize;
const paged = filtered.slice(start, start + pageSize);
res.json({
items: paged,
total,
page,
pageSize,
});
});
export default router;编译通过,手动测试 /api/items?q=alpha 返回相应数据。
第二轮:修复边界情况
验证发现:当 page 超出总页数时,返回空数组,但 total 仍为过滤后的总数,分页信息未体现越界。另外,未处理 q 参数为纯空格的情况。
修正 Prompt:
text
两个问题:
1. 如果 page 超过最大页数,应返回空数组,但 total 依然正确。此外,响应中可以添加 maxPage 字段以帮助客户端判断。
2. 搜索关键词为纯空格时,应当等同于无搜索条件,返回全部数据。
请更新实现。AI 更新代码,为 res.json 增加 maxPage 字段,并在过滤前将 q.trim() 后的结果作为判断依据。
第三轮:优化与最终审查
- Express 每个请求都是独立的,对过滤结果没有必要进行跨请求缓存。如果 AI 在生成代码时添加了不必要的性能优化注释,可要求其删除。
- 确认错误处理:对于非数字字符串参数,已通过
parseInt和||降级处理,无须额外修改。 - 运行
tsc --strict、eslint以及针对搜索、分页、边界页码的集成测试,全部通过。
最终获得约 60 行的路由文件,遵循项目现有结构,可直接挂载到 Express 应用。
时间对比:
- 纯手写并调试可能需要 1.5 小时。
- 通过 vibe coding 分三轮完成,耗时约 25 分钟(编写 prompt 5 分钟,生成与运行验证 10 分钟,两轮修复 10 分钟)。过程中对关键逻辑(分页计算、过滤)做了确认,并非完全不读代码。
注意点
理解债务
如果通过 vibe coding 生成大量代码但只理解其中一小部分,剩余部分会形成“理解债务”。当需要修改核心逻辑、排查实际运行故障或进行架构升级时,这些债务会一次性到期。建议每完成一个功能模块后,花 15~30 分钟回溯关键路径和数据流,而不必逐行阅读实现细节。这有助于在负债规模还小的时候清偿。
调试能力退化
传统的调试依赖于通过阅读代码推断行为的能力。如果长期依赖“将错误信息复制给 AI—>应用修复”的循环,这项能力会因为缺少练习而下降。一旦遇到 AI 无法解决的难题,自身排查效率会明显减弱。保留一部分手动调试或阅读代码的实践,可以延缓这种退化。
架构的局部最优陷阱
AI 生成代码通常倾向于在单个函数或文件内做到正确,但多个功能之间的全局一致性(错误处理策略、状态管理、依赖方向)需要刻意约束。如果不主动在 prompt 中要求并 review 这些全局属性,系统会逐渐积累循环依赖、不一致的异常处理、散落的全局状态等反模式。这些问题不会在单次功能验证中暴露,而在系统规模增大后以难以定位的形式显现。
所有权感缺失
亲手编写的模块通常会伴随较强的维护动机和心理所有权。由 AI 生成的代码在心理上容易被归为“外部产物”,当出现 bug 时第一反应往往是“让 AI 修复”而非深入排查根源。这种倾向不会在单个功能上产生问题,但会影响系统的长期维护质量。有意识地进行定期 review 并将关键模块的所有权明确标记(如 CODEOWNERS 文件)可以部分缓解。
分层使用
将系统划分为三个层次,不同层次采用不同的编程方式,可以平衡效率与风险:
- 核心层(基础设施、认证、核心业务逻辑、核心数据模型):由开发者手写,保证完全理解。
- 功能层(CRUD 页面、表单、常规接口):可用 vibe coding 生成,但必须经过人工 review 确认关键路径的正确性。
- 样板层(配置文件、类型定义、简单工具函数):完全可由 vibe coding 生成,仅需通过自动化验证门即可。
Prompt 与版本控制
每次 vibe coding 使用的 prompt 应作为代码规格的一部分保存到版本库中。这样在后续回溯设计意图或排查与规格不符的行为时,能有明确的依据。
限制
Vibe coding 不适合以下场景:
- 核心算法与数据结构:需要精确推理,不适合依赖模式匹配。
- 安全关键代码:认证、授权、加密等模块必须逐行理解,不能依赖表面正确性。
- 跨模块的复杂状态管理:AI 难以主动发现全局不一致和副作用风险。
- 性能极度敏感的代码:AI 通常输出“正确但不高效”的实现,需要进行深度优化时,往往需要理解 CPU 缓存、内存布局、GC 行为等底层细节。
- 系统级 bug 的调试:当问题源于架构假设错误而非局部代码缺陷时,AI 擅长的局部修复会不断掩盖根因。
此外,如果一项任务的描述需要 10 句话以上才能表达清楚,或验证结果需要超过几分钟的复杂分析,通常意味着该任务的理解或验证成本过高,此时手写加调试可能是更合适的方式。
应用
以下场景适合引入 vibe coding:
- CRUD 类页面及表单:模式固定,验证简单。
- 一次性工具脚本:数据转换、文件批处理、迁移脚本等。
- 样板代码:类型定义、配置、测试桩。
- 快速原型:在短时间内产出可交互的界面或接口。
- 已知问题域的重复实现:开发者清楚大致正确的实现形态,只是不想手写。
团队在引入时,可以从非关键模块(如内部工具、管理后台的某个页面)开始试点,逐步建立适用于自身项目的 prompt 规范、验证门和分层策略,验证有效后再扩展使用范围。
参考链接
- Karpathy, A. (2025). Vibe coding. [Tweet]. X. 可在主页检索:https://x.com/karpathy
- Claude Code 官方文档:https://docs.anthropic.com/en/docs/claude-code
- Cursor 文档:https://docs.cursor.com
- Windsurf 文档:https://docs.codeium.com/windsurf
