02|Spec:别再对 AI 说「帮我做个功能」

2026-09-11 15:23:46 0点赞 1收藏 0评论

本篇是《从头重新学 AI 编程》系列第 2 篇。

上一篇我们聊了一件事,你跟 AI 写代码之间的差距,不在 prompt 写得多精妙,而在你有没有把边界划清楚。

那篇最后我留了个小练习,让你试着把一个模糊需求改写成带边界的版本。如果你真的动手改了一遍,你大概已经感受到了,光是换个说法,AI 的输出质量就能差很多。

这一篇就把这件事系统地讲清楚。

我要聊的东西叫 Spec

这个词听着有点正式,但其实没那么复杂。你可以把它理解成,在你让 AI 动手之前,先把你想清楚的事情写下来。

它可以是一段话,可以是一份 Markdown 文档,甚至可以是一个 GitHub Issue。形式不重要,重要的是它得回答三个问题,你到底要做什么,什么能动什么不能动,怎么算做完了。

我自己的叫法是,意图、约束、验收标准。三样东西缺一个,AI 就得自己替你做决定。而 AI 替你做决定这件事。。。坦率的讲,十次里有七八次不是你想要的。

02|Spec:别再对 AI 说「帮我做个功能」

我给你看一个具体的例子,你就明白了。

还是我们这个系列的贯穿案例,那个待办事项应用。假设现在列表里的数据越来越多,你想加一个筛选功能。

如果你跟 AI 说「帮我做一个待办事项的筛选功能」,它会怎么做?

它可能给你加一个搜索框。也可能给你加三个下拉菜单。也可能给你搞一套复杂的过滤语法。它怎么选的?你不知道。它为什么这么选?它自己可能也不知道,就是在训练数据里见过类似的做法。

你拿到结果一看,技术上没什么问题,能跑。但跟你脑子里想的完全不是一回事。

然后你开始改,改了三轮,越改越乱,最后整个重来。

这种体验我经历过太多次了。

后来我慢慢养成了一个习惯,在让 AI 动手之前,先花两分钟把 Spec 写清楚。

同样是那个筛选功能,如果我这样写,

基于现有待办列表组件,增加筛选功能。 支持按状态筛选,全部、进行中、已完成。 支持关键词搜索,300ms 防抖。 筛选状态同步到 URL,刷新不丢失。 不改后端接口,前端处理。 无匹配结果时显示空状态。

你看,这段话做了什么?它把 AI 需要自己做决定的空间压到了最小。它不需要猜你要什么筛选维度,不需要猜数据在哪处理,不需要猜空状态怎么展示。你都告诉它了。

你没有写一行代码,但你把 Agent 的注意力框在了正确的范围里。

这就是 Spec。

02|Spec:别再对 AI 说「帮我做个功能」

说到这个,我想聊聊好 Spec 长什么样。我自己写了一段时间之后,发现好的 Spec 不管长短,都有三个共同点。

第一个,意图清晰

不是「做一个功能」,而是「基于什么模块,做什么事,用什么方式」。你写得越具体,AI 能自由发挥的空间越小,结果就越接近你想要的。

这块其实跟带人干活是一回事。你跟一个新来的同事说「把这个搞一下」,他大概率会来回问你三遍。但你说「把 UserList 组件里的分页逻辑抽成一个 hook,入参是 pageSize 和 fetchFn,返回当前页数据和翻页方法」,他就能直接动手了。

跟 AI 说话也是一样的道理。

第二个,约束明确

约束就是「不要做什么」。这个东西很多人会忽略,但我觉得它比「要做什么」还重要。

因为 AI 的默认行为是,只要你没说不能做,它就可能去做。它可能引入一个你不想要的依赖,可能改了一个你没让它碰的文件,可能动了数据库 schema,可能把你精心设计的函数签名给改了。

所以我现在写 Spec 的时候,一定会专门写一段「不做什么」。比如不引入新依赖、不改后端接口、不动某个目录下的文件、保持现有函数签名兼容。

这些话看着很简单,但你不说,AI 真的就会去动。

第三个,验收标准可测

「做完了」是什么意思?你得定义一个可以验证的标准。

好的验收标准是这样的,每一条都能被客观验证,要么看到了,要么没看到。不存在「差不多算完成」的空间。

比如「筛选栏显示在列表上方」「点击状态标签切换筛选,列表即时更新」「刷新页面后筛选状态保留」「无匹配结果时显示空状态提示」。

