Agent 提的 PR 你敢合吗:AI Friendly 后端架构的三件事


Agent 给你提了个 PR,订单服务加一个状态。

改动不大,代码本身挑不出毛病,你 review 完合了。过一阵,结算那边开始出现对不上的数据。

问题不在那段代码。它在订单服务内部是对的,错在支付、履约、结算和运营后台都依赖原来那套状态语义,而这件事没有写在任何 Agent 能读到的地方。它在几个老同事的脑子里,在某次会议纪要里,在群聊上下文里。

这就是整件事的起点。Agent 改不好你的系统,多半不是模型不够聪明,是系统知识压根不在系统里。

它只能从代码、文档、日志、测试、运行环境里去推断。三五个服务的时候推断出不了大事,服务上了几十个,推断就是事故的来源。

整件事的推导链是这样的,先看一眼骨架,后面每一节都挂在这张图上。虚线那两条是关键,一条是走过的死路,一条是全程都得守住的约束。

flowchart TD
    P["系统知识不在系统里<br/>它藏在人脑 · 群聊 · 口头约定 · 历史事故里"]
    P -->|"因为"| C1["Agent 只能从代码 · 文档 · 工具<br/>日志 · 测试 · 运行环境去推断"]
    C1 -->|"所以只能"| C2["局部推断<br/>而服务一多,局部推断就是危险的"]
    C2 -->|"后果"| C3["把局部修复做成全局破坏"]

    X1["传统文档已经是一次显式化尝试<br/>但过期 · 分散 · 无版本 · 无 owner<br/>不与代码和运行态关联"]
    X1 --> X2["对人还能打个折看<br/>对 Agent 直接变成误导源"]
    X2 -.->|"所以光写下来不够"| N

    C3 ==>|"必须显式化,且要满足"| N["五个条件<br/>可被人阅读 · 可被 Agent 检索 · 可被工具引用<br/>可被 CI 校验 · 可被 Harness 执行"]

    N --> M1["六类系统事实<br/>架构 · 服务 · 领域<br/>接口 · 数据 · 运行"]
    N --> M2["任务包与 Harness<br/>把经验和规矩变成可执行的"]
    N --> M3["测试作为门禁<br/>权限是测试挣来的"]

    M1 --> G["可被智能体维护的系统"]
    M2 --> G
    M3 --> G
    G --> E["逐步扩大可信半径"]

    Y1["约束 · 先追可验证,不要先追无人化"] -.-> E

    style P fill:#E0E7EE,stroke:#5B7B9E,color:#37474F
    style C1 fill:#ECEFF1,stroke:#5B7B9E,color:#37474F
    style C2 fill:#ECEFF1,stroke:#5B7B9E,color:#37474F
    style C3 fill:#ECEFF1,stroke:#5B7B9E,color:#37474F
    style X1 fill:#F0ECEC,stroke:#9E7B5B,color:#37474F
    style X2 fill:#F0ECEC,stroke:#9E7B5B,color:#37474F
    style N fill:#E0E7EE,stroke:#5B7B9E,color:#37474F
    style M1 fill:#E3F0F7,stroke:#5B7B9E,color:#37474F
    style M2 fill:#E3F0F7,stroke:#5B7B9E,color:#37474F
    style M3 fill:#E3F0F7,stroke:#5B7B9E,color:#37474F
    style G fill:#E0E7EE,stroke:#5B7B9E,color:#37474F
    style E fill:#E0E7EE,stroke:#5B7B9E,color:#37474F
    style Y1 fill:#F5F2E8,stroke:#9E8B5B,color:#37474F

图里那条虚线的死路值得单独看一眼。传统文档不是没做过,是做过了并且失败了,而失败的方式恰恰对 Agent 最有害。后面第一节讲的就是这条。

下面分几部分。先讲为什么补文档解决不了,真正的判据是什么;再讲要补的六类事实分别该写到什么程度;然后讲经验和规矩怎么变成可执行的东西,测试和权限这道闸怎么设;最后给一条能照着走的落地路线。

一,光把文档补齐没有用

第一反应通常是补文档。拉个专项,花三个月,把架构图、接口文档、数据库说明全部补一遍。

这条路很多团队走过,结果你也见过。半年后那批文档全部过期,然后没人维护,没有 owner,散在几个地方,跟代码和运行态都对不上。

