大型项目如何真正落地 AI Native 开发
从 repowiki、分层检索、Spec、Sub-agent、ATDD 和 Harness 出发,拆解大型代码库中的 AI 编程工程化方法
最近看到一段关于 AI 编程落地的分享。对方维护的是一个前后端合计 8 个 repo、代码量百万行级别的超大型项目。他的做法大致是:
- 先按 repo 产出 repowiki;
- 再拆分 wiki,结合 skill 和 RAG 做定位;
- 进一步沉淀项目级 SDD、ATDD 和 harness;
- 把 MCP、上线、监控、CLI 等基础设施串起来;
- 最后让少量工程师配合 AI 维护迭代。
后面他又补充了一个更重要的观点:这件事并不是“把项目资料全部喂给模型”这么简单。上下文越多,并不一定越准。过于丰富的 wiki 反而会拖累模型,导致上下文窗口被占满、幻觉率上升、主 agent 汇总时爆炸。所以他们后来把流程改成:
需求澄清
-> 代码图谱与依赖定位
-> 留存临时 spec
-> 压缩冲突和冗余上下文
-> compact 后拆成前端 session 和后端 session
-> 分别实现
-> 自动化测试
-> 多轮自修复
我认为这套思路的价值,不在于里面用了多少新词,而在于它把 AI 编程从“个人提示词技巧”推进到了“工程系统设计”。
先说结论
这套方法的方向是对的,但不能被理解成一套可复制粘贴的银弹。
真正值得提炼的是四件事:
-
上下文是预算,不是仓库。 LLM 的上下文窗口不是知识库,不能把所有 wiki、源码、日志、需求都塞进去。上下文越多,模型越容易丢重点。
-
Spec 是 Agent 的工作记忆。 长任务不能只靠聊天记录维持连续性。需求澄清、依赖图谱、接口契约、改动边界、测试策略,都应该沉淀成结构化 spec。
-
Sub-agent 是分治工具,不是堆算力。 多 agent 的核心价值不是“更多模型一起干活”,而是把上下文、责任边界和产出物拆开,降低单个会话的认知负载。
-
Harness 才是可信度来源。 AI 生成代码是否可用,不能靠感觉判断。构建、测试、静态检查、回归用例、接口契约、灰度和监控,才是让 AI 产出变得可控的基础设施。
换句话说,AI Native 开发的关键不是“让模型更聪明”,而是“让模型在更清晰、更窄、更可验证的轨道里工作”。
为什么 repowiki 一开始有用,后来会变成负担
大型项目引入 AI 时,第一反应通常是整理文档:为每个 repo 生成 wiki,记录目录结构、模块职责、核心链路、接口定义、数据库表和常见修改点。
这一步当然有价值。因为没有 repowiki,模型进入大型代码库时就像站在陌生城市里,连地图都没有。它可能需要反复搜索文件、猜测模块边界、读大量无关代码。
但问题是,wiki 一旦过度详细,就会从地图变成另一座城市。
它会带来几个副作用:
- 内容滞后于代码,旧 wiki 会误导模型;
- 模块说明过细,占用大量上下文;
- 相似概念重复出现,模型难以判断哪个才是当前任务的关键;
- 主 agent 汇总多个检索结果时,上下文迅速膨胀;
- 模型开始“看起来知道很多”,但真正改代码时抓不住最短路径。
所以 repowiki 不应该追求“百科全书式完整”,而应该追求“路由索引式可定位”。
更合理的定位是:
repowiki 不是答案本身,而是找到答案的索引。
它应该告诉 agent:
- 这个需求大概率从哪个 repo 开始看;
- 前端路由对应哪个页面、组件和状态模块;
- 后端接口对应哪个 controller、service、schema 和表;
- 哪些模块是稳定公共能力,哪些模块是业务局部实现;
- 修改前必须确认哪些测试和契约。
真正的最终依据仍然应该是当前代码,而不是 wiki。
分层检索的本质:用最短路径找到关键代码
他提到的“多层检索”很值得展开。
在真实业务里,需求通常不是这样来的:
请修改 apps/web/src/pages/order/detail.tsx 第 42 行。
而是这样来的:
某个已有入口需要增加一段新的状态展示,并且服务侧要返回对应状态。
这类需求天然从产品界面出发,所以第一层检索应该解决的是“入口在哪里”。
一个可落地的分层检索链路可以是:
| 层级 | 目标 | 输出 |
|---|---|---|
| 需求层 | 判断需求属于哪个业务域 | 业务关键词、用户路径、页面入口 |
| 路由层 | 从页面或功能定位 repo/module/package | 路由、组件、状态模块、API 调用点 |
| 接口层 | 找到前后端契约 | API、DTO、schema、错误码、权限 |
| 模块层 | 读取模块级 wiki 或索引 | 模块职责、依赖边界、常见坑 |
| 代码层 | 以源码作为最终 spec | 精确改动文件、函数、测试点 |
这里最关键的一句是:最后一层必须回到代码。
wiki、RAG、skill、搜索索引都只是降低定位成本。真正决定怎么改的,应该是当前分支上的代码、测试和类型系统。
如果跳过代码层,模型就容易基于“历史知识”写出看似合理但和当前实现不一致的代码。
上下文窗口:40% 到 50% 不是魔法数字,而是风险提醒
对方提到他们的经验是上下文窗口 40% 到 50% 左右会成为一个关键分水点。这个数字不一定适用于所有模型、所有任务和所有工具,但背后的经验是成立的。
上下文窗口不是越大越好。它至少有三类成本:
-
注意力成本 模型需要在更多信息中选择重点。无关内容越多,关键约束越容易被稀释。
-
冲突成本 旧需求、旧代码、旧 wiki、旧测试结果可能互相矛盾。模型不一定能稳定判断哪条信息优先级更高。
-
汇总成本 多个 sub-agent 的结果回到 main agent 后,如果没有统一格式和压缩策略,主会话会快速膨胀。
所以,好的上下文工程不是“尽量多给”,而是“刚好给到能做决策”。
可以把上下文分成三类:
| 类型 | 是否应该进入主上下文 | 例子 |
|---|---|---|
| 决策上下文 | 应该进入 | 需求目标、约束、改动边界、接口契约 |
| 定位上下文 | 用完即丢或压缩 | 搜索结果、候选文件、模块索引 |
| 证据上下文 | 按需读取 | 源码片段、测试失败日志、构建报错 |
很多团队的问题是,把定位上下文和证据上下文长期留在主会话里,导致主 agent 背着大量已经过期的信息继续工作。
Spec:把“聊天”变成“工程资产”
我认为这套流程里最重要的不是 repowiki,而是 spec。
长任务的失败,很多时候不是模型不会写代码,而是它在多轮对话后忘记了最初的边界:
- 这个需求到底解决哪个用户问题;
- 哪些文件确认要改,哪些文件只是参考;
- 前后端契约是否已经定下来;
- 有哪些兼容性要求;
- 哪些测试必须通过;
- 哪些方案已经被排除。
这些信息如果只存在聊天记录里,迟早会被压缩、截断或稀释。spec 的作用就是把它们从“对话上下文”提升为“任务状态”。
一个轻量的需求到代码图谱 spec 可以长这样:
# Change Spec
## Goal
用一句话说明业务方或使用方要验收的目标。
## Scope
- In: 本次明确要改的模块、接口、页面或行为
- Out: 本次明确不处理的内容
## Entry Points
- Frontend route:
- Backend API:
- Database/table:
- Feature flag/config:
## Current Behavior
当前代码如何工作,引用关键文件和函数。
## Target Behavior
目标行为,包括边界条件和错误处理。
## Contract
- Request:
- Response:
- Error:
- Permission:
## Files
- Must change:
- Likely change:
- Read only:
## Tests
- Unit:
- Integration:
- E2E:
- Manual check:
## Open Questions
还没有确认的问题。
这份 spec 不需要很长,关键是要成为后续 session 的交接物。
当上下文需要 compact 时,保留完整聊天记录不现实;但保留一份高质量 spec 是现实的。
Sub-agent:拆的是责任,不是简单拆任务
很多人使用 sub-agent 会犯一个错误:把一个大任务随便拆成几个小任务,然后让多个 agent 同时查同一片代码。结果是每个 agent 都带回一堆相似信息,main agent 汇总时反而更乱。
有效的 sub-agent 拆分,应该按责任边界来做。
例如一个前后端需求,可以这样拆:
| Agent | 责任 | 产出 |
|---|---|---|
| Explorer | 定位代码图谱 | 入口文件、依赖关系、风险点 |
| FE Agent | 实现前端变化 | UI、状态、API 调用、前端测试 |
| Server Agent | 实现服务端变化 | 接口、schema、业务逻辑、后端测试 |
| Test Agent | 验证和补测试 | 失败复现、测试覆盖、回归风险 |
| Review Agent | 审查 diff | bug、边界条件、遗漏测试 |
这里的重点不是“并发越多越好”,而是每个 agent 的上下文都应该更小、更专注,产出格式也应该可合并。
如果前端 agent 和后端 agent 没有共享 contract spec,它们很可能各自实现一个“合理但不一致”的接口。最后 main agent 看似完成了汇总,实际上埋下了联调问题。
所以 sub-agent 工作流里最重要的不是 spawn,而是边界和交接:
先统一 contract,再并行实现。
先统一输出格式,再汇总结果。
先定义验证方式,再相信结果。
SDD、ATDD 和 Harness 分别解决什么问题
这几个词容易听起来很重,但可以用更朴素的方式理解。
SDD:让设计先于代码
这里的 SDD 可以理解为 Spec Driven Development。它解决的是“模型到底按什么设计写代码”的问题。
没有 SDD 时,agent 可能会直接从需求跳到实现。小需求这样做没问题,大型项目会很危险,因为它可能绕过已有架构,写出局部能跑但整体不一致的代码。
SDD 至少要回答:
- 这次改动属于哪个业务域;
- 是否复用现有模式;
- 是否需要新增接口或配置;
- 是否影响权限、缓存、埋点、国际化、灰度;
- 是否改变已有 contract。
ATDD:让验收先于实现
ATDD 可以理解为 Acceptance Test Driven Development。它解决的是“怎么判断需求真的完成”的问题。
对 AI 编程来说,ATDD 特别重要。因为模型很擅长写出“看起来完成”的代码,但它不一定覆盖真实验收路径。
ATDD 可以提前定义:
- 用户从哪个入口触发;
- 正常路径应该看到什么;
- 异常路径应该如何提示;
- 老数据、空数据、权限不足时怎么办;
- 前端、后端、接口、数据库分别如何验证。
Harness:让验证自动发生
Harness 是整套系统的执行和验证框架。
它可以包括:
- 启动本地环境;
- 执行 lint、typecheck、unit test、integration test;
- 准备测试数据;
- 调用关键接口;
- 抓取页面或接口快照;
- 收集失败日志;
- 把结果压缩成 agent 能理解的反馈。
没有 harness,AI 写代码后只能靠人工看 diff。这个模式在小项目里可以接受,但在大型项目里不可持续。
MCP 和 CLI 的价值:把组织能力变成工具能力
分享里提到基础设施部门有 MCP,并且把功能聚合到一个 CLI。这个方向也很关键。
很多公司内部能力本来就有,只是散落在不同系统里:
- 服务发现;
- 日志查询;
- 链路追踪;
- 发布平台;
- 配置中心;
- 数据库变更;
- 权限系统;
- 监控告警;
- 工单系统。
如果 agent 只能读代码,它最多是一个会写代码的助手。若它能通过 MCP 或 CLI 访问这些内部系统,它才有机会完成更完整的工程闭环。
但这里也要克制。工具不是越多越好。一个好工具应该返回高信号结果,而不是把底层系统的所有字段都倒给模型。
例如查询接口错误时,不应该只返回 5000 行日志,而应该返回:
- 相关 trace id;
- 错误聚合;
- 最近变化;
- 可疑版本;
- 关键堆栈;
- 下一步建议读取的文件或服务。
工具的设计目标不是展示系统有多强,而是降低 agent 做正确决策的成本。
我会怎么把这套方法落到一个团队
如果一个团队想实践这套方法,我不建议一上来就做全量 repowiki、全量 RAG 和复杂多 agent 平台。
更稳妥的方式是从一个高频业务域开始,做一个垂直闭环。
第一阶段:建立最小地图
先由业务方提供一个高频使用场景或明确问题域。
为它整理:
- 页面路由到组件的映射;
- 前端 API 调用到后端接口的映射;
- 后端接口到 service、schema、表的映射;
- 常见测试命令;
- 最近 3 到 5 个真实需求的改动文件。
目标不是覆盖全项目,而是让 agent 能更快进入业务方指定的问题范围。
第二阶段:引入 Change Spec
每个 AI 任务先生成一份 change spec,再进入实现。
要求 agent 在动代码前先回答:
- 要改哪些文件;
- 为什么是这些文件;
- 哪些文件只是参考;
- 有哪些接口契约;
- 准备用哪些测试验证。
这一步能显著降低“边做边猜”的概率。
第三阶段:拆分前后端 session
当任务跨前后端时,不要强行让一个会话从头做到尾。
更好的方式是:
- 第一轮只做需求澄清和代码图谱;
- 产出 contract spec;
- compact;
- 前端 session 和后端 session 分别实现;
- 最后用测试和 review 合并验证。
这样做不是因为模型不能处理长任务,而是因为工程上需要降低耦合。
第四阶段:建设 harness
优先把最常见的验证自动化:
- 一键 typecheck;
- 一键跑相关测试;
- 一键启动本地服务;
- 一键构造测试请求;
- 一键收集失败日志。
不要先追求完美平台,先让 agent 每次改完代码都能稳定自测。
第五阶段:回顾 agent 失败案例
真正的调优来自失败样本。
每周挑几次 AI 产出失败的任务,记录:
- 是定位错了;
- 是 spec 不清楚;
- 是上下文太多;
- 是测试不足;
- 是工具返回了低质量信息;
- 是 sub-agent 交接格式不一致;
- 还是模型确实能力不足。
然后只针对高频失败点改流程。
这套方法最容易踩的坑
1. 把 wiki 当真理
wiki 只要存在,就会过期。越详细的 wiki,维护成本越高。
建议把 wiki 做成索引和导航,把源码、测试和 schema 作为最终依据。
2. 把 RAG 当万能检索
RAG 适合召回候选信息,不适合直接决定改动方案。
大型项目里,语义相似不代表工程相关。最后一定要回到依赖关系、调用链和代码事实。
3. 给模型太多规则
很多团队会不断往 system prompt 里加规则。短期看能修一个问题,长期看会让模型背负大量互相竞争的约束。
规则应该分层:
- 全局规则只放少量稳定原则;
- 语言规则按技术栈加载;
- 项目规则按 repo 加载;
- 任务规则写进 change spec。
4. 过早平台化
如果还没有搞清楚 agent 经常失败在哪里,就急着做平台、做全量索引、做复杂权限系统,很容易造出一套很重但不好用的东西。
先用真实需求跑出闭环,再把重复动作工具化。
5. 只看生成效率,不看回归成本
AI 让代码变快了,但如果 review、联调、回归和线上问题更多,总成本并没有下降。
衡量 AI Native 开发效果,至少要看:
- 首次构建通过率;
- 测试一次通过率;
- review 发现的缺陷数;
- 需求返工次数;
- 联调问题数量;
- 线上回滚或告警数量;
- 人工介入的时间。
对“没有秘密,难点在落地”的看法
我同意这句话。
现在让 Claude、Codex 或其他强模型聊一天,确实可以得到一份看起来很完整的 AI 编程方案。方案本身已经不稀缺。
真正困难的是把方案放进一个真实组织:
- 每个项目的历史包袱不同;
- 每个 repo 的边界不同;
- 每个团队的测试基础不同;
- 每个业务域的隐性知识不同;
- 每个公司内部工具和权限系统不同;
- 每个工程师对 AI 的信任阈值也不同。
所以,“好的代码千篇一律,巨石项目各有各的问题”这个判断很准确。
AI Native 的落地不是一次性架构升级,而是一组持续调优的工程实践:
观察失败
-> 压缩经验
-> 改进 spec
-> 改进工具
-> 改进测试
-> 再观察失败
它更像 DevOps、测试平台、工程效能建设,而不是单纯换一个 IDE 插件。
我提炼出的实践原则
最后把这套方法压缩成几条原则:
-
先定位,再实现。 不要让 agent 直接从需求跳到改代码。先产出代码图谱和 change spec。
-
先 contract,再并行。 跨前后端任务必须先统一接口契约,再拆 session 或 sub-agent。
-
wiki 做索引,代码做真相。 wiki 用来降低定位成本,最终判断必须回到当前代码。
-
上下文要流动,不要堆积。 搜索结果、日志、候选文件用完就压缩或丢弃,只保留决策信息。
-
agent 输出必须可验证。 没有测试、构建、日志和监控闭环,就不要相信“看起来完成”。
-
从一个业务域做闭环。 不要一开始追求全公司级平台。先拿一个高频业务跑通,再复制经验。
-
持续回顾失败样本。 真正提升 AI 产出质量的,不是更多提示词,而是对失败模式的系统性修复。
结论
我对这套工程化思路的整体判断是:方向正确,而且非常接近大型团队真正会走的路线。
它的核心不是 repowiki、RAG、MCP、sub-agent 这些单点技术,而是把 AI 当成一个需要上下文管理、任务分解、接口契约、自动验证和运行反馈的工程系统。
对个人项目来说,也许一个 Codex 会话就能完成大部分事情。对百万行级别的大型项目来说,AI 编程的竞争力不在于“模型一次能写多少代码”,而在于团队能否把复杂项目整理成模型可以稳定理解、稳定修改、稳定验证的工作面。
没有银弹。但有方向:少给噪音,多给结构;少赌模型,多建反馈;少追求一次做完,多沉淀可交接的 spec 和可重复的 harness。
基于这篇文章,我把可复用部分沉淀成了三份 Agent 资产,建议一起使用。它们只提供通用工程方法,不预设任何产品定位、产品方向或业务细节;这些信息需要由业务方或需求提供方输入。
- AI Native 工程化执行规则:作为底层 rules 长期启用,约束 agent 必须先定位、先写 Change Spec、先统一 contract、验证后交付。
- AI Native 大型代码库开发工作流:作为复杂任务 skill 按需调用,覆盖需求澄清、代码图谱、上下文预算、sub-agent 拆分和验证闭环。
- AI Native Change Spec 启动 Prompt:作为一次任务的启动 prompt 使用,适合复制到 Claude、Codex、Cursor 中,让 agent 在写代码前先产出代码图谱和 Change Spec。
三者的关系可以这样理解:
rules = 长期规矩,保证不跑偏
skill = 工作流方法,保证复杂任务拆得开
prompt = 启动模板,保证每次任务先对齐 spec
实际使用顺序建议是:先让项目加载 rules;遇到大型需求时调用 skill;正式开始某个需求时,把 prompt 作为第一轮输入,让 agent 先输出 Change Spec,确认后再进入对应实现单元或测试实现。