☰
AI编程工作流v2.0:从需求清洗到自动化自测的完整流水线
2026/9/28 19:26:38 网站建设 项目流程

两年前我刚开始把 AI 塞进日常开发时,路子特别野:哪里不会问哪里,写完能跑就算赢。结果代码越补越脏,上下文越聊越偏,最后连我自己都看不下去。于是有了 v1.0,把“随口提问”改成了“需求写清楚、边界列明白、代码分步出”;但这套东西跑了一阵子又暴露了新的问题——提示词虽然规范,可阶段之间没有接力,AI 改完需求后经常把前面定的方案推翻。今年我把整套流程重构了一遍,也就是这篇想聊的AI 编程完整工作流程 v2.0。它不再是一堆 prompt 的拼凑,而是把需求清洗、方案契约、分步实现、自动化自测、文档沉淀串成一条流水线。如果你也在用 Cursor、Copilot、Trae 这类 AI 辅助工具,却总觉得“生成一时爽,维护火葬场”,这篇应该能给你一套可以直接抄的框架。

1. 为什么还要单独设计一套 AI 编程工作流

1.1 从零散提问到流水线作业

大部分人对 AI 编程的用法,还停留在“编辑器里开个对话框,把需求一句话甩过去”。比如“帮我写一个解析日志的 Python 脚本”,AI 确实能给你一个能跑的版本,但这里的隐患是:需求不完整,边界靠猜,函数命名全看心情。换个人来看代码,根本不知道当初为什么这么写。

更麻烦的是,零散提问没有状态继承。你今天让它写模块 A,明天让它改模块 B,它完全不记得昨天的约定。结果就是模块 A 用了parse_line(),模块 B 里又出现一个parse_log_line(),功能重叠、命名混乱、调用关系像一团毛线。这在单人项目里还能靠记忆力硬撑,一旦代码量过万行,或者团队协作,就完全失控。

所以我设计工作流的第一个出发点,不是追求“AI 一次生成完美代码”,而是“怎么让 AI 生成的代码具备人写的代码一样的可维护性”。v2.0 的核心思想是:把 AI 当作一个思路清晰、但记忆力很差的实习生。你不可能指望实习生一句话就搞定所有事,你得给他任务书,给他反馈机制,还要在关键节点验收成果。

1.2 v2.0 与 v1.0 的核心差异

v1.0 的时候,我的流程大概是这样:需求描述 → 让 AI 给方案 → 直接生成完整代码 → 报错就丢回给 AI 修。听起来好像也成体系,但实际操作中会发现三个致命问题。

第一,AI 给的方案和它最终写的代码经常不一致。方案里说要三个模块,代码里却揉成了一个函数;方案里设计了错误处理,代码里全是裸调用。这就是因为方案和代码生成之间没有强约束。

第二,需求变更是常态,但 v1.0 没法处理变更。今天说日志解析用正则,明天说性能不行要改成按行 split,AI 在每一轮都是全新任务,根本不知道要保留哪些逻辑、替换哪些逻辑、影响哪些调用方。

第三,缺少“验收”环节。AI 说代码写完了,你就以为真写完了。可它所谓的“写完”,往往是编译器的网开一面和运行时的不测风云之间那个灰色地带。

v2.0 针对这三个问题,引入了三条硬规则:

  • 方案必须落到“契约文件”,代码生成必须基于契约文件,不允许直接改代码。
  • 需求变更先改契约文件,再让 AI 按增量说明去实施,而不是推倒重来。
  • 每个功能模块必须带上最小自测用例,AI 交付代码时同时交付测试,没有测试的一律视为未完成。

这三条规则看着简单,其实是把我过去踩过的坑全部压扁了重新摆出来。后面我会一个个细说。

2. AI 编程工作流 v2.0 的总体架构

2.1 五个环节和一条纪律

v2.0 把整个开发过程拆成五个环节,顺序固定,不允许跳步:

  1. 需求池清洗:把所有诉求收集在一起,去掉模糊表达,拆成可执行、可验证的最小任务。
  2. 方案契约订立:针对每个任务输出技术方案,方案里必须包含模块划分、数据结构、接口签名、错误处理策略。
  3. 分步实现:按模块逐个生成代码,每生成一个模块就做一次本地编译或语法检查。
  4. 自动化自测:用 AI 生成的测试用例对代码做验证,测试不过就不允许进入下一模块。
  5. 文档与交接沉淀:把关键决策、使用方式、已知问题写回项目内的文档,方便后续 AI 和人都能读取。

一条纪律是:所有交互都以“文件状态”为准。AI 不是从头到尾在一个对话框里完成所有事,而是每进入下一个环节,都重新读取当前项目里最新的契约文件、最新的代码结构文件、最新的变更记录。这套做法,本质上是在模拟真实团队里“口头约定全部落到文档”的管理方式。

2.2 上下文管理:别让 AI 只靠记忆干活

AI 编程工具最容易被忽视的问题,是上下文长度和记忆可靠性。你在这个会话里跟 AI 聊了两小时,你以为它全都记得,其实它在长对话后期对早期内容的引用准确率会明显下降。更现实的场景是:你换了台机器,开了新会话,之前的约定全部归零。

所以 v2.0 里专门有一条“上下文外置”的原则:所有重要约定必须写到项目目录里的文件里,比如docs/contract.md、docs/decisions.md。每次需要 AI 继续干活时,先用读取指令把这些文件喂进去,再提新需求。

这样做有个额外好处:人可以审、AI 可以读、后续加入项目的同事也能快速理解项目状态。相当于把 AI 的工作记忆和外置存储分开,让 AI 专注于推理和执行,让文件系统承担信息持久化。

2.3 模块拆分的粒度:最小可验证单元

v2.0 里最费心思的是“粒度”。拆太粗,一个模块几百行代码,AI 生成的风格容易跑偏,出错后排查范围太大;拆太细,一个文件十几个小函数,上下文引用和调度成本反而高。

我现在的标准是:一个模块应该能独立编译、独立运行、独立验证。比如日志解析器,拆成loader、parser、reporter三个模块就合适。parser再往下拆date_parser、level_parser就过度了。判断方法很简单:如果这个模块的测试需要引入其他模块才能跑,说明拆得不够;如果删掉这个模块会导致另一个模块的功能不完整,说明拆得太狠。

每个模块的代码量,我一般控制在 50 到 150 行之间。这个区间对 AI 的生成质量最友好:上下文够了,不会漏依赖;代码短了,人也容易 review。超过 200 行,AI 生成内部逻辑时经常出现函数引用顺序混乱、重复定义之类的问题。

3. 实操:v2.0 跑通一个真实需求

3.1 用一个内部脚本做完整演示

理论说多了容易飘,我用最近做的一个内部小工具来走一遍完整流程。需求是这样的:团队在写技术博客时,Markdown 文件里经常引用本地图片,但图片被移动或删除后,文档里留下的链接就变成死链。人工检查很烦,所以想做一个小脚本,扫描指定目录下所有.md文件,找出引用了本地图片但文件不存在的链接。

这个需求不算复杂,但拿来演示 v2.0 特别合适,因为它有明确的输入输出、有错误处理需求、有可验证标准。如果连这种小需求都跑不顺,那大项目就更不用谈。

3.2 第一步:需求池清洗

在让 AI 写代码之前,先把这个需求写成一条一条的明确任务。我的做法是在项目目录下建立一个docs/requirements.md,内容大概长这样:

# Markdown 图片链接检查器 ## 功能需求 - 输入参数:待扫描目录 `dir`,支持相对路径和绝对路径 - 输出结果:列出所有包含本地图片引用的 md 文件,以及对应缺失文件路径 - 支持链接形式:`![](./images/foo.png)`、`<img src="images/bar.jpg">` - 忽略远程链接:以 `http://`、`https://` 开头的图片链接跳过 ## 边界条件 - 目标目录不存在时,退出码 1,打印可读错误信息 - md 文件编码只考虑 UTF-8 - 图片路径包含空格时,允许使用 `%20` 形式,需要解码后判断

这些信息不需要一次写全,但至少要覆盖“输入是什么、输出是什么、哪些情况算正常、哪些情况算异常”。写需求池的过程,本质上是在帮 AI 排除它最爱做的“自由发挥”。你越是把边界条件写清楚,后面生成代码越不会跑偏。

3.3 第二步:方案契约订立

拿到需求池之后,再让 AI 做技术方案。我这里用的是 Claude 和 ChatGPT 类模型做方案设计,再把方案整理进docs/contract.md。方案不需要很花哨,但必须包含模块划分和接口签名,让代码生成阶段有据可依。

实际生成的契约文件长这样(简化版):

# 技术契约 ## 模块划分 - `walk_files.py`: 遍历目录,收集所有 `.md` 文件路径 - `extract_links.py`: 解析 md 内容,提取本地图片引用 - `check_missing.py`: 判断引用文件是否存在,输出缺失结果 - `cli.py`: 命令行入口,汇总以上模块,负责参数解析和错误处理 ## 接口定义 - walk_files.find_md_files(root: Path) -> list[Path] - extract_links.extract_local_image_paths(md_path: Path, base_dir: Path) -> list[Path] - extract_links.is_remote_url(src: str) -> bool - check_missing.filter_missing(paths: list[Path]) -> list[Path] - cli.main(argv: list[str]) -> int ## 错误处理 - 目录不存在:抛出 DirectoryNotFoundError,cli 层捕获后返回 1 - 文件解码失败:跳过该文件,在 stderr 输出 warning,不中断整体检查

契约文件最大的价值,是让 AI 在实现阶段没有“设计自由”。它只能按接口去写,接口不对就是不合格。我在实际项目中见过太多 AI 自作主张改接口的行为,契约文件就是用来斩断这种冲动的。

3.4 第三步:按契约分步实现

实现阶段,我不让 AI 一口气生成所有模块,而是每打开一个模块对话,先让它读docs/contract.md,再单独实现当前模块。比如先实现walk_files.py,prompt 大概是:

请阅读 docs/contract.md,只实现 walk_files.find_md_files 函数。要求: - 使用 pathlib.Path.rglob 方式递归查找 - 只返回后缀为 .md 的文件 - 函数类型注解必须与契约一致 - 不要写额外的函数或 import

这里有一个很关键的动作:限制 AI 只做一件事。不要让它在实现 walk 的时候顺带把 extract 的逻辑也写了,不然模块边界立刻模糊。每完成一个函数,我会让 AI 粘贴出来,人工快速扫一眼有没有越界,然后再进入下一个模块。

这四个模块全部生成后,工程结构大概是这样的:

. ├── cli.py ├── walk_files.py ├── extract_links.py ├── check_missing.py └── docs ├── requirements.md └── contract.md

代码层面没有神奇之处,但整棵文件的调用关系是清晰的,每个函数都能单独读、单独改。对于一个 AI 辅助生产的项目来说,结构清晰比代码惊艳重要一百倍。

3.5 第四步:自动化自测

模块都实现完,下一步是让 AI 写测试。注意,这里不是“让 AI 跑一下看对不对”,而是“让 AI 为每个模块给出一组最小测试用例”。测试文件我放在tests/目录下,命名对应模块。

拿extract_links.py来举例,AI 生成的测试大概是:

from pathlib import Path from extract_links import extract_local_image_paths, is_remote_url def test_extract_local_image_paths_finds_missing_image(): md_path = Path("tests/fixtures/sample.md") base_dir = Path("tests/fixtures") result = extract_local_image_paths(md_path, base_dir) assert any(p.name == "missing.png" for p in result) def test_is_remote_url_returns_true_for_http(): assert is_remote_url("https://example.com/a.png") is True def test_is_remote_url_returns_false_for_local(): assert is_remote_url("./images/a.png") is False

生成测试后,我会运行pytest -q。第一次跑往往是失败的——不是因为代码错了,而是因为边界条件没对齐。比如测试里创建了临时目录,但代码用了相对路径解析,目录基准不一致。这个时候把报错信息丢回给 AI,让它修改代码或者修改测试,哪个更合理,需要人来判断。

这一步是整个工作流里面最容易偷懒但最不能偷懒的。许多人的 AI 编程越到后面越乱,就是因为缺少“验收”这道关卡。没有测试的代码,AI 自己都不知道自己写错了什么,更别提后续迭代了。

3.6 第五步:文档与交接沉淀

测试跑通后,工作流还没有结束。最后一步是把这次实现过程中的关键判断写进docs/decisions.md。比如:

  • 为什么用Path.rglob而不是手动 os.walk:写法更简洁,且返回的是 Path 对象,类型一致。
  • 为什么忽略远程链接:内网博客不需要检查外链,如果要支持,后续按 http 前缀过滤即可。
  • 为什么图片路径需要做%20解码:因为 Markdown 里的 URL 编码规则和本地文件系统规则不完全一致。

文档不需要写成长篇小说,三五行即可。但这三五行会在未来某一天救你一次。比如版本迭代到 v3.0,你让 AI 重构这块逻辑时,它重新读取docs/decisions.md,就不会再犯一遍同样的错。

4. 工具选型与搭配方式

4.1 不是选一个,而是组一套

总有人问我“哪个 AI 编程工具最好”,我的回答一直是:看场景。真正用顺手的 AI 编程工作流,往往是多个工具配合,而不是依赖某一个全能选手。我自己目前的组合是:

环节工具说明
方案设计Claude 或 ChatGPT善于结构化思考,适合生成契约文件
编辑器内补全GitHub Copilot日常写函数、补参数、写测试时效率最高
多文件重构Cursor对跨文件改动、代码库规模较大的项目更好用
长上下文续接Windsurf 或 Trae处理已经足够大的上下文时,分段续写更稳定
本地私密代码通义灵码或 CodeGeeX代码不方便出公司内网时,可以靠私有化部署解决

这套组合的思路是:方案生成靠对话模型,因为它不需要直接操作代码库;具体实现靠编辑器内嵌工具,因为它能拿到最近的代码上下文;跨文件重构靠 Cursor,因为它的索引机制在处理大型仓库时比单纯的对话模型靠谱得多。

这里我特别想提醒一点:不要迷信“一个工具吃遍天下”。我自己踩过最大的坑,就是把所有代码工作全丢给一个对话模型去处理。它对单个文件的理解没问题,但项目一复杂,它不知道哪些文件被改过、哪些依赖快失效了。编辑器类工具之所以能补齐这个短板,是因为它们背后有本地代码索引和文件变更感知,这是纯对话模型不具备的。

4.2 提示词模板库管理

v2.0 里除了工具,我还会维护一个prompts/目录,把经常用的提示词模板沉淀下来。模板不是在 UI 里复制粘贴,而是作为文件存在项目仓库里。比如prompts/implement_function.md长这样:

你是本仓库的资深开发。请基于 docs/contract.md 实现以下接口: {interface_signature} 要求: 1. 不得修改契约中定义的函数签名和返回类型 2. 不允许新增额外模块 3. 必须处理契约 Error Handling 章节里列出的异常场景 4. 实现完成后附上 2-3 个最简测试用例

这些模板最大的价值,是把“可靠的 AI 使用方法”固化成团队资产。新人加入时,不需要从头摸索哪些写法容易让 AI 产生幻觉,直接把模板拿过去用就行。我自己维护了大概二十多个模板,覆盖需求清洗、契约生成、单模块实现、测试生成、代码 review、重构扩散分析等常见场景。

4.3 让 AI 理解现有代码库的方式

很多人问:为什么明明已经跟 AI 聊了很久,它还是不理解项目里已有的代码?这里的问题在于,大多数对话模型并不知道你仓库里有什么。它们只能看到你在对话框里贴出来的内容。想让 AI 真正理解代码库,要么用编辑器类工具的索引功能,要么主动把关键文件喂给它。

v2.0 的做法是:在项目根目录维护一个docs/architecture.md,用极简的方式描述每个目录的职责、核心模块的位置、关键数据流的方向。每次开始较大规模的修改前,我会先把这张文档发给 AI。它花不了多少 token,但能让 AI 在一开始就站在正确的位置上去理解问题,而不是从文件名瞎猜。

如果项目已经很大,还可以考虑用代码检索类插件做 RAG 式问答。这类工具会把代码库切片后做向量化索引,AI 回答时可以检索相关片段。不过我在实际使用时发现,它对单个文件的理解尚可,跨文件的调用关系分析还是经常出错。所以我的原则是:RAG 工具只当检索器用,真正的流程约束仍然靠契约文件。

5. 常见问题与排查技巧实录

5.1 AI 越改越乱:需求变更没有走契约通道

这个问题我在 v1.0 阶段天天遇到。需求从“检查本地图片是否存在”变成“同时检查图片体积是否超过 1MB”,如果直接让 AI 改代码,它大概率会把原来的链接解析逻辑重写一遍,甚至把输出格式也给改了。因为你没有告诉它“哪些是不能动的”,它自然以为哪里都要动。

解决方式很朴素:需求变更时,先改docs/requirements.md和docs/contract.md,然后再让 AI 读这两个文件,生成一份“变更影响说明”。AI 需要列出新增了哪些模块、修改了哪些接口、影响了哪些测试。这份说明由人来确认后,才允许进入实现阶段。看起来多了一道工序,但恰恰是这道工序挡住了 AI 最擅长的大规模回归。

5.2 编译过了,运行就崩:错误处理被忽略了

AI 生成的代码有个很典型的问题:它能保证“正常路径”通顺,但几乎不做异常路径。文件不存在、目录权限受限、日志文件为空、图片链接格式异常,这些边界场景 AI 一律不关心。所以很多项目出现“编译 OK、跑起来必崩”的现象。

我的排查技巧是:在契约阶段就把错误处理策略写死,并且让 AI 在实现每个模块时,额外输出一段“错误路径说明”,回答“如果本函数传入空列表会怎样?如果文件不存在会怎样?”。这个问题会强迫 AI 去思考边界,而不是只盯着主流程。测试用例里也必须至少包含一个异常输入,没有异常测试的模块,我会直接打回重做。

5.3 上下文越用越脏:旧信息污染新决策

长对话进行到后半程,AI 经常会受前面错误信息的影响。比如你在某个模块的调试中随口说了一句“可能是路径编码问题”,AI 之后的所有代码就都开始疑神疑鬼,拼命加各种编码转换,搞得代码里全是无用逻辑。

这就是上下文污染。避免的关键手段,是“该翻篇就翻篇”。一个独立模块的实现和调试结束后,直接开新会话,不要让旧会话继续承载新任务。新任务开始前,让 AI 读取docs/contract.md和最新的docs/decisions.md,这样它拿到的是精简后的消息,而不是冗长且包含大量中间试错过程的聊天记录。

5.4 AI 生成了 200 行,但我只需要 20 行

这是特别常见的失控现象。AI 为了展示“认真负责”,会把函数拆得极碎,或者加上一堆你根本不需要的配置项。解决这种问题,不能靠事后删,得在 prompt 层面做约束。

我在模板里会写明:

  • 不允许新增需求里没提到的功能
  • 不允许预留 YAGNI 性质的扩展接口
  • 函数的行数上限可以写死,例如“主函数体控制在 60 行以内,超出则重新设计”

这类约束不会百分之百生效,但能显著减少 AI 的自我发挥空间。如果 AI 还是生成了大量无用代码,我通常会直接点明:“这段属于智能补全事故,请删掉所有与需求无关的逻辑”。对大多数模型来说,明确表达“你写多了”比泛泛说“精简一点”有效得多。

6. 落地之后的一些个人体会

这套 v2.0 工作流真正跑起来之后,我最大的感觉是:AI 编程从“碰运气”变成了“看流程”。同样一个需求,以前直接丢给 AI 生成的代码,可能能用,但我不知道它是怎么得出这个方案的;现在每一轮输出都有契约、有测试、有决策记录,代码的可解释性和可回退性都强了很多。

我也逐渐意识到,AI 编程最难的点其实不在工具,而在于人能不能忍住“不去问最后一个问题”的冲动。工作流是一层保险,它不能消除所有意外,但能让你在意外发生时快速定位是哪一环掉了链子。如果你也想试 v2.0,我建议从一个小项目开始,先把契约文件这条线走通,再逐步加入测试和文档沉淀。流程本身不复杂,真正值钱的是坚持把每一步都做到位。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询