问题从来不在有没有人写,在于写完就开始烂。

对人来说,烂掉的文档还能凑合用。你打开一份旧的接口文档,心里自动打个折,知道它可能不准,会去代码里对一眼。Agent 不打这个折。它把过期文档当成事实,然后基于错误的事实去改代码。所以同一份烂文档,对人是聊胜于无,对它是有害的。

那判据是什么?

不是有没有写下来。是这份东西过期的时候,有没有人会被通知到。

完整的说法是五条,一份系统事实要同时做到可被人阅读、可被 Agent 检索、可被工具引用、可被 CI 校验、可被 Harness 执行。前三条管拿不拿得到,后两条管会不会过期、能不能直接跑。

分水岭是 CI 校验那一条。前三条管的都是好不好用,只有它管的是会不会烂掉,而烂掉正是上一次失败的死因。写在 Wiki 里的架构图,过期了没人知道。写在 README 里的依赖说明,过期了也没人知道。只有进了 CI 的东西,跟代码对不上那天会有人被拦下来。

最后那条 Harness,指的是 Agent 干活时的那套执行框架,管它怎么装载上下文、能调什么工具、什么时候必须停下来。后面会专门讲。

二,要补的六类事实

知道判据之后,接下来的问题是补什么。这一层可以拆成六类,各自回答一个不同的问题,缺哪一类,Agent 就在哪一类上瞎猜。

它们的分工大致是这样,从 Agent 拿到一个需求开始算起。

flowchart TD
    T["Agent 拿到一个需求"] --> A["架构事实<br/>全局地图"]
    A -->|"该动哪个服务"| S["服务事实<br/>节点身份"]
    S -->|"这个服务干什么的<br/>边界在哪"| D["领域事实<br/>业务语义"]
    D -->|"这么改违不违反业务规则"| I["接口事实<br/>协作契约"]
    I -->|"改了字段谁会受影响"| DA["数据事实<br/>状态基础"]
    DA -->|"这个字段到底什么意思"| R["运行事实<br/>真实反馈"]
    R -->|"这条链路现在什么状况"| OK["可以动手了"]

    A -.->|"缺了就在这一层瞎猜"| M1["改错服务<br/>局部修复做成全局破坏"]
    D -.->|"缺了就在这一层瞎猜"| M2["语法正确<br/>业务错误"]
    DA -.->|"缺了就在这一层瞎猜"| M3["猜字段语义<br/>最危险的一类"]

    style T fill:#E0E7EE,stroke:#5B7B9E,color:#37474F
    style A fill:#E3F0F7,stroke:#5B7B9E,color:#37474F
    style S fill:#E3F0F7,stroke:#5B7B9E,color:#37474F
    style D fill:#E3F0F7,stroke:#5B7B9E,color:#37474F
    style I fill:#E3F0F7,stroke:#5B7B9E,color:#37474F
    style DA fill:#E3F0F7,stroke:#5B7B9E,color:#37474F
    style R fill:#E3F0F7,stroke:#5B7B9E,color:#37474F
    style OK fill:#E0E7EE,stroke:#5B7B9E,color:#37474F
    style M1 fill:#F0ECEC,stroke:#9E7B5B,color:#37474F
    style M2 fill:#F0ECEC,stroke:#9E7B5B,color:#37474F
    style M3 fill:#F0ECEC,stroke:#9E7B5B,color:#37474F

图上那条主链是理想顺序,实际未必这么线性,但缺哪一环、Agent 会在哪一步瞎猜,这个对应关系是成立的。虚线标的三处是后果最重的。

架构事实:地图要写的是拓扑之外的东西

Agent 拿到一个需求,第一件事是判断该在哪儿改,这个判断需要一张全局地图。

服务拓扑图不解决这个问题。那种图只描述现状,而现状 Agent 自己就能扒出来,调用链、配置、代码引用里都有。地图真正要写的是拓扑之外的东西,也就是那些约束。

