你跟 AI 说"写一个排序函数",AI 其实在内心崩溃
我跟你说一个真事。有一次我让 Claude 帮我写一个排序函数,就这么说的:"帮我写一个排序函数。"
Claude 倒是立刻就给了我一个函数。用 Python 写的,冒泡排序,没有类型注解,没有错误处理,输入参数叫 arr。
但我要的是什么?我要的是一个 TypeScript 函数,对一个对象数组按照 createdAt 字段降序排列,要处理 createdAt 为空的情况,要有完整的类型定义。
你看,我脑子里有这么多细节,但我嘴上只说了"写一个排序函数"。AI 不是神仙,它只能根据你给的信息来猜。你给的信息越少,它猜的成分就越大,结果离你想要的就越远。
这个问题在日常聊天场景里可能不太严重——你让 AI 写一篇文章,写得不太对你改几个字就行。但代码不一样。代码差一个分号都可能报错,差一个类型定义就可能导致线上 Bug。代码生成对 Prompt 的精确度要求,比任何其他场景都高。

大多数人写代码 Prompt 时的通病
很多人第一次让 AI 写代码时,Prompt 都是这个风格:
- "帮我写一个登录页面"
- "写一个数据库查询"
- "做一个 API 接口"
- "帮我处理一下这个数据"
就好像你去餐厅说"来一道菜"。服务员问你"要什么菜?"你说"都行。"服务员给你端了一份蒜蓉西兰花。你说:"不是,我想吃肉。"——可你一开始也没说你想吃肉啊。
在 Vibe Coding 里,这个问题更严重,因为你不是在写一个小函数,你是在做一个完整的项目。你跟 Cursor 说"帮我写一个登录页面",它可能给你用 MUI 做一个表单——但你的项目用的是 Tailwind CSS。它可能给你接了一个 Firebase Auth——但你用的是 Supabase。它可能给你做了一个弹窗式的登录——但你要的是全屏的登录页。
然后你就开始了漫长的"不对,改一下"循环。改了三四轮之后,代码已经被补丁搞得面目全非,你也失去了耐心。

五要素:让 AI 一次就写对
经过大量的踩坑和总结,我发现一个好的代码 Prompt 需要包含五个要素。不是说每次都得写全——简单任务可能两三个就够了——但你至少要知道有这五个,然后根据情况判断哪些需要写。
第一要素:语言和框架。
这是最基础的,但很多人真的会忘。你不说用什么语言,AI 可能给你用 Python,也可能给你用 JavaScript,还可能给你用 Go。你不说用什么框架,AI 可能自己挑一个你项目里根本没有的。
而且光说"用 React"是不够的,你要说"用 Next.js 14 App Router + TypeScript"。光说"用 CSS"是不够的,你要说"用 Tailwind CSS,不用任何 UI 组件库"。越具体,AI 生成的代码和你现有项目的兼容性就越高。
如果你的项目有 PRD 或者 CLAUDE.md,技术栈已经写在里面了,这一步可以省略——AI 会自动读到。但如果没有,每次写代码 Prompt 都要带上。
第二要素:功能描述(输入 -> 处理 -> 输出)。
这是五要素里最核心的。你要清楚地描述:这个函数/组件/页面接收什么输入、做什么处理、产出什么输出。
对比一下:
| 差 | 好 |
|---|---|
| "写一个解析 CSV 的函数" | "写一个函数,接收 CSV 格式的字符串,第一行是表头,返回对象数组" |
| "做一个搜索功能" | "做一个搜索框组件,用户输入关键词后实时过滤文章列表,匹配标题和标签" |
| "处理一下日期" | "写一个函数,输入 ISO 格式日期字符串,输出'3 天前'、'刚刚'这样的相对时间" |

第三要素:约束条件。
约束条件就是"除了功能本身,代码还要满足什么要求"。这包括:
- 代码风格:"使用 ESM 语法"、"优先用 const 和箭头函数"、"函数不超过 30 行"
- 类型要求:"包含完整的 TypeScript 类型定义"、"不要用 any"
- 注释要求:"包含 JSDoc 注释"
- 依赖限制:"不使用第三方库"、"只能用项目已有的依赖"
- 安全要求:"不使用 eval()"、"SQL 查询使用参数化"
第四要素:边界情况。
边界情况是"正常输入之外,还有哪些特殊情况需要处理"。比如:
- 输入为空怎么办?
- 输入格式不对怎么办?
- 数据量特别大怎么办?
- 网络请求失败怎么办?
说实话,边界情况是最难想全的,因为你要假设"什么可能会出错"。但你不需要想全,你只需要把你能想到的最明显的几个写上去。AI 看到你列了边界情况,通常还会自己补充一些你没想到的。

第五要素:示例(输入输出对)。
如果你能给一个具体的输入输出示例,AI 的理解准确度会飙升。因为自然语言描述再清楚,也不如一个例子来得直观。
示例:
输入:"name,age\nAlice,30\nBob,25"
输出:[{name: "Alice", age: "30"}, {name: "Bob", age: "25"}]
有了这个示例,AI 就不可能搞错"CSV 的第一行是表头"、"输出是对象数组"这些关键信息了。
完整的 vs 最简的
你可能会问:每次写代码 Prompt 都要写这五个要素,不累吗?
当然不用每次都写全。这取决于任务的复杂度:
| 任务复杂度 | 需要的要素 | 示例 |
|---|---|---|
| 简单改动 | 1-2 个 | "把这个按钮的文字从'提交'改成'发送'" |
| 新功能/组件 | 3-4 个 | 需要语言、功能描述、约束 |
| 核心逻辑 | 全部 5 个 | 需要所有要素才能保证正确性 |
还有一个我个人的经验:第一次做一个功能的时候,宁可多写几句。 因为 AI 第一次生成的代码决定了整个功能的基础结构。如果第一版就跑偏了,后面修修补补的成本远大于你多写几行 Prompt 的成本。这跟盖房子是一个道理——地基歪了,上面怎么修都是歪的。
在 Vibe Coding 里怎么用这五要素
最后说一下这五要素在具体的 Vibe Coding 工具里怎么用。
如果你用 Cursor,在 Composer 里写 Prompt 的时候,可以用 @ 符号引用你项目里的文件。这意味着你不用在 Prompt 里重复写技术栈和代码风格——你可以 @你的 PRD.md 或 .cursorrules,让 AI 自己读。这时候你的 Prompt 只需要写功能描述 + 边界情况 + 示例就够了。
如果你用 Claude Code,CLAUDE.md 里写好了项目规范之后也是一样的效果。你的代码 Prompt 可以更简洁,因为约束条件已经在项目配置里了。
但如果你用的是 ChatGPT 或 Claude 网页版,没有项目上下文,那你每次都要把五要素写得比较完整。这也是为什么 IDE 类工具(Cursor、Claude Code)在做项目时比聊天类工具(ChatGPT 网页版)效率高得多的原因之一——它们自带上下文。
代码 Prompt 五要素
为什么你让 AI 写的代码总要改好几遍