1. 当生成速度远远跑在治理能力前面:项目是怎么走到 25 万行的
说实话,接到这个项目时,我心里是没底的。一个从零开始的产品,所有代码都来自 AI 工具,没有一行是人工手工敲出来的,半年不到积到了 25 万行。听起来很爽,但真到了第 10 万行左右,团队里的每个人——包括 AI 工具本身——都开始明显感觉到一种“窒息感”。不是生成不了代码,而是生成出来的东西没人看得过来、改不动、不敢动。
先交代一下背景。这个项目的本质是一个带数据采集和处理能力的中台服务,早期为了抢时间,团队决定全面转向 AI 编码:需求拆解后丢给 Claude Code、Cursor 等工具生成模块,再由人来集成和验证。前 3 万行的时候非常顺利,几次大的功能模块,AI 在几小时内就能产出可编译、能跑通的实现。但过了某个临界点之后,问题的性质变了。
这个临界点不是行数,而是“依赖关系”的密度。3 万行的时候,模块之间彼此独立,改一个服务不影响另一个;到了 15 万行以上,光是一个订单状态的流转,就有六七个模块在订阅同一套事件。AI 每次生成的代码在自己的局部范围内看是完全正确的,但放到全局,它根本“看不见”旁边模块的约定。这个问题,行数越滚越大,就越发难解。
所以这个标题里那句话,我是举双手同意的:真正难的不是生成,而是治理。生成是能力问题——工具够不够强、模型够不够聪明;治理是系统问题——代码能不能被持续理解、修改、演进和信任。能力问题可以用更好的模型、更大的上下文解决;系统问题没有银弹,只能靠机制。
这个项目给我最大的教训是:治理必须在第一天就设计,不能在失控之后再补。失控之后再补,就像在已经建好的高楼上重新打地基,代价远远超出想象。接下来的内容,我会把 25 万行过程中实际踩过的坑、做过的治理决策和最终沉淀下来的机制,一条条摊开讲。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 从“能跑”到“能维护”:一致性治理是第一块硬骨头
2.1 AI 的“创意”过剩:同一件事有五种写法
25 万行代码里,我做过一次抽样统计(用脚本粗扫):同样的“从 Redis 读取缓存并处理空值”的逻辑,全库有 5 种主流写法;同样的日期时间格式化,有 7 种。为什么?因为每次丢给 AI 一个新的子任务,它在没有明确约束的前提下,会从自己的训练分布里“自由发挥”,而训练分布里各种风格的代码都有。上周 A 模型生成的代码用 ZonedDateTime,这周 B 模型生成的同功能代码用 Instant,再下周上下文一换,又变成 LocalDateTime。单看任何一段都挺优雅,放到一起就是灾难。
这件事对维护的影响是坏的。人还能靠记忆和经验来做判断,AI 没有长期记忆,它每次进上下文看到的都是“局部真相”。如果全库的写入路径、错误处理、日志格式、事务边界都是随机的,AI 后续生成的新代码也只能继续随机。一致性不是审美问题,在 AI 编码项目里,它直接决定了整个代码库是否具备“可被 AI 继续理解”的基础。
2.2 用架构决策记录把“风格”变成“硬约束”
我们的做法是:把一致性要求从人的口头约定,变成机器可读、AI 可提示的硬约束。具体落地了三样东西。
一是架构决策记录库。每定下一个关键技术选型,就写一条 ADR,存在仓库的 docs/adr/ 目录下。比如事件消息的 payload 必须包含 event_id、occurred_at、version 三个字段;所有外部 API 调用必须经过统一的 HTTP 客户端;所有缓存键必须遵循 业务域:实体:ID 格式。这些条目不是为了给人看的,而是为了让 AI 在生成代码时,通过系统提示词或检索增强,第一时间就能读到“这个仓库的规矩”。
二是脚手架和模板。让 AI 生成一个模块时,我们不再只说“帮我实现用户查询服务”,而是给一个完整的模块模板,包含目录结构、接口定义、异常体系、日志规范、单元测试框架。AI 只需要往模板里填业务逻辑,自由度被大大压缩。这听起来像是限制了 AI 的能力,但实际证明,让 AI 在既有框架里填充,产出的代码质量和可维护性远超让它自由发挥。
三是静态检查把规矩钉死。我们用 ESLint、ArchUnit 等工具把 ADR 里的规则自动化。比如“缓存键必须符合格式”,就写一个 ArchUnit 规则,CI 里跑,违反就红。AI 生成的代码可以跑得快,但过不了自动检查。只有这层兜住了,一致性才有底线。没有这层,规范和 ADR 都只是文档,AI 不会主动去看它,人类也不会记得去查它。
| 治理层级 | 主要手段 | 解决什么问题 |
|---|---|---|
| 决策层 | ADR、架构原则文档 | 告诉 AI“这个仓库的规矩是什么” |
| 生成层 | 脚手架、模块模板、系统提示词 | 压缩 AI 的自由发挥空间 |
| 验证层 | 静态检查、架构测试、CI 卡点 | 让违规代码根本合不进来 |
3. 上下文治理:25 万行代码里的“AI 失忆症”与破解方案
3.1 问题:AI 的局部正确与全局盲区
到后期,团队反馈最多的一个现象是:AI 帮我们改一个服务时,改出来的代码在单元测试层面全绿,但在集成测试里炸成一片。根因不是 AI 能力不行,而是它看不到全局。在一个 25 万行的仓库里,没有任何模型能把全部代码塞进上下文窗口。每次生成,它拿到的只是用户手动挑选或工具自动检索的几个文件,是几十上百个文件的“局部真相”。
这个局部的上下文文本里,往往没有全局的不变量。比如“库存扣减必须发生在订单状态为已支付之后”,这一条规则可能写在一个核心服务里,而 AI 在改动外围服务时根本不会读那个文件。于是它可能在一个看似无关的地方引入了并发问题,或者把一个本来幂等的方法改成了非幂等。我们一开始的做法是让工程师在 prompt 里手动贴关键文件,但人总是会漏,而且人大脑里能记住的全局约束也有限。后来我们转变思路——不追求让 AI 看到全部代码,而是把“全局关键信息”提炼成一份独立的知识层,每次 AI 开工前强制注入。
这里有个细节值得多说一句:我们观察到 AI 编码工具在管理上下文窗口时,会想尽办法控制 token 占用,这给了我们一个启发——与其让工具被动地塞文件,不如在项目侧提供更精准、更高价值的检索内容,而不是一股脑把大文件丢给 AI。工具侧怎么缓存是它的事,项目侧怎么组织知识是我们的事。
3.2 可检索的知识中枢:术语表、接口契约与影响分析
我们在仓库里维护了三层知识。
第一层是领域术语表。这个项目有一条特殊的业务规则——“订单状态机共分 8 个状态,合法流转只有 12 条边”。我把它单独写成一个 markdown 文档,AI 生成代码前,系统会自动把这份文档塞进上下文。这个动作看起来简单,但效果立竿见影:AI 生成的订单相关代码,状态流转的错误率直线下降。不妨类比一下:人进一个新团队干活,最先看的一定是业务 Glossary,AI 也一样。
第二层是接口契约层。我们把所有跨模块调用的接口定义收敛到 contracts/ 目录,只放接口签名、数据结构定义和关键注释。AI 写一个调用方时,我们不是让它看服务的完整实现,而是让它看接口契约。这相当于把“全局”的复杂度降维成了“接口”的确定性。数据治理领域常说“先采集再清洗”,代码治理也一样——先把散落在 25 万行里的跨模块依赖关系采集出来,再清洗成一份干净的契约文档。
第三层是变更影响提示。每次需求改动,我们要求 AI 先输出“影响分析”,列出它准备改哪些文件、可能影响的模块、是否存在破坏性变更。人类评审这个影响分析后,AI 才继续动代码。这一步把很多错误挡在了生成阶段之前,而不是等代码写完了再返工。
3.3 模块隔离:让 AI 每次只需理解一小块世界
除了知识层,架构上也要配合。我们把大单体按业务域切开,每个域提供稳定的对外接口,内部实现完全私有。这样 AI 在改某个域的内部实现时,上下文只需要覆盖该域的几个文件,不牵扯全局。
这种做法有额外的好处:CI 可以针对变更的域做精准测试,而不是每次全量跑 25 万行的整个测试套件。测试反馈越快,AI 的迭代就越快。“治理促进效率”这个说法,在传统项目里经常被当成口号,但在 AI 编码项目里是实打实的收益——好的治理让 AI 在更小的上下文里更快地被验证,整体交付速度不降反升。
4. 安全与依赖治理:AI 代码的风险放大器
4.1 漏洞不是 AI 发明的,但 AI 会成批生产
25 万行代码是 AI 生成的,意味着其中每一个潜在漏洞模式,都有可能在多个模块中被重复复制。比如 AI 在处理用户上传的文件时,第一次生成的代码里用了简单的路径拼接,后续所有类似需求都会复刻这个模式;再比如日志里把整个请求对象打出来,可能包含敏感字段。单点问题在传统项目里可能是一个偶发 bug,在 AI 项目里会扩散成系统性风险。
我们给项目做过一次安全扫描,结果触目惊心:超过 30 处硬编码的访问密钥和 token 散落在不同模块里,绝大多数是 AI 为了“让代码跑通”而直接内联的。这个现象背后的逻辑很简单——安全约束没有进入 AI 的生成条件,它默认以“功能正确”为第一目标,不会主动考虑密钥托管、权限最小化这些工程实践。在 100% 由 AI 生成代码的项目里,你基本可以认为:所有生成式的安全陋习都会出现一遍,而且出现很多遍。
4.2 扫描、卡点与依赖准入:安全治理不能靠自觉
针对这个问题,治理手段必须层层叠加。我先说三样实际验证有效的做法。
第一是秘密扫描。用 Gitleaks 这类工具扫提交历史,把散落的密钥全部轮换掉,并在 CI 里加入同样检查,一旦检测到符合密钥格式的字符串出现在代码里,直接阻断合并请求。
第二是静态安全分析。用 CodeQL 或 Semgrep 针对已知的危险模式做规则扫描,比如路径穿越、未处理的异常、硬编码密钥、SQL 拼接等。每个模式都可能被 AI“创意复制”,所以安全规则的覆盖要尽量广,而且要定期从安全事故中提炼新规则。
第三是依赖治理。AI 很擅长“添加一个依赖来解决问题”,但它不会评估这个依赖的维护状况和供应链风险。我们必须用 Dependabot 或 Renovate 自动跟踪依赖更新,对每个新增依赖做准入评估——维护者活跃度、license、下载量、已知漏洞。这块没有捷径,完全靠流程。
有个特别痛的教训:别让 AI 直接操作依赖文件。我们曾经让 AI 升级某个库,它顺手把几十个传递依赖也改到了未知版本,测试没发现,但上线后出现诡异的兼容性问题。此后我们的规则就改成:AI 可以提出升级建议,但实际的依赖变更必须由人类在受控环境里操作。这条规则现在写进了 ADR,谁都不能破例。
4.3 权限最小化:给 AI 的“手”戴上手套
还有一个很容易被忽略的治理点:AI 编码工具的权限。我们在项目里禁用了 AI 直接执行带有副作用的生产操作,比如连接数据库执行变更、推送生产环境配置。所有这类操作必须走到审批流。
这些限制在初期会让人觉得繁琐,但一旦养成习惯,收益非常明显:AI 生成代码的能力没有被削弱,但它造成的风险事故面被压缩了。用一句大白话总结:AI 是个能力极强的实习生,你可以放手让它写代码,但不能把生产环境的钥匙也给它。治理不是把 AI 关进笼子,而是把它的活动范围画在一个可控的圆圈里。
5. 技术债治理:AI 代码的腐烂速度比人写的更快
5.1 技术债为什么会快速累积
以前我们评价人类工程师写的代码,技术债大多来自“时间紧、任务重”的妥协。AI 生成的代码不一样,它的技术债主要是“无意识累计”:为了让某个测试通过,它可能绕开架构做局部 hack;为了兼容当时的输入数据,它写了一堆判断分支,后来数据格式变了,分支留在那里无人敢删;还有大量为了满足当时质量标准而复制的样板代码,后续演进时改一处漏三处。
AI 还有个特点,它对“删除”非常谨慎,但对“新增”毫无心理负担。于是代码库像一个只进不出的房间,函数越堆越长,依赖越来越重,路径越来越绕。我们后来统计了一下,25 万行里至少有 30% 属于“可以被安全删除或合并”的冗余代码,但这些冗余恰恰又是 AI 上下文变大的原因之一,形成恶性循环。行数不是财富,行数是负担,这句话在 AI 编码项目里尤其成立。
5.2 量化技术债:让隐性问题进入会议议程
治理技术债的第一步,是把隐性问题变成显性数字。数据治理领域有句话叫“先采集再清洗”,代码治理也一样——先把 25 万行里的所有结构信息采集出来,再清洗成可行动的指标。我们从四个维度做度量,每个月出一份报告:
| 指标 | 参考阈值 | 观测目的 |
|---|---|---|
| 循环复杂度 | 单函数不超过 15 | 捕捉 AI 生成的过度嵌套逻辑 |
| 重复代码率 | 重复块占比低于 5% | 发现复制粘贴型生成模式 |
| 未注释的导出接口比例 | 低于 10% | 衡量代码可读性与可理解性 |
| 变异测试通过率 | 高于 70% | 判断测试是不是“凑数”的 |
这四个指标不追求绝对完美,但必须趋势可控。只要某个指标连续两个月恶化,就说明这个区域的治理机制失效了,需要人来介入。这种量化的价值不在于打分,而在于让“代码健康”成为一个可见、可讨论、可追踪的话题,而不是某个人心里模糊的担忧。25 万行的项目,没有人能凭感觉判断健康状况,只能靠数据。
5.3 让 AI 帮我们还债:窄任务重构是可行的
到后期我们发现,AI 不但能写新代码,也能在严格边界下做清理。前提是给它非常明确的规则,比如“只删除未被引用的函数”“只合并两个参数列表相同的函数”“不得改变任何公开 API 签名”。在这种窄任务下,AI 的表现相当好,一次能清理大量低风险冗余,比人工效率高出一个数量级。我们还用 AI 帮我们补文档——不是让它重新解读代码,而是让它阅读 git diff 和关联测试,生成变更说明。
但重构一定要遵循“一次只做一种类型的变更”的原则。我们吃过亏:让 AI 同时做重命名和逻辑调整,结果它把两个动作混在一起,评审时几乎无法辨别行为是否保持不变。拆成“先重命名,再调逻辑,最后清理”三个独立 MR 之后,问题就消失了。这条经验后来也写进了 AI 编码团队的协作守则里。
6. 流程与人的治理:AI 编码模式下,团队角色发生了什么变化
6.1 人不再写代码,但人的工作没有变少
25 万行的过程中,团队最大的变化是人不再写代码,但人的工作量并没有减少太多——只是从“动手实现”变成了“定义目标、评审输出、修复边界”。每个模块开始前,工程师要写清楚三件事:功能定义、约束清单、验收标准。这三样东西写得越清楚,AI 的表现越好。用一句我们在内部常说的大白话:“AI 之神只回应足够清晰的祈祷。”
这里有个被放大的 Garbage In, Garbage Out:在传统项目里,需求描述模糊,写出来的代码也模糊,但人至少自己知道哪里糊;在 AI 项目里,需求模糊,AI 会信心十足地写出看似完整的代码,把模糊掩盖起来,等到集成阶段才爆。所以我们建立了一个强制仪式:AI 开工前,先写一份工作计划,人类评审通过后 AI 才开始写代码。这份计划包含技术选型、受影响模块、风险清单。听起来耽误时间,实际上这是唯一能防止 AI 跑偏的手段。跑了九个月,我们统计下来,AI 的“一次性通过率”从早期的不到 20% 提升到了 50% 以上,贡献最大的就是开工前计划书。
6.2 评审流程分层:人类看成略,工具看实现
25 万行的代码,如果依赖人类逐行 review,一天也过不了几万行。我们的评审策略是分三层。第一层是机器评审,包括格式、静态检查、安全扫描、依赖检查,全部自动化,没有人工参与的必要。第二层是 AI 结对评审,用另一个模型对生成的代码做独立检查,找逻辑漏洞和边界缺失。两套模型互相制衡,能减少单一模型的系统性盲区。第三层才轮到人类,只看那些机器和 AI 都判断不了的问题——架构方向、未来扩展性、业务语义。
这套分层评审跑通之后,一个 500 行以内的 MR,从提交到合入,平均耗时从原来的两三天压缩到了几小时。人没有被淹没在代码细节里,而是把精力放在真正需要判断力的地方。这是 AI 编码项目组织方式上最值得复制的一条经验。
6.3 变更规模控制:把大 PR 拆成一堆小 PR
这也是一个很实用的治理经验:强制限制 AI 单次生成的代码量。如果一次任务超过大概 500 行,我们就把任务进一步拆小。原因很简单:MR 越大,人越看不懂,AI 的上下文越混乱,回归风险也越高。把它拆小之后,每个 MR 的含义清晰,AI 的上下文刚好装得下,评审人也能真正看懂。
25 万行这个目标,不是靠一次生成 2 万行堆出来的,而是几千个平均 200 到 500 行的小 MR 累积出来的。这背后还有一个反直觉的规律:AI 生成大段代码的“初稿质量”随行数增加急剧下降。500 行以内的任务,AI 的表现稳定可靠;超过 1000 行以后,经常会出现前后矛盾、重复逻辑、遗漏边界的问题。与其让 AI 写一大段再花大力气 review,不如把它拆成多个小任务逐个解决。
7. 真正的收尾:治理的本质是把自由度换回确定性
严格来说,这篇文章没有“结论”。因为治理这件事不是项目结束之后才开始做,也不是做到某个程度就可以收工的。我个人体会最深的一点是:治理本质上是在和 AI 的自由度做交易。AI 生成代码的自由度太高,短期爽,长期痛;把自由度压缩起来,通过模板、规范、接口契约、自动化检查来约束它,看起来是给 AI 戴上了枷锁,实际上是给整个项目买到了确定性——确定性意味着可理解、可预测、可维护。
最后再分享一个小技巧:治理规则不是写一份就完事的,它会随项目的演化不断更新。我们的 ADR 库已经积累了 60 多条,每一条都是真实事故换来的教训。每次 AI 犯错,不要只顾着修 bug,顺手把它变成一条可操作的检查规则。让一次事故成为系统的免疫记忆,而不是永远靠人来重复踩坑。
25 万行只是一个时点。按照这个速度,下一个 25 万行可能只需要几个月。到那时候,真正决定项目生死的仍然不是生成能力,而是治理机制是否跟得上。希望这篇东西能帮同行少走一些弯路。
