AI 辅助编程实战:从需求边界到可审查交付
开发中最容易出现的误解是:只要把需求丢给 AI,它就能交付一个功能。
实际上,AI 擅长整理上下文、生成候选方案、补全局部实现、解释报错和发现可疑点;需求边界、技术取舍、风险判断、测试验证与最终合并责任,仍然必须由人承担。
下面用一个基于常见内部系统改编的案例跑完整个闭环。它不是某个具体公司的真实项目复盘,但保留了团队开发中常见的权限、历史数据、接口兼容、测试与代码审查约束。
案例:给任务系统增加"批量归档"
团队已有一个任务系统。任务完成后不会立即删除,而是保留在"已完成"列表中。运营同学提出新需求:
当前项目的项目管理员可以一次选择多条已完成任务并归档;归档后,默认任务列表不再展示,但具备该项目归档查看权限的管理员可在归档列表中恢复。
这句话还不能直接开始写代码,因为它没有明确权限范围、状态转换、重复请求和返回结果。
先把需求翻译成可交付的边界
可以让 AI 先做"需求质检员":复述已知条件,列出歧义和潜在风险;但最终规则必须由产品、开发或负责人确认。
本例最终确认如下:
| 项目 | 确认结果 |
|---|---|
| 操作对象 | 仅允许归档状态为 completed 且尚未归档的任务 |
| 操作权限 | 只有当前项目的项目管理员可操作,成员只能查看 |
| 操作范围 | 单次最多归档 100 条,且任务必须属于当前项目 |
| 数据策略 | 不物理删除,写入 archivedAt、archivedBy |
| 幂等性 | 已归档任务再次提交时不报错、不重复写入,并返回可识别原因 |
| 返回结果 | 返回成功数、跳过数,以及可安全披露的跳过原因 |
| 非目标 | 本期不做自动归档、跨项目批量操作和归档导出 |
可验收标准是:管理员能归档本项目中符合条件的任务;无权限用户不能产生写入;未完成、已删除、跨项目或不存在的任务不会被错误归档;重复点击不会产生重复副作用;归档后默认列表、归档列表、分页和筛选结果符合既有规则。
**人机分工很明确:**AI 可以帮助暴露问题,人必须决定规则。规则没有定下来,再漂亮的代码也只是把猜测固化进系统。