一份能用的地图至少要回答九个问题。

  1. 系统有哪些业务域。用户、商品、订单、支付、库存、履约、营销、风控、结算这些。这决定了一个需求该落在哪个边界里,而不是看到哪儿有相似代码就改哪儿。
  2. 服务怎么分层。网关层、BFF 层、应用服务层、领域服务层、基础能力层、数据平台层。这决定了哪些逻辑该放接入层、哪些该沉到领域层、哪些代码不该发生反向依赖。
  3. 核心链路怎么流转。下单、支付、退款、履约、登录、风控、消息通知。每条链路经过哪些服务、每一步是同步还是异步、失败了怎么补偿、哪些步骤影响用户实时体验、哪些允许最终一致。
  4. 调用拓扑是什么。谁调谁、哪些是高频、哪些在核心链路上。Agent 要新增一个远程调用时,靠这个判断风险。
  5. 消息拓扑是什么。谁生产哪些 topic、谁消费、事件语义是什么、允不允许重复消费、要不要求顺序、有没有死信队列和补偿任务。很多系统真实的业务流不在同步接口里,在异步消息里,看不懂消息拓扑就看不懂系统真正的状态流动。
  6. 数据所有权怎么划分。每张核心表、每类核心数据、每个缓存 key、每个搜索索引,谁能写、谁只能读、谁禁止直接访问。缺了这条,Agent 很容易为了快速实现需求写出跨服务直连数据库、绕过领域服务的代码。
  7. 强弱依赖怎么定义。有些服务挂了主链路直接失败,有些只影响推荐、展示、通知、埋点、异步统计。有没有缓存、有没有兜底、能不能超时跳过,都得写清楚。
  8. 发布边界和故障隔离边界在哪。哪些服务能独立发布、哪些必须联动、哪些配置能灰度、哪些故障会传导到核心链路。这条缺了,Agent 即使代码写对了,也会给出错误的发布方案。
  9. 历史遗留和未来方向是什么。哪些模块是 legacy、哪些是 target、哪些能力正在迁移、哪些接口只允许维护不允许扩展。

第九条最容易漏,后果也最隐蔽。不标出来的话,Agent 会老老实实往遗留模块里继续加功能,而且每一次它都觉得自己干得挺对,债务就这么滚起来了。

服务事实:每个服务一张身份证

有了全局地图,Agent 进到某个具体服务之前,还需要一份这个服务的说明。这张卡片放在服务仓库根目录,内容大致十一项。

  • 服务定位,属于哪个业务域,解决什么问题,以及不解决什么问题
  • 核心职责,列 3 到 7 条。超过 7 条通常说明这个服务的边界已经腐化了
  • 核心实体,本服务直接拥有什么,比如订单服务拥有 Order、OrderItem、OrderStatus
  • 数据所有权,哪些表本服务拥有、哪些只能读、哪些禁止跨服务访问
  • 接口清单,核心 RPC 和 HTTP 接口、调用方是谁、稳定性等级、是否对外暴露、允不允许新增字段
  • 消息清单,生产和消费哪些 topic,每条消息的语义、幂等 key、重试策略、死信处理
  • 依赖清单,依赖哪些服务、库、缓存、队列、三方平台,哪些是强依赖、哪些可降级
  • 运行特征,QPS、峰值、延迟目标、错误率目标、监控 dashboard、关键告警
  • 变更约束,哪些代码不能随便改、哪些字段必须兼容、哪些逻辑涉及资金库存权限风控
  • 测试入口,单测命令、集成测试命令、契约测试命令、本地怎么启动、怎么 mock
  • 发布与回滚,发布平台、灰度策略、配置开关、回滚方式、数据回滚注意事项

比字段清单更重要的是两个要求。

一是由 CI 检查它存不存在、必填字段全不全、跟实际依赖对不对得上,否则它就是另一份会烂掉的文档。

二是不该完全手写。接口从 IDL 或者 OpenAPI 生成,依赖从调用链和配置生成,表结构从 schema 生成,监控链接从服务注册信息生成,人只维护业务解释、边界约束和历史注意事项这几块。

不过自动生成救不了全部。留给人写的那一小块,恰恰就是开头说的那些藏在老同事脑子里的东西,它不会因为别的部分自动化了就自己保鲜。自动生成只是把会烂掉的面积压到最小。

领域事实:把不变量写成能断言的形式

这一类最容易被跳过,但后端系统真正的复杂度在这儿,不在技术。

系统里有一批规则,任何时候都必须成立。

  • 已支付订单不能随意回到未支付
  • 退款金额不能超过支付金额
  • 库存扣减必须和订单状态保持一致
  • 优惠券不能重复核销
  • 账户余额不能变成负数
  • 同一请求不能重复入账
  • 风控拒绝后的交易不能绕过审批

