让 AI 写出可维护的代码:一套团队工程实践
结合 Anthropic、Sanity 等团队实践,从工程规范、需求设计到代码评审,构建可持续的 AI 编程工作流。
slashslashdev·

AI 显著提升了编码效率,但维护成本并没有因此同步下降。越来越多的研究都指向同一个趋势:AI 正在加快代码产出的同时,也在更快地积累技术债。
关键要点
- 2026 年的一项大规模研究分析了数千个真实生产仓库中的 AI 辅助代码,结果显示:AI 引入的问题中,近九成属于影响代码可维护性的「代码坏味道」,其中超过两成至今仍保留在仓库最新版本中,最终沉淀为长期技术债。
- 代码分析平台 GitClear 在 2025 年发布的报告指出,2024 年成为有统计以来首次「复制式代码」超过「重构复用式代码」的一年,重复代码块的出现频率相比两年前增长约八倍。
- METR 于 2025 年开展的一项对照实验得出了一个颇具启发性的结论:资深开源开发者接入 AI 编码工具后,整体开发效率反而下降了约 19%。研究认为,影响效率的关键并非工具能力,而是团队的使用方式及配套工程流程。
- 越来越多的团队已经形成了一套相对成熟的实践:在编码前向 AI 提供完整的工程上下文,在需求阶段明确可维护性要求,并通过代码评审和自动化测试进行持续校验。本文结合 Anthropic、Sanity、Armin Ronacher、Simon Willison 等在 2025—2026 年分享的 AI 编程实践,系统梳理这套方法如何真正落地。
技术债,正在随着 AI 编码一起增长
AI 编程最直接的优势就是快。借助生成式 AI,开发者往往只需几秒钟,就能生成数百行代码。不过,多项研究也在提醒我们:效率提升的同时,维护成本并没有同步下降。
2026 年发布的一项专项研究追踪了约 6300 个真实生产仓库中的 AI 辅助提交,共识别出超过 48 万个由 AI 引入的代码问题。其中,影响代码可读性、可调试性和可维护性的「代码坏味道」占全部问题的 89.3%。
其中有两个数字尤其值得关注:
- 所有主流 AI 编码助手中,都有超过 15% 的提交至少包含一个代码问题。
- 已识别出的问题中,有 22.7% 一直保留在仓库最新版本,没有得到修复,最终演变为长期技术债。
GitClear 的长期统计也反映出类似趋势。其 2025 年报告分析了 2020—2024 年约 2.11 亿行代码的变更记录,发现开发模式正在发生明显变化。
代表复制式开发的代码占比从 8.3% 上升至 12.3%;而代表重构与复用的代码移动占比,则从 2021 年接近 25% 持续下降,到 2024 年已不足 10%。
因此,2024 年成为一个重要的分界点:复制式代码首次超过重构复用式代码,五行及以上重复代码块的出现频率相比两年前增长约八倍。
安全质量方面同样值得关注。
代码评审平台 CodeRabbit 在 2025 年 12 月发布的《State of AI vs Human Code Generation》报告,对 470 个开源 PR(其中 320 个使用 AI 辅助、150 个完全由人工开发)进行了对比分析。
结果显示:
- AI 参与的 PR 平均包含 10.8 个问题,而人工开发的 PR 平均为 6.5 个;
- AI 代码中的问题总量约为人工开发的 1.7 倍;
- 安全相关问题增加约 1.5~2 倍;
- XSS 漏洞数量达到人工开发的 2.74 倍。
这一结果与前述研究形成了相互印证:在当前阶段,AI 编码在安全层面的整体表现仍然呈现出「引入的问题多于修复的问题」这一趋势,安全风险存在净增长。
为什么 AI 带来的技术债更难治理?
要解决 AI 带来的技术债,首先需要弄清楚,它与传统技术债到底有什么不同。
两者最大的区别,在于是否经历了人工的工程决策与权衡。
传统技术债通常源于开发者有意识的取舍。例如,为了满足上线时间,团队可能会采用一个临时方案,并明确计划在后续版本中进行重构。这种技术债本质上是一种经过评估的短期妥协。
AI 生成的技术债则有所不同。模型能够生成语法正确、可以运行,也能够通过常规测试的代码,但它缺乏对系统整体架构和长期演进方向的理解。在上下文信息不足时,模型往往会选择局部最优方案,在开发者没有察觉的情况下,引入重复实现、不合理抽象或架构偏移等问题,为项目埋下长期维护隐患。
这也是 AI 生成的代码更容易通过评审的重要原因。
AI 编写的代码通常格式规范、注释完整、语法正确,整体可读性较好。但真正影响项目长期可维护性的往往不是这些表面特征,而是架构是否合理、逻辑是否重复、边界条件是否覆盖充分等深层次问题。这些问题通常很难通过一次代码评审直接发现。
与此同时,AI 将代码产出效率提高了 30%~70%,团队需要评审的代码量也随之快速增加,而评审资源和审核能力却很难同步扩张。最终,不少隐藏问题随着代码一起进入主干分支,并逐渐积累为新的技术债。
当然,技术债也不能完全归因于模型本身。
AI 研究机构 METR 在 2025 年开展的一项标杆实验具有较高的参考价值。实验邀请了 16 位资深开源开发者(平均拥有五年以上大型开源项目经验,参与维护过数万 Star、数百万行代码的项目),完成 246 项标准化开发任务。
结果显示,在接入 AI 编码工具后,整体开发效率反而下降了约 19%。
METR 也特别说明,这只是针对特定开发场景的一次阶段性观察,并不能简单推广到所有开发工作。但它至少说明了一点:决定 AI 编程效果的,并不仅仅是模型能力,更重要的是团队是否建立了与 AI 相匹配的工程流程。
实验中的开发者本身具备成熟的软件工程能力,真正缺失的是围绕 AI 建立的上下文管理、开发规范以及代码评审机制。
接下来,我们将按照完整的软件开发流程,介绍如何将可维护性的要求融入 AI 编程的每一个环节,并结合一线团队的实践经验,看看这些方法如何真正落地。
编码前:先为 AI 建立项目上下文,完成「冷启动」
这是成本最低、收益却往往最高的一步,也是许多团队最容易忽略的一步。
每开启一次新的 AI 对话,对于编码智能体来说,都相当于迎来一位刚加入项目的新成员。它并不知道项目使用的是 PostgreSQL 还是 SQLite,不了解团队禁止直接捕获异常,也不知道所有代码在提交前必须通过测试。缺少这些上下文时,模型只能依据通用知识生成代码,最终得到的往往是适用于通用场景、却不符合项目规范的实现。
目前较为成熟的做法,是在代码仓库中维护一份可供 AI 自动读取的项目规则文件,为智能体提供统一的工程上下文。
不同工具采用的配置方式略有不同,例如 Claude Code 使用 CLAUDE.md,Cursor 使用 .cursor/rules/,GitHub Copilot 使用 .github/copilot-instructions.md。2026 年,Google、OpenAI、Sourcegraph、Cursor、Factory 等厂商共同推动了 AGENTS.md 这一通用规范。
目前越来越多团队采用的实践是:以 AGENTS.md 作为统一的项目规则来源,再由各个 AI 工具引用这份配置。这样既能避免不同工具维护多份规则带来的不一致,也能降低后续维护成本。
案例:Anthropic 的团队实践
Anthropic 曾公开总结内部十个团队使用 Claude Code 的经验,其中一个核心结论是:CLAUDE.md 中记录的项目背景、工作流程和开发规范越完整,AI 输出的代码质量和项目适配程度就越高。
例如,其数据基础设施团队将 CLAUDE.md 作为理解代码库的重要入口。通过不同目录下的规则文件,清晰描述数据管道之间的依赖关系,以及数据表、看板之间的映射关系,从而替代了过去依赖人工维护的数据目录。在新增数据管道等标准化开发场景中,AI 能够直接依据这些规则完成开发,大幅提升迭代效率。
安全工程团队则借助这套规则,重新梳理了开发流程,将过去「先写设计文档、快速编码、后续重构、最终放弃测试」的模式,逐步演进为能够稳定产出可测试代码的标准化流程。
可落地建议: 不要把上下文规则文件仅仅当作配置文件,而应把它视为一份「新人入职指南」,完整介绍项目的设计目标、核心架构、历史经验以及团队约定,让 AI 能够快速建立项目认知。
一份高质量的 AI 上下文规则文件,通常应包含以下内容:
- 项目的技术栈及整体架构;
- 目录结构与模块边界(例如禁止跨层调用);
- linter 无法覆盖的团队规范,例如命名规则、异常处理方式、日志规范;
- 测试编写要求;
- 项目明确禁止采用的实现方式(例如禁止使用 ORM,统一采用原生 SQL)。
不过,相比内容是否全面,规则是否足够精炼同样重要。
HumanLayer 在介绍 CLAUDE.md 最佳实践时提到,目前主流大模型能够稳定遵循的自定义规则数量是有限的,而工具自身的系统提示词已经占用了相当一部分上下文容量。因此,团队更应把有限的规则空间留给真正重要的信息。
行业中比较普遍的经验包括:
- 格式问题交给自动化工具处理。 缩进、尾逗号等格式要求应交给 Prettier、ESLint 等工具自动完成,而不是写进规则文件。这样既能减少规则数量,也能让模型把注意力集中在业务逻辑上。可以结合 Git Hook,在 AI 完成代码生成后自动执行格式检查,并将报错反馈给模型进行修正。
- 采用按需加载,而不是一次性提供全部信息。 没有必要把所有项目资料都写进规则文件,只需告诉模型相关文档所在的位置(例如 docs/ 目录),让它根据具体任务主动查阅即可。
- 规则文件由团队维护,而不是交给 AI 自动生成。 AI 自动生成的规则文件往往内容冗长、重点不突出。DeployHQ 的实践数据显示,当规则文件超过约 500 行后,其中相当一部分内容实际上不会被模型有效利用,反而增加维护成本。
案例:Armin Ronacher 的实践经验——让 AI 看见系统运行状态
Flask、Jinja 框架作者 Armin Ronacher 分享过一条门槛不高、却非常实用的经验:与其反复在提示词中描述系统当前的运行状态,不如直接把这些信息开放给 AI,让它自行感知、分析并完成纠错。
他的做法很简单:在调试模式下,将系统发送的邮件、验证码等关键输出统一打印到标准输出,并将这项约定写入 CLAUDE.md。有了这项配置,AI 在实现登录、密码找回等功能时,可以主动读取运行日志、获取验证码,并自行完成整条业务流程,无需开发者不断补充上下文或解释运行环境。
不过,他也强调了这套方法的边界。
AI 确实能够快速完成「功能可用」的基础实现,但在性能、稳定性等工程细节上仍然容易出现遗漏,例如限流策略缺少随机抖动、数据存储方案选择不合理等。这类问题仍然需要开发者通过评审和测试进行最终把关。
可落地建议: 尽可能向 AI 开放日志、测试结果、健康检查等真实运行数据,让模型具备一定的自查和自纠能力;同时,坚持人工验收作为最终质量保障,只在自己能够充分理解和验证的业务场景中,让 AI 自主完成更多开发工作。
另一条经过大量实践验证的经验是:与其罗列大量抽象规则,不如直接提供一段符合团队规范的示例代码。
相比冗长的文字说明,一段真实、规范、符合项目风格的代码示例,往往更容易帮助 AI 理解项目约定,并生成符合团队编码风格的实现。
例如:下面是一份适用于 NestJS 后端 API 项目的 AGENTS.md 模板,可根据实际项目直接调整和复用。
# AGENTS.md
## 项目概览
订单中心后端 API。技术栈为 NestJS 10 + TypeScript + PostgreSQL(Prisma)+ Redis。
对外提供 REST 接口,部署于 K8s 集群,支撑多个前端业务模块调用。
## 分层与边界
- 标准分层结构:Controller → Service → Repository(Prisma)
- Controller 仅负责参数校验与流程编排,不编写业务逻辑,不直接操作数据库
- 所有业务逻辑收敛至 Service 层,所有数据库操作收敛至 Repository / Prisma 层
- 跨模块调用统一通过对方导出的 Service 实现,禁止直接引入其他模块的 Repository
- 新增功能前,优先检索 src/modules/ 目录现有 Service,优先复用存量能力
## 自定义规范(linter 未覆盖)
- 所有请求入参统一通过 DTO + class-validator 校验,禁止 any 类型接收请求体
- 统一通过 NestJS HttpException 子类抛错,禁止裸抛出 Error 异常
- 数据库变更必须配套 Prisma migration,禁止手动修改数据表结构
- 环境变量统一通过 ConfigService 获取,禁止直接读取 process.env
## 测试规范
- 测试框架使用 Jest,Service 层编写单元测试,Repository 层采用 mock 测试
- 每个 Controller 必须配套至少一个 e2e 测试(supertest),覆盖鉴权失败等异常场景
- 代码修改完成后,需执行 `npm run test` 与 `npm run test:e2e`,所有用例通过后方可提交
## 协作约束
- 开发前优先查阅同模块存量代码,严格遵循项目既有编码风格
- 本地调试统一使用 Nest Logger 输出日志,验证码、外部通知等信息打印至控制台,方便 AI 与人工自查
- 设计方案存疑时优先输出技术方案评估,禁止直接进入编码阶段编码中:把可维护性写进需求规格
项目规则文件解决的是 AI 对整体工程上下文的理解,而每一个开发任务如何描述,则直接决定了最终代码的质量。
GitHub 在开源工具 Spec Kit 的介绍中提出了一个很形象的比喻:很多人把 AI 编码助手当成搜索引擎使用,但它更像是一位严格按照指令执行的结对开发伙伴。它擅长根据已有模式完成实现,却高度依赖明确、具体且没有歧义的需求描述。
近年来逐渐普及的规格驱动开发(Specification-driven Development),正是为了解决这一问题。它将一句模糊的「帮我实现这个功能」,拆解为一套包含人工审核节点的标准开发流程。
以 Spec Kit 为例,一个完整的开发流程通常包括四个阶段:
/specify:将需求整理为明确的规格说明;/plan:生成技术方案;/tasks:拆分为可独立验证的小任务;implement:按计划逐步完成实现。
每完成一个阶段,都需要人工确认后再进入下一步,从而降低 AI 偏离需求的风险。
案例:Simon Willison 总结的 AI 编码三项实践
长期研究 AI 编程的开发者 Simon Willison 将大模型形容为一位「过度自信的结对开发伙伴」,并总结出三项值得借鉴的实践。
1. 用函数签名定义实现边界
先由开发者确定函数签名,包括参数名称、参数类型和返回值类型,把系统架构和接口设计牢牢掌握在自己手中,再让 AI 负责具体实现。
接口边界一旦明确,AI 的发挥空间也会受到约束,从而减少逻辑偏离和架构失控的风险。
2. 先确认方案,再开始编码
对于中等及以上复杂度的需求,建议先让 AI 输出完整的技术方案,经人工确认后,再进入编码阶段。
这一思路与 JetBrains 智能体 Junie 官方推荐的流程基本一致:先读取 requirements.md,生成聚焦于实现目标、核心步骤、依赖资源和潜在风险的 plan.md,待方案审核通过后再开始实现。
例如,可以直接使用如下提示词:
读取
requirements.md,生成完整实现方案,包括开发目标、核心步骤、依赖项和风险点。暂不编写代码,并将结果输出为plan.md。
3. 使用行业术语,提高指令表达效率
Simon Willison 发现,很多行业约定本身就是高质量的提示词。
例如,一句 Use red/green TDD(采用红绿测试驱动开发),就足以让模型理解整个开发流程,而无需再详细解释每一个步骤。
相比冗长的规则说明,适当地使用业内通用术语,通常能够让 AI 更准确地理解开发意图,也能有效减少提示词长度。
除此之外,还有两项实践同样值得长期坚持。
第一,坚持小步迭代。
不要直接要求 AI「实现用户认证」,而应拆分成「实现邮箱格式校验」「实现注册接口」「实现登录接口」等可以独立测试的小任务。这样既能减少一次生成大量代码带来的冗余,也更方便评审和修改。
第二,使用具体约束,而不是模糊描述。
诸如「代码优雅」「逻辑清晰」这类描述几乎无法指导模型生成更高质量的代码。只有明确提出复用要求、设计约束、测试要求等具体标准,AI 才能输出真正符合团队预期的实现。
例如:
- 低效指令:「帮我新增导出 CSV 的功能。」
- 更有效的指令:「在
order.service.ts中新增 CSV 导出方法,优先复用当前模块已有的文件读写逻辑,禁止重复实现。保持单一职责原则,并为数据为空、字段包含逗号两种边界情况补充测试用例。请先输出实现方案,确认后再开始编码。」
微软在规格驱动开发文档中也强调:需求规格的质量,很大程度上决定了最终代码的质量。
Augment Code 的工程师则给出了一个更实用的判断标准:如果需求理解出现偏差会导致明显返工,就应该投入时间编写完整的规格说明;如果偏差只需补充一句说明即可修正,则保持快速迭代即可。规格不需要越详细越好,而应根据项目复杂度,在开发效率和沟通成本之间取得平衡。
编码后:建立一套适用于 AI 代码的评审机制
即使前期已经完成了工程规范配置和需求设计,最后一道人工评审仍然不可或缺。
这一阶段,可以参考 Sanity 一位资深工程师公开分享的六周实践总结。这套方法已经经过团队验证,具有较强的可操作性,也适合作为团队建立 AI 代码评审流程的参考。
案例:Sanity 团队如何评审 AI 生成的代码
这位工程师在复盘中提到,AI 首次生成的代码,大约有 95% 都需要进一步修改。不过,这并不意味着工具本身存在缺陷,而是 AI 编程本身就是一个持续迭代、不断优化的过程。
Sanity 团队采用了一套相对固定的工作方式:给予模型三轮迭代优化机会,每一轮都将上一轮发现的问题和修改意见反馈给模型,同时始终按照**「评审一位经验尚浅的新成员」**的标准,对所有 AI 生成的代码进行严格审核。
在长期实践中,团队逐渐形成了几项值得借鉴的原则。
- 明确标注人工修改内容。 人工优化后的代码应与 AI 原始输出保持清晰区分,避免模型在下一轮迭代中误判上下文,将已经修正的问题重新生成。
- 避免多个 AI 同时处理同一任务。 多个智能体同时参与同一功能开发,容易产生实现方式不一致、规则冲突等问题,最终增加后续维护成本。
- 坚持「谁交付,谁负责」。 无论代码来自人工还是 AI,最终提交代码的工程师都应对交付结果负责,避免出现「AI 写的代码无人负责」的情况。
- 保持客观的评审标准。 相比亲手编写的代码,开发者通常不会对 AI 生成的代码产生心理上的偏好,因此更容易从架构、逻辑和可维护性的角度进行客观评审。这种距离感,反而有助于发现隐藏问题。
除此之外,还有几项实践同样值得纳入团队的标准流程。
首先,可以要求 AI 对自己生成的代码进行解释。如果模型无法清晰说明某段实现背后的设计思路,往往意味着这部分代码存在值得进一步检查的问题。
其次,可以引入第二个模型参与评审,让不同模型相互发现问题,再根据评审意见完成重构。这种交叉验证的方式,能够在一定程度上提高问题发现率。
另外,测试用例不仅是质量保障工具,也可以作为需求规格的具体体现。将需求中的验收标准转化为可执行的测试断言,有助于确保 AI 的实现始终符合预期。
与此同时,团队还应坚持增量重构,避免因为 AI 提高了编码效率,就不断新增代码而忽视已有代码的持续优化。
GitClear 的研究反映出一个值得关注的现象:AI 大幅降低了新增代码的成本,许多团队因此更加倾向于快速开发新功能,而对已有代码的整理、抽象和重构投入不足。
更可持续的做法,是将重构纳入日常开发流程。例如,定期利用 AI 识别重复逻辑、抽取公共能力、封装可复用模块,并要求模型在生成新代码之前,优先检索并复用项目中的已有实现,而不是重复开发相同功能。
Anthropic 安全工程团队已经将这一流程进一步自动化。他们通过 GitHub Actions 触发 Claude 对 Pull Request 进行自动评审,完成代码格式检查、测试用例优化以及冗余逻辑识别等重复性工作;而开发者则将更多精力投入到架构设计、业务逻辑和系统合理性等更需要工程判断的工作中。
这种分工方式,也体现了当前 AI 编程较为成熟的一种协作模式:让 AI 负责标准化、重复性的工程任务,把真正需要经验和判断的工作留给开发者。
从个人经验到团队能力:把 AI 编程实践沉淀为工程资产
如果希望长期稳定地利用 AI 产出高质量、可维护的代码,关键并不在于个人掌握了多少提示词技巧,而是能否将这些实践沉淀为团队统一、可复用的工程资产。
相比个人开发习惯,团队的一致性更加重要。
AI 上下文规则文件应与业务代码一起纳入版本管理,作为项目的一部分持续维护。这些规则不仅帮助智能体理解项目,也能够统一团队的开发规范、评审标准和工程约定,让新成员接手项目时更快建立一致的开发方式,并获得符合团队规范的 AI 辅助结果。
对于采用 Monorepo(多仓库单体)架构的团队,可以在仓库根目录维护一份全局规则,在各个子服务目录维护对应的局部规则。当前主流 AI 编码工具通常能够自动向上查找并合并这些规则,从而根据不同模块生成更符合项目实际情况的代码。
代码评审同样需要针对 AI 代码建立不同于人工代码的关注重点。
对于 AI 生成的代码,应重点检查是否存在重复实现、抽象层次不合理、表面符合规范但整体架构已经偏离设计等高频问题,而不仅仅关注代码风格或语法正确性。
与此同时,团队还应持续沉淀已经验证有效的提示词、需求规格模板以及工程规范,将个人经验逐步转化为团队共享资产,让优秀的实践能够持续复用,而不是依赖个别开发者的经验积累。
附:AI 代码可维护性自查清单
下面这份清单汇总了全文介绍的实践方法,覆盖 AI 编程的完整开发流程,可直接用于团队 Wiki、代码评审或开发自查。
编码前:建立项目上下文
- 仓库已配置
AGENTS.md、CLAUDE.md等规则文件,并纳入版本管理。 - 规则文件明确说明项目技术栈、模块边界、异常处理方式、命名规范等核心工程约定。
- 格式化规则统一交由 Linter 或格式化工具处理,不占用 AI 的自定义规则空间。
- 上下文规则保持简洁,详细资料统一放置在
docs/等目录,并支持按需查阅。 - 已提供符合团队规范的示例代码,帮助 AI 学习项目风格。
- 日志、测试结果、验证码等关键运行信息可供 AI 获取,以支持自查和调试。
编码中:规范需求描述
- 中等及以上复杂度的需求,先生成技术方案并完成评审,再进入编码阶段。
- 需求已经拆分为可独立验证的小任务,避免一次生成大量代码。
- 提示词采用明确、可执行的约束,避免使用「优雅实现」「代码漂亮」等模糊描述。
- 明确要求 AI 优先复用已有代码,避免重复实现。
- 为核心功能和边界场景补充测试用例,确保实现符合预期。
编码后:加强代码评审
- 按照评审初级开发者代码的标准审核 AI 输出,重点关注逻辑是否清晰、设计是否合理。
- 采用双模型交叉评审等方式,提高问题发现率。
- 重点检查重复逻辑、抽象层次以及架构偏移等 AI 高频问题。
- 人工修改内容已明确标注,避免后续被 AI 覆盖。
- 落实「谁交付,谁负责」原则,AI 生成代码同样纳入工程责任体系。
团队层面:建立长期机制
- 上下文规则、提示词模板、需求规格模板等已经沉淀为团队共享资产。
- 评审流程能够区分 AI 代码与人工代码的不同风险点,并采用针对性的检查策略。
- 将增量重构纳入日常开发流程,持续平衡新增功能与存量优化,避免技术债持续积累。
结语
要让 AI 持续产出可维护的代码,真正需要解决的并不是模型能力,而是工程实践。
只有将团队长期积累的工程规范、开发标准和架构原则,转化为 AI 能够理解和执行的显性规则,再配合完善的需求规格和严格的代码评审,才能把可维护性的要求真正融入整个开发流程。
从 Anthropic、Sanity 等团队的实践,到 Armin Ronacher、Simon Willison 等开发者的经验,可以看到一个共同的结论:成熟的 AI 编程,并不是依赖模型「自觉写出好代码」,而是依靠清晰的工程规范和完善的开发流程,引导模型稳定地产出符合团队标准的代码。
正如 METR 实验所反映的那样,AI 编程的效果最终取决于团队如何使用它,而不是模型本身的能力。
代码始终是开发者意图的体现。当需求定义足够清晰、工程规范足够完善、评审机制足够严格时,AI 才能真正成为提升研发效率、而不是增加维护成本的工程助手。