第一步:先拆"小变更",不要索要"一整个功能"
本例可以拆成六个任务:
- 确认数据模型:归档字段、恢复字段和必要索引。
- 定义接口契约:请求参数、响应、错误和幂等行为。
- 实现权限、项目归属和状态校验。
- 实现批量更新,并记录操作者与时间。
- 调整默认列表和归档列表查询。
- 补齐测试、变更说明、风险点和验证结果。
可以要求 AI 每次只处理一个任务,并固定返回:修改哪些文件、依赖哪些假设、尚未覆盖哪些场景、应执行哪些验证命令。这样得到的是一系列可追溯的候选变更,而不是一大段难以审查的代码。
第二步:让 AI 比较方案,而不是替你做架构决定
批量归档至少有两种实现方式。
方案 A:逐条读取并更新
读取任务、逐条校验、逐条更新并汇总结果。优点是失败原因细,缺点是数据库往返次数多,并且要明确部分成功时的事务语义。
方案 B:按条件批量更新,再计算结果
先验证当前用户是否为该项目管理员,再用"项目 ID + 任务 ID 集合 + 已完成 + 未归档"的条件批量更新;随后根据影响行数和补充查询计算成功、跳过结果。优点是通常更高效,缺点是要额外设计逐条原因的查询和并发语义。
本例选择方案 B,因为单次最多 100 条,且只要求汇总级结果。需要注意:仅凭 updateMany 的影响行数,通常不能区分"不存在""跨项目""未完成"和"已归档";如果接口承诺逐条原因,就必须补充受控查询,或调整接口契约。
AI 可以比较复杂度、失败模式和索引需求,但事务边界、ORM 能力、并发规则以及是否值得提前抽象,必须由开发者结合现有代码库决定。为了一个归档功能新增通用规则引擎、事件总线或多层策略类,可能只是过度设计。Google 的代码审查实践也强调,应优先解决已经明确存在的问题,而不是为想象中的未来需求堆叠复杂度。
第三步:把接口写成可验证的契约
http
POST /projects/:projectId/tasks/archive
Content-Type: application/json
{
"taskIds": ["task_101", "task_102", "task_103"]
}
成功响应示例:
json
{
"archivedCount": 2,
"skipped": [
{
"taskId": "task_103",
"reason": "ALREADY_ARCHIVED"
}
]
}
还要提前规定空数组、重复 ID、超过 100 条、无权限、跨项目、未完成、已删除或不存在、数据库失败,以及请求期间发生并发恢复或状态修改时的行为。
常见错误是只按 ID 更新,遗漏 projectId 条件。权限、归属和状态应当同时出现在服务端的查询或更新条件中,而不能依赖前端传参或 AI 的口头保证。伪代码可以接近:
ts
const result = await taskRepository.updateMany({
where: {
id: { in: uniqueTaskIds },
projectId,
status: "completed",
archivedAt: null
},
data: {
archivedAt: now,
archivedBy: currentUser.id
}
});
这段代码仍不完整:它没有展示管理员身份验证、参数校验、错误映射、审计日志、逐条跳过原因和事务边界。
第四步:让 AI 写局部代码,同时暴露假设
较好的顺序是:先解释仓库中相似功能,再草拟服务方法签名;人工确认接口和错误码后,实现最小更新逻辑;最后生成测试骨架和审查建议。每一步都要求 AI 标出假设,例如:
假设:
TaskRepository已有支持条件更新的updateMany方法;权限中间件已保证登录态;未覆盖:并发恢复任务与归档请求同时发生的情形。
假设清单能把隐蔽的模型幻觉变成可检查项目。GitHub 对 AI 编程助手的说明也提醒,模型建议不一定最优或完整,使用者仍需验证输出。
第五步:测试不是让 AI"补几个用例"
测试应从验收标准反推。可以先建立矩阵,再让 AI 补充测试骨架、测试数据和反例:
| 测试维度 | 关键场景 | 预期结果 |
|---|---|---|
| 正常路径 | 管理员归档 3 个已完成任务 | 3 条被归档,默认列表不再出现 |
| 权限 | 普通成员发起归档 | 无权限且不产生写入 |
| 归属 | 提交其他项目任务 ID | 不更新,并按契约返回跳过或拒绝 |
| 状态 | 提交进行中的任务 | 不归档并返回原因 |
| 幂等 | 已归档任务再次提交 | 不重复写入,结果可解释 |
| 输入校验 | 空数组、重复 ID、超过 100 条 | 返回参数错误 |
| 并发 | 归档期间任务被恢复 | 符合既定事务或条件更新约定 |
| 查询回归 | 默认列表、归档列表、分页筛选 | 旧功能不受影响 |
| 失败处理 | 数据库异常或超时 | 返回统一错误,不泄露内部细节 |
还可以让 AI 扮演"反例生成器":如果删除 projectId 条件,哪条测试会失败?如果漏掉 archivedAt: null,重复请求会怎样?如果权限判断放在批量更新之后,数据会发生什么?
好的测试不只是"跑绿",还要确认错误实现确实会让测试失败。Google 的审查指南建议,在同一变更中检查生产代码及相应测试,并确认断言有效、不会产生假阳性。
第六步:用失败的生成结果练习审查
ts
async archiveTasks(taskIds: string[]) {
return this.taskRepository.updateMany({
where: { id: { in: taskIds } },
data: { archivedAt: new Date() }
});
}
这段代码可能通过最简单的成功测试,但不能直接合并,至少存在以下问题:没有权限校验、项目归属限制、状态限制、幂等约束、操作者审计字段和可解释结果。它说明了一个关键现实:局部答案"看起来合理",不等于符合业务、工程和安全约束。
第七步:把 AI 放进代码审查,但不要把审批权交给它
提交 Pull Request 后,可以让 AI 总结改动、标出可疑空值路径、检查重复逻辑、解释失败流水线并提出候选问题;但作者和人工评审者仍需判断是否修复、是否符合仓库约定以及是否可以合并。GitHub 相关文档应以当前产品能力和团队权限配置为准,不能把 AI 的评论当成人工批准。
AI 辅助代码审查清单
- 正确性:验收标准、权限、项目归属、状态、幂等和并发是否完整。
- 可维护性:是否沿用既有分层、命名和错误处理,是否引入不必要抽象。
- 安全与隐私:是否遗漏后端授权;日志、提示词和测试数据中是否包含密钥、令牌、生产数据或个人信息;代理是否采用最小权限;高影响操作是否保留人工确认。
- 性能与数据规模:是否存在 N+1 查询,条件字段是否需要索引,批量大小和返回体是否合理。
- 异常处理:参数错误、无权限、状态冲突和系统错误是否区分,是否泄露内部细节,部分成功能否安全重试。
- 测试覆盖:是否验证数据库最终状态,移除权限或归属条件时测试是否会失败。
- 项目一致性:API、错误码、日志、审计、文档、接口定义和前端调用是否同步,变更是否便于回滚。
OWASP 关于具备代理能力的 LLM 应用建议采用最小功能、最小权限和人工确认原则;下游系统仍应独立完成授权校验,不能相信模型自行判断权限。
一页式工作流:每次让 AI 参与开发都留下这些产物
| 阶段 | 阶段产物 | AI 可以做什么 | 人必须确认什么 | 通过条件 |
|---|---|---|---|---|
| 需求澄清 | 边界、非目标、验收标准、待确认问题 | 复述需求、发现歧义 | 业务规则与优先级 | 每条验收标准可验证 |
| 任务拆解 | 小任务清单、依赖关系、风险排序 | 拆分技术任务、列遗漏项 | 粒度与顺序 | 每项可独立测试或审查 |
| 方案设计 | 接口契约、数据变化、方案对比 | 比较路径、生成草图 | 架构取舍与兼容性 | 符合现有约定 |
| 局部编码 | 小范围 Diff、假设清单 | 编写样板、重构局部逻辑 | 业务条件、权限与异常 | 静态检查和测试通过 |
| 测试调试 | 测试矩阵、复现步骤 | 生成骨架、解释报错 | 边界和修复有效性 | 错误可复现且修复通过 |
| 代码审查 | PR 描述、风险点、审查记录 | 总结改动、提出问题 | 是否修复、是否合并 | 人工审批和流水线通过 |
最后的边界:AI 可以加速,但不能替你交付
AI 辅助编程的效率,不是让开发者少思考,而是把重复整理、候选生成、代码解释和初步检查交给工具,让人把时间集中在理解业务、做取舍、验证结果和承担责任上。
真正的交付物不只是一段批量更新代码,而是一组可追溯证据:明确的验收标准、受约束的接口、可解释的异常处理、覆盖风险的测试、可审查的 Pull Request,以及人工确认后的合并决定。
可以从一个原则开始:每次让 AI 生成或修改代码,都要求它说明上下文、假设、未覆盖场景与验证方式;每次准备合并,都由人用测试和审查把这些回答逐一验真。