这些规则现在散落在代码、数据库约束、消息消费、运营后台甚至人工流程里。人靠经验知道哪儿不能动,Agent 不知道。它在重构时会把一个看起来多余的判断删掉,在加功能时会绕开某个关键校验,而且它有充分的理由,那段代码看起来确实像是冗余的。

所以领域模型这一层要写四样东西。

不变量,写成清晰、可测试、可断言的形式。不是"支付成功后要有流水"这种描述,是能变成一条断言、能被单测覆盖的形式。

状态机,订单、退款、审核、配送、账号,每个都要有明确的状态枚举、可流转路径、禁止路径、触发事件和补偿动作。最好不只有图,还有机器可读的定义,能拿去生成校验逻辑和测试用例。很多业务 bug 的根源就是状态流转错误。

幂等与一致性策略,分布式系统里重试、超时、重复消息、乱序都是常态。哪个接口靠 requestId 幂等、哪个消息用 businessKey 去重、哪个流程允许最终一致、哪个必须强一致、哪个场景要事务消息或者 outbox,这些得写下来。

风险等级,资金、库存、权限、隐私、风控、结算属于高风险;内容展示、运营配置、非核心推荐属于中低风险。这个分级直接决定 Agent 在不同区域能自动到什么程度。

还有一层,单个领域的模型管不了跨域的事。下单链路可能涉及用户、营销、订单、库存、支付、风控、履约、通知八个服务,退款链路涉及订单、支付、资金、库存、优惠券、结算、通知。任何一个局部改动都可能影响整条链路的一致性。

领域模型管的是单个业务对象内部的规则,管不了跨服务的一致性。开头那个 PR 出的正是后一类问题。

说实话这一层目前还没有成熟做法。全局地图该回答什么、服务卡片该写什么字段,这些都有清单可抄,但一条业务链路跨了七八个服务、每一步的补偿和一致性要求怎么写成机器能校验的东西,我还没见到讲清楚的。想做得自己设计。

接口事实与数据事实:字段语义是最危险的地方

接口这一层,除了 URL、参数、返回值,还要写清楚调用方是谁、是否幂等、能不能重试、超时多久、限流策略、鉴权方式、错误码含义、兼容性要求、字段废弃策略、灰度字段、历史坑点。

BFF、网关、APP 后端、开放平台这几类接口还有一条额外要求,必须写明端版本兼容关系。否则 Agent 改一个字段,可能直接让老版本客户端崩溃,而它完全意识不到。

数据这一层要写表结构、字段含义、索引设计、分库分表规则、冷热数据策略、归档策略、敏感字段、唯一性约束、状态字段枚举、逻辑删除规则、数据修复脚本。

其中最要紧的是枚举说明。大规模系统里字段名经常不足以表达真实含义,status=3 到底是已支付、已取消还是处理中,必须写下来。取值集合不封闭,Agent 就会去猜,而 AI 对字段语义的猜测,是未来自动化开发中最危险的风险点之一。

运行事实:静态代码之外的那一半

Agent 不能只看静态代码。某个接口 QPS 多高、TP99 多大、错误率多少、是不是核心链路、是不是强依赖、有没有降级、最近有没有出过事故、哪个 consumer lag 经常涨、哪个 Redis key 是热点,这些都得在它能访问的观察层里。

这一层的要求跟给人看的可观测性不一样,要更结构化。

日志格式要统一,必须包含 traceId、spanId、脱敏后的主体标识、bizId、errorCode、耗时、关键状态。自然语言日志可以保留,但关键字段必须结构化。

错误码要有语义,不能所有异常都叫 SYSTEM_ERROR。Agent 需要靠错误码分辨这是参数问题、依赖超时、库存不足、权限失败、幂等冲突还是数据不一致。

Trace 要能关联业务实体,排查订单问题时,能从 orderId 找到完整调用链、消息链、数据库变更和状态流转。

指标要有业务含义,除了 CPU、内存、QPS、延迟,还要有订单创建成功率、支付成功率、退款失败率、库存扣减失败率、消息积压量、风控拦截率。

每个告警要关联 Runbook,写明可能原因、排查步骤、常用查询、风险等级、临时止血方式、长期修复建议。没有 Runbook 的告警,对 Agent 来说只是噪音。

三,把经验和规矩变成可执行的东西

上面六类事实解决的是"Agent 能不能读懂系统"。接下来是"它干活时按什么规矩来"。

把高频任务沉淀成任务包

团队里有一批任务是反复做的,加个字段、加个 consumer、加个订单状态、排查 TP99 升高、排查 Kafka 堆积、给接口加限流、把同步调用改异步、写一次性数据修复脚本。

这类任务可以封装成一个个可复用的包,每个包写清楚七件事。

  • 适用场景,什么时候该用这个包,什么时候不该用
  • 输入信息,需要哪些参数,服务名、接口名、实体名、字段名、topic 名、错误日志、traceId
  • 相关文件,controller、service、repository、domain、DTO、mapper、schema、test、配置文件分别在哪
  • 操作步骤,先改 IDL、再生成代码、再补业务逻辑、再补单测、再更新接口文档、再跑契约测试
  • 风险检查,会不会影响老版本客户端、要不要灰度开关、涉不涉及数据迁移、要不要补偿脚本
  • 验证命令,本地测试、集成测试、lint、schema 检查分别怎么跑
  • 输出要求,PR 描述必须包含变更点、兼容性、测试结果、回滚方式

七段结构听起来抽象,拿开头那个场景填一遍就清楚了。假设要给订单加一个状态,这个包大致长这样。

  • 适用场景,订单主流程要新增一个业务状态
  • 输入信息,新状态的名字和语义、它的前驱状态、它能流转到哪些状态、由什么事件触发
  • 相关文件,状态枚举、状态机定义、订单实体、对外接口的状态映射、消费状态变更事件的下游清单
  • 操作步骤,先在状态机定义里加节点和边,再改枚举,补流转校验,补单测覆盖新增的合法与非法流转,更新对外接口文档的状态说明,最后跑契约测试
  • 风险检查,逐个下游确认它是不是依赖原有的状态集合、老版本客户端拿到未知状态会走哪条分支、按状态过滤的报表和对账逻辑要不要跟着改、要不要灰度、历史数据要不要回填
  • 验证命令,单测、状态机契约测试、涉及下游的集成测试
  • 输出要求,PR 里写清楚新增了哪个状态、影响哪些下游、兼容性怎么处理、怎么回滚

开头那个 PR 出事,缺的就是第五条。Agent 有能力做这些检查,只是没人告诉过它这类改动的风险清单长什么样。写下来之后,这份清单对人和对它同时生效。

这也是这套东西真正的价值,不只是让 Agent 少犯错,更是把资深工程师的经验复制出来。很多团队的效率差异不是工具差异,是经验差异。老工程师知道加字段的正确顺序是先兼容写、再兼容读、再回填、再切流量、最后清理旧字段,新人和 Agent 都不知道。把这个顺序写进任务包,它就从个人经验变成了组织资产。

用 Harness 圈出执行轨道

任务包是能力,Harness 是轨道。它决定 Agent 怎么拿上下文、怎么选工具、怎么执行命令、怎么处理权限、怎么验证结果、什么时候必须停下来上报。

这七层不是并列的七个模块,是一次改动依次要穿过的七道关卡。

sequenceDiagram
    participant U as 需求
    participant CTX as 上下文装载层
    participant PLAN as 计划层
    participant EXEC as 执行层
    participant VER as 验证层
    participant H as 人

    U->>CTX: 一个任务进来
    CTX->>CTX: 按任务装载服务卡片 领域模型 schema 最近PR 相关事故
    Note over CTX: 不是把整个代码库塞给模型
    CTX->>PLAN: 带着精准上下文进入
    PLAN->>PLAN: 先输出计划 改哪些文件 为什么 预期影响
    alt 低风险
        PLAN->>EXEC: 自动继续
    else 高风险
        PLAN->>H: 停下来等审批
        H-->>EXEC: 批准后放行
    end
    EXEC->>EXEC: 独立分支 独立 worktree 独立 sandbox
    Note over EXEC: 不污染主干 不动共享开发环境
    EXEC->>VER: 改完了
    VER->>VER: 单测 集成 契约 静态检查 安全扫描 schema
    alt 验证不过
        VER-->>EXEC: 打回去重做
    else 验证通过
        VER->>H: 才允许进 PR
    end

图上是主流程,还有三层没画进去,它们要么横贯全程、要么是给每一步兜底的。

工具层决定 Agent 手上有什么。代码搜索、文件编辑、测试执行、依赖分析、日志查询、trace 查询、数据库只读查询,每样都要有权限边界。这一层的关键不是给多少工具,是每个工具的边界画在哪,生产库默认只读、敏感表脱敏、危险命令直接禁掉。

审计层记录它做过什么、读过什么、改过什么、执行过什么命令、为什么这么决策。回滚层要求每个变更都附带回滚方案,涉及配置、数据库、消息、缓存、数据修复的还要说明怎么恢复。

无人值守不是不需要责任,是需要更强的可追溯性,这两层就是那个可追溯性。

主流程那四层里,上下文装载和独立执行环境这两处的设计意图值得点一句。前者的价值不在装了多少,在于它不装什么,整个代码库一股脑塞进去等于没有上下文。后者坚持独立分支和 sandbox,是为了让失败可丢弃,Agent 搞砸了直接扔掉重来,成本低到可以允许它多试几次。

再往前一步,Harness 不只是执行环境,还能当架构规则的执行器。把系统分层、依赖方向、数据所有权、消息规范、核心链路约束、强依赖准入规则写成一组机器可检查的策略,Agent 提交计划或者改代码时自动检查有没有越界。

具体要拦的是这五种。

  • BFF 层直接写核心业务库
  • 非 owner 服务访问其他服务的私有表
  • 核心交易链路新增未登记的同步 RPC
  • 基础服务反向依赖业务服务
  • 异步解耦的链路被改成强同步调用

这些过去靠架构师在架构评审或者 Code Review 里凭经验发现,现在得尽量变成自动检查。

文档和架构都进 CI

前面说判据是"过期时有没有人被通知到",落到工程上就是这两件事。

文档即代码。新增接口必须更新 OpenAPI 或 IDL,新增数据库字段必须更新 schema 文档和字段说明,新增 topic 必须更新消息契约,新增配置项必须写明默认值、作用域、是否支持热更新,新增领域状态必须更新状态机,改核心逻辑必须更新对应的任务包或 Runbook。CI 检查这些缺没缺,检测到新增 controller 但没更新接口文档、新增 migration 但没有字段说明、新增 consumer 但没有 topic 文档,就阻止合并。

架构即代码。把业务域划分、服务分层、允许的依赖方向写进 architecture.yaml,把每张表、每个 topic、每个 API 的 owner 写进 ownership.yaml,把核心链路和延迟预算写进 critical-path.yaml,把不同风险等级下 Agent 能自动执行到哪一步写进 risk-policy.yaml。这几份文件参与 CI/CD 之后,全局架构就不再是 PPT 或者 Wiki 页面,而是能被读取、被校验、被执行的工程资产。

代码本身也要好导航

这一条容易被忽略,但它直接影响 Agent 找不找得对地方。

目录、命名、分层约定要稳定,controller、application、domain、infrastructure、repository、client、config、test 的边界要清楚,DTO、DO、Entity、VO、Command、Event、Mapper 不要混用。服务调用、消息发送、缓存访问、数据库访问不要散落在任意位置。

更重要的是减少隐式魔法。过度复杂的反射、动态代理、运行时拼接、隐式扫描,如果没有足够的文档,Agent 很难判断真实调用关系。不是说这些技术不能用,是必须让它们可解释、可追踪、可测试。

再具体一点,代码里要有这么几个固定的导航锚点。

  • 每个接口有明确入口
  • 每个领域实体有独立文件
  • 每个状态机有集中定义
  • 每个外部依赖有 client 封装
  • 每个消息 topic 有 producer 和 consumer 定义
  • 每个配置项有说明和默认值
  • 每张数据库表有对应的 repository

这些约定的作用是压缩 Agent 猜路径的空间。它越容易找到正确位置,越不容易在错误的层级上乱改。

四,测试不再是给人兜底的

过去测试不足也能撑,因为有人兜底。开发知道哪儿不能碰,测试知道重点回归哪里,运维知道出事了怎么处理。这层兜底是隐性的,从来没写进任何文件。

Agent 参与之后它就没了。

所以测试的角色变了,不是程度变了。把覆盖率从 60% 提到 80% 解决不了这个问题,因为你补的还是那种验证函数返回值的测试,而你真正需要的是一道能告诉 Agent 它有没有资格往下走的闸。

具体要覆盖七类。

  • 单元测试,重点覆盖不变量、状态机、金额计算、权限判断、风控规则。Agent 改完代码,单测应该第一时间发现它破坏了业务规则
  • 契约测试,防止它在当前服务里测试通过,却破坏了跨服务兼容。新增字段、删除字段、改枚举、调错误码,都可能影响调用方
  • 集成测试,订单、支付、库存、消息这类链路要有端到端环境。只验证一个函数不够,得验证完整业务流
  • 回归用例库,每次线上事故、重要 bug、历史兼容问题都沉淀成用例。这是在给 Agent 划新的红线,让它不会反复踩同一个坑
  • 数据迁移测试,schema migration 是最危险的变更之一,要验证兼容性、耗时、锁表风险、回滚脚本
  • 性能测试,Agent 的修改可能引入 N+1 查询、缓存击穿、额外 RPC、锁竞争。核心链路的变更,性能基准应该是硬门槛
  • 架构验证,这一类是新增的,它验证的不是行为而是结构

最后一类值得单独说。服务依赖有没有违反分层,领域服务有没有被 BFF 反向污染,非 owner 有没有直接访问别人的库,核心链路有没有新增未备案的强依赖,消息 schema 有没有破坏兼容,migration 会不会锁表。这些是结构性问题,而结构正是 Agent 最容易悄悄侵蚀的东西。

顺着这条线,有些原本听起来很严苛的规定就变得合理了。没有验证的 Agent 修改不进 PR。允许它在低风险服务上自动合并发布,前提永远是测试、灰度、回滚三件套齐全。

权限是测试挣来的。

五,两套分级别混着用

推进这件事的时候,你大概会遇到两套分级,它们经常被混着用。

一套讲的是组织走到哪一步了。最初 Agent 只是帮着写代码补测试,此时系统只需要基本文档、代码规范和测试入口。往后它能独立完成中低风险任务,加接口、修 bug、补单测、写 migration、改配置、生成 PR,此时系统需要服务卡片、任务包、领域模型、契约测试和 CI 约束。再往后才谈得上参与线上值守,接告警、分析日志、定位问题、提修复、执行回滚、生成复盘,此时需要完整的可观测性、权限分级、审计、自动化发布、灰度、回滚和安全策略。

另一套讲的是单次操作给多大权限,一般分成这么几档。

最低一档只能读代码和文档,适合做问答、解释和影响面分析。往上一档能在本地 sandbox 改代码、跑测试,但碰不到任何真实数据。再往上才允许查脱敏日志、测试环境数据库和监控指标。更高一档能提 PR、触发 CI、生成灰度配置,但不能直接发布。再往上是能在低风险服务上自动合并发布,前提是测试、灰度、回滚条件都满足。最高那一档才允许执行生产修复动作,回滚、降级、扩容、切配置,而且必须有强审计、强策略和人类预授权兜着。

这两套不是一条线上的刻度,是两个独立的轴。

组织成熟度单次操作权限
衡量什么你整套系统配不配这一次动作允许它做到哪
回答的问题敢不敢启动这类自动化这次任务能放到哪一步
粒度整个组织、整套系统每个服务、每次任务

同一个团队完全可以对核心交易服务只给最低权限,同时让某个内部工具服务自动合并。反过来看也一样,同样是中间那一档,敢不敢真的授出去,取决于整套系统当时具备了什么。

混成一条线,你就会得出"我们还在第二阶段所以不能开放自动合并"这种结论,白白卡住本来可以放开的那部分。

另外,权限具体分几级、每级给什么,各家划法都不一样,这套分层是个参考框架不是标准,提出它的人自己也建议各团队按业务特色重新设计。资金、库存、权限、风控这些高风险域,无论走到哪一步都得留人工审批。

数据安全那条线也得单独划。日志里的手机号、身份证、邮箱、地址、支付信息、token、cookie、密钥必须脱敏。Agent 不应该直接接触明文敏感数据。生产库查询默认只读,并且限行数、限字段、限时间窗口,全量审计。密钥、证书、生产配置走专门的 secret manager,不能出现在 prompt、日志或者代码生成的上下文里。能力弱的 Agent 最多写错代码,能力强但权限失控的,可以直接制造生产事故。

六,一条能照着走的路线

