Vibe Coding 完全实战指南:当自然语言成为编程语言——从范式革命到生产级落地的 2026 深度解析
2025 年 2 月,前 OpenAI 研究员、特斯拉前 AI 总监 Andrej Karpathy 在社交媒体上抛出了一句让整个开发社区震动的话:"There's a new kind of coding I call 'vibe coding', where you fully give in to the vibes, embrace exponentials, and forget that the code even exists."(有一种新的编程方式,我称之为"氛围编程",你完全顺应这种感觉,拥抱指数级变化,甚至忘记代码本身的存在。)
短短一年过去,Vibe Coding 已经从一句推文演变成 2026 年最热门的开发范式。独立开发者用它在 48 小时内从想法走到 Chrome Web Store 上架;艺术生团队用它在 48 小时内做出获奖硬件产品;普通人也能够用自然语言"说"出一个可用的 SaaS 产品。
但这背后到底是什么?是炒作还是真正的范式转移?本文将从技术原理、工具链选型、实战工作流、代码片段、性能优化到生产落地,全方位深度剖析 Vibe Coding 的本质,帮你真正掌握这种新的编程方式。
目录
- 编程范式的四次跃迁:Vibe Coding 从何而来
- Vibe Coding 核心哲学:不是"AI 写代码"那么简单
- Vibe Coding vs Spec Coding:双轨制开发的新现实
- 工具链深度横向对比:2026 年主流 Vibe Coding 工具全景
- 三段式迭代工作流:生产级 Vibe Coding 的核心方法论
- 实战案例一:用 TRAE 从零构建 Chrome 插件(完整迭代实录)
- 实战案例二:NestJS 权限守卫 + 自定义装饰器(企业级场景)
- 实战案例三:Flask REST API 表单 SaaS 后端(全栈实战)
- Prompt 工程 for Vibe Coding:如何让 AI 真正理解你的"Vibe"
- 上下文管理:Vibe Coding 中最容易被忽视的核心技能
- Token 优化策略:让 Vibe Coding 的经济账算得过来
- Vibe Coding 的局限性:什么时候不该用、如何用得更安全
- 从 Vibe Coding 到 Agentic Engineering:开发者的下一个进化方向
- 总结:Vibe Coding 不是终点,而是新的起点
1. 编程范式的四次跃迁:Vibe Coding 从何而来
要真正理解 Vibe Coding,必须先看清编程范式经历了哪几次重大跃迁。每一次跃迁的核心变化都一样:抽象层级上升,表达意图更直接。
第一次跃迁(1960s→1970s):汇编 → 高级语言
; 汇编语言(写给机器看)
MOV AX, BX
ADD AX, 1
CMP AX, 10
JL LOOP_START
// C 语言(写给编译器看)
for (int i = 0; i < 10; i++) {
// ...
}
开发者从"手动管理寄存器、内存地址"解放出来,开始用接近人类逻辑的方式描述计算任务。但这仍然要求你理解计算机的底层执行模型。
第二次跃迁(1990s→2000s):高级语言 → 框架/库
// 原生 JavaScript(写给框架看)
const xhr = new XMLHttpRequest();
xhr.open('GET', '/api/users');
xhr.onload = function() { /* ... */ };
// React(写给框架看)
function UserList() {
const { data } = useQuery(['users'], fetchUsers);
return <List items={data} />;
}
框架进一步抽象了通用模式(HTTP 请求、DOM 操作、状态管理),开发者不再需要从零实现每一个功能,而是"组合"现有的能力。但框架学习曲线陡峭,且你需要理解框架的设计哲学。
第三次跃迁(2010s→2020s):框架 → 低代码/无代码
用户通过拖拽组件、配置表单来构建应用,
理论上"不需要写代码"。
低代码平台试图让非程序员也能开发软件。但现实是:低代码平台的能力边界非常明显,一旦遇到定制化需求就无法满足,而且"配置"本身也是一种需要学习的 DSL(领域特定语言)。
第四次跃迁(2025→现在):Vibe Coding
开发者:"帮我做一个用户登录页面,要支持 GitHub OAuth,
样式用 Tailwind,移动端适配,错误提示要友好。"
AI:(直接生成完整可用的代码)
这是第一次,开发者不再需要学习任何语言的语法、任何框架的 API——你只需要能够清晰地描述你想要什么。编程语言从"文本"变成了"自然语言"。
为什么是现在?
Vibe Coding 之所以在 2025-2026 年爆发,有三个技术前提终于成熟:
大语言模型代码能力的质变:Claude 3.5/4 系列、GPT-4o/5、Qwen 2.5/3 等在代码生成质量上已经达到甚至超过中级开发者的水平,尤其是在常见技术栈上。
IDE 深度集成的实现:Cursor、Windsurf、TRAE 等 AI 原生 IDE 不再是把 ChatGPT 嵌进 VSCode 那么简单,而是从文件系统、LSP、调试器层面深度整合 AI 能力,让 AI 能够真正"理解"你的项目。
Agent 自主能力的突破:2026 年的 AI Coding 工具已经不再是"问答模式"(你问一句,它答一句),而是"Agent 模式"(你给一个目标,它自主完成多步操作:读代码、写代码、运行测试、修 Bug)。
2. Vibe Coding 核心哲学:不是"AI 写代码"那么简单
很多人对 Vibe Coding 的理解停留在"AI 帮我写代码,我复制粘贴"的层面。这是对 Vibe Coding 最严重的误解。
Vibe Coding 的本质是"意图驱动开发"
传统开发流程:
需求分析 → 系统设计 → 选型 → 写代码 → 调试 → 测试 → 部署
(人类做所有决策,人类写所有代码)
Vibe Coding 流程:
描述意图 → AI 生成方案+代码 → 人类审核判断 → 迭代优化 → 部署
(人类做决策,AI 执行实现)
关键区别:在传统开发中,"写代码"是核心活动;在 Vibe Coding 中,"做判断"是核心活动。你不再需要花费大量时间在语法细节、框架 API 的记忆、样板代码的编写上,而是把精力集中在:
- 这个功能到底要解决什么问题?(需求判断)
- AI 生成的方案是否合理?(架构判断)
- 这段代码有没有潜在的安全/性能问题?(质量判断)
- 下一步应该往哪个方向迭代?(产品判断)
"Forget that the code even exists"的深层含义
Karpathy 说"忘记代码的存在",不是说代码不重要,而是说:你不应该被代码语法细节分散注意力,而应该专注于更高层的逻辑和问题本身。
当你用 Vibe Coding 方式开发时,你的思维过程是这样的:
传统思维:
"我需要在 React 里用一个 useEffect 来监听路由变化,
然后在依赖数组里加上 location.pathname,还要处理 cleanup..."
Vibe Coding 思维:
"我希望每次路由变化时,页面标题跟着更新。"
(然后让 AI 去处理 useEffect、依赖数组、cleanup 这些细节)
这不是"懒",而是把认知资源集中在真正需要人类判断的地方。
Vibe Coding 的三层能力模型
要在 Vibe Coding 范式下高效工作,你需要三种能力:
| 能力层 | 传统开发 | Vibe Coding |
|---|---|---|
| 领域知识 | 需要(不变) | 需要(不变) |
| 技术实现能力 | 需要(手写代码) | 弱化(AI 生成代码) |
| 意图表达/判断能力 | 弱化(写在代码里) | 核心(自然语言+审核) |
最大的误区:认为 Vibe Coding 让开发者"不需要懂技术"。恰恰相反,Vibe Coding 对开发者的架构判断能力、代码审查能力、产品感知能力要求更高——因为现在没有人帮你兜底,AI 生成的代码可能看起来对,但实际上有严重的设计缺陷。
3. Vibe Coding vs Spec Coding:双轨制开发的新现实
2026 年的现实是:Vibe Coding 和 Spec Coding 不是对立关系,而是互补关系。聪明的开发者会根据场景选择合适的模式,甚至在同一个项目中混用两种模式。
什么是 Spec Coding?
Spec Coding(规格化编程)是 Vibe Coding 的对立面(但也不是传统的手写代码)。在 Spec Coding 中,开发者先写一份高度结构化的规格文档(Spec),AI 严格按照 Spec 生成代码。
Spec 文档通常包含:
## 功能:用户认证中间件
### 接口协议
- 输入:HTTP Request,Header 中携带 Authorization Bearer <token>
- 输出:解码后的用户信息注入 req.user;失败返回 401
### 数据结构
interface JwtPayload {
userId: string;
role: 'admin' | 'user';
exp: number;
}
### 边界条件
- token 过期 → 401 { error: 'TOKEN_EXPIRED' }
- token 非法 → 401 { error: 'TOKEN_INVALID' }
- 非 Bearer 格式 → 401 { error: 'AUTH_HEADER_INVALID' }
### 依赖
- jsonwebtoken (npm)
- HTTP 状态码用 401,不要用 403(前者是未认证,后者是未授权)
AI 拿到这份 Spec 后生成代码,鲁棒性远高于"帮我写个 JWT 中间件"。
Vibe Coding 适合什么场景?
| 场景 | 适合 Vibe Coding | 原因 |
|---|---|---|
| UI/UX 快速原型 | ✅ | 视觉反馈快,迭代周期短 |
| MVP/ Demo 开发 | ✅ | 速度优先,不要求完美架构 |
| 独立开发者全栈项目 | ✅ | 人力有限,需要快速覆盖多端 |
| 创意/艺术类项目 | ✅ | 需求本身模糊,需要快速试错 |
| 学习新技术栈 | ✅ | AI 可以提供交互式教学 |
Spec Coding 适合什么场景?
| 场景 | 适合 Spec Coding | 原因 |
|---|---|---|
| 企业级后端系统 | ✅ | 逻辑复杂,对鲁棒性要求高 |
| 高并发/高性能服务 | ✅ | 需要精确控制 every detail |
| 安全敏感模块(支付、认证) | ✅ | 不能容忍 AI "看起来对"的代码 |
| 多人协作的大型项目 | ✅ | Spec 即文档,便于协作和审查 |
| 监管合规场景 | ✅ | 需要完整的设计和决策留痕 |
双轨制实战:同一个项目如何混用?
实际项目中最有效的方式是:
前期探索阶段 → Vibe Coding(快速验证想法,看清需求)
↓
架构确定后 → Spec Coding(把核心模块用 Spec 约束,保证质量)
↓
后续迭代 → 混合(UI 快速变动用 Vibe,核心逻辑用 Spec)
具体示例:假设你在开发一个 SaaS 产品的后台管理系统。
## 双轨制分工示例
### Vibe Coding 负责的部分
- 所有前端页面组件(列表、表单、图表)
- 样式和交互细节
- 脚手架和样板代码
- 单元测试的用例生成
### Spec Coding 负责的部分
- 认证鉴权模块(Spec 定义所有边界情况)
- 数据库 Schema 和 Migration
- 核心业务逻辑(订单处理、支付流程)
- API 接口协议(Request/Response 格式)
4. 工具链深度横向对比:2026 年主流 Vibe Coding 工具全景
2026 年的 Vibe Coding 工具已经形成了明显的差异化竞争格局。下面从架构设计、核心能力、适用场景、优缺点四个维度深度对比主流工具。
4.1 Cursor:AI 原生 IDE 的标杆
架构特点:基于 VSCode fork,深度改造了编辑器内核,AI 能够直接访问编辑器状态(光标位置、选区、诊断信息)。
核心能力:
- Agent Mode(代理模式):最强杀手功能。你给 Cursor 一个任务("修复所有 TypeScript 编译错误"),它会自主进行:读取错误 → 定位文件 → 修改代码 → 重新编译 → 循环直到全部修复。整个过程不需要你手动操作。
- Tab 补全:不只是代码补全,而是"意图补全"。它能预测你下一步要写什么,很多时候按一次 Tab 就能完成一整段代码的编写。
- Cmd+K 局部编辑:选中一段代码,按 Cmd+K,用自然语言描述你想怎么改,Cursor 会给出 diff 视图让你确认后再应用。
优点:
- 产品成熟度最高,Bug 最少
- Agent Mode 在多文件重构场景下表现出色
- 社区生态好,有大量共享的
.cursorrules配置
缺点:
- 价格较贵($20/月 Pro 版本)
- 对最新技术栈的支持有时滞后于社区最新动态
- 完全闭源,无法自部署
适用人群:专业开发者、全栈工程师、需要稳定工具链的生产环境。
4.2 Claude Code:终端原生的 Agentic 编程体验
架构特点:命令行工具,无 GUI。核心设计哲学是"AI 直接在终端里像人一样操作"——它能执行 shell 命令、读写文件、运行测试。
核心能力:
- 完全自主的 Agent 循环:你给一个任务,Claude Code 自己决定要读哪些文件、要运行什么命令、要改哪些代码。你可以通过
--max-turns控制自主迭代次数。 - Git 集成:自动理解 diff,生成 commit message,做 code review。
- 无界面:适合服务器端开发、远程开发场景。
优点:
- 对代码理解和生成质量最高(Claude 3.7/4 系列)
- 适合命令行工作流重度用户
- 可以处理超大型代码库(通过智能文件索引)
缺点:
- 没有 GUI,对新手不友好
- 需要一定的 Prompt 工程能力才能用好
- 只支持 Anthropic 系列模型(无法切换)
适用人群:后端开发者、DevOps 工程师、CLI 工具开发者、已经在终端工作的开发者。
4.3 TRAE(原字节跳动 Solo):国内首款 AI 原生 IDE
架构特点:与 VSCode 同源,但完全重写了很多模块。最大特点是多模型支持——可以在同一个项目中自由切换 Claude、GPT、Gemini、Qwen 等模型。
核心能力:
- 三模式合一:
- IDE 模式:传统的代码补全+行内编辑
- Work 模式(原 Solo 模式):AI 接管整个项目,自主完成多文件开发
- Builder 模式:专门用于从零构建完整项目
- CUE 智能预测:预测你下一步要写什么代码,很多时候一次 Tab 就能完成整段逻辑
- 10 万级文件索引:支持超大型单体仓库
优点:
- 国内网络访问稳定,不需要科学上网
- 多模型支持,可以根据任务类型切换最合适的模型
- 对中文描述的理解更好(训练数据包含更多中文技术内容)
- 免费版额度相对较高
缺点:
- 产品迭代速度快,偶尔有稳定性问题
- 社区生态还在建设中
- 部分高级功能需要付费
适用人群:国内开发者、需要中文支持的团队、希望灵活切换模型的开发者。
4.4 Windsurf(原 Codeium):多 Agent 协作的先驱
架构特点:基于 Codeium 的代码生成引擎,架构上最大的创新是支持多个 AI Agent 同时协作——一个负责写代码,一个负责写测试,一个负责做 Code Review。
核心能力:
- 多 Agent 协作:可以同时启动多个 AI 工作流,互不干扰
- Cascade 模式:类似 Cursor 的 Agent Mode,但支持更细粒度的控制
- 完整的 Codeium 生态:包括本地模型支持、企业私有化部署
优点:
- 对大型企业代码库的支持最好
- 支持本地部署(数据不出内网)
- 价格相对友好(有免费版)
缺点:
- 产品体验不如 Cursor 流畅
- 对最新 AI 模型的跟进速度有时慢于竞争对手
适用人群:企业用户、对数据隐私有严格要求的组织、大型代码库维护者。
4.5 Replit:从原型到部署的一站式平台
架构特点:云端 IDE,最大的特点是"全栈项目零配置"——你不需要在本地配置 Node.js、数据库、环境变量,Replit 全部帮你搞定。
核心能力:
- Instant Deployment:代码写完,点一个按钮就部署到公网
- AI 辅助全栈开发:从数据库设计到前端组件到 API 接口,AI 全覆盖
- 协作开发:多人同时编辑,类似 Google Docs 的体验
优点:
- 入门门槛最低,打开浏览器就能用
- 非常适合快速做 Demo 和原型
- 对全栈项目的支持最完整(数据库+后端+前端一站式)
缺点:
- 免费版资源限制较多
- 不适合大型项目(性能和文件管理有限制)
- 锁定在 Replit 平台上,迁移成本高
适用人群:初学者、产品设计师、需要快速验证想法的创业者、教育工作者。
工具选型决策矩阵
| 你的场景 | 首选工具 | 备选工具 |
|---|---|---|
| 专业开发者,日常生产环境 | Cursor | TRAE |
| 后端/CLI 开发,喜欢终端 | Claude Code | Cursor |
| 国内开发者,中文环境 | TRAE | Cursor(需梯子) |
| 企业用户,数据隐私要求高 | Windsurf(本地部署) | Cursor Enterprise |
| 快速原型/Demo | Replit | Cursor + Vercel |
| 零基础初学者 | Replit | TRAE(有中文支持) |
5. 三段式迭代工作流:生产级 Vibe Coding 的核心方法论
很多人用 Vibe Coding 方式是:"让 AI 生成代码 → 直接用 → 出问题了再让 AI 修"。这种方式在小型项目中可能凑合,但在生产级项目中必然翻车。
经过大量实践,2026 年已经形成了一套相对成熟的方法论:三段式迭代工作流。
第一段:意图结晶(Crystallization)
在让 AI 生成任何代码之前,先花时间把需求"说清楚"——不是给人听,是给 AI 听。
给 AI 描述需求比给同事描述需求要求更高,因为:
- 你不能依赖 AI 拥有你行业的默认知识
- 你不能假设 AI 理解你的项目上下文(除非你主动提供)
- 自然语言本身有歧义,AI 可能会"合理误解"你的意思
意图结晶的产出是一份"AI 友好的需求描述",格式如下:
## 功能:用户行为埋点中间件
### 背景
我们的 SaaS 产品需要在前端捕获用户行为(页面访问、按钮点击、表单提交),
发送到后端 Analytics 服务。要求对主业务性能影响最小。
### 具体需求
1. 自动捕获页面访问(route change)
2. 支持手动埋点(trackEvent('button_click', { buttonId: 'xxx' }))
3. 批量发送(每 5 秒或队列长度 > 50 时发送)
4. 网络失败时本地缓存(localStorage),下次恢复时补发
5. 可选关闭(开发环境、用户选择退出时)
### 技术约束
- 框架:React(用 react-router v6)
- 语言:TypeScript
- 包体积:gzip 后 < 10KB
- 兼容性:支持 iOS Safari 14+
### 不需要的(负向需求)
- 不需要可视化埋点(埋点仍然需要开发者手动声明)
- 不需要支持 React 17 及以下
关键技巧:
- 主动列出"不需要的":AI 倾向于"过度实现",明确告诉它不要做什么,比告诉它要做什么更重要。
- 指定技术约束:框架版本、浏览器兼容性、包体积限制——这些在传统开发中可能是"团队规范文档"里的内容,在 Vibe Coding 中必须显式告诉 AI。
- 用具体数字:不要说"性能影响最小",而要说"gzip 后 < 10KB";不要说"批量发送",而要说"每 5 秒或队列长度 > 50"。
第二段:AI 初版生成 + 人类审查(Generation + Review)
把第一段产出的需求描述交给 AI,让它生成初版代码。
但这里有一个关键决策点:你是让 AI 直接改项目代码,还是先让它生成到一个临时文件/分支?
推荐做法(生产环境):
1. 让 AI 生成代码到临时文件(如 /tmp/feature_x_draft.ts)
2. 人工做第一轮审查(重点看架构合理性和边界条件处理)
3. 提出修改意见,让 AI 迭代
4. 确认基本可行后,才合并到项目代码中
5. 运行测试,做集成验证
人工审查的重点(不同于传统 Code Review):
| 审查维度 | 传统 Code Review | Vibe Coding Review |
|---|---|---|
| 代码风格 | 重点检查 | 快速浏览(AI 通常风格一致) |
| 逻辑正确性 | 重点检查 | 重点检查(AI 可能"看起来对"但逻辑有误) |
| 边界条件 | 检查 | 重点检查(AI 常常忽略边界情况) |
| 安全漏洞 | 检查 | 重点检查(AI 训练数据可能包含不安全写法) |
| 性能问题 | 检查 | 重点检查(AI 倾向于生成"直观但低效"的代码) |
| 架构合理性 | 检查 | 重点检查(AI 不了解你的整体架构设计) |
第三段:精准口令迭代优化(Precision Iteration)
初版代码通常是不完美的(有时候甚至有明显错误)。这时候需要用精准口令来驱动 AI 做针对性修复。
错误示范(模糊口令):
"这个代码有点问题,帮我改一下。"
"性能不太好,优化一下。"
"这里好像有 Bug,你看看。"
正确示范(精准口令):
"在 handleSubmit 函数中,表单验证失败时没有给用户视觉反馈,
请在验证失败的字段旁边加上红色报错文字,
用 <FormError field={fieldName} /> 组件实现。"
"这个实现每次 render 都创建了新的箭头函数,导致子组件无意义重渲染,
请用 useCallback 包装事件处理函数。"
"在 processQueue 函数中,如果 fetch 失败,整个队列会丢失。
请改为:失败时把当前批次写回 localStorage,并设置一个 30 秒后重试的 setTimeout。"
精准口令的公式:
[具体位置] + [当前问题的现象] + [期望的修复方向] + [技术细节约束]
完整的三段式工作流图示
┌─────────────────────────────────────────────────────┐
│ 第一段:意图结晶 │
│ • 写 AI 友好的需求描述 │
│ • 明确技术约束和负向需求 │
│ • 产出:Spec 文档(Markdown) │
└──────────────────┬──────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────┐
│ 第二段:AI 初版生成 + 人类审查 │
│ • AI 根据 Spec 生成代码 │
│ • 人类做架构/边界/安全/性能审查 │
│ • 产出:初版代码 + 审查意见列表 │
└──────────────────┬──────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────┐
│ 第三段:精准口令迭代优化 │
│ • 用精准口令驱动 AI 针对性修复 │
│ • 每次迭代后运行测试 │
│ • 产出:生产可用的代码 │
└─────────────────────────────────────────────────────┘
6. 实战案例一:用 TRAE 从零构建 Chrome 插件(完整迭代实录)
下面用一个完整的真实案例来展示 Vibe Coding 的实际工作流。案例目标:从想法到 Chrome Web Store 上架,全程 Vibe Coding。
背景
需求:做一个"网页截图标注插件"——用户可以在任意网页上截图,然后在截图上进行箭头、文字、马赛克标注,最后一键复制到剪贴板或保存为 PNG。
第一轮:意图结晶
我先写了一份需求描述(Spec),交给 TRAE 的 Work 模式:
## Chrome 插件:网页截图标注工具
### 核心功能
1. 点击插件图标 → 进入截图模式(鼠标变成十字光标)
2. 拖拽选择截图区域 → 截取选中区域
3. 标注工具栏:箭头、矩形、文字、马赛克、撤销、保存、复制到剪贴板
4. 标注在截图上方绘制(不修改原图数据)
### 技术约束
- Manifest V3(必须用 V3,V2 已被 Chrome 淘汰)
- 用 html2canvas 或类似库实现截图
- 标注用 Canvas 2D API 实现
- popup.html 只放一个"开始截图"按钮(保持 UI 极简)
- 标注界面用 content script 注入的浮层实现
### 不需要的
- 不需要云端同步
- 不需要账号系统
- 不需要支持视频截图(只截图静态页面内容)
第二轮:AI 初版生成
TRAE Work 模式拿到需求后,自主完成了以下操作(我通过它的实时日志看到的):
1. 创建项目结构
├── manifest.json
├── popup.html / popup.js
├── content.js (content script)
├── annotation.js (标注逻辑)
├── style.css
└── vendors/ (html2canvas)
2. 实现截图功能(基于 html2canvas)
3. 实现标注工具栏 UI
4. 实现 Canvas 标注逻辑
AI 初版代码(annotation.js 核心部分):
// AI 生成的初版标注逻辑(有 Bug 版本)
class AnnotationTool {
constructor(canvas) {
this.canvas = canvas;
this.ctx = canvas.getContext('2d');
this.tools = ['arrow', 'rect', 'text', 'blur'];
this.activeTool = 'arrow';
this.isDrawing = false;
}
onMouseDown(e) {
this.isDrawing = true;
this.startX = e.offsetX;
this.startY = e.offsetY;
}
onMouseMove(e) {
if (!this.isDrawing) return;
// Bug #1: 每次 mousemove 都重绘整个 canvas,但没有保存已完成标注的状态
this.drawShape(e.offsetX, e.offsetY);
}
onMouseUp(e) {
this.isDrawing = false;
// Bug #2: 标注完成后的状态没有 push 到历史栈,无法撤销
}
drawShape(currentX, currentY) {
// Bug #3: 箭头绘制用了固定的 10px 大小,没有根据拖拽距离动态计算
if (this.activeTool === 'arrow') {
this.drawArrow(this.startX, this.startY, currentX, currentY);
}
// ...
}
}
第三轮:人类审查 + 精准口令迭代
我审查代码后发现了上述问题,用精准口令让 AI 修复:
口令 #1(修复状态管理):
在 AnnotationTool 中,当前实现每次 mousemove 都直接在原 canvas 上绘制,
导致之前的标注被覆盖。请修改为:
1. 增加一个 history 数组,每次 mouseup 时把当前 canvas 状态(用 toDataURL)存入 history
2. mousemove 时先 restore 上一个 history 状态,再绘制当前形状(这样才能看到"拖拽预览")
3. 实现 undo() 方法:pop history,然后 restore 到上一个状态
AI 的修复版本(核心改动):
class AnnotationTool {
constructor(canvas) {
this.canvas = canvas;
this.ctx = canvas.getContext('2d');
this.history = []; // ← 新增:历史栈
this.redoStack = []; // ← 新增:重做栈
this.currentShape = null; // ← 新增:当前正在拖拽的形状
}
onMouseMove(e) {
if (!this.isDrawing) return;
// ← 新增:先恢复上一个"已完成"状态
this.restoreFromHistory();
// ← 新增:把当前拖拽中的形状绘制到临时 layer(用 globalCompositeOperation)
this.drawShapePreview(e.offsetX, e.offsetY);
}
onMouseUp(e) {
this.isDrawing = false;
// ← 新增:把最终状态存入历史栈
this.pushToHistory();
}
pushToHistory() {
this.history.push(this.canvas.toDataURL());
// 限制历史栈长度,避免内存溢出
if (this.history.length > 50) this.history.shift();
}
restoreFromHistory() {
if (this.history.length === 0) return;
const img = new Image();
img.onload = () => {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.ctx.drawImage(img, 0, 0);
};
img.src = this.history[this.history.length - 1];
}
undo() {
if (this.history.length <= 1) return; // 保留初始状态
this.history.pop();
this.restoreFromHistory();
}
}
口令 #2(修复箭头绘制):
当前箭头绘制用了固定大小,请改为根据拖拽距离动态计算:
箭头的两条"翼"的长度 = 箭头主轴长度的 1/3,最大 20px,最小 8px。
用向量计算:先算主轴向量 (dx, dy),归一化后旋转 ±30 度得到翼向量。
AI 修复版本:
drawArrow(x1, y1, x2, y2) {
const dx = x2 - x1;
const dy = y2 - y1;
const length = Math.sqrt(dx * dx + dy * dy);
// 主轴
this.ctx.beginPath();
this.ctx.moveTo(x1, y1);
this.ctx.lineTo(x2, y2);
this.ctx.stroke();
// 箭头翼(动态计算)
const headLength = Math.min(Math.max(length / 3, 8), 20);
const angle = Math.atan2(dy, dx);
// 左翼(旋转 -30 度)
const leftAngle = angle - Math.PI / 6;
this.ctx.beginPath();
this.ctx.moveTo(x2, y2);
this.ctx.lineTo(
x2 - headLength * Math.cos(leftAngle),
y2 - headLength * Math.sin(leftAngle)
);
this.ctx.stroke();
// 右翼(旋转 +30 度)
const rightAngle = angle + Math.PI / 6;
this.ctx.beginPath();
this.ctx.moveTo(x2, y2);
this.ctx.lineTo(
x2 - headLength * Math.cos(rightAngle),
y2 - headLength * Math.sin(rightAngle)
);
this.ctx.stroke();
}
最终结果
经过 4 轮迭代(截图 → 标注 UI → 箭头/文字工具 → 复制到剪贴板),整个插件开发完成,从开始到 Chrome Web Store 上架总共不到 48 小时,其中 AI 生成的代码约占 80%,人类的工作主要是:需求描述、架构审查、精准口令迭代、打包上架。
7. 实战案例二:NestJS 权限守卫 + 自定义装饰器(企业级场景)
企业级后端开发中,权限控制是一个经典的需求。下面展示如何用 Vibe Coding + Spec Coding 混合方式实现一个生产级的权限系统。
Spec 文档(Spec Coding 部分)
## 功能:NestJS RBAC 权限守卫
### 核心需求
1. 支持基于角色的访问控制(RBAC):Admin / Editor / Viewer 三种角色
2. 支持基于资源的访问控制(ABAC):比如"只能编辑自己创建的文档"
3. 用自定义装饰器声明权限需求(@RequireRole、@RequireOwnership)
4. 权限守卫自动读取装饰器元数据,决定是否允许访问
### 接口设计
#### @RequireRole 装饰器
@RequireRole('admin') → 只允许 Admin
@RequireRole('editor', 'admin') → 允许 Editor 或 Admin
#### @RequireOwnership 装饰器
@RequireOwnership('document') → 需要从请求参数中解析资源 ID,
查询数据库确认当前用户是否是资源所有者
### 错误响应格式
权限不足时返回:
{
"error": "PERMISSION_DENIED",
"message": "Admin role required",
"required": ["admin"],
"actual": "viewer"
}
(注意:实际生产环境中,不应该返回 actual role,这里只是为了调试)
### 技术约束
- TypeScript 严格模式
- 用 NestJS 的 Guard + Decorator + Metadata 实现
- 数据库连接用 TypeORM
- 用户身份信息从 JWT 解码后注入到 req.user
AI 生成的核心代码
把上述 Spec 交给 Cursor(Agent Mode),它生成了以下代码:
// guards/rbac.guard.ts
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { Role } from '../enums/role.enum';
import { ROLES_KEY } from '../decorators/require-role.decorator';
@Injectable()
export class RbacGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
// 从装饰器元数据中读取所需角色
const requiredRoles = this.reflector.getAllAndOverride<Role[]>(ROLES_KEY, [
context.getHandler(),
context.getClass(),
]);
// 如果没有 @RequireRole 装饰器,默认允许访问
if (!requiredRoles) return true;
const { user } = context.switchToHttp().getRequest();
// 检查用户是否拥有所需角色之一
return requiredRoles.some((role) => user?.role === role);
}
}
// decorators/require-role.decorator.ts
import { SetMetadata } from '@nestjs/common';
import { Role } from '../enums/role.enum';
export const ROLES_KEY = 'roles';
export const RequireRole = (...roles: Role[]) => SetMetadata(ROLES_KEY, roles);
// decorators/require-ownership.decorator.ts
import { SetMetadata } from '@nestjs/common';
export const OWNERSHIP_KEY = 'ownership';
// resourceType 用于告诉 Guard 如何去查询资源所有者
export const RequireOwnership = (resourceType: string) =>
SetMetadata(OWNERSHIP_KEY, resourceType);
// guards/ownership.guard.ts
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { OWNERSHIP_KEY } from '../decorators/require-ownership.decorator';
@Injectable()
export class OwnershipGuard implements CanActivate {
constructor(
private reflector: Reflector,
@InjectRepository(Document) private documentRepo: Repository<Document>,
// ... 其他资源的 Repository
) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const resourceType = this.reflector.getAllAndOverride<string>(
OWNERSHIP_KEY,
[context.getHandler(), context.getClass()]
);
if (!resourceType) return true;
const request = context.switchToHttp().getRequest();
const user = request.user;
// 从路由参数中获取资源 ID(假设路由是 /documents/:id)
const resourceId = request.params.id;
if (!resourceId) return false;
// 根据 resourceType 查询资源所有者
const resource = await this.getResource(resourceType, resourceId);
return resource?.createdBy?.id === user?.id;
}
private async getResource(type: string, id: string) {
switch (type) {
case 'document':
return this.documentRepo.findOne({ where: { id }, relations: ['createdBy'] });
// ... 其他资源类型
default:
throw new Error(`Unknown resource type: ${type}`);
}
}
}
人类审查发现的问题 + 精准迭代
问题 #1:OwnershipGuard 中用了 switch-case 来路由不同的资源类型,每增加一种资源就要改 Guard 代码,违反开闭原则。
精准口令:
OwnershipGuard 当前用 switch-case 来分发不同资源类型的查询,
这样每增加一种资源就要修改 Guard。请改为:
1. 定义一个 OwnershipChecker 接口(或抽象类),包含一个 check 方法
2. 为每种资源注册一个 checker(用 NestJS 的自定义 Provider)
3. OwnershipGuard 通过依赖注入获取所有 checker,
根据 resourceType 找到对应的 checker 来执行
这样可以做到:新增资源类型时,只需要新增一个 checker Provider,不需要改 Guard。
AI 重构后的版本:
// interfaces/ownership-checker.interface.ts
export interface OwnershipChecker {
resourceType: string;
check(userId: string, resourceId: string): Promise<boolean>;
}
// checkers/document-ownership.checker.ts
@Injectable()
export class DocumentOwnershipChecker implements OwnershipChecker {
resourceType = 'document';
constructor(
@InjectRepository(Document)
private documentRepo: Repository<Document>,
) {}
async check(userId: string, resourceId: string): Promise<boolean> {
const doc = await this.documentRepo.findOne({
where: { id: resourceId },
relations: ['createdBy'],
});
return doc?.createdBy?.id === userId;
}
}
// guards/ownership.guard.ts(重构后)
@Injectable()
export class OwnershipGuard implements CanActivate {
constructor(
private reflector: Reflector,
// ← 注入所有 OwnershipChecker 实现
@Inject(OWNERSHIP_CHECKERS) private checkers: OwnershipChecker[],
) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const resourceType = this.reflector.getAllAndOverride<string>(
OWNERSHIP_KEY,
[context.getHandler(), context.getClass()]
);
if (!resourceType) return true;
const request = context.switchToHttp().getRequest();
const user = request.user;
const resourceId = request.params.id;
// ← 找到对应 resourceType 的 checker
const checker = this.checkers.find(c => c.resourceType === resourceType);
if (!checker) {
throw new Error(`No OwnershipChecker registered for: ${resourceType}`);
}
return checker.check(user.id, resourceId);
}
}
问题 #2:当前的 Guard 组合方式不够灵活——有些路由只需要角色检查,有些只需要所有权检查,有些需要两者都满足。
精准口令:
当前 RbacGuard 和 OwnershipGuard 是独立的两个 Guard,
需要在 Controller 上同时加 @UseGuards(RbacGuard, OwnershipGuard)。
这样不够灵活:有些路由需要"角色 OR 所有权"(比如管理员可以编辑任何文档,
所有者也可以编辑自己的文档),有些需要"角色 AND 所有权"。
请实现一个组合 Guard @RequireAuth(options),options 格式:
{
roles: ['admin', 'editor'], // 角色条件
ownership: 'document', // 所有权条件(可选)
mode: 'OR' | 'AND' // 角色和所有权之间的逻辑关系
}
逻辑:
- mode=OR:满足角色条件 OR 满足所有权条件 → 允许
- mode=AND:满足角色条件 AND 满足所有权条件 → 允许
- 没有 ownership → 只检查角色
这个迭代让整个权限系统变得非常灵活且类型安全。最终产出的代码可以直接用于生产环境。
8. 实战案例三:Flask REST API 表单 SaaS 后端(全栈实战)
这个案例展示如何用 Vibe Coding 快速搭建一个表单 SaaS 产品的后端 API。
需求描述(意图结晶)
## 表单 SaaS 后端 API
### 核心功能
1. 用户注册/登录(JWT 认证)
2. 创建表单(标题、字段定义、设置)
3. 表单字段类型:text / email / number / select / checkbox / file
4. 收集表单提交数据
5. 查看表单的提交记录(分页 + 筛选)
6. Webhook:表单提交时推送到用户配置的 URL
### 技术栈
- Flask + SQLAlchemy + SQLite(MVP 阶段用 SQLite,后续迁移到 PostgreSQL)
- JWT 认证(PyJWT)
- 表单字段定义存在 SQLite 的 JSON 字段里(不用单独建表)
- 文件上传:存在本地 uploads/ 目录,返回可访问的 URL
### API 设计(RESTful)
POST /auth/register
POST /auth/login
POST /forms # 创建表单
GET /forms # 列出我的表单
GET /forms/:id # 获取表单详情(包含字段定义)
POST /forms/:id/submit # 提交表单(公开接口,不需要认证)
GET /forms/:id/submissions # 查看提交记录(需要认证,且是表单所有者)
POST /webhooks # 配置 webhook
AI 初版生成(Claude Code 终端模式)
我用 Claude Code 来生成这个后端。给我的 prompt:
用 Flask 实现一个表单 SaaS 后端 API,完整实现以下功能:
(粘贴上面的需求描述)
请按照生产级标准实现:
- 所有接口有完整的参数校验
- 错误信息格式统一
- 用 Blueprint 组织路由
- 用 SQLAlchemy Model 定义数据模型
- 每个文件不超过 200 行
Claude Code 在终端里自主完成了以下步骤(我通过它的输出日志看到的):
1. 创建项目结构
form-saas-backend/
├── app.py
├── models.py
├── auth/
│ ├── __init__.py
│ ├── routes.py
│ └── utils.py
├── forms/
│ ├── __init__.py
│ ├── routes.py
│ └── models.py
├── submissions/
│ └── routes.py
└── config.py
2. 实现数据模型(User / Form / Submission / Webhook)
3. 实现认证逻辑(JWT 生成 + 验证)
4. 实现表单 CRUD
5. 实现表单提交接口(公开访问)
6. 实现提交记录查询(带分页)
7. 实现 Webhook 推送(用 requests 库,异步用 threading)
AI 生成的核心代码片段(forms/routes.py):
# forms/routes.py
from flask import Blueprint, request, jsonify, current_app
from flask_jwt_extended import jwt_required, get_jwt_identity
from ..models import db, Form, Submission
from ..auth.utils import get_current_user
forms_bp = Blueprint('forms', __name__, url_prefix='/forms')
@forms_bp.route('', methods=['POST'])
@jwt_required()
def create_form():
user = get_current_user()
data = request.get_json()
# 参数校验
if not data.get('title'):
return jsonify({'error': 'TITLE_REQUIRED'}), 400
# 字段定义校验
fields = data.get('fields', [])
for i, field in enumerate(fields):
if not field.get('type') or not field.get('name'):
return jsonify({
'error': 'INVALID_FIELD_DEFINITION',
'detail': f'Field at index {i} missing type or name'
}), 400
# 校验字段类型是否合法
if field['type'] not in ['text', 'email', 'number', 'select', 'checkbox', 'file']:
return jsonify({
'error': 'INVALID_FIELD_TYPE',
'detail': f'Field type "{field["type"]}" not allowed'
}), 400
form = Form(
title=data['title'],
description=data.get('description', ''),
fields=fields, # JSON 字段
settings=data.get('settings', {}),
owner_id=user.id,
)
db.session.add(form)
db.session.commit()
return jsonify({'id': form.id, 'title': form.title}), 201
@forms_bp.route('/<form_id>/submit', methods=['POST'])
def submit_form(form_id):
"""公开接口:提交表单(不需要认证)"""
form = Form.query.get_or_404(form_id)
# 根据表单的 fields 定义来动态校验提交数据
data = request.form.to_dict() # 文本字段
files = request.files # 文件字段
errors = []
for field in form.fields:
field_name = field['name']
field_type = field['type']
required = field.get('required', False)
if required and field_name not in data and field_name not in files:
errors.append({'field': field_name, 'error': 'REQUIRED'})
if field_type == 'email' and field_name in data:
# 简易邮箱格式校验
if '@' not in data[field_name]:
errors.append({'field': field_name, 'error': 'INVALID_EMAIL'})
# 文件字段处理
if field_type == 'file' and field_name in files:
file = files[field_name]
# 保存文件
filename = secure_filename(f"{uuid.uuid4()}_{file.filename}")
file.save(os.path.join(current_app.config['UPLOAD_FOLDER'], filename))
data[field_name] = f"/uploads/{filename}" # 替换为文件 URL
if errors:
return jsonify({'errors': errors}), 400
submission = Submission(
form_id=form_id,
data=data,
ip_address=request.remote_addr,
)
db.session.add(submission)
db.session.commit()
# 异步触发 Webhook(简化版:用 threading)
if form.webhook_url:
threading.Thread(
target=trigger_webhook,
args=(form.webhook_url, submission.to_dict())
).start()
return jsonify({'submission_id': submission.id}), 201
人类审查 + 迭代
问题 #1:/forms/<form_id>/submit 接口中,文件保存用了 os.path.join 和 current_app.config['UPLOAD_FOLDER'],但没有做文件类型校验和大小限制,存在安全风险。
精准口令:
在 submit_form 接口的文件处理部分,请增加:
1. 文件类型白名单校验(只允许 image/* 和 application/pdf)
2. 文件大小限制(单文件最大 5MB)
3. 用 werkzeug.utils.secure_filename 处理文件名(防止路径遍历)
4. 把上传的文件信息(original_name, saved_path, size, mime_type)
存到 submission 的 data 里,方便后续管理
如果文件校验失败,返回 400 和具体的错误信息。
问题 #2:Webhook 推送用了 threading.Thread,但没有任何错误处理——如果 Webhook URL 不通,异常会被静默吞掉。
精准口令:
trigger_webhook 函数当前用了 threading.Thread,
但没有错误处理和重试机制。请改为:
1. 用 Tenacity 库实现指数退避重试(最多重试 3 次)
2. Webhook 推送失败要有日志记录(用 Python logging 模块)
3. 把 Webhook 推送记录存到数据库(WebhookLog model),
包含:submission_id, webhook_url, status_code, error_message, created_at
这样用户可以后续在后台查看 Webhook 推送状态
9. Prompt 工程 for Vibe Coding:如何让 AI 真正理解你的"Vibe"
Vibe Coding 的核心技能不是"写代码",而是"让 AI 准确理解你的意图并生成高质量代码"。这需要专门的 Prompt 工程技巧。
九大 Prompt 原则(Vibe Coding 专用)
原则一:用具体替代抽象
❌ 差:"做一个高性能的 API"
✅ 好:"做一个 Flask REST API,支持每秒 500 次请求,
响应时间 P99 < 100ms,用 SQLAlchemy 连接池,
关键路径加 Redis 缓存"
❌ 差:"UI 要好看"
✅ 好:"用 Tailwind CSS,配色用 blue-600 主色 + gray-100 背景,
卡片用 rounded-xl + shadow-md,移动端用响应式布局"
原则二:主动声明"不要什么"(负向约束)
AI 倾向于"过度实现"——你让它做一个表单,它可能会顺便把表单验证、错误处理、单元测试、Dockerfile 全部生成出来。
"实现一个登录接口,只需要 JWT 生成部分。
不需要:
- 不需要密码重置功能
- 不需要 OAuth(GitHub/Google)
- 不需要限流(后续再加)
- 不需要刷新 Token 机制(MVP 阶段用长效 JWT)"
原则三:提供"决策上下文"
AI 在生成代码时需要做很多决策(用什么库?用什么设计模式?怎么处理错误?)。如果你不提供决策上下文,AI 会做"默认决策",但默认决策不一定适合你的项目。
"技术选型决策上下文:
- 我们团队对 SQLAlchemy 最熟悉(不用 Django ORM、不用 Peewee)
- 前端用 React + Tailwind(不用 Vue、不用 Bootstrap)
- 部署目标是 Docker + Nginx(不用 Serverless、不用 PaaS)
- 团队编码规范:类型标注必须写、不允许 any 类型、
每个函数不超过 50 行"
原则四:用"示例驱动"替代"描述驱动"
当你需要 AI 生成特定格式的输出时,直接给它一个示例,比用文字描述格式更有效。
❌ 差:"表单字段定义的 JSON 格式要有 type、name、label、required 字段"
✅ 好:"表单字段定义的 JSON 格式如下(请严格按照这个格式):
[
{
\"type\": \"text\",
\"name\": \"full_name\",
\"label\": \"Full Name\",
\"required\": true,
\"placeholder\": \"Enter your full name\"
},
{
\"type\": \"select\",
\"name\": \"country\",
\"label\": \"Country\",
\"options\": [\"US\", \"CN\", \"JP\"],
\"required\": true
}
]"
原则五:分步骤,不要一次性给大任务
Vibe Coding 中最常见的失败模式是:给 AI 一个太大的任务,AI 生成的代码质量很差,而且你不知道从哪里开始修。
❌ 差:"用 React + TypeScript 做一个完整的后台管理系统"
✅ 好(分步骤):
步骤1:"用 React + TypeScript 搭建后台管理系统的脚手架,
用 Vite 构建,包含布局(侧边栏 + 顶栏 + 内容区)"
步骤2:"在布局基础上,实现侧边栏菜单(写死几个菜单项即可:
仪表盘、用户管理、设置)"
步骤3:"实现用户管理页面的列表视图(用 Ant Design Table 组件,
假数据先写死)"
步骤4:"接入真实的 API(GET /api/users),替换假数据"
原则六:要求 AI "先解释再实现"
当你让 AI 实现一个有一定复杂度的功能时,要求它先解释设计思路,再写代码。这样你可以先判断设计是否合理,再让它写代码。
"实现一个支持插件机制的 Node.js 应用框架。
要求:
1. 先解释你的设计方案(用 Markdown 格式,包含架构图文字描述)
2. 等我确认设计方案后,再开始写代码
3. 代码实现时,每个核心类/函数都要有 JSDoc 注释"
原则七:用"角色设定"提升代码质量
在 Prompt 的开头给 AI 设定一个角色,可以显著提升生成代码的质量和专业度。
"你是一个有 10 年经验的后端架构师,精通 Node.js / TypeScript /
微服务设计。你特别注重:代码可维护性、错误处理完整性、
性能优化、安全性。请按照生产级标准实现以下需求:..."
原则八:明确要求"完整的错误处理"
AI 生成的代码经常忽略错误处理(因为" happy path "的代码更短,训练数据中也更多)。你必须明确要求。
"所有数据库操作都要有完整的错误处理:
- 连接失败 → 重试 3 次,然后抛自定义异常
- 唯一约束冲突 → 返回 409 和友好错误信息
- 外键约束失败 → 返回 400 和具体哪个字段有问题
- 超时报错 → 返回 503 和 'Database timeout, please retry'
每个错误处理都要用 logger.error() 记录详细上下文(请求 ID、
用户 ID、SQL 语句),方便排查问题。"
原则九:用"代码审查口令"让 AI 自己找 Bug
让 AI 生成代码后,不要直接就用,而是先让它做自我审查。
"代码生成后,请做以下自查:
1. 有没有可能的 SQL 注入 / XSS / CSRF 漏洞?
2. 有没有竞态条件(race condition)?
3. 有没有内存泄漏风险(比如 event listener 没有清理)?
4. 有没有边缘情况没有处理(空数组、null、网络超时)?
5. 代码里有没有"写死"的值应该做成配置项的?
如果发现有问题,先列出所有问题,再逐一修复。"
10. 上下文管理:Vibe Coding 中最容易被忽视的核心技能
Vibe Coding 工具(Cursor、TRAE、Claude Code 等)的核心能力之一是"理解你的项目上下文"。但如果你的项目很大(几万行代码),AI 不可能一次性把所有代码都放到上下文窗口里(通常有 8K-200K token 的限制)。
上下文管理的本质:在 AI 有限的上下文窗口里,放入"最相关的信息"。
上下文的五个层次
| 层次 | 内容 | Token 消耗 | 何时使用 |
|---|---|---|---|
| L0 | 当前文件 | 低 | 局部编辑、单文件修改 |
| L1 | 当前文件 + 直接依赖(import 的文件) | 中 | 重构、跨文件修改 |
| L2 | 当前模块(相关的一批文件) | 高 | 新功能开发、模块级重构 |
| L3 | 项目架构文档 + 核心文件 | 高 | 架构决策、跨模块功能 |
| L4 | 完整项目代码 | 极高(通常放不下) | 避免用到这个层次 |
实战技巧:用 .cursorrules / .traerules 文件管理上下文
主流 Vibe Coding IDE 都支持在项目根目录放置一个规则文件(Cursor 用 .cursorrules,TRAE 用类似的配置文件),这个文件的内容会被自动注入到每一次 AI 对话的上下文中。
这是一个生产级的 .cursorrules 示例:
# 项目规则(自动注入 AI 上下文)
## 项目概述
这是一个 SaaS 产品的后台管理系统,基于:
- 前端:React 18 + TypeScript + Tailwind CSS + Ant Design
- 后端:Node.js + Express + TypeScript + PostgreSQL
- 部署:Docker + Nginx
## 架构约束
- 前端状态管理用 Zustand(不用 Redux)
- API 请求统一用 src/api/ 目录下的封装函数(基于 axios)
- 后端用分层架构:Controller → Service → Repository
- 数据库 Model 定义在 src/models/ 目录
## 代码规范
- 所有函数必须有 JSDoc / TSDoc 注释
- 不允许使用 any 类型(用 unknown 或具体类型)
- 每个文件的代码不超过 200 行
- 组件命名用 PascalCase,工具函数用 camelCase
## 禁止事项
- 不要使用 console.log(用 logger 工具函数)
- 不要直接操作 DOM(React 项目中用 ref 或状态管理)
- 不要在客户端存储敏感信息(用 httpOnly cookie)
- 不要生成不使用的数据(死代码)
## 已知坑点
- Ant Design Table 组件的 pagination 参数在 v5 改了,
需要用 pagination={{ current, pageSize, total }} 格式
- Node.js 18 以上自带 fetch,不需要额外安装 node-fetch
- PostgreSQL 的 jsonb 字段查询用 -> 和 ->> 操作符
上下文窗口不够用时怎么办?
当你的项目很大,需要 AI 理解多个不相邻的文件时,不要用"把文件内容复制粘贴给 AI"这种原始方式,而是:
方法一:用"文件索引"技巧
先让 AI 生成一个项目文件索引(Markdown 格式),然后把索引交给 AI,告诉它"如果需要看某个文件的详细内容,告诉我,我会提供"。
方法二:用 embedding + 向量检索(高级技巧)
对于超大型项目,可以用 codebase-memory-mcp 这样的工具(之前在程序员茄子网站上介绍过),它会对整个代码库建立语义索引,AI 可以根据需要"检索"最相关的代码片段放入上下文。
11. Token 优化策略:让 Vibe Coding 的经济账算得过来
Vibe Coding 不是免费的。以 Claude 3.7 Sonnet 为例,输入 Token 约 $3/MTok,输出 Token 约 $15/MTok。一次典型的交互可能在 2-10K Token 左右,如果每天进行几十次交互,一个月的 API 费用可能达到几百美元。
但这是可以优化的。下面介绍几种已经被验证有效的 Token 优化策略。
策略一:用 Headroom 类工具压缩上下文
Headroom 是专门用来压缩 AI 编程助手上下文的开源工具(在程序员茄子网站上有深度介绍)。它支持多种压缩算法,可以把长达几十万 Token 的项目上下文压缩到几千 Token,同时保持"语义完整性"。
核心原理:
- CCR(Context Compression with Reconstruction):可逆压缩,AI 可以根据压缩后的上下文"重建"出原始信息的要点
- 智能摘要:把代码文件摘要为"接口定义 + 核心逻辑",去掉实现细节
- Prompt Cache 保护:压缩后的上下文仍然可以利用 LLM 的 Prompt Cache,避免重复计费
策略二:避免重复注入相同的上下文
很多人在用 Vibe Coding 工具时,每次对话都重新把项目背景、技术栈、架构说明交给 AI,这是巨大的浪费。
正确做法:
- 把项目背景信息写入
.cursorrules(一次写入,永久自动注入) - 对于 CLAUDE.md(Claude Code 的上下文文件),定期更新,不要每次都重新生成
- 用"引用"而不是"复制":告诉 AI"这个信息在项目根目录的 ARCHITECTURE.md 里",让 AI 去读文件,而不是你复制内容给它
策略三:用小型模型做"初筛",用大型模型做"精修"
不是所有的编程任务都需要 Claude 3.7 这个级别的模型。建立分层使用策略:
简单任务(代码补全、语法检查、单文件修改)→ GPT-4o mini / Qwen 2.5 Coder
中等任务(单模块开发、Bug 修复)→ Claude 3.5 Haiku / GPT-4o
复杂任务(架构设计、跨模块重构、性能优化)→ Claude 3.7 Sonnet / GPT-5
TRAE 的多模型支持在这个场景下特别有用——你可以在同一个项目中根据不同的任务类型切换模型。
策略四:用本地模型处理敏感代码
如果你在做一个闭源商业项目,把代码发给云端 AI 服务可能有数据泄露风险,也可能产生大量的 API 费用。
解决方案:用本地运行的代码大模型(如 Qwen 2.5 Coder 32B、DeepSeek Coder V2)来处理日常开发任务,只在遇到特别复杂的问题时才用云端大模型。
12. Vibe Coding 的局限性:什么时候不该用、如何用得更安全
Vibe Coding 不是银弹。了解它的局限性,才能用它用得更好。
局限性一:AI 不知道它不知道的事情
大语言模型的训练数据有截止日期(Claude 3.7 的知识截止日期大约是 2025 年初)。如果你所用的技术栈有最新的变化(比如某个框架刚发布了 v3,而 AI 只知道 v2),AI 生成的代码可能是错误的。
应对方法:
- 在 Prompt 中明确声明你用的版本号
- 把关键文档(API Reference)的链接或内容提供给 AI
- 对最新的技术栈,先做一波调研,确认 AI 训练数据中有相关知识后再用 Vibe Coding
局限性二:AI 生成的代码可能有"隐性 Bug"
"隐性 Bug"指的是:代码能运行,在大多数情况下结果也是正确的,但在某些边界条件下会出错。这类 Bug 最难发现,而 AI 生成的代码恰好容易有这类问题。
典型案例:
// AI 生成的时间格式化函数(有隐性 Bug)
function formatDate(date) {
const d = new Date(date);
return `${d.getFullYear()}-${d.getMonth() + 1}-${d.getDate()}`;
}
// 问题:getMonth() 返回 0-11,所以 " + 1 " 是对的
// 但是:如果月份或日期是个位数,没有补零,
// 导致格式不统一(2026-6-5 vs 2026-06-05)
// 这在某些场景下(比如作为文件名、URL 参数)会导致 Bug
应对方法:
- 要求 AI "必须写单元测试覆盖边界情况"
- 关键函数要求 AI 先写 Spec(输入/输出/边界条件),再实现
- 用自动化测试工具(Jest / Pytest)做回归测试
局限性三:过度依赖导致"技能退化"
如果你所有的编码工作都交给 AI,久而久之你会发现自己失去了"手写代码"的能力。这不是耸人听闻——2026 年已经有很多开发者自嘲是"Vibe Coding 受害者",他们无法在没有 AI 辅助的情况下完成哪怕简单的编程任务。
应对方法:
- 保持"手写代码"的练习(比如每周做一个不借助 AI 的小项目)
- 深入理解你让 AI 生成的每一行代码(不要盲目接受)
- 把 AI 当作"高级助手"而不是"替代者"
局限性四:安全漏洞风险
AI 训练数据中包含大量不安全的代码写法(比如 SQL 拼接、未经验证的用户输入、硬编码密钥)。如果直接让 AI "实现一个登录功能",它可能会生成不安全的代码。
应对方法:
- 在 Prompt 中明确声明安全约束("必须用参数化查询,不能拼接 SQL")
- 用自动化安全扫描工具(Snyk / Bandit / ESLint security rules)
- 关键安全模块(认证、支付、权限)用 Spec Coding 方式,人工严格审查
13. 从 Vibe Coding 到 Agentic Engineering:开发者的下一个进化方向
Vibe Coding 是起点,不是终点。2026 年下半年到 2027 年,开发范式还在继续演化。
Agentic Engineering 是什么?
Vibe Coding 的核心是"你描述需求,AI 生成代码"。但代码只是手段,不是目的。真正的目的是"实现某个功能/解决某个问题"。
Agentic Engineering 的核心思想是:不让 AI 只生成代码,而是让 AI Agent 直接完成"从需求到上线"的完整闭环。
Vibe Coding 工作流:
你:"做一个用户登录页面"
AI:生成代码
你:复制代码到项目,运行,调试,部署
Agentic Engineering 工作流:
你:"做一个用户登录页面"
AI Agent:
1. 分析现有项目结构
2. 生成代码
3. 运行测试
4. 如果测试失败,自动修复
5. 提交 PR
6. 部署到预览环境
7. 通知你 Review
已经可用的 Agentic Engineering 工具
| 工具 | 能力 | 成熟度 |
|---|---|---|
| Cursor Agent Mode | 多文件自主编辑 + 运行命令 | ⭐⭐⭐⭐ |
| Claude Code | 终端自主操作 + Git 集成 | ⭐⭐⭐⭐⭐ |
| GitHub Agentic Workflows | 自然语言 CI/CD | ⭐⭐⭐(早期) |
| Devin AI | 自主完成完整开发任务 | ⭐⭐⭐(限量 Beta) |
开发者需要的新技能
在 Agentic Engineering 时代,开发者的核心价值不再是"写代码",而是:
- 产品设计能力:能够清晰地定义"要解决什么问题"
- 架构决策能力:能够在 AI 提供的多个方案中选出最优解
- 质量把关能力:能够审查 AI 生成的代码,发现潜在问题
- Agent 管理能力:能够高效地给 AI Agent 分配任务、审查结果
14. 总结:Vibe Coding 不是终点,而是新的起点
Vibe Coding 代表了编程范式的一次重大跃迁——从"手写代码"到"意图驱动开发"。它不会让开发者失业,但会让"不会用 AI 辅助开发"的开发者失业。
关键要点回顾
- Vibe Coding 的本质是意图驱动,不是"AI 写代码那么简单"
- Vibe Coding 和 Spec Coding 是互补的,根据场景选择
- 工具选型要看场景:专业开发用 Cursor,国内用 TRAE,终端用 Claude Code
- 三段式迭代工作流是生产级 Vibe Coding 的核心方法论
- Prompt 工程是核心技能,用具体替代抽象、主动声明负向约束
- 上下文管理决定了 AI 能否真正理解你的项目
- Token 优化让 Vibe Coding 的经济账算得过来
- 局限性要认清:AI 不知道它不知道的事情,代码要做人工审查
行动建议
如果你还没有尝试过 Vibe Coding,现在是最好的时机:
- 选一个工具开始:推荐 Cursor(最成熟)或 TRAE(国内友好)
- 找一个真实项目练手:不要只用"帮我写一个 Todo List"这种教程项目
- 强迫自己用自然语言描述需求:哪怕你很清楚怎么手写代码,也试着用 Vibe Coding 方式实现
- 记录你的 Prompt:好的 Prompt 是可以复用的,建立自己的 Prompt 库
Vibe Coding 不是未来,是现在。拥抱它,理解它,掌握它——然后在它的基础上继续进化。
本文写于 2026 年 6 月,所有工具信息和实践经验均基于 2026 年上半年的真实使用情况。Vibe Coding 领域变化极快,建议持续关注各工具的官方更新。
参考资料:
- Andrej Karpathy 的原始推文(2025 年 2 月)
- Cursor 官方文档(https://cursor.sh/docs)
- TRAE 官方文档(https://trae.com/docs)
- Anthropic Claude Code 文档(https://docs.anthropic.com)
- "Vibe Coding and Spec Coding" - CSDN 博客系列
- 程序员茄子网站相关文章(Headroom、codebase-memory-mcp、Agent Skills 等)