技术AI辅助编程AgentClaude CodeCodex工程化

大型项目如何真正落地 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 编程从“个人提示词技巧”推进到了“工程系统设计”。

先说结论

这套方法的方向是对的,但不能被理解成一套可复制粘贴的银弹。

真正值得提炼的是四件事:

  1. 上下文是预算,不是仓库。 LLM 的上下文窗口不是知识库,不能把所有 wiki、源码、日志、需求都塞进去。上下文越多,模型越容易丢重点。

  2. Spec 是 Agent 的工作记忆。 长任务不能只靠聊天记录维持连续性。需求澄清、依赖图谱、接口契约、改动边界、测试策略,都应该沉淀成结构化 spec。

  3. Sub-agent 是分治工具,不是堆算力。 多 agent 的核心价值不是“更多模型一起干活”,而是把上下文、责任边界和产出物拆开,降低单个会话的认知负载。

  4. 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% 左右会成为一个关键分水点。这个数字不一定适用于所有模型、所有任务和所有工具,但背后的经验是成立的。

上下文窗口不是越大越好。它至少有三类成本:

  1. 注意力成本 模型需要在更多信息中选择重点。无关内容越多,关键约束越容易被稀释。

  2. 冲突成本 旧需求、旧代码、旧 wiki、旧测试结果可能互相矛盾。模型不一定能稳定判断哪条信息优先级更高。

  3. 汇总成本 多个 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

当任务跨前后端时,不要强行让一个会话从头做到尾。

更好的方式是:

  1. 第一轮只做需求澄清和代码图谱;
  2. 产出 contract spec;
  3. compact;
  4. 前端 session 和后端 session 分别实现;
  5. 最后用测试和 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 插件。

我提炼出的实践原则

最后把这套方法压缩成几条原则:

  1. 先定位,再实现。 不要让 agent 直接从需求跳到改代码。先产出代码图谱和 change spec。

  2. 先 contract,再并行。 跨前后端任务必须先统一接口契约,再拆 session 或 sub-agent。

  3. wiki 做索引,代码做真相。 wiki 用来降低定位成本,最终判断必须回到当前代码。

  4. 上下文要流动,不要堆积。 搜索结果、日志、候选文件用完就压缩或丢弃,只保留决策信息。

  5. agent 输出必须可验证。 没有测试、构建、日志和监控闭环,就不要相信“看起来完成”。

  6. 从一个业务域做闭环。 不要一开始追求全公司级平台。先拿一个高频业务跑通,再复制经验。

  7. 持续回顾失败样本。 真正提升 AI 产出质量的,不是更多提示词,而是对失败模式的系统性修复。

结论

我对这套工程化思路的整体判断是:方向正确,而且非常接近大型团队真正会走的路线。

它的核心不是 repowiki、RAG、MCP、sub-agent 这些单点技术,而是把 AI 当成一个需要上下文管理、任务分解、接口契约、自动验证和运行反馈的工程系统。

对个人项目来说,也许一个 Codex 会话就能完成大部分事情。对百万行级别的大型项目来说,AI 编程的竞争力不在于“模型一次能写多少代码”,而在于团队能否把复杂项目整理成模型可以稳定理解、稳定修改、稳定验证的工作面。

没有银弹。但有方向:少给噪音,多给结构;少赌模型,多建反馈;少追求一次做完,多沉淀可交接的 spec 和可重复的 harness。

基于这篇文章,我把可复用部分沉淀成了三份 Agent 资产,建议一起使用。它们只提供通用工程方法,不预设任何产品定位、产品方向或业务细节;这些信息需要由业务方或需求提供方输入。

三者的关系可以这样理解:

rules  = 长期规矩,保证不跑偏
skill  = 工作流方法,保证复杂任务拆得开
prompt = 启动模板,保证每次任务先对齐 spec

实际使用顺序建议是:先让项目加载 rules;遇到大型需求时调用 skill;正式开始某个需求时,把 prompt 作为第一轮输入,让 agent 先输出 Change Spec,确认后再进入对应实现单元或测试实现。