看到这儿你可能觉得工程量大得没法启动。确实,所以不建议一上来就搞平台,比较现实的顺序是这样。

flowchart TD
    S1["1 选试点<br/>中等复杂度 · 可灰度可回滚"] --> S2["2 最小可用的全局架构地图<br/>可以粗,但必须真实"]
    S2 --> S3["3 补齐试点服务的服务卡片"]
    S3 --> S4["4 梳理核心领域模型<br/>实体 状态机 不变量 幂等"]
    S4 --> S5["5 沉淀 5 到 10 个高频任务包"]
    S5 --> S6["6 补测试和契约<br/>先覆盖核心链路与高频变更点"]
    S6 --> S7["7 建 Agent 的 PR 模板"]
    S7 --> S8["8 把 CI 变成硬门槛"]
    S8 --> S9["9 接入只读可观测工具<br/>脱敏 限权 审计"]
    S9 --> S10["10 允许低风险自动 PR<br/>但先不自动合并"]
    S10 --> S11["11 再扩大到更多服务与更复杂任务"]

    G["贯穿全程 · 每一步都要能被验证<br/>验证不了就别往下走"] -.-> S8
    G -.-> S10

    style S1 fill:#E0E7EE,stroke:#5B7B9E,color:#37474F
    style S2 fill:#E0E7EE,stroke:#5B7B9E,color:#37474F
    style S3 fill:#ECEFF1,stroke:#5B7B9E,color:#37474F
    style S4 fill:#ECEFF1,stroke:#5B7B9E,color:#37474F
    style S5 fill:#ECEFF1,stroke:#5B7B9E,color:#37474F
    style S6 fill:#E3F0F7,stroke:#5B7B9E,color:#37474F
    style S7 fill:#E3F0F7,stroke:#5B7B9E,color:#37474F
    style S8 fill:#E3F0F7,stroke:#5B7B9E,color:#37474F
    style S9 fill:#E3F0F7,stroke:#5B7B9E,color:#37474F
    style S10 fill:#E3F0F7,stroke:#5B7B9E,color:#37474F
    style S11 fill:#E0E7EE,stroke:#5B7B9E,color:#37474F
    style G fill:#F5F2E8,stroke:#9E8B5B,color:#37474F

图上每一步的内容都写在框里了,这里只补几处做错了会白干的判据。

挑试点的标准是有真实复杂度但摔得起。最边缘的玩具服务验证不出什么,它本来就没有跨服务依赖、没有历史包袱,Agent 在上面表现好不说明任何问题;支付、资金这类又摔不起。中间那一档才既能暴露问题、又不至于出事。

建地图这一步,想一次画完美是最常见的失败方式。它的作用不是当作交付物,是让团队和 Agent 先获得系统级方向感。初版可以很粗,但必须真实;可以不完整,但不能误导。一张只标了一部分、但标出来的全对的地图,比一张画满、其中掺着过时信息的图有用得多,因为后者会让 Agent 在过时的那部分上自信地犯错。

补测试那一步,判据是覆盖核心链路和高频变更点,不是覆盖率数字。很容易滑向刷覆盖率,而刷出来的那些测试对约束 Agent 没有用。

整条路线里最该忍住的是第十步,只放自动 PR、不放自动合并。先让人 review 一段时间,看看它产出的质量到底怎么样。这个观察期的价值在于你会看清它出错的模式,而那些模式正是下一轮该补进测试和策略的东西。

整条路线的关键在于,先追求可验证,别先追求无人化。

最后

如果这一整套暂时动不了,有一个问题可以今天就问。

找出你那份最重要的架构文档,问一句,它跟代码对不上的时候,谁会知道?

如果答案是等有人踩坑了才知道,那它就还停在传统文档那一层,补得再全也一样。这个问题不需要任何投入,但能立刻告诉你现在处在什么位置。

还有一件事值得说。这套改造即使没有 Agent 也是划算的,系统知识更清晰、流程更规范、风险控制更自动化,本来就该做。区别只在于以前不做,代价是慢慢还;往后不做,Agent 就进不了你的系统。


延伸阅读:《后端架构 AI Friendly 的标准与路径:面向无人值守开发时代的系统重构》,https://mp.weixin.qq.com/s/XpSpAiWY-nXjw8d8QPbabg

相关文章

快来做第一个评论的人吧~