每一条你都能打开页面去测,过了就是过了,没过就是没过。

02|Spec:别再对 AI 说「帮我做个功能」

回到 Spec 这块,还有一个问题你可能会想,是不是每次都要写一份很正式的文档?

不需要。

我自己把 Spec 分成两种,一种轻量版,一种重量版。

轻量版就是直接写在对话里。适合小改动、一个会话能搞定的事。比如你想给 UserService 加一个注销方法,

在 UserService 加一个 deleteAccount 方法, 软删除(设 deleted_at)而不是物理删除。 同时撤销该用户所有的 session。 写一个单元测试覆盖正常流程和用户不存在的情况。

三五行就够了。意图清楚、约束明确、验收标准也有。直接贴在对话里,AI 就能执行。

重量版就是写成一个独立的 Markdown 文档。适合跨天的功能、涉及多个文件、需要多轮会话才能完成的事。

重量版我一般存成 specs/feature-xxx.md,结构大概长这样,

# 待办事项筛选功能 ## 背景 用户待办列表变长后,需要按状态和关键词快速找到目标项。 ## 目标 在列表上方增加筛选栏,支持按状态和关键词筛选。 ## 非目标 不做日期筛选。不做多选批量操作。不做服务端筛选。 ## 约束 - 不改现有 API - 不引入新依赖 - 筛选状态需要 URL 可同步 ## 验收标准 - [ ] 筛选栏显示在列表上方 - [ ] 点击状态标签切换筛选,列表即时更新 - [ ] 输入关键词后 300ms 防抖过滤 - [ ] 刷新页面后筛选状态保留 - [ ] 无匹配结果时显示空状态提示

重量版的好处是什么?你可以跨多个会话引用它。每次开新会话的时候把 Spec 文件贴进去,AI 就知道当前任务的全貌,不用你每次都从头解释一遍。

什么时候用哪种?我的判断标准很简单。一个会话能搞定的,写在对话里。需要跨天、跨会话、涉及多个模块的,写成文档。如果你不确定,先写轻量版,发现不够用了再升级。

不用纠结形式。Spec 的核心就是「把你想清楚的东西告诉 AI」,不管写在哪,写清楚就行。

这块需要注意一下,很多人把 Spec 当成写完就不管的东西。但实际开发过程中,你会不断发现新的约束、新的边界 case、新的技术限制。

Spec 是活的。

它不是一份一次性文档,而是你和 Agent 之间的合约。你更新了,Agent 就按新的来。你不更新,它就按旧的来,然后你又要花时间去纠正它。

我自己踩过好几次这个坑,前面写了个 Spec,后来发现需求变了但忘了更新文档,结果 AI 按旧的来,又白忙活一轮。

02|Spec:别再对 AI 说「帮我做个功能」

好,最后给你一个模板,你可以直接拿去用。

# [功能名称] ## 背景 为什么要做这个?解决什么问题? ## 目标 具体要实现什么。 ## 非目标 明确不做什么。 ## 约束 - 不改什么 - 不引入什么 - 兼容什么 ## 验收标准 - [ ] 标准 1 - [ ] 标准 2 - [ ] 标准 3

你不需要每次都把所有字段填满。小改动可能只需要「目标 + 约束 + 验收标准」三行。大功能才需要完整的结构。

关键是养成这个习惯,在让 AI 动手之前,先把你想清楚的东西写下来。

我知道这听着像废话。但你想想看,你上次让 AI 做一件事的时候,有没有先写 Spec?还是直接就说了一句「帮我做个 XXX」然后等结果?

如果是后者,试试下次先花两分钟写一段 Spec。哪怕只有三行。你会发现 AI 的输出质量会有一个明显的跳跃。

这不是什么高深的技巧,就是先想清楚再动手。只不过以前你是想清楚了自己写代码,现在你是想清楚了交给 AI 写。

下一篇我们聊一个跟 Spec 配合使用的东西,AGENTS.md怎么让 AI 一进你的项目就知道自己该看什么、遵守什么规矩,不用每次都从头解释

作者声明本文无利益相关,欢迎值友理性交流,和谐讨论~

展开 收起
0评论

当前文章无评论,是时候发表评论了
提示信息

取消
确认
评论举报

相关文章推荐

更多精彩文章
更多精彩文章
最新文章 热门文章
1
扫一下,分享更方便,购买更轻松