第一性原理:端到端的 5 个不变命题
从 Issue 到 PR 这条链上,无论 Agent 如何演进,这 5 条不能变。
- 不可跳步 —— Issue 分析、检索、理解、规划、修改、测试、Review、评测,一步都不能省。省了任何一步,PR 都不能称为"交付"。
- 可定位 —— 任何失败都必须能落到具体模块。没有归属的失败,不允许简单重跑。
- 可回滚 —— Agent 引入的修改必须可逆,且必须能区分"用户改的"与"Agent 改的"。
- 可审查 —— 交付物不是一段回答,而是一份 Patch、一组测试日志、一份 PR 说明与一份评测报告,每一份都要能被打回重做。
- 可复现 —— 全链路 Trace 必须从 Issue 一直贯穿到 PR。没有 Trace,PR 是怎么生成的永远无法解释。
真正的交付物不是"PR 文本",而是一份可审查系统——每一段产出都有证据链。— 这份笔记的全部主张都建立在这 5 条之上
端到端总架构
Agent Orchestrator 是协调器,不是合并器;12 个模块各自有专属职责。
设计原则
- Orchestrator 负责模块间协调与状态流转
- 不替代各模块的专属职责
- 不把所有逻辑塞进一个 Agent Prompt
核心约束
- 每个模块有独立输入输出契约
- 失败可定位到具体模块
- 全链路 Trace 从 Issue 贯穿到 PR
Anti-Pattern · 巨型 Prompt
把所有职责塞进同一个 Prompt 看似省事,实际上让失败无法定位——一旦它出错,你不知道是"分析错了"还是"理解错了"。把模块拆开是给失败一个家。
IssueAnalyzer:先把问题读清楚
自然语言 → 结构化任务输入。这是后续 Search 与 Planner 共用的"事实基础"。
提取维度
现象 & 触发条件
用户看到的现象、复现路径
成功标准
什么样的修复算成功?
影响模块
大致涉及哪些模块,风险多大
缺口信息
偏环境、复现步骤、版本差异
输出契约
// IssueAnalyzer 输出(结构化) { "phenomenon": "刷新后偶发退出", "trigger": "登录后刷新页面", "scope": ["Auth", "Session", "Router"], "success_criteria": [ "刷新后不再退出", "补充 Session 刷新测试" ], "constraints": ["不破坏现有登录主流程"], "risk_level": "medium" }
为什么契约必须明确
同一个 Issue 在不同模块看来意义不同:Search 关心 scope,Planner 关心 success_criteria,TestRunner 关心 constraints。没有这个共同"事实层",后端各模块会各自脑补出不同版本的 Issue。
理解代码:Search Layer + Code Understanding
先找代码,再走向调用链。两步都不能省,谁先谁后不能颠倒。
Search Layer
输入来源
- 结构化 Issue(来自 IssueAnalyzer)
- 项目 Memory(模块路径、历史问题)
- 仓库索引(语义 + 词法)
输出
- 候选文件列表 + 每个文件的
SearchEvidence - 相关
Symbol线索 - 测试文件候选
- 不确定项(标出"需进一步探索")
Code Understanding
四步流水线
- 解析 AST:抽取 Symbol 定义
- 构建调用图:Definition × References
- 类型分析:评估影响范围
- 输出报告:列出关键函数、调用方、潜在修改点
| 候选文件 | 角色 | 关键发现 |
|---|---|---|
web/src/auth/session.ts |
Session 核心逻辑 | 高置信度候选 |
web/src/auth/AuthProvider.tsx |
Auth 状态管理 | 高置信度候选 |
web/src/router/guard.ts |
路由守卫 | 中置信度候选 |
tests/session-refresh.test.ts |
测试候选 | 需要补强的回归测试 |
关键洞察 · Bug 往往藏在调用链里
从 AuthProvider 走到 restoreSession,再到 refreshSession(它返回 Promise),最后到 routerGuard(依赖 currentUser)。文件级搜索找不到异步缺口,只有调用图能指出——某个 await 在错过的瞬间把状态切走了。
诊断:根因假设必须可验证
Agent 不应直接宣布根因。每个假设必须携带证据、验证文件、验证方法。
假设 A · 异步时序
refreshSession 返回 Promise,但路由守卫没有 await,它就基于一个尚未完成的会话状态去做判断。
验证方法:检查 routerGuard 是否 await restoreSession。
假设 B · 401 中间件
401 中间件在 Session 刷新期间过早早清了 Session 状态,导致后续刷新被误判为未登录。
验证方法:检查 401 拦截器与 refreshSession 的执行顺序。
假设 C · 状态恢复顺序
Cookie 与 localStorage 的状态恢复顺序在不同浏览器存在差异,导致 Session 还没准备好路由就走了。
验证方法:检查 restoreSession 的两个存储读取顺序。
Anti-Pattern · "我看着像"式结论
模型靠经验拍脑袋给的根因,常常恰好蒙对——但错的时候没人能复盘验证。根因必须挂在"可重现的命令 / 可断言的代码位置 / 可跑的脚本"上,否则就是猜测。
规划:TaskGraph 而非一锅汤
修复任务 = 一张有依赖关系的图。每个节点都有契约,不是"一句口语任务"。
T1 · 验证 Session 恢复调用链
T2 · 确认异步时序缺口
T3 · 修改 AuthProvider 或路由守卫
T4 · 补充刷新保持登录测试
T5 · 运行 Auth 相关测试套件
T6 · Review Diff
T7 · 生成 PR 说明
每个 TaskNode 必须包含
- Input:前置任务输出的 Artifact
- Output:本任务产出的结构化 Artifact
- Dependencies:依赖的节点 ID
- Success Criteria:可验证的通过条件(最好绑定测试)
- Risk Level:low / medium / high
硬约束
修复任务必须拆成可独立验证的节点,而不是一句"把登录改对"。节点太粗等于让 Sub-Agent 重新陷入"一锅汤"困境。
执行取舍:什么时候用 Sub-Agent
Sub-Agent 不是越多越好,它是"为可隔离的 TaskNode 开的副作用空间"。
适合派给 Sub-Agent
- Search Agent · 并发检索全部相关调用方
- Coder Agent · 实现局部 Patch,范围明确
- Tester Agent · 运行测试、分析日志
- Reviewer Agent · 检查 Diff 和风险边界
不适合的场景
- 高度耦合的同一文件修改
- 极限风险的操作(如生产凭证擦写)
- 无法结构化验证的主观判断
- 过于细小、委派成本高于收益的任务
Sub-Agent 是给"可隔离、可验证、可并行"的 TaskNode 开的。
安全修改:Patch Pipeline
模型不能直接覆盖文件。修改的原子单位是 Patch(Diff),而不是整个文件。
Patch 必须满足
- 可审查 · 最小修改范围
- 可验证 · 基于已验证的正确文件版本
- 幂等 · 不覆盖用户修改
- 可回滚 · 留 Artifact 记录
交付单位
代码修改的文件单位必须是 Patch(Diff),不是整文件覆盖。这也是 Rollback 与 Review 能成立的前提。
验证:Sandbox TestRunner + Reviewer
验证发生在受控环境里;Review 发生在 Patch 落盘之后、PR 之前。
Sandbox TestRunner · 受控执行
- 选择相关测试集:基于 Patch 影响范围自动选取
- 创建 Sandbox:限制资源、隔离网络与文件系统
- 运行并截断日志:
pnpm test session-refresh - 结构化失败分类:输出 Test Artifact,供 Replan 使用
铁律
测试结果必须来自真实工具执行,不是模型口头声称——一旦 Agent 能"编"测试结果,整个验证闭环失效。
Reviewer Agent · 三维度门控
Diff 范围
- Diff 是否过大
- 是否越权修改
- 是否遗漏调用方
API & 安全
- 破坏公共 API?
- 引入安全风险?
- 违反安全策略?
测试 & 说明
- 是否补强测试
- PR 说明是否忠实
- 是否有未解决问题
Review 是 PRBuilder 的前置门控
测试通过 ≠ 可合并。Review 负责发现"测试覆盖不到的" 风险。
失败处理:分类决定路径
失败不是终点,是进入 Replan 或 Rollback 的信号。先分类,再决定。
| 失败原因 | 具体表现 | 处理路径 |
|---|---|---|
| 实现错误 | Coder Sub-Agent 产出的 Patch 与意图不符 | Rollback · 回滚 Patch,更新 TaskGraph 再 Replan |
| 根因错误 | 修好了症状,没修到根因 | 补充读取代码,回到 IssueAnalyzer 重新分类 |
| 测试选择 | 现有测试集没暴露这个 Bug | 扩大检索范围 / 补充新测试 |
| 环境缺失 | 依赖缺失、版本问题、Sandbox 拒绝 | 请求用户确认环境来源,或转人工介入 |
| 权限被拒 | Sandbox 拒绝命令(敏感路径 / 网络) | 请求提升白名单,或拆分命令为更安全的形式 |
| 反复失败 | 同一 TaskNode 连续 N 次失败 | 转人工介入,存档为 Memory 中的失败模式 |
核心原则
- 系统不能在测试失败后简单重跑
- 必须先由 FailureClassifier 对失败原因分类
- 分类后再决定分支,分类不明先扩大检索
- 超出 Agent 处理边界 → 升级人工介入
设计隐喻
失败是 Replan / Rollback 的入口,不是"再来一次"的信号。每一次失败都必须 留下结构化原因,否则下次模型会用同一套假设碰同一面墙。
回滚:只撤销 Agent 引入的修改
Rollback 是 Patch Pipeline 的镜像:保护用户工作区,而不是清盘。
- 01定位
applied_patch:从 Agent Edit Ledger 查找对应记录 - 02检查当前文件 hash:确认是否混入用户自己改过的内容
- 03反向应用 Agent Patch:只撤销 Agent 这一份变更
- 04保存 rollback Artifact:更新 TaskGraph 状态,触发 Replan
硬性禁止
⛔ 禁止默认执行 git reset --hard。这会把用户当天的工作区一起清掉,且无法审计。
保护原则
回滚必须保护用户工作区,只撤销 Agent 通过 PatchApplier 引入的变更,且必须留下可审计的 Artifact。
记忆边界:Memory 参与而不替代
Memory 给你"线索",但不能替代你"重新读代码"。
Memory 可以提供
- 项目测试命令与模块路径
- 历史失败经验与修复模式
- 用户输出偏好与安全约束
- 常见修复流程(加速路径生成)
Memory 不能替代
- 读取当前代码(文件可能已变更)
- 运行当前测试(环境可能已变更)
- 当前 Patch 的 Review 验证
正确用法
历史记录:曾因缺少 await 导致 Session 测试失败。
→ 用作假设 A 的支持线索,再去代码里检查 routerGuard 是否 await restoreSession。
错误用法
直接跳过代码读取环节,给出结论。
→ 模型把历史当事实,结论无法证伪,下次问题相同。
Memory 加速定位,但不能取代当前证据链。
缓存边界:稳定前缀 vs 动态内容
缓存能省钱,但 Stale Cache 会污染权限判断和工具结果。
可缓存(稳定前缀)
- System Prompt + Tool Schema:跨任务不变,缓存收益最高
- 安全规则 + 项目稳定摘要:每次任务重复加载,适合缓存
- Task 协议 + Reviewer 输出 Schema:结构固定,缓存可降低多轮成本
动态内容(不可缓存)
- 最新工具执行结果
- 当前 Patch Diff
- 测试日志与错误输出
- 当前 TaskNode 状态
工程准则
必须严格区分稳定前缀与动态内容。一旦把"工具结果"放进缓存前缀,下一轮 Agent 会基于上一轮的旧结果做判断——这是最容易出问题的隐性 bug。
可观测性:每一步独立 Span
没有 Trace,就无法解释"PR 是怎么生成的",也无法定位失败原因。
一个 Span = 一个可问责单元
每一步都要有独立的 Span(耗时、token、关键决策)和 Artifact 引用(上游输出物)。Trace 缺失等同于:"为什么这个 PR 被合并了"——没人能答。
评测 Gate 与关键指标
单次成功可被 Gate 验证;多次成功被指标刻画。
成功标准 · Gate 检查
- ROOT 根因定位正确,有证据支持
- PATCH Patch 能干净应用,无冲突
- TEST 相关测试通过,无回归
- DIFF Diff 可审查、无越权修改
- DESC PR 说明忠实反映修改
- ACCEPT Reviewer 或用户接受
Task Success Rate
端到端完成率
Patch Correctness
Patch 正确性
Regression Rate
回归引入率
Human Intervention Rate
人工介入率
关键提醒
Issue-to-PR 成功不是"PR 文本"生成,而是可验证的修复。
项目级评估:双维度 8 指标
单轮 Gate 验证是底线,长期看的是交付质量能否稳定。
过程质量
Root Cause Accuracy
根因定位准确率
Patch Correctness
Patch 正确应用率
Regression Rate
回归引入率(越低越好)
Rollback Success Rate
回滚成功且保护用户改
交付质量
Issue Resolution Rate
Issue 最终被解决率
PR Acceptance Rate
PR 被 Reviewer 接受率
Cost per Merged PR
每个可合并 PR 的推理成本
Human Intervention Rate
需要人工介入的任务比例
最终评估的核心问题只有一个:
能否稳定交付可合并 PR,且人工介入率持续下降?
收束:3 条 takeaway + 9 步交付流
把这一季的所有主张压缩到一页。
1 · 不能跳步
从 Issue 到 PR 必须经历检索、理解、规划、修改、测试、Review 与评估。每一步都有结构化的输入输出和 Artifact。
2 · 失败是闭环的一部分
失败后能 Rollback 或 Replan,Trace 可追溯。不让模型以"成功"替代硬验证。
3 · 真正的交付物
不是一段回答,而是一份可审查系统——Patch、测试结果、PR 说明与评测报告,每一项都有证据链。