1. 为什么“随口问 AI 写代码”迟早会翻车
我刚开始用 AI 辅助写代码那阵子,跟大多数人一样:打开对话框,敲一句“帮我写个用户登录接口”,然后把生成的代码复制到项目里,跑不通就再问一句“报错了,帮我改改”。头几周确实爽,效率肉眼可见地涨。但项目一复杂,问题就全冒出来了——同一个需求,今天问出来的代码和昨天问出来的结构完全不一样;改了三轮之后,我自己都忘了最初的需求边界在哪;更别提团队里其他人接手时,面对一堆散落在聊天记录里的代码片段,根本拼不出完整逻辑。
这不是 AI 不行,是用法不对。把 AI 当成一个“随叫随到的代码生成器”,本质上是在做无状态的单次调用,而真实的软件开发是有状态、有上下文、有阶段划分的。需求从模糊想法到可交付代码,中间要经过澄清、拆解、设计、实现、验证、回归好几个环节,每个环节的输入输出都不一样。你把这些环节全塞进一个对话框里,AI 自然只能给你碎片化的答案。
所以我后来做了一件事:把需求开发流程编排成一条可复用的流水线。核心思路是把“问 AI 写代码”这个动作,从一次性的对话,变成一条有明确阶段、明确输入输出、可重复执行的管道。每个阶段由专门的 AI 角色或提示词模板负责,阶段之间通过结构化的产物传递信息。这样一来,同一个需求无论谁来跑,产出的代码结构、命名风格、测试覆盖都保持稳定,而且整条流水线可以沉淀下来,下次遇到类似需求直接复用。
这套东西我内部叫它Maestro 式编排——不是指某个具体工具,而是一种“指挥多个 AI 角色协同完成开发任务”的思路。下面我把整条流水线的设计、每个环节的实操细节、以及踩过的坑,完整拆一遍。适合已经用过 AI 写代码但觉得“不够稳”的开发者,也适合想把 AI 引入团队流程的技术负责人。
2. 流水线整体设计与角色拆解
2.1 为什么是“流水线”而不是“超级提示词”
很多人第一反应是:那我写一个超长的提示词,把所有要求都塞进去不就行了?我试过,不行。原因有三个。
第一,上下文窗口是有限资源。你把需求描述、编码规范、历史代码、测试要求全塞进一个提示词,AI 的注意力会被稀释,越靠后的要求越容易被忽略。实测下来,当提示词超过 2000 字,模型对中间部分的指令遵循度明显下降。
第二,不同阶段的认知模式不同。需求澄清需要的是“追问和质疑”,代码实现需要的是“严谨和收敛”,代码审查需要的是“挑刺和边界思维”。你让一个模型同时扮演这三种角色,它会在风格上互相干扰,写出来的东西四不像。
第三,不可复用。超级提示词是绑死在某个具体需求上的,换个需求就得重写。而流水线的每个阶段是通用的,只有“需求输入”这一项在变。
所以流水线的本质是关注点分离:把一个大任务拆成若干个小任务,每个小任务有独立的提示词模板、独立的输入输出格式、独立的验收标准。AI 在每个阶段只专注一件事,质量自然上去了。
2.2 五个核心阶段与角色定义
我把整条流水线分成五个阶段,每个阶段对应一个 AI 角色。这里说的“角色”不是指不同的模型,而是同一模型在不同提示词下的工作模式。
| 阶段 | 角色名 | 核心职责 | 输入 | 输出 |
|---|---|---|---|---|
| 1 | 需求分析师 | 澄清模糊点、补全边界条件 | 一句话需求 | 结构化需求文档 |
| 2 | 架构设计师 | 拆解模块、定义接口 | 需求文档 | 模块清单+接口签名 |
| 3 | 代码实现者 | 按接口写实现 | 接口签名+规范 | 可运行代码 |
| 4 | 测试工程师 | 生成测试用例 | 代码+需求 | 测试文件 |
| 5 | 代码审查员 | 检查规范与边界 | 代码+测试 | 审查报告 |
这五个阶段串起来,就是一条完整的“需求到代码”流水线。每个阶段的输出是下一个阶段的输入,格式固定,可以人工检查,也可以自动化传递。
2.3 阶段之间的“契约”设计
流水线能跑通的关键,是阶段之间的契约——也就是上游必须产出什么格式的东西,下游才能稳定消费。我踩过最大的坑就是:需求分析师输出了一段自由文本,架构设计师读完之后理解偏了,后面全错。
所以每个阶段的输出我都强制结构化。比如需求分析师的输出必须是这样的 JSON:
{ "feature_name": "用户登录", "inputs": ["用户名", "密码"], "outputs": ["token", "错误信息"], "boundary_conditions": [ "用户名为空时返回参数错误", "密码错误超过5次锁定账户" ], "out_of_scope": ["第三方登录", "记住密码"] }架构设计师拿到这个 JSON,就不需要再去猜需求边界,直接基于字段做模块拆解。这种“契约式”传递,是整条流水线稳定性的根基。
注意:契约格式不要设计得太复杂。我一开始搞了二十几个字段,结果 AI 经常漏填或者填错。后来精简到 6 个核心字段,遵循率立刻上来了。字段越少,AI 越不容易跑偏。
3. 核心环节的提示词模板与实操要点
3.1 需求分析师:把一句话变成可执行规格
这个阶段最容易被人跳过,但恰恰是最重要的。我见过太多人直接拿“帮我写个登录”去问 AI,然后抱怨生成的代码不能用。问题不在 AI,在于“登录”这两个字本身就有几十种解释。
需求分析师的提示词模板我打磨了十几版,核心是强制 AI 先提问再输出。模板大致是这样:
你是一名资深需求分析师。用户会给你一句话需求。 你的任务: 1. 先列出这个需求中至少5个模糊点,每个模糊点给出2-3种可能的解释。 2. 然后基于最常见的业务场景,选择一种合理解释,并说明选择理由。 3. 最后输出结构化需求文档,格式如下: - 功能名称 - 输入参数(含类型和约束) - 输出结果(含成功和失败情况) - 边界条件(至少3条) - 明确不做的范围 用户需求:{这里放一句话需求}实测下来,这个模板能让 AI 主动补全 80% 以上的边界条件。比如你输入“用户登录”,它会追问:是手机号登录还是用户名登录?密码错误几次锁定?token 有效期多久?要不要记录登录日志?这些问题如果你自己没想到,AI 帮你想到了,后面返工的概率就大幅降低。
3.2 架构设计师:接口先行,实现后置
拿到需求文档后,不要急着让 AI 写实现。先让它设计接口。这一步的价值在于:接口是稳定的,实现是可替换的。你把接口定死了,后面无论谁来写实现,只要符合接口,整个系统就能跑通。
架构设计师的提示词要点:
- 要求 AI 输出每个模块的函数签名,包含参数类型和返回值类型
- 要求说明模块之间的依赖关系,谁调用谁
- 要求标注每个函数的复杂度预估,超过一定复杂度的要拆
我通常会让它输出这样的结构:
# 模块:auth def login(username: str, password: str) -> LoginResult: """ 用户登录 参数: username: 用户名,长度3-20,仅允许字母数字下划线 password: 密码,长度8-32,必须含大小写和数字 返回: LoginResult: 包含 token 或 error_code 复杂度:中等,涉及密码校验和token生成 """ pass这个阶段我有个硬性要求:不允许 AI 写函数体。一旦它开始写实现,就会不自觉地“顺手”改接口,导致契约漂移。只出签名,实现留到下一阶段。
3.3 代码实现者:一次只写一个函数
到了实现阶段,很多人会让 AI“把整个模块写出来”。我试过,出来的代码质量参差不齐,而且一旦某个函数有问题,整段都要重来。
我的做法是按函数逐个生成。把接口签名、需求文档中对应的边界条件、以及项目的编码规范,一起喂给 AI,让它只实现这一个函数。提示词模板:
你是一名严谨的Python开发工程师。请实现以下函数。 要求: 1. 严格遵循给定的函数签名,不得修改参数和返回值类型。 2. 必须处理需求文档中列出的所有边界条件。 3. 代码风格遵循PEP8,函数不超过50行。 4. 每个关键分支必须有注释说明意图。 5. 不得引入未在依赖清单中的第三方库。 函数签名:{签名} 边界条件:{从需求文档中提取} 依赖清单:{项目已有依赖}这样做的好处是:每个函数的生成都是独立的,质量可控;如果某个函数有问题,只需要重新生成这一个,不影响其他部分;而且因为边界条件是显式传入的,AI 漏处理的概率大大降低。
3.4 测试工程师与审查员:让 AI 自己挑自己的刺
代码写完之后,不要直接合并。让 AI 切换成测试工程师角色,基于需求文档生成测试用例。这里的关键是:测试用例必须覆盖需求文档中的每一条边界条件,而不是让 AI 自由发挥。
我会在提示词里明确要求:
你是一名测试工程师。基于以下需求文档和代码,生成单元测试。 要求: 1. 需求文档中的每一条边界条件,必须对应至少一个测试用例。 2. 测试用例命名格式:test_功能_场景_预期结果。 3. 必须包含正常路径、异常路径、边界值三类测试。 4. 使用 pytest 框架。生成完测试后,再让 AI 切换成代码审查员,检查代码是否真的满足了需求。审查员的提示词要强调“挑刺”:
你是一名严格的代码审查员。请找出以下代码中的问题。 重点检查: 1. 是否有未处理的边界条件? 2. 是否有硬编码的魔法数字? 3. 是否有潜在的异常未捕获? 4. 命名是否清晰表达意图? 5. 是否有安全风险(如SQL注入、明文密码)? 每条问题给出:位置、原因、修改建议。这套“自己写、自己测、自己审”的流程,能把大部分低级错误在提交前拦下来。我统计过,经过这条流水线产出的代码,人工 review 时发现的问题数量比直接问 AI 生成的代码少了大约 70%。
4. 完整实操:从一句话需求到可运行代码
4.1 实操环境与工具准备
这套流水线不依赖特定工具,你用什么 AI 助手都能跑。我日常用的是支持长上下文对话的模型,配合一个本地的 Markdown 文件来记录每个阶段的产物。具体准备:
- 一个 AI 对话窗口(用于执行各阶段提示词)
- 一个项目目录,里面建
docs/文件夹存放需求文档和接口设计 - 一个
prompts/文件夹存放各阶段的提示词模板 - 版本控制工具,每个阶段的产物都提交一次,方便回溯
如果你想把流程自动化,可以用脚本把各阶段的输出串起来。但我的建议是先手动跑通三遍,等你对每个阶段的输入输出都心里有数了,再考虑自动化。上来就搞自动化,出了问题你都不知道是哪个环节的锅。
4.2 第一轮:需求澄清实战
我拿一个真实的小需求来演示:“给博客系统加一个文章草稿自动保存功能”。
把这句话丢给需求分析师提示词,AI 返回的模糊点包括:
- 自动保存的触发条件是什么?定时还是内容变化?
- 保存到哪里?本地缓存还是服务端?
- 保存频率多少?会不会造成请求过多?
- 草稿保留多久?要不要覆盖旧草稿?
- 用户关闭页面后草稿还在吗?
然后它基于常见博客场景,选择了这样的解释:内容变化后 3 秒触发、保存到服务端、每个用户每篇文章保留一份草稿、草稿保留 7 天、关闭页面后重新打开可恢复。
输出的结构化需求文档我存到docs/draft-autosave.md。这一步花了大概 5 分钟,但省掉了后面至少半小时的返工。
4.3 第二轮:接口设计与实现
架构设计师基于需求文档,输出了三个函数签名:
def should_autosave(last_save_time: float, current_time: float, content_changed: bool) -> bool: """判断是否触发自动保存""" def save_draft(user_id: int, article_id: int, content: str) -> DraftResult: """保存草稿到服务端""" def load_draft(user_id: int, article_id: int) -> Optional[Draft]: """加载草稿,超过7天返回None"""然后逐个实现。以should_autosave为例,我把签名和边界条件(“内容未变化不保存”“距离上次保存不足3秒不保存”“首次保存立即触发”)一起喂给代码实现者,生成的代码逻辑清晰,每个分支都有注释。
这里有个细节:时间参数用 float 而不是 datetime,因为需求文档里没规定时区处理,用时间戳可以避免时区问题。这是我在提示词里额外加的约束,AI 不会主动想到这一层。
4.4 第三轮:测试与审查
测试工程师基于边界条件生成了 6 个测试用例,覆盖了正常触发、内容未变、时间不足、首次保存、草稿过期、草稿不存在等情况。跑下来全部通过。
审查员则指出了两个问题:一是save_draft里没有对 content 做长度限制,可能导致超大内容写入;二是load_draft的过期判断用了硬编码的7 * 24 * 3600,建议提取成常量。这两个问题都很实在,我直接采纳修改。
整个流程从需求到可运行代码,大约 40 分钟。如果直接问 AI,可能 10 分钟就能拿到代码,但后续调试和返工的时间远超 30 分钟。更重要的是,这条流水线产出的代码,结构清晰、边界完整,团队里任何人接手都能看懂。
5. 常见问题与排查技巧实录
5.1 阶段输出格式跑偏怎么办
最常见的问题是 AI 不按你要求的 JSON 格式输出,而是自由发挥写了一段话。我的排查顺序是:
- 检查提示词里有没有给示例。AI 对格式的遵循度,给一个完整示例比描述十句都管用。
- 检查字段数量。超过 8 个字段的 JSON,AI 漏填概率急剧上升,能砍就砍。
- 检查是否要求了“只输出 JSON”。如果不强调,AI 总喜欢在 JSON 前后加解释文字。
如果还是跑偏,我会在提示词末尾加一句:“如果无法确定某个字段的值,填 null,不要省略字段。”这一句能解决大部分格式问题。
5.2 代码实现阶段 AI 擅自改接口
这个问题我遇到过好几次。AI 在写实现时,觉得某个参数类型不合理,就自作主张改了。解决办法是在提示词里加一条硬约束:
你只能实现函数体,不得修改函数签名中的任何字符。如果认为签名有问题,在代码注释中用 TODO 标注,但不得实际修改。
加了这条之后,接口漂移基本杜绝。
5.3 测试用例覆盖不全
AI 生成的测试往往偏向正常路径,异常路径覆盖不足。我的技巧是:在提示词里明确列出需要覆盖的边界条件编号,要求每个编号对应至少一个测试。比如“边界条件 3:密码错误超过5次锁定账户,必须有一个测试模拟连续6次错误登录”。把边界条件编号化,AI 就不容易漏。
5.4 多轮对话后上下文混乱
一条流水线跑下来,对话轮次可能超过 20 轮。到后面 AI 会开始“忘记”前面的约定。我的做法是每个阶段开一个新对话,把上一阶段的产物作为输入粘贴进去。虽然麻烦一点,但稳定性远好于在一个长对话里连续跑。
| 问题现象 | 可能原因 | 解决动作 |
|---|---|---|
| 输出格式跑偏 | 提示词缺示例或字段过多 | 加完整示例,字段砍到6个以内 |
| 接口被擅自修改 | 缺少硬约束 | 提示词加“不得修改签名” |
| 测试覆盖不全 | 边界条件未编号 | 边界条件编号化,逐个对应 |
| 后期上下文混乱 | 单对话轮次过多 | 每阶段开新对话,产物手动传递 |
| 代码风格不一致 | 未传入规范 | 提示词附上项目编码规范摘要 |
5.5 独家避坑心得
说几个文档里不会写、但实际跑起来一定会遇到的坑。
第一个坑:不要相信 AI 的“自我评估”。我试过让 AI 在生成代码后自己打个质量分,结果它给自己打 9 分,但实际跑起来有三个边界没处理。后来我改成让它“列出三个最可能出问题的地方”,这个反而准得多。让 AI 挑刺比让它自评靠谱。
第二个坑:提示词模板要版本化。我一开始把提示词随手写在对话里,改了几次之后自己都忘了哪版好用。后来建了prompts/文件夹,每个模板用日期命名,改动记录写在文件头。这样哪个版本效果好,一目了然。
第三个坑:不要追求全自动。我见过有人想把整条流水线用脚本串起来,一键从需求生成代码。结果中间某个阶段输出格式变了,后面全崩,排查起来极其痛苦。我的建议是阶段之间保留人工确认点,尤其是需求文档和接口设计这两个阶段,人工看一眼只要 30 秒,但能避免后面几小时的返工。
第四个坑:模型选择要分阶段。需求分析和架构设计阶段,用推理能力强的模型;代码实现阶段,用代码专精的模型;测试和审查阶段,用长上下文模型。不同阶段用不同模型,整体效果比全程用一个模型好不少。
6. 流水线的复用与扩展
6.1 把流水线沉淀成团队资产
一个人跑通流水线之后,下一步就是把它变成团队可复用的东西。我的做法是把每个阶段的提示词模板、输出格式定义、验收标准,整理成一个内部文档。新成员入职时,不需要理解背后的原理,照着模板跑一遍,产出的代码质量就能达到团队基线。
这里有个关键点:模板要带示例。光给提示词模板,新人不知道怎么填。我每个模板都配一个填好的示例,新人照着改就行。示例比说明文档有效十倍。
6.2 扩展到更多场景
这条流水线最初是为后端接口开发设计的,后来我把它扩展到了几个新场景。
前端组件开发:把“架构设计师”换成“组件设计师”,输出的是组件 props 定义和状态流转图,后面的实现和测试阶段基本不变。
数据脚本编写:需求分析师阶段增加“数据源确认”和“输出格式确认”,架构设计师阶段增加“数据量预估”,实现阶段强调异常处理和重试逻辑。
代码重构:把“需求文档”换成“重构目标”,架构设计师输出的是重构前后的接口对比,实现阶段要求“行为不变”,测试阶段要求“原有测试全部通过”。
每个场景的调整幅度都不大,核心的“分阶段、契约传递、角色切换”思路是通用的。
6.3 度量流水线的效果
我跟踪了三个月的数据,对比直接问 AI 和走流水线两种方式:
| 指标 | 直接问 AI | 走流水线 |
|---|---|---|
| 首次可运行率 | 约 40% | 约 85% |
| 人工 review 问题数 | 平均 8 个/百行 | 平均 2.5 个/百行 |
| 需求返工次数 | 平均 2.3 次 | 平均 0.4 次 |
| 从需求到合并耗时 | 约 2 小时 | 约 1.5 小时 |
首次可运行率和返工次数的差距最明显。走流水线虽然前期多花了时间做需求澄清和接口设计,但后面几乎不需要返工,总耗时反而更短。
6.4 后续可以怎么扩展
如果你已经把基础流水线跑顺了,可以尝试这几个方向。
一是引入多 AI 协作。让两个不同模型分别实现同一个函数,然后对比结果,取长补短。我试过用两个模型分别写测试用例,合并后的覆盖率比单模型高 15% 左右。
二是建立提示词库。把每个阶段验证有效的提示词片段存起来,比如“边界条件处理模板”“异常捕获模板”“日志埋点模板”,实现阶段按需拼装。这样新需求的提示词构建时间能从 10 分钟压缩到 2 分钟。
三是接入项目管理系统。需求文档直接关联到 issue,接口设计关联到 PR 描述,测试报告关联到 CI 结果。整条流水线的产物和项目管理工具打通,追溯起来非常方便。
我个人在实际操作中的体会是:这套流水线最大的价值不是“让 AI 写出更好的代码”,而是“让 AI 写出的代码变得可预测”。可预测意味着可管理、可复用、可交接。当你不再需要每次都对 AI 的输出提心吊胆时,AI 辅助开发才算真正融入了工程流程。