先说个常见的情况

先说个常见的情况

大家应该有遇到过这种情况:接到一个需求,图省事,直接一句话甩给 AI ——"帮我实现 xxx",然后它"啪"地给你写了一大坨代码。

乍一看挺像样,但细看就会冒出一些问题:它可能顺手改了几个你没让它动的文件、自己脑补了一些你没交代过的边界处理、或者明明项目里已经有现成的工具函数,它非要自己再写一个。最后你花在"读它到底写了啥、再把多余的改动择出去"上的时间,未必比自己写少多少。

这不是 AI 不行,而是它在​信息不全的时候只能靠猜​。我们没把"要做什么、不要做什么"讲清楚,它就只好替我们做主。

2. Spec-First 工作流:先约定,再实现

2.1 一句话定义

做需求前,先让 AI 输出一份可被人工 review 的实现方案(spec),人工确认后再让它按方案写代码。

注意三个关键词:

  • 可被 review​:方案是中文说明,不是直接的代码,其他同学也能都看得懂
  • 人工确认​:spec 要通过确认后才能让 AI 去执行,避免在错误前提上累积工作量
  • 按方案写​:第二轮 prompt 把 spec 喂回去,让 AI 按既定方案写,约束自由发挥的空间

2.2 五步概览

1. 喂上下文:提示词、产品需求说明、设计稿、AGENTS.md、相关代码/文档、... 2. 出方案:让 AI 输出 spec 3. Review 改方案:重要的一步,人工主导,必须经人工确认后才可进行下一步 4. 按方案实现:让 AI 严格依据 spec 编码 5. 验收 reveiw:AI reveiw + 人工 reveiw

2.3 适用 / 不适用

场景是否适用备注
新功能开发最佳场景
旧模块重构spec 阶段需要先对齐边界
技术方案调研spec 就是调研报告本身
Bug 修复⚠️修复 bug 主要在于问题排查,改动往往是小范围的,效果有限
纯 Code Review代码审查是为了提前发现问题,没有必要

3. 完整案例

Step 1 · 给 AI 足够的上下文

AI 出方案之前,先要让它"看到"足够的信息。对于一个常规需求,我们的输入主要有:

  • 用户提示词(手动书写,需要包含基本的一些描述)
  • 需求说明(形式可以为截图或文本描述,需要注意脱敏)
  • figma 设计稿(形式可以是截图或 MCP 读取,推荐使用 MCP)
  • AGENTS.md(agent 自动读取)

Step 2 · 让 AI 出方案

上下文准备好之后,​这一轮的目标不是写代码,是写方案​。给 AI 的提示词大致是这样:

我要在菜单下,新增一个模块: - 需求原型见上传的截图(需要手动上传) - figma设计稿如下: https://www.figma.com/xxx 请根据需求原型、figma设计稿和当前代码上下文输出详细实现的方案。 注意: - 需求原型截图和figma设计稿中的顶部导航栏和侧边菜单栏是已有的,不需要实现 - 原型截图中的红色文案是业务逻辑相关描述,要重点关注 - 不清楚的地方需要和我进行确认,禁止随意推测

可以指定编程工具当前为 plan 模式(这个 claude、codex、cursor 都支持),输出实现方案。

AI 输出方案示例:

Step 3 · 人工 Review 并修正方案

我们 review 方案的时候通常会改这几类东西:

  1. 需求理解偏差​:AI 复述的需求和我们想的不一样,及时纠正,spec 阶段发现成本最低
  2. 越界改动​:AI 顺手要改一些跟当前需求无关的文件,要砍掉,保持最小范围
  3. 复用顺序错​:AI 想自己新写一个工具函数,但目前项目里已经有了
  4. 假设没说明​:AI 默默地假设了一些边界条件,要让它显式写出来或主动进行确认
  5. 遗漏边缘情况​:加载状态、空状态、权限、异常分支等

Review 完后让 AI 重新生成 spec,再进行确认,直到 spec 双方都认可,才进入 Step 4。

示例:

Step 4 · 让 AI 按方案实现

第二轮的提示词示例:

请严格按照上面确认的方案实现。 - 不引入方案之外的改动 - 实现完成后,请按方案的"实现步骤"逐条说明你做了什么 - 如果实现过程中发现方案有问题,先停下来告诉我,不要自行调整

或者有的 AI 工具直接提供了 spec 的 build 按钮,可以不需要额外提示词。

AI 生成代码示例:

import React, { useCallback, useEffect, useState } from 'react'; import OverviewPanel from './components/overviewPanel'; import RecordTable from './components/recordTable'; // ...省略 const ApiMonitor: React.FC = () => { const [overviewData, setOverviewData] = useState<IApiMonitorOverview>(); const [overviewLoading, setOverviewLoading] = useState(false); // ...省略 return ( <div className="api-monitor"> <OverviewPanel data={overviewData} loading={overviewLoading} /> <RecordTable data={recordData} loading={recordLoading} total={total} current={listParams.current ?? 1} pageSize={listParams.size ?? DEFAULT_PAGE_SIZE} sortField={sortField} sortOrder={sortOrder} searchForm={ <SearchForm callerOptions={callerOptions} onSearch={handleSearch} onReset={handleReset} /> } onPageChange={handlePageChange} onTableChange={handleTableChange} /> </div> ); }; export default ApiMonitor;

页面效果: