AI Coding经验总结:从大模型工具到 Agent 工作流
摘要
从 SDD、TDD、API 契约、特征测试、安全重构、GitHub Workflow 到 Rules/Spec/Skills,整理一套让 AI Coding 从工具使用走向 Agent 工作流的工程方法。
AI Coding 经验总结:从大模型工具到 Agent 工作流
写在前面
AI Coding 的问题已经不再是“模型会不会写代码”。对今天的开发者来说,更现实的问题是:AI 已经可以很快生成一大段看起来合理的代码,但这段代码到底能不能相信,能不能维护,能不能进入团队协作和生产环境。
过去我们讨论编程效率,重点常常放在“谁写得更快”。现在这个瓶颈正在变化。大模型和 Coding Agent 确实显著降低了写初稿、补样板、改重复逻辑、查资料和生成测试的成本,但它并没有消除审查、架构、调试、测试、安全和维护这些工程责任。很多时候,AI 只是把负担从“亲手写每一行代码”转移到了“设计流程、定义边界、判断质量、控制风险”上。
所以我现在更愿意把 AI Coding 分成三个层次:
大模型工具:像一个更强的搜索框、解释器和代码补全器,适合生成片段、解释代码、补样板、写脚本。
Coding Agent:能读仓库、改文件、跑命令、看测试失败,再继续修正,适合完成有明确边界的任务。
Agent 工作流:把规格、测试、契约、Git、CI、文档和人审串起来,让 AI 生成代码变成可验证、可追踪、可回退的工程过程。
真正值得长期沉淀的不是“某个模型今天有多强”,而是这一套工作流。模型会变,工具会变,但规格、测试、边界、契约、门禁、审查这些工程基本功不会过期。
1. 从“让 AI 写代码”到“让 AI 在边界里交付”
小任务里,直接让 AI 写代码通常很有效。比如写一个 Python 脚本、生成一个 React 组件、解释一段报错、把 SQL 改成 ORM 查询,这些任务上下文短、边界清楚、失败也容易肉眼发现。
但项目一变大,问题就完全不同。AI 可能看不全系统的真实入口,可能不知道哪些历史行为不能动,可能顺手“修正”一个它认为奇怪但业务上必须保留的逻辑,也可能一次改太多文件,让人无法审查。
大项目里的 AI 风险主要有三个:
看不全:仓库里真正的行为分散在入口函数、数据库副作用、日志、事件、缓存、隐式状态、老接口和公共 import 路径里。AI 如果只看一个文件,很容易漏掉系统边界。
改不敢:遗留代码往往没有足够测试。AI 生成的新结构可能更清晰,但没人能证明它没有改坏旧行为。
产出管不住:AI 很高产,也很自信。如果没有 Git、测试、CI、PR 和审查门禁,它会把流程里的裂缝放大。
因此,大项目里不能把 AI 当成“自由发挥的程序员”,更适合把它当成“被流程约束的执行者”。人的职责是定边界、定标准、审语义;AI 的职责是在边界里填实现、补测试、做机械重构、根据失败信息迭代。
一个更稳的分工是:
人负责定义模块边界、接口契约、验收标准、风险范围、不可改动行为。
AI 负责阅读代码、整理结构、生成规格草案、补测试、做小步修改、解释失败原因。
机器门禁负责执行类型检查、Lint、单元测试、特征测试、构建和 CI。
人最终决定业务语义是否正确、风险是否可接受、能不能合并。
这套分工的核心不是降低人参与,而是把人的注意力从“手写实现”提升到“控制系统正确性”。
2. SDD:先把“什么算对”写清楚
很多 AI Coding 失败,不是因为模型不会写代码,而是因为人没有说清楚“什么算对”。
传统需求经常是这样的:
做一个 Todo API,支持新增、查询和完成。
这个描述对人来说看似够了,但对 AI 来说边界太松。标题能不能为空?是否要 trim?最大长度多少?完成一个不存在的任务返回什么?重复完成是报错还是幂等?数据是否持久化?是否需要分页、认证、删除、编辑?
如果这些不写清楚,AI 就会自己补设定。补得合理不代表补得符合你的系统。
SDD,也就是 Spec Driven Development,核心是把规格当成第一产物。先写“怎么用、什么行为、哪些边界、明确不做什么”,再让 AI 根据规格写测试和实现。
一个好规格至少要包含五块:
例如 Todo API 可以写成这样:
这份规格的价值不在于写得漂亮,而在于它可以被测试。每一条规则都能变成一个明确的断言。AI 不再需要猜“我想要什么”,而是根据规格去生成测试和实现。
我现在使用 AI Coding 时,会遵守三条简单规则:
先写规格:没有规格,不让 AI 直接写核心代码。
规格必须可验证:每条关键规则都应该能对应测试、类型约束或人工审查项。
小步可回滚:一次只解决一个明确问题,不把重构、修 bug、新功能混在一起。
3. TDD:把“对不对”变成机器能判
SDD 解决的是“什么算对”,TDD 解决的是“怎么证明它对”。
TDD 的红绿重构循环并不新:
Red:先按规格写测试,此时没有实现,测试应该失败。
Green:补最小实现,让测试通过。
Refactor:在测试保持绿色的前提下整理结构。
AI 时代,TDD 反而更重要。原因很简单:AI 写代码很快,如果没有测试,它会把错误也写得很快;AI 写测试也很快,所以过去“测试太贵”的成本被降低了。
一个更适合 Coding Agent 的 TDD 流程是:
让 AI 根据规格只写测试,不写实现。
人审测试,确认测试锁的是想要的行为,而不是 AI 自己幻想的行为。
运行测试,确认它们真的红。
让 AI 根据失败信息补实现。
失败时不要只说“修一下”,而是把失败输入、期望、实际输出、堆栈信息回喂给 AI。
全绿后,再允许做结构整理。
故意改坏一处关键逻辑,确认测试能红,避免测试只是摆设。
失败信息要结构化,例如:
这类反馈比“测试失败了你看看”有效得多。Agent 能根据具体失败点收敛,而不是继续扩大修改范围。
4. API 契约:让确定性向下一层传递
后端规格和测试不是终点。一个成熟的工作流里,上游产出的确定性应该继续约束下游。
以 Web 项目为例:
后端先写规格。
根据规格写测试。
实现接口。
生成 OpenAPI。
前端根据 OpenAPI 生成 typed client、请求类型、mock 数据和表单约束。
这样,后端的规则不会只停留在文档里,而是会进入前端开发过程。
例如规格里写了:
title必填。trim 后长度必须在 1 到 100。
非法输入返回 422。
这些约束可以通过 OpenAPI 的 schema 进入前端,前端表单就不应该再凭感觉写一套不同的校验逻辑。API 定义不是“附属文档”,而是下一层开发的规格。
这个思路可以推广到很多地方:
数据库 schema 约束 DAO 和迁移脚本。
OpenAPI 约束前端请求和 mock。
Protobuf 约束服务间通信。
Zod schema 约束服务端输入、客户端表单和测试数据。
设计稿变量约束组件样式和主题系统。
核心原则是:上一层已经明确的契约,不要让下一层重新猜。
5. 大项目第一步:不要先改,让 AI 只读
面对遗留系统,最危险的做法是直接让 AI “帮我重构一下”。重构前最重要的工作不是改代码,而是让 AI 只读代码,产出结构梳理和当前行为说明。
我通常会先让 AI 输出五类信息:
Public API 和入口:哪些函数、路由、组件、命令、导出路径被外部调用。
职责板块:当前代码实际承担了哪些职责,例如校验、计算、持久化、通知、风控、缓存。
状态地图:哪些状态会被读写,状态如何流转,哪些副作用会发生。
多套真相:同一个规则是否在多个地方重复实现,例如前端校验、后端校验、数据库约束不一致。
可疑行为:看起来像 bug,但重构前不能顺手修的历史行为。
可以直接使用这样的 prompt:
这里最关键的是“只读”。AI 很容易在理解过程中顺手改代码,但遗留系统里很多看起来奇怪的行为都可能是线上依赖。没有测试前,先不要修。
6. 特征测试:安全重构的第一道门
特征测试,也可以理解为 characterization test 或 golden master test,问的不是“这个行为是否理想”,而是“改完以后和改前是否一致”。
这对遗留代码非常重要。因为你往往无法马上判断旧行为是不是正确,但你必须先保证重构没有无意改变旧行为。
重构前要锁住的行为面包括:
返回值结构。
正常路径和异常路径。
数据库写入、更新、删除等副作用。
事件、日志、消息队列、邮件通知。
warning、错误码、状态码。
public import 路径和老入口函数。
排序、取整、默认值、空值处理。
性能边界和缓存行为。
可以按四步做:
架构梳理:让 AI 只读代码,找入口、职责、状态、副作用和可疑行为。
当前行为 spec:把现有行为写成“当前就是这样”的说明,不急着评价对错。
生成特征测试:覆盖主路径、边界路径、可疑行为、老入口和隐式状态。
人审并跑绿:确认测试锁的是现状,全部绿以后才允许重构。
这条铁律非常重要:
没有特征测试,不让 AI 重构遗留核心逻辑。
如果 AI 发现了疑似 bug,也应该先写入“可疑行为表”,而不是马上修。正确节奏是:先锁现状,再开单独任务讨论是否修复。
7. 安全重构:只改变结构,不改变行为
重构的目标是让结构更清楚,而不是趁机改变业务语义。AI 做重构时尤其容易混入“顺手优化”,所以流程要非常小步。
我会把安全重构拆成这样的执行规则:
保留旧入口和 public API。
一次只抽一个职责,例如只抽校验、只抽金额计算、只抽通知发送。
新模块先由旧入口委托调用,不直接删除旧入口。
每一步都跑特征测试。
如果红灯,先停,不继续叠加修改。
如果发现真实 bug,记录下来,单独开任务修。
这其实接近“绞杀者模式”:旧系统入口仍然存在,新实现逐步接管内部职责。外部调用方感知不到结构变化,风险就小很多。
一个典型节奏是:
每个 commit 都应该能单独解释、单独回退。不要让一个 PR 同时包含“重构订单计算”“修优惠券 bug”“新增会员等级”“改 UI 文案”。这种 PR 人很难审,AI 也很难保持一致。
8. 复杂结构:先画依赖图和状态图
很多系统看起来只是“文件多”,实际复杂点在隐式耦合:
近似循环依赖。
import 时就产生副作用。
全局变量被多个模块读写。
请求上下文在多层之间隐式传递。
public import 路径被外部依赖。
同一个规则在前端、后端、数据库里各有一版。
这种情况下,让 AI 直接改文件很危险。更好的做法是先让它输出依赖图、状态图和隐藏契约清单。
图不一定要精美,关键是让人能看到系统边界。只要边界清楚,AI 后续就可以在一个局部范围里工作;边界不清楚,AI 就会扩大上下文,最后变成不可审查的大 diff。
9. Git:把 AI 产出变成可追踪、可回退的工程对象
AI 生成代码越快,越需要 Git 轨道。Git 不是简单的保存记录,而是风险控制工具。
我现在会这样理解 Git 里的几个对象:
对象 | 在 AI 工作流里的作用 |
|---|---|
Issue | 定义边界:这次到底解决什么,不解决什么。 |
Branch | 隔离风险:AI 的改动不能直接污染主线。 |
Commit | 定位责任:每一步修改都能解释和回退。 |
Diff | 审查对象:让人能看到 AI 到底改了什么。 |
PR | 协作入口:把规格、测试、实现、风险说明放在一起审。 |
Required Check | 强制纪律:机器门禁不过,不进入人工合并。 |
一个适合 AI 的 Git 节奏是:
从 issue 开始,不从一句模糊 prompt 开始。
为每个任务开独立分支。
第一组 commit 只加规格和测试。
第二组 commit 小步实现或重构。
每个 commit 后跑相关测试。
PR 里说明锁住了哪些行为、没有修哪些疑似 bug、影响范围在哪里。
CI 失败时以 CI 为准,不以 AI 的解释为准。
这套流程可以让 AI 的高产变得可管理。否则 AI 一次生成几百行代码,看起来很努力,但团队没有办法判断它是否可靠。
10. GitHub Workflow:把门禁交给机器
人审很重要,但人审不应该替代机器门禁。Lint、类型检查、测试、构建这些事情应该交给 GitHub Workflow 或其他 CI 系统自动执行。
对于当前这种 TypeScript / Bun 项目,可以用类似下面的最小工作流:
如果是 Python 项目,则可以换成 ruff check、pytest、pyright 等检查。
Workflow 的价值不只是“自动跑命令”,而是:
每个 PR 都会触发同一套检查。
检查结果对团队可见。
可以配合 branch protection,要求通过后才能合并。
可以逐步扩展安全扫描、覆盖率、部署预览、端到端测试。
AI 生成的代码和人写的代码走同一套门禁。
AI review 可以辅助发现问题,但不能替代 deterministic workflow。AI 说“没问题”没有意义,测试、构建和人审通过才有意义。
11. 质量飞轮:生成、验证、修正、记录
一个好的 Agent 工作流不是单轮 prompt,而是质量飞轮:
这个飞轮里最容易被忽略的是“记录”。如果每次 AI 犯错后只是当场修掉,下次还会再犯。更好的做法是把经验沉淀到三个地方:
Rules:项目规则,例如
AGENTS.md,写目录约定、命名习惯、禁止事项、测试命令、提交要求。Spec:功能规格和状态账本,记录 planned、implemented、archived,避免需求漂移。
Skills:可复用流程,例如新闻更新、论文整理、特征测试生成、安全重构流程。
可以把它理解为:
Rules 约束 AI 怎么写。
Spec 说明 AI 要写什么。
Skills 告诉 AI 遇到某类任务怎么做。
这样项目不会每次都从零解释背景,AI 也不会一直重复同样的错误。
12. 活 Spec:让需求和实现保持同一套账
在多人协作或长期维护里,spec 不能写完就丢。更好的方式是把 spec 当成“活文档”维护。
一个简单目录可以这样设计:
其中:
governance放长期规则,例如架构边界、命名规范、测试策略。planned放准备做但还没实现的功能规格。implemented放已经落地的功能规格。archived放废弃或被替代的方案。
PR 合并前,不只看代码,也要看 spec 状态是否同步迁移。一个改动不算完成,直到实现、测试、文档、示例、兼容说明和 spec 状态讲的是同一个故事。
Issue 也应该分类:
局部 bug:范围明确,直接修。
新功能:先写规格,再实现。
公共接口变化:必须写兼容和迁移说明。
架构边界调整:需要更严格评审。
同根因问题:合并治理,不要分散修。
影响面不清:先做只读梳理,不直接改。
这种治理方式看起来比“直接让 AI 改”慢,但它让后续迭代变快。因为边界清楚,审查清楚,回滚清楚。
13. 两道审查:AI 自审和人类终审
AI 可以参与审查,但它不应该成为最后裁决者。
我会让 AI 自审这些问题:
AI 自审适合发现明显遗漏、重复代码、异常路径、测试缺口。但最后仍然需要人审:
这个改动是否真的解决了 issue?
业务语义是否正确?
是否影响已有用户或历史数据?
是否有不可逆副作用?
测试覆盖的是核心行为还是表面行为?
diff 是否小到可以审查?
如果出问题,能否快速回退?
AI 很擅长解释“代码在做什么”,但人必须判断“系统应该做什么”。
14. 工具选择:按任务选,不按名气选
不同 Coding Agent 的优势不一样。选择工具时,我更关注这些维度:
是否能稳定遵守 spec。
是否擅长读大仓库和跨文件上下文。
是否能可靠执行命令和根据失败信息迭代。
是否适合 UI、文档、测试、脚本或工程重构。
是否容易接入 Git、CI、MCP、项目规则和团队流程。
成本、速度、中文理解、隐私和权限控制是否符合项目要求。
可以粗略这样理解:
Codex 这类工具适合规格清楚、需要读仓库、改代码、跑命令、按工程流程推进的任务。
Claude Code 这类工具在探索性任务、长上下文理解、UI 和文档整理上通常体验很好。
接入 DeepSeek、Kimi、GLM 等模型的工具在中文内容、成本和本地化场景上可能更合适,但要更注意 spec 遵从和验证。
Copilot 更适合编辑器内补全和局部辅助,不适合把它当成完整工程流程本身。
重点不是哪个工具“最强”,而是你的流程能不能把工具产出纳入同一套规格、测试、Git 和 CI 里。
15. 三套可直接复用的工作流
15.1 新功能:Spec -> TDD -> Contract -> UI
适合新接口、新页面、新业务功能。
人先写一句话目标和明确不做。
AI 根据目标补数据模型、接口、边界条件。
人审规格,删掉 AI 自己扩展的范围。
AI 只写测试,确认测试先红。
AI 补实现,按失败信息迭代到全绿。
生成或更新 API 契约。
前端根据契约生成 typed client、mock 和表单校验。
PR 中附上规格、测试覆盖、影响范围。
15.2 遗留模块:只读梳理 -> 特征测试 -> 小步重构
适合订单、权限、计费、数据同步、认证等风险较高模块。
AI 只读代码,输出入口、职责、状态、副作用、可疑行为。
把当前行为整理成 spec,不评价对错。
生成特征测试,覆盖主路径、边界路径、可疑行为和隐式契约。
人审测试,确认锁住的是现状。
全绿后,每次只抽一个职责。
每步跑测试,红了先停。
疑似 bug 单独建 issue,不混在重构 PR 里。
15.3 团队协作:Issue -> Branch -> Commit -> PR -> CI -> Review
适合多人项目和长期维护项目。
关键要求:
Issue 里写清楚范围和不做事项。
分支隔离 AI 改动。
Commit 小而可解释。
PR 不混重构、修 bug 和新功能。
CI 不过不合并。
人审关注业务语义和不可逆风险。
16. 我现在的实践原则
经过一段时间使用 AI Coding,我对它的期待变得更清晰了。
我不会再把 AI 当成“自动完成任务的魔法按钮”,而是把它放进工程流程里:
先理解原有逻辑,再修改。
先写规格,再写测试。
先锁现状,再做重构。
先小步提交,再扩大范围。
先过机器门禁,再做人审。
先记录规则,再期待下次更稳。
AI 生成代码不因为它“看起来对”而可信,也不因为它“解释得很流畅”而可信。它可信,是因为它被清晰的规格约束,被足够的测试验证,被 Git 记录,被 CI 拦截,被人审裁决。
这也是我理解的 Agent 工作流:不是让 AI 替代工程纪律,而是用工程纪律把 AI 的高产能力变成稳定交付能力。
最后可以用一个问题判断自己的流程是否成熟:
当前这一层的输出,能不能成为下一层的可靠规格?
如果需求能变成 spec,spec 能变成测试,测试能约束实现,实现能产出契约,契约能约束前端,失败能回到规则,那么 AI Coding 就不再只是“写得快”,而是开始接近“信得过”。
