Vibe Coding 正确姿势指南我怎样把 AI 编程从碰运气变成可复现摘要我是重度 AI 编程用户。每天大部分代码都经由 Cursor 这类工具产出或改写。早期我以为 Vibe Coding 就是「想到什么说什么让 AI 自己悟」——结果经常改了三轮越改越偏或者 AI 自信地写了一堆跑起来全错。后来我才明白Vibe Coding 不是少说话而是说对话。氛围感来自你和 AI 同频流动不是来自模糊的灵感喷射。本文把我踩坑后总结的方法写下来附带20 真实开发场景的 Prompt 写法对比。你可以直接复制改用自己的项目。核心结论先行如果你现在…先做这件事AI 改完跑不起来补上复现步骤 报错栈 相关文件改了三轮还在跑偏用纠偏 Prompt 收窄范围别重发同一句每次都要重复说规范写进 Cursor Rules别在对话里唠叨大功能一次甩给 AI拆成「探索 → 计划 → 实现 → 验证」四段会话不知道 Prompt 怎么写套本文五要素骨架对照场景示例改一、Vibe Coding 到底是什么很多人把 Vibe Coding 理解成「不写计划、不看文档、全靠感觉」。我觉得不对。对我来说Vibe Coding 是在保持心流的前提下用结构化对话驱动 AI 完成开发。你负责方向和约束AI 负责展开和实现。你说得越含糊AI 就越只能猜——猜错了你的心流就断了。技巧的核心只有一句把「我想要的感觉」翻译成「AI 能执行的规格」。二、我的 Prompt 五要素骨架不管什么任务我尽量让每条消息包含这五块┌─────────────────────────────────────────────┐ │ 1. 目标 Goal — 做完是什么状态 │ │ 2. 约束 Constraints — 什么不能动 │ │ 3. 上下文 Context — 文件 / 报错 / 截图 │ │ 4. 验收 Done — 怎样算完成 │ │ 5. 格式 Format — 先计划 / 直接改 / 只分析 │ └─────────────────────────────────────────────┘检查口诀换一个人类同事听了我这句话也不知道具体干什么——那 AI 一定也不知道。三、三种对话模式模式什么时候用典型开场探索型还没想清楚怎么做「先别写代码列 3 种方案比较…」执行型方向已定要落地「按方案 2 实现只改这两个文件…」纠偏型AI 已经跑偏「停。不要重构。只修第 47 行的竞态…」四、场景 Prompt 大全模糊 vs 清晰以下每个场景都给出我早期踩坑的「模糊版」和现在使用的「清晰版」。清晰版可以直接复制替换括号里的内容。场景 1新功能开发 — 列表分页模糊版我早期这么干给这个列表加分页。清晰版给 ProductList 加前端分页。 【目标】 - 每页 20 条用现有 getProducts API 的 page/limit 参数 - 分页器放表格下方居中 - 切换页时保留当前筛选条件category、keyword - 样式沿用 OrderList 的分页组件 【约束】 - 不引入新依赖 - 不改 getProducts 接口签名 - 只改 ProductList.tsx 和相关的 hooks 【上下文】 src/pages/ProductList.tsx src/pages/OrderList.tsx参考分页实现 src/api/product.ts 【验收】 1. 默认显示第 1 页共 N 页正确 2. 筛选后分页重置为第 1 页 3. 现有测试全部通过 【格式】 先列出你准备改哪些文件、改什么我确认后再写代码。场景 2Bug 修复 — 偶发数据错误模糊版这个数据有时候不对帮我看看。清晰版订单总额偶发少算运费。 【复现步骤】 1. 购物车有商品 选了运费模板 2. 快速连续点两次「结算」按钮 3. 约 30% 概率 total 不含 shippingFee 【我已排除】 - 不是接口返回问题Network 面板看 shippingFee 有值 - 不是单个商品场景多商品也会触发 【上下文】 src/stores/checkoutStore.tscalculateTotal 方法 src/pages/CheckoutPage.tsxhandleSubmit 【我的猜测】 重复提交导致 state 被覆盖可能是竞态问题 【约束】 - 先定位根因不要直接大改 - 修完后补一个防重复提交的 guard 【格式】 先分析根因给出修复方案我确认后再改代码。场景 3Bug 修复 — 报错栈直接贴模糊版报错了修一下。清晰版运行 npm test 失败修这个测试和相关代码。 【报错】 TypeError: Cannot read properties of null (reading id) at UserCard (src/components/UserCard.tsx:28:32) at renderWithHooks (react-dom.development.js:15486:18) 【触发条件】 - 用户未登录时访问 /profile 页面 - UserCard 在 user 为 null 时仍然渲染 【期望行为】 - user 为 null 时显示骨架屏或跳转登录 - 不应抛异常 【上下文】 src/components/UserCard.tsx src/pages/ProfilePage.tsx 【约束】 - 用项目现有的 LoadingSkeleton 组件 - 补一个 usernull 的单元测试 【格式】 直接改代码改完说明改了什么。场景 4重构 — 拆分臃肿文件模糊版这个文件太乱了重构一下。清晰版重构 authService.ts拆分 token 管理逻辑。 【目标】 1. 把 token 刷新逻辑抽到 tokenManager.ts 2. 把 storage 读写抽到 tokenStorage.ts 3. authService.ts 只保留 login / logout / refreshToken 编排 【约束】 - 对外 API 签名不变login、logout、refreshToken - 不改其他文件的 import 路径用 authService 再 export - 不升级依赖 - 不「顺手」改其他模块 【上下文】 src/services/authService.ts src/services/看现有文件命名风格 【验收】 1. 现有调用方零改动 2. 补 tokenManager 单元测试覆盖刷新失败场景 3. npm test 全部通过 【格式】 先出重构计划和文件结构我确认后再动手。场景 5重构 — 组件拆分模糊版这个组件太大了拆分一下。清晰版拆分 DashboardPage.tsx当前 680 行。 【拆分方案】 - DashboardHeader顶部统计卡片区域 - DashboardChart图表区域含筛选器 - DashboardTable底部数据表格 - DashboardPage只负责布局和组合 【约束】 - 每个子组件放 src/pages/dashboard/ 目录 - props 类型明确定义不用 any - 不改任何业务逻辑纯结构拆分 - 样式保持原样把 className 跟着走 【上下文】 src/pages/DashboardPage.tsx 【验收】 1. DashboardPage.tsx 不超过 100 行 2. 页面渲染效果和拆分前一致 3. 不新增 lint 警告 【格式】 先列出拆分后的文件结构和 props 设计确认后执行。场景 6API 接口开发模糊版帮我写一个用户管理的 CRUD 接口。清晰版实现用户管理 REST API。 【接口清单】 - GET /api/users — 分页列表page, limit, keyword - GET /api/users/:id — 详情 - POST /api/users — 创建name, email, role - PUT /api/users/:id — 更新 - DELETE /api/users/:id — 软删除 【约束】 - 用现有 Express Prisma 栈 - 遵循 src/routes/order.ts 的路由风格 - 统一用 src/utils/response.ts 的 success/error 包装 - 参数校验用 zod - 需要登录复用 authMiddleware 【上下文】 src/routes/order.ts参考风格 prisma/schema.prismaUser 模型已存在 src/middleware/auth.ts 【验收】 1. 每个接口有基本的参数校验 2. 列表返回 { data, total, page, limit } 3. 补 routes/users.test.ts 覆盖 CRUD happy path 【格式】 先出路由文件结构确认后写代码。场景 7数据库 Schema 变更模糊版给用户表加个字段。清晰版给 User 表加 lastLoginAt 字段。 【变更】 - 新增 lastLoginAt DateTime?可选默认 null - 登录成功时更新该字段 【约束】 - 用 Prisma migration不手动改数据库 - 不改现有字段 - 已有数据 lastLoginAt 保持 null不需要回填 【上下文】 prisma/schema.prisma src/services/authService.tslogin 方法 【验收】 1. migration 文件可正常执行 2. login 成功后 lastLoginAt 更新为当前时间 3. 现有测试不受影响 【格式】 直接改改完告诉我 migration 命令。场景 8写单元测试模糊版帮我补测试。清晰版给 priceCalculator.ts 补单元测试。 【要覆盖的场景】 1. 单个商品无折扣 → 返回原价 2. 多个商品有满减券 → 正确扣减 3. 运费模板匹配 → 加上正确运费 4. 优惠券过期 → 抛 CouponExpiredError 5. 商品价格为 0 → 抛 InvalidPriceError 6. 满减门槛未达到 → 券不生效 【约束】 - 用 vitest项目现有测试框架 - 测试文件放 src/utils/__tests__/priceCalculator.test.ts - 不 mock 内部纯函数只 mock 外部 API 调用 - 每个 test case 有中文描述的 it 名称 【上下文】 src/utils/priceCalculator.ts src/utils/__tests__/看现有测试风格 【格式】 直接写测试代码。场景 9写 E2E 测试模糊版写个端到端测试。清晰版用 Playwright 写登录流程 E2E 测试。 【测试流程】 1. 打开 /login 2. 输入测试账号 testexample.com / password123 3. 点击登录 4. 断言跳转到 /dashboard 5. 断言顶部显示用户名「测试用户」 【约束】 - 测试文件放 e2e/auth/login.spec.ts - 用项目现有的 playwright.config.ts 配置 - 测试账号在 .env.test 里不要硬编码 - 登录失败场景也写一个错误密码 → 显示 toast 【上下文】 e2e/看现有 E2E 风格 playwright.config.ts src/pages/LoginPage.tsx 【格式】 直接写测试代码。场景 10性能优化模糊版这个页面好卡优化一下。清晰版ProductList 页面滚动卡顿做性能优化。 【现象】 - 列表 200 条商品时滚动明显掉帧 - Chrome Performance 面板显示 Scripting 占用高 - 每次滚动都触发全量 re-render 【约束】 - 优先用 React 层面优化memo、虚拟列表不改后端 - 不引入超过 5KB gzip 的新依赖 - 不改 UI 样式和交互行为 【上下文】 src/pages/ProductList.tsx src/components/ProductCard.tsx 【验收】 1. 200 条数据滚动流畅无明显掉帧 2. 首屏渲染时间不明显增加 3. 功能行为和优化前一致 【格式】 先分析瓶颈在哪列出优化方案和预期收益确认后实施。场景 11样式 / UI 调整模糊版这个按钮不好看改好看点。清晰版调整 Sidebar 底部「退出登录」按钮样式。 【目标】 - 改成幽灵按钮样式透明底、红色文字、红色边框 - hover 时红色背景 10% 透明度 - 和 Sidebar 顶部「设置」按钮风格统一 - 图标和文字间距 8px 【约束】 - 用项目 CSS 变量--color-danger, --radius-md - 不引入新图标库 - 只改 Sidebar.tsx 里的退出按钮部分 【上下文】 src/components/Sidebar.tsx src/styles/variables.css 【格式】 直接改改完不要解释 CSS 基础知识。场景 12暗色模式 / 主题模糊版加个暗色模式。清晰版给项目加暗色模式切换。 【目标】 - 顶部导航栏加切换按钮太阳/月亮图标 - 切换后全局主题立即生效不用刷新 - 用户选择存 localStorage下次打开保持 - 默认跟随系统 prefers-color-scheme 【约束】 - 用现有 CSS 变量体系在 variables.css 加暗色值 - 不引入 tailwind dark: 或新 CSS-in-JS 库 - 不改组件结构只改颜色变量 【上下文】 src/styles/variables.css src/components/Navbar.tsx src/App.tsx 【验收】 1. 切换按钮点击后 200ms 内完成主题切换 2. 刷新页面后保持用户选择 3. 所有现有页面在暗色下可读文字对比度足够 【格式】 先列出需要新增/修改的 CSS 变量清单确认后实施。场景 13国际化 i18n模糊版做一下多语言。清晰版给 Settings 页面加中英文切换。 【范围】 - 只做 Settings 页面其他页面后续再做 - 支持中文zh-CN和英文en-US - 语言切换器放 Settings 页面顶部 【约束】 - 用项目现有的 react-i18next 配置 - 翻译文件放 src/locales/{zh-CN,en-US}/settings.json - 不硬编码任何可见文字 - key 命名用 settings.xxx 前缀 【上下文】 src/pages/SettingsPage.tsx src/locales/看现有 i18n 结构 src/i18n/config.ts 【验收】 1. 切换语言后 Settings 页面所有文字即时切换 2. 无硬编码中文/英文残留 3. 翻译 key 不和其他页面冲突 【格式】 先列出 Settings 页面需要翻译的文字清单确认后实施。场景 14错误处理统一模糊版错误处理不规范统一一下。清晰版统一 API 调用的错误处理。 【现状问题】 - 有的用 try/catch console.log - 有的用 .catch(() null) - 有的根本不处理 - 用户看不到错误提示 【目标】 - 所有 API 调用统一走 useApi hook - 错误自动弹 toast用现有 toast 组件 - 401 自动跳转登录 - 500 显示「服务异常请稍后重试」 【约束】 - 先改 src/hooks/useApi.ts - 再改 src/pages/OrderList.tsx 作为示范 - 不要一次改所有页面我后续自己推广 - 不改 API 接口本身 【上下文】 src/hooks/useApi.ts src/pages/OrderList.tsx src/components/Toast.tsx 【格式】 先改 hook 一个示范页面改完说明其他页面怎么迁移。场景 15Code Review 请求模糊版帮我 review 一下代码。清晰版Review 我这个 PR 的改动重点关注安全问题。 【审查范围】 src/routes/users.ts新增的用户管理接口 src/middleware/rbac.ts新增的权限中间件 【审查重点】 1. 有没有 IDOR 漏洞用户能访问别人的数据吗 2. 权限校验是否完整普通用户能调 admin 接口吗 3. SQL 注入 / 参数注入风险 4. 敏感信息有没有泄露到响应里 【约束】 - 不要给风格建议缩进、命名那些我自己看 - 每个问题标注严重程度Critical / Warning / Info - 给出具体修复建议不要只说「有问题」 【格式】 按严重程度列出问题清单每个问题包含位置、风险、修复建议。场景 16依赖升级模糊版帮我升级 React。清晰版把 React 从 18.2 升级到 18.3。 【范围】 - 只升级 react 和 react-dom - 连带升级 types/react types/react-dom 【约束】 - 先查 CHANGELOG 看 breaking changes - 不升级其他依赖 - 不重构代码来「适配新版本」 【上下文】 package.json package-lock.json 【验收】 1. npm install 无冲突 2. npm run build 成功 3. npm test 全部通过 4. 如果有 API 废弃警告列出来但不强制改 【格式】 先告诉我 18.2 → 18.3 有没有 breaking changes确认后再改 package.json。场景 17写 Git Commit Message模糊版帮我写个 commit message。清晰版根据当前 git diff 帮我写 commit message。 【规范】 - 用 conventional commits 格式feat/fix/refactor/test/chore - 第一行不超过 72 字符 - 正文说明「为什么改」不要罗列「改了什么」 - 中文 【上下文】 当前 staged 的改动运行 git diff --cached 查看 【格式】 给 1 个推荐 message再给一个备选。场景 18写技术文档 / README模糊版帮我写个 README。清晰版给这个项目写 README.md。 【必须包含的章节】 1. 项目简介一句话说清干什么 2. 技术栈 3. 本地开发启动步骤从 clone 到跑起来 4. 环境变量说明引用 .env.example 5. 常用脚本dev / build / test / lint 6. 目录结构说明只列关键目录 【约束】 - 中文 - 命令可以直接复制执行 - 不要写「未来计划」「贡献指南」等废话章节 - 不要编造不存在的功能 【上下文】 package.json看 scripts 和 dependencies .env.example src/看目录结构 【格式】 直接写 README.md 文件。场景 19排查线上问题模糊版线上出问题了帮我查一下。清晰版线上订单导出功能报错帮我排查。 【现象】 - 时间今天 14:30 开始 - 影响约 15% 的导出请求返回 500 - 错误日志 Error: ENOENT: no such file or directory, open /tmp/export-xxx.csv at ExportService.generateCSV (exportService.ts:87) 【我已确认】 - 不是存储空间问题/tmp 有 2GB 可用 - 14:30 正好部署了 v2.3.1但 changelog 没改导出模块 【上下文】 src/services/exportService.ts src/routes/export.ts 本次部署的 git diffv2.3.0...v2.3.1 【约束】 - 先分析原因不要直接改 - 考虑是不是并发导致临时文件被提前清理 【格式】 给出根因分析 修复方案 紧急止血方案如果需要。场景 20AI 跑偏后的纠偏模糊版越说越错不对重新来。清晰版停。当前方向不对重新来。 【你做错了什么】 - 你重构了整个 auth 模块但我只需要修 token 刷新 - 你引入了 jsonwebtoken 库但项目用的是 jose - 你改了 5 个文件但我明确说了只改 authService.ts 【重新来只做这些】 - 只改 authService.ts 的 refreshToken 方法 - 修竞态并发调用时只发一次刷新请求 - 用现有 jose 库不引入新依赖 - 不改其他任何文件 【上下文】 src/services/authService.ts只看这一个文件 【格式】 先说你理解的问题和修复思路我确认后再改。场景 21探索新技术方案模糊版Redis 缓存怎么加清晰版评估给商品列表加 Redis 缓存的方案。 【背景】 - 商品列表 QPS 约 500P99 延迟 200ms - 数据变更频率低每天 10 次更新 - 已有 Redis 实例团队运维的可直接用 【请比较 3 种方案】 1. Cache-Aside应用层手动管理 2. 读穿透Read-Through 3. 用 Redis 直接做 API 响应缓存 【每个方案说明】 - 实现复杂度1-5 - 缓存一致性怎么保证 - 对现有代码改动量 - 预估 P99 能降到多少 【约束】 - 先别写代码 - 结合我项目现有架构分析Express Prisma Redis 【上下文】 src/routes/products.ts src/services/productService.ts 【格式】 用表格对比最后给出你的推荐和理由。场景 22配置 CI/CD模糊版帮我配个 GitHub Actions。清晰版创建 GitHub Actions CI 流水线。 【触发条件】 - PR 到 main 分支时 - push 到 main 分支时 【流水线步骤】 1. checkout 2. 安装 Node 20 3. npm ci 4. npm run lint 5. npm run test 6. npm run build 【约束】 - 用 .github/workflows/ci.yml - 测试需要 PostgreSQL 服务用 GitHub Actions service - 缓存 npm 依赖加速 - 不加 deploy 步骤后续再加 【上下文】 package.json看 scripts .env.example看需要哪些环境变量 【格式】 直接写 ci.yml 文件。场景 23数据迁移脚本模糊版帮我写个数据迁移。清晰版写脚本把旧订单表的 status 字段迁移到新枚举值。 【映射关系】 - pending → OrderStatus.PENDING - paid → OrderStatus.PAID - shipped → OrderStatus.SHIPPED - done → OrderStatus.COMPLETED - cancel → OrderStatus.CANCELLED - 其他未知值 → OrderStatus.UNKNOWN并打印日志 【约束】 - 用 Prisma 的 migrate 或独立脚本你建议哪种 - 分批处理每批 500 条总量约 10 万条 - 支持 dry-run 模式只打印不写入 - 可回滚 【上下文】 prisma/schema.prisma src/types/order.tsOrderStatus 枚举 【验收】 1. dry-run 模式输出迁移预览 2. 正式执行不锁表超过 5 秒 3. 迁移完验证条数一致 【格式】 先建议用 migration 还是独立脚本确认后写代码。场景 24日志与监控埋点模糊版加点日志。清晰版给支付流程加结构化日志。 【埋点位置】 1. 创建支付订单记录 orderId, amount, channel 2. 调用第三方支付记录 request/response 耗时 3. 支付回调记录 callback 原始参数 4. 支付失败记录错误码和错误信息 【约束】 - 用项目现有的 winston loggersrc/utils/logger.ts - JSON 格式加 requestId 串联 - 不记录银行卡号、密码等敏感信息 - 日志级别正常流程 info失败 error 【上下文】 src/services/paymentService.ts src/utils/logger.ts src/routes/payment.ts 【格式】 直接改代码改完列出每个埋点位置和日志字段。场景 25并发 / 线程安全模糊版这里有并发问题修一下。清晰版修复库存扣减的并发超卖问题。 【现象】 - 100 个并发请求扣减库存 1 件商品库存只有 10 - 实际卖出了 15 件 【上下文】 src/services/inventoryService.tsdeductStock 方法 src/routes/order.tscreateOrder 调用链 【约束】 - 优先用数据库层面方案乐观锁或悲观锁 - 不改接口签名 - 库存不足时返回明确错误 InventoryInsufficientError 【验收】 1. 写一个简单的并发测试验证不超卖 2. 正常单线程扣减不受影响 【格式】 先比较乐观锁 vs 悲观锁方案确认后实施。五、迭代对话模板我常用的后续消息第一轮 Prompt 之后我通常用这些模板继续验证通过后继续下一步测试通过了。接下来做第二步[具体描述]。 约束和之前一样只改 [文件]。验证失败贴结果跑了一下有问题。 【实际结果】 [贴报错 / 截图描述 / 不符合预期的行为] 【预期结果】 [应该怎样] 继续修不要改其他已经正确的部分。缩小范围方向对了但改动太大。 这一轮只做 [一件具体的事]其他不动。要求解释代码我跑通了但想理解一下。 用三句话解释 [某个函数/设计] 为什么这样写不要泛泛科普。批量推广OrderList 的错误处理改法很好。 按同样模式改 ProductList 和 UserList只改错误处理不改业务逻辑。 src/pages/ProductList.tsx src/pages/UserList.tsx src/pages/OrderList.tsx参考六、上下文管理比 Prompt 技巧更重要6.1 写进 Cursor Rules别每次重复我对 AI 重复第三遍的话就该变成规则。我在.cursor/rules/里固定写- 技术栈React 18 TypeScript Vite Prisma Express - 不自动 git commit - 不引入新依赖除非我明确要求 - 改动优先最小 diff不要顺手重构 - 回复用中文 - 先给计划我确认后再写大改动6.2 会话分工任务类型我的做法大功能拆成 4 个会话探索 → 计划 → 实现 → 修 bug小 bug一个会话搞定探索方案单独开明确说「不写代码」已跑偏开新会话带上纠偏 Prompt 和文件6.3 用 diff 说话别用形容词❌ 这个写法不太好改进一下。 ✅ fetchData 在错误时返回 undefined调用方没处理。 请改成错误时抛出 ApiError在 useProducts 里 catch 显示 toast。七、我踩过的坑反模式清单坑后果正确做法「你看着办」AI 猜猜错你擦屁股给 2-3 个选项或明确约束「按最佳实践」它的实践不是你的「参照 src/utils/http.ts 的风格」一次甩整个需求抓错重点分阶段每阶段有交付物不纠正重发同类 Prompt同样错误再来一遍指出具体错在哪把 AI 当搜索引擎浪费上下文探索型任务也说清项目背景不说「不要做什么」AI 顺手重构明确列 Constraints一个会话塞 5 个需求上下文糊掉一会话一任务八、发 Prompt 前的 7 秒检查清单说清做完是什么不是「做一下」说清不能动什么用指向相关文件给了验收标准或复现步骤说了输出格式先计划 / 直接改 / 只分析当前会话只有一个主任务上一条跑偏时做了具体纠偏而不是重发七个里做到五个反馈质量就会明显好很多。九、最后说一点实在的Vibe Coding 不是「少思考多生成」。恰恰相反你越清楚自己要什么AI 越像资深搭档你越模糊它越像会瞎编的实习生。好 Prompt 的本质是你对问题的理解已经到位了只是懒得亲手敲每一行。把意图说清楚把边界画明白把验证跑起来——剩下的交给 AI 去展开。这才是我理解的 Vibe Coding不是摆烂式编程而是高带宽的人机协作。全文完。场景 Prompt 可复制后替换括号内容直接使用。