Skill-Agent 协作架构篇:从单 Skill 到 Multi-Agent 编排¶
核心结论:当一个 Skill 同时承载的任务维度过多时,高优先级任务会系统性压制低优先级任务的执行——即使 Skill 明确禁止跳过也无效。这是 LLM 的结构性限制,不能通过加强提示词消除,只能通过架构手段解决。解法是 Skill-Agent 协作:将重度 Skill 拆分为聚焦单一维度的垂直 Skill,各由独立 Agent 在隔离上下文中执行;配合 Grep-Gated 执行协议,将 75% 的检查项转为规则驱动的预扫描,进一步降低维度内的概率性遗漏。
目录¶
17. 注意力稀释:架构问题,不是提示词问题¶
17.1 注意力稀释的规律(以代码审查 Skill 为例)¶
单 Skill 同时处理多个维度时,高优先级任务会天然抢占模型注意力,导致低优先级任务被系统性遗漏——这不是偶发错误,而是可复现的结构性失效,代码审查场景尤为典型。
以 Go 代码审查为例,以下代码交给 go-code-reviewer Skill 处理:
func getBatchUser(ctx context.Context, userKeys []*UserKey) ([]*User, error) {
userList := make([]*User, 0) // ← 无容量预分配
var wg sync.WaitGroup
for i, u := range userKeys {
if u == nil { continue }
wg.Add(1)
go func() {
defer wg.Done()
user, err := redis.GetGuest(ctx, u.Id)
if err != nil {
log.WarnContextf(ctx, "no found guest user: %v", u)
continue // ← goroutine 内 continue,编译错误
}
userList = append(userList, user) // ← 数据竞争
}()
}
return userList, nil // ← 缺少 wg.Wait()
}
Skill 发现了 4 个 High 级并发缺陷(编译错误、数据竞争、goroutine 泄漏、循环变量捕获),但漏报了一个 Medium 级性能问题:
// 实际代码(错误)
userList := make([]*User, 0)
// 应该写成(已知上界 len(userKeys),应预分配容量)
userList := make([]*User, 0, len(userKeys))
这完全符合 Skill 的 Performance checklist 中"Slice Pre-allocation"检查项。Skill 本身也明确规定:
Execute ALL checklist categories regardless of how many High findings have already been identified
但模型仍然漏报了。人工指出遗漏后,模型立即识别并承认:
"当 4 个 High 级别的并发缺陷占据了注意力后,我在走 Performance checklist 时不够仔细,错误地将这个问题归入了'可忽略的小问题'而没有正式报告。"
关键发现:问题不在于模型"不会"——指出后立即承认,说明它具备识别能力。问题在于单次调用中同时处理 5 个审查维度,High 级别 Findings 天然更"吸引"注意力,压缩了模型分配给其他维度的认知资源。
17.2 根因:上下文窗口的注意力竞争¶
单 Agent 加载重度 Skill 时,上下文窗口承载了所有维度的知识、全部代码,以及已发现的 Findings:
[单个 Agent 的上下文窗口]
┌─────────────────────────────────────────┐
│ go-code-reviewer SKILL.md(全量知识) │
│ ├── 安全规则(SQL 注入、XSS...) │
│ ├── 并发规则(竞态、死锁、泄漏...) │
│ ├── 性能规则(预分配、N+1...) │ ← 被挤压
│ ├── 错误处理规则(wrap、nil check...) │ ← 被挤压
│ └── 质量规则(命名、结构...) │ ← 被挤压
│ │
│ 已发现的 Findings: │
│ ├── [High] REV-001 编译错误 ←────────┐ │
│ ├── [High] REV-002 数据竞争 ←────────┤ │ 注意力集中在这里
│ ├── [High] REV-003 goroutine 泄漏 ←──┤ │
│ └── [High] REV-004 循环变量捕获 ←────┘ │
│ │
│ Performance checklist: │
│ Slice Pre-allocation → ??? (未检查) │ ← 注意力不足
└─────────────────────────────────────────┘
Anthropic 的内部研究对这一现象提供了量化支撑:在多 Agent 研究系统评测中,token 使用量解释了 80% 的性能差异,核心原因是每个 Agent 在干净的上下文窗口中执行,token 使用效率更高——这正是上下文污染(Context Rot)会拉低单 Agent 性能的直接证据。
这不是提示词写法的问题,是架构问题。 已尝试的缓解措施如下:
| 缓解措施 | 效果 | 局限 |
|---|---|---|
| 在 Skill 中强调"不可跳过 checklist" | 部分有效 | 规则本身也在同一上下文中竞争注意力 |
| 写入 Memory"High findings 不能跳过其余 checklist" | 下次有帮助 | 无法根本解决单上下文多维度的注意力竞争 |
| 增加 checklist 的强制性语言 | 有限改善 | LLM 的注意力机制是概率性的,无法仅靠指令稳定覆盖 |
这些措施仅能把执行遗漏概率从高降为中,无法消除。迭代篇(§15-16)已记录这一上限:在规则层的最终修复率约为 67%,仍有系统性残差。本篇给出架构层的根本解法。
17.3 为什么 Multi-Agent 是正确方向¶
17.3.1 Multi-Agent 的精确定义与四大机制¶
Multi-Agent 架构是指多个 AI Agent 在明确的角色分工和协作协议下,协同完成一个复杂任务。每个 Agent 拥有独立的上下文窗口、专用的工具集和清晰的职责边界。
这与软件工程中的微服务演进高度类似:
| 软件演进 | AI Agent 演进 |
|---|---|
| 单体应用代码库太大,难以维护 | 单体 Agent 上下文窗口积累太多,性能下降 |
| 单点故障影响全局 | 单个维度失误影响整条审查链路 |
| 无法独立扩展模块 | 无法为不同任务选择最优模型 |
| 职责边界模糊 | Agent 角色混乱导致输出质量下降 |
就像单体应用最终需要被拆分为微服务一样,单体 Agent 在任务足够复杂时,也需要被拆分为多个专职 Agent。
Multi-Agent 对 Go 代码审查场景的四大优势机制:
| 优势 | 机制 | 对本场景的意义 |
|---|---|---|
| 专注的上下文窗口 | 每个 sub-Agent 在全新、干净的上下文中运行,不受其他维度 Findings 污染 | 并发审查发现 4 个 High 不会影响性能审查对 make([]*User, 0) 的敏感度 |
| 深度专业化 | 每个 Agent 的系统提示聚焦单一领域,工具集精简 | Security Agent 只看安全缺陷;Performance Agent 只看性能问题——无需兼顾其他 |
| 多视角质量保障 | 多个 Agent 独立评估,彼此不知道其他 Agent 的 Findings | 并发、错误、性能审查各自独立得出结论,交叉验证相互强化 |
| 灵活的模型配置 | 主会话(编排 Skill)用强模型做分诊和汇总,Workers 用快速模型执行审查 | 主会话负责分诊 + 去重,Workers 使用 Haiku/Sonnet 控制成本 |
第一个优势直接对应本文的核心问题:当单个上下文窗口同时持有多个高严重度 Findings 时,模型对低优先级检查项的覆盖率会系统性下降。这是提示词难以修复的结构性缺陷——Multi-Agent 通过让每个维度在独立上下文中运行,显著降低了跨维度的注意力竞争。
17.3.2 实证数据:Anthropic + AgentCoder¶
Anthropic 多 Agent 研究系统实测(来源:Anthropic Engineering Blog, 2025): - Claude Opus 4(Lead)+ Claude Sonnet 4(Workers)的多 Agent 系统,在内部研究评测中比单 Agent Opus 4 性能高出 90.2% - Token 使用量解释了 80% 的性能差异——关键不在于模型更强,而在于每个 Agent 在干净的上下文中专注完成单一任务
AgentCoder 学术研究(来源:arXiv:2312.13010): - 多 Agent 代码生成(Programmer + Test Designer + Test Executor)在 HumanEval 上达到 96.3% pass@1,单 Agent SOTA 为 90.2% - 使用更少的 token(56.9K vs 138.2K)达到更高的准确率,证明专业化分工可以同时提升质量和效率
这组数据揭示了一个反直觉的结论:Multi-Agent 的优势不来自"用了更多算力",而来自让每个 Agent 在干净的上下文中做更专注的事。
17.3.3 架构换模型:降低对顶尖推理模型的依赖¶
§17.3.2 的实证数据指向一个值得单独提炼的结论:Multi-Agent 架构不仅仅是"用便宜的模型做同样的事"——而是用更便宜的模型,做更好的事。
| 配置 | 模型 | 审查质量(基准案例) | 漏报数 |
|---|---|---|---|
| 单 Agent | Opus 4 | 4 High,漏报 1 Medium | 1 |
| Multi-Agent Orchestrator-Workers | Sonnet 4 Workers + Sonnet Lead | 全部捕获 13/13 | 0 |
为什么更便宜的模型 + 更好的架构能超越更强的模型 + 单 Agent?
根因在于任务结构与模型能力的匹配度。Opus 在单一聚焦任务上的表现确实优于 Sonnet——但当它被要求在同一个上下文中同时覆盖 5 个独立维度时,注意力稀释会系统性拉低它在每个维度上的实际发挥。而 Sonnet 在只负责一个维度(如仅审查并发问题)时,专注度接近满状态,不受跨维度注意力竞争的影响。
换一种说法:对于多维度任务,Sonnet × N 个聚焦 Agent 的组合效能,可以超过 Opus × 1 个泛化 Agent。
成本权衡:
| 维度 | 单 Opus Agent | Multi-Agent Sonnet Workers |
|---|---|---|
| 单次推理成本 | 高(Opus 约为 Sonnet 定价的 5–10 倍) | 低(每个 Worker 用 Sonnet/Haiku) |
| 总 token 消耗 | 低(单次调用) | 高(多个并行 Agent 累计) |
| 整体账单 | 中 | 中(token 更多但单价更低,近似持平) |
| 审查质量 | 有注意力稀释风险 | 更全面、更稳定 |
多 Agent 并行虽然累计 token 消耗更高,但每次推理调用使用的是更低价位的模型。两者相抵,整体账单往往近似持平,而质量却显著提升。
核心洞察:这一结论改变了模型选型的思路框架。传统问法是"我应该用哪个最强的模型?"——更好的问法是"我的任务架构,能否把模型从需要同时擅长多件事,改造成只需专精一件事?"如果能,次优模型配合优质架构往往优于顶尖模型配合平凡架构。
对于遭遇注意力稀释的场景,这意味着:你不需要等待更强大的下一代模型来解决漏报问题——架构重构是在现有模型上更可控、更可预期的解法。
17.4 五种编排模式全景:各有所长,各有所用¶
明确了 Multi-Agent 的优势之后,面临的下一个问题是:选哪种编排模式? 本节系统性梳理五种基础模式,帮助 Skill 设计者为不同任务找到最合适的架构,而不只是为代码审查场景做选型。
Anthropic 定义了五种基础编排模式,按子任务决策时机和执行结构分类:
| 模式 | 核心机制 | 子任务来源 | 执行结构 |
|---|---|---|---|
| Prompt Chaining | 步骤线性传递,A 的输出是 B 的输入 | 固定线性序列 | 顺序 |
| Routing | 分类输入,路由到唯一的专门处理器 | 固定分支,取其一 | 排他选择 |
| Parallelization | 预先固定的多条路并行执行,聚合结果 | 固定集合,全部执行 | 并行 |
| Orchestrator-Workers | 编排者动态决定需要哪些 Workers | 运行时决定,按需执行 | 动态并行 |
| Evaluator-Optimizer | 生成→评估→改进,直到满足阈值 | 固定两角色,迭代循环 | 循环 |
模式一:Prompt Chaining(提示词链)¶
核心:步骤 A 的输出直接成为步骤 B 的输入,形成线性管线,每一步都在前一步的基础上加工。
适用条件:任务有明确的顺序依赖关系;步骤间存在信息单向传递;每步的输出质量直接影响下一步。
后端开发典型场景:接口驱动的代码生成管线
从 OpenAPI 规范出发,逐步生成完整代码链路:
OpenAPI 规范(输入)
│
↓
[Step 1:接口解析 Agent]
输出:Go struct 和接口类型定义
│
↓
[Step 2:代码生成 Agent]
输入:Step 1 的 struct → 输出:handler + service 骨架
│
↓
[Step 3:测试生成 Agent]
输入:完整代码 → 输出:集成测试
│
↓
完整代码 + 测试(输出)
每一步依赖前一步的输出;handler 必须引用已存在的 struct,测试必须针对已知的接口结构。类似场景还有:数据库迁移辅助(分析现有 schema → 生成迁移 SQL → 生成回滚 SQL → 生成变更文档),步骤之间有单向依赖。
对代码审查的评估:✗ 不适用。安全/并发/性能各审查维度之间没有顺序依赖,不需要 A 的输出喂给 B。
模式二:Routing(路由)¶
核心:对输入分类,路由到最合适的专门处理器。每个请求只走一条路径,不同类型的输入走完全不同的处理逻辑。
适用条件:输入类型可以被明确分类;不同类型需要完全不同的处理方式;每次请求只需要其中一种处理。
后端开发典型场景:多语言代码审查路由
根据文件扩展名路由到对应语言的 Skill,每次请求只走一条路:
代码文件(输入)
│
↓
[Classifier:检测文件类型]
│
├─ .go → [Go 审查 Skill] ← 本项目的专项规则
├─ .py → [Python 审查 Skill] ← 不同的 checklist 和 reference
├─ .ts → [TypeScript 审查 Skill]
└─ .sql → [SQL 审查 Skill]
另一个典型场景:SQL 操作类型路由——将 SQL 语句按操作类型分流,因为读优化和写安全是完全不同的问题域:
SQL 语句
├─ SELECT → [读性能 Agent](关注 Index Scan、rows 数量)
├─ INSERT/UPDATE → [写安全 Agent](关注事务隔离、锁范围、幂等性)
└─ DDL → [迁移安全 Agent](关注零停机方案、回滚计划)
对代码审查的评估:✗ 不适用。一次 Go 代码审查需要同时覆盖安全、并发、性能等多个维度,而不是从中选一个。
模式三:Parallelization(并行化)¶
核心:将任务拆分为预先固定的多个子任务,全部并行执行,最后聚合结果。子任务集合在设计时就已确定,每次输入都执行完整的 N 路。
适用条件:子任务之间相互独立;无论输入内容如何,这几项检查都需要执行;完成时间取决于最慢的子任务。
后端开发典型场景一:多格式文档同步生成
对同一个服务接口,同时生成多种格式的产出——三条路完全独立,无论接口定义是什么内容,总是同时执行:
服务接口定义(输入)
│
├─→ [中文 README Agent] → README.zh-CN.md
├─→ [英文 README Agent] → README.md
└─→ [OpenAPI Agent] → openapi.yaml
后端开发典型场景二:固定合规扫描流水线
每次 PR 合并都必须跑完全部三项,没有例外——这三项检查与代码内容无关:
这是 Parallelization 最适合的场景:固定的、必须全量执行的检查集合,与输入内容无关。
Parallelization 与 Orchestrator-Workers 的本质区别:
Parallelization:
代码 → [固定派发: Security + Concurrency + Performance + ...] → 汇总
子任务在设计时确定,每次审查都跑完整的 N 路
Orchestrator-Workers:
代码 → [Lead Agent 分析 diff] → 动态决策 → 按需派发 K 路(K ≤ N)→ 汇总
子任务在运行时确定,根据代码内容决定需要哪些维度
对代码审查的评估:△ 接近但不是最优。若代码只改了变量名,Parallelization 仍会启动全部 8 个 Agent,每次约 $0.16;Orchestrator-Workers 只需 2 个 Agent,约 $0.02。
模式四:Orchestrator-Workers(编排者-工作者)¶
核心:中央编排者分析输入,在运行时动态决定需要哪些 Workers 以及各自的任务边界,然后并行调度,最后汇总。子任务列表不在设计时固定,由编排者根据具体输入决策。
适用条件:所需子任务取决于输入内容,无法在设计时预知;不同输入需要不同的处理组合;需要一个"理解全局、分配任务"的协调角色。
后端开发典型场景一:内容驱动的代码审查(本文案例详见 §18)
根据代码内容决定派发哪些维度的审查 Agent:
代码 diff(输入)
│
↓
[Lead Agent 分诊]
│
├─ 有 go func / sync → 派发 Concurrency Agent
├─ 有 make([], 0) + append → 派发 Performance Agent
├─ 有 _test.go 变更 → 派发 Test Agent
├─ 始终派发 → Quality + Logic Agent
└─ 无 SQL/HTTP 模式 → 跳过 Security Agent(记录原因)
5 行变量名修改:2 个 Agent;引入并发和性能问题的 PR:5 个 Agent——动态分配,按需付出成本。
后端开发典型场景二:自适应 Bug 修复管线
Lead Agent 分析 bug 影响面,动态决定需要哪些修复动作——修复范围完全取决于 bug 性质:
Bug 报告(输入)
│
↓
[Lead Agent 分析影响范围]
│
├─ 涉及数据库操作 → 派发 DB 修复 + 迁移 Agent
├─ 涉及 API 接口 → 派发接口修复 + 契约更新 Agent
├─ 测试需要补充 → 派发测试补全 Agent
└─ 跨模块传播 → 额外派发文档更新 + 通知 Agent
对代码审查的评估:✅ 最优解。"需要派发哪些 Agent 取决于被审查代码的内容"——这正是 Anthropic 对 Orchestrator-Workers 适用场景的定义:"无法提前预测需要哪些子任务,需要 Orchestrator 根据输入动态决策"。
模式五:Evaluator-Optimizer(评估者-优化者)¶
核心:生成→评估→改进的迭代循环,直到满足质量阈值或达到迭代上限。评估结果决定是否继续迭代,以及如何改进。
适用条件:初版输出质量不稳定,需要迭代精化;有可操作化的质量标准(能判断"通过/不通过");迭代改进有收益,且能在几轮内收敛。
后端开发典型场景一:SQL 查询自动优化
执行计划有明确的"好/坏"判断标准(Index Scan vs Seq Scan),评估可机械化,是 Evaluator-Optimizer 的理想场景:
业务查询需求(输入)
│
↓
[生成 Agent] → 初版 SQL
│
↓
[评估 Agent] ← 执行 EXPLAIN,检查执行计划
│
├─ 通过(Index Scan,rows 估算 ≤ 阈值)→ 输出 SQL
└─ 不通过(Seq Scan 或 rows 超限)
│
↓
[优化 Agent] → 重写 SQL 或建议添加索引
│
└─→ 循环(上限 3 轮)
后端开发典型场景二:测试覆盖率自动补全
用实际测试运行结果作为评估依据,驱动迭代生成直到覆盖率达标:
待测函数代码(输入)
│
↓
[生成 Agent] → 初版测试代码
│
↓
[评估 Agent] ← 运行 go test -race -cover
│
├─ 通过(覆盖率 ≥ 80%,无 data race)→ 输出测试代码
└─ 不通过(标注未覆盖的代码路径)
│
↓
[补全 Agent] → 针对未覆盖路径补充边界测试
│
└─→ 循环(上限 2 轮)
后端开发典型场景三:API 设计质量迭代
以 checklist 通过率作为评估标准,驱动接口定义的迭代精化:
功能需求(输入)
│
↓
[设计 Agent] → 初版接口定义
│
↓
[评估 Agent] ← REST 规范 checklist + 安全 checklist + 向后兼容检查
│
├─ 通过(所有 checklist 项 ✅)→ 输出接口定义
└─ 不通过(列出具体不符合项)
│
↓
[改进 Agent] → 修订接口定义
│
└─→ 循环(上限 2 轮)
Evaluator-Optimizer 的关键权衡:每次迭代增加延迟和 token 消耗,适合输出质量对业务影响重大、且有可操作化评估标准的场景。若评估标准模糊(如"代码可读性"),容易陷入无效循环。
对代码审查的评估:✗ 不适用。代码审查是诊断任务,应如实反映代码现状——"改进审查报告"和"修复被审查的代码"是不同的任务,不应在 Evaluator-Optimizer 循环中混淆。
选型决策树¶
面对一个新的 Multi-Agent 任务,如何选型?
步骤之间有顺序依赖(A 的输出是 B 的输入)?
是 → Prompt Chaining
否 ↓
输入可分类,且每次只需一种处理方式?
是 → Routing
否 ↓
需要迭代精化,且有可操作化的质量阈值?
是 → Evaluator-Optimizer
否 ↓
无论输入内容如何,总是执行固定的几条路?
是 → Parallelization
否 → Orchestrator-Workers(子任务取决于输入内容,运行时动态决定)
对 Go 代码审查场景的最终选型:需要派发哪些 Agent 取决于被审查代码的内容(有并发才需要 Concurrency Agent,有 make([], 0) 才需要 Performance Agent),这是典型的"子任务在运行时决定"场景,决策树终点指向 Orchestrator-Workers。§18 展示了完整的实施与验证过程。
18. Skill-Agent 协作架构:设计、实施与验证¶
本章以
go-code-reviewer→ 7-Agent 编排体系为贯通案例,演示 Orchestrator-Workers 架构的完整实施路径。所涉及的设计原则(垂直拆分、主会话负责编排、按需分诊、Grep-Gated 协议)不局限于代码审查场景,适用于任何遭遇注意力稀释的重度 Skill。
18.1 三种架构对比(决策矩阵)¶
| 架构 | 特点 | 已知问题 | 推荐度 |
|---|---|---|---|
| A:单 Skill | 1 个 Agent 加载全量审查知识,一次调用完成所有维度 | 注意力稀释;High Findings 系统性压制其他维度;已证实漏报 | 基础场景 |
| B:Multi-Agent 无 Skill | 7 个垂直 Agent 仅靠提示词,无 Skill 加载;主会话负责编排 | 上下文干净,但缺少领域审查规则;只能依赖 AI 通用知识;可能漏掉项目特定规则 | 不推荐 |
| C:Multi-Agent + 垂直 Skill | 主会话加载 go-review-lead Skill 负责分诊与汇总;7 个垂直 Agent 各自加载领域 Skill | 设计和维护成本略高 | ✅ 推荐 |
架构 C 的核心原则:
原则一:每个 Agent 只加载一个维度的 Skill。Performance Agent 的上下文中主要只有性能相关知识和待审查代码,没有其他维度的规则,也不接收其他 Agent 的 Findings。这会显著提高它把注意力放在 Performance checklist 上的概率。
原则二:主会话(编排角色)不审查代码。主会话加载 go-review-lead Skill 后扮演编排角色,只做分诊和汇总,不加载任何垂直审查 Skill,不直接分析代码逻辑。若主会话自己也做审查,它的发现会影响对其他 Agent 结果的汇总判断——和重度 Skill 是同一个问题。
原则三:垂直 Agent 通过 Skill 工具按需加载知识。Agent 定义文件是轻量的(几十行提示词),审查知识保存在独立的 Skill 文件中,Agent 在运行时通过 Skill() 工具加载。不存在内容重复,Skill 文件可被多个 Agent 复用。
原则四(平台约束):编排必须由主会话执行,不能由 subagent 执行。Claude Code 明确规定子代理不能生成子代理("Subagents cannot spawn other subagents")。因此 go-review-lead 只能以 Skill 形式运行在主会话,不能配置为 .claude/agents/ 中的 agent 定义文件——否则它会作为子代理运行,Agent 工具调用将被平台忽略,并行步骤被跳过。
完整架构全景(主会话 Skill 编排 + 7 个垂直 Agent):
PR Diff / 代码片段
│
↓
[主会话 + go-review-lead Skill]
职责:分诊 + 派发 + 汇总
加载 go-review-lead Skill
不加载垂直审查 Skill
不直接审查代码
│
Phase 1-4: 分诊
grep + 模式匹配,判断涉及哪些维度
│
┌────────┬────────┬───────┼───────┬────────┬────────┐
↓ ↓ ↓ ↓ ↓ ↓ ↓
[Security][Concurr][Perf] [Error] [Quality] [Test] [Logic]
Agent Agent Agent Agent Agent Agent Agent
│ │ │ │ │ │ │
加载安全 加载并发 加载性能 加载错误 加载质量 加载测试 加载逻辑
Skill Skill Skill Skill Skill Skill Skill
│ │ │ │ │ │ │
独立审查 独立审查 独立审查 独立审查 独立审查 独立审查 独立审查
└────────┴────────┴───────┴───────┴────────┴────────┘
│
↓
主会话汇总
合并 Findings + 去重 + 按严重度排序
│
↓
最终报告
18.2 Skill 拆分指南(以 go-code-reviewer 为例)¶
拆分判断标准:
| 信号 | 是否应该拆分 |
|---|---|
| Skill 的 checklist 覆盖 3 个以上独立维度 | 是——维度间会互相抢注意力 |
| 单次审查经常产生 5+ 个 High Findings | 是——High Findings 越多,其他维度被挤压越严重 |
| 审查后用户经常指出"这个应该发现但没发现" | 是——典型的注意力稀释症状 |
| Skill 只覆盖 1 个维度,且 checklist < 15 项 | 否——上下文负担不大,单 Agent 足够 |
目录结构(以 go-code-reviewer 为例):
skills/
├── go-security-review/SKILL.md # SQL 注入、XSS、密钥泄露、权限
├── go-concurrency-review/SKILL.md # 竞态、goroutine 泄漏、死锁、WaitGroup
│ └── references/go-concurrency-patterns.md
├── go-performance-review/SKILL.md # 预分配、N+1、索引、内存
│ └── references/go-performance-patterns.md
├── go-error-review/SKILL.md # 错误包装、资源关闭、panic 处理
├── go-quality-review/SKILL.md # 命名、结构、lint 规则、注释规范
├── go-test-review/SKILL.md # 测试覆盖率、断言质量、测试隔离
└── go-logic-review/SKILL.md # 业务逻辑、边界条件、nil、错误传播
# go-review-lead 以 Skill 形式运行在主会话,不在 .claude/agents/ 中
# 主会话通过 Skill 工具加载 skills/go-review-lead/SKILL.md
.claude/agents/ # 仅包含 7 个垂直 Worker Agent
├── go-security-reviewer.md # 加载 go-security-review
├── go-concurrency-reviewer.md # 加载 go-concurrency-review
├── go-performance-reviewer.md # 加载 go-performance-review
├── go-error-reviewer.md # 加载 go-error-review
├── go-quality-reviewer.md # 加载 go-quality-review
├── go-test-reviewer.md # 加载 go-test-review
└── go-logic-reviewer.md # 加载 go-logic-review
checklist 上限原则:每个垂直 Skill 的 checklist 项不超过 15 条。如果超过,说明该维度还可以继续拆分。这一上限并非任意设定——15 条以内的 checklist 在独立上下文中仍然处于模型注意力可覆盖的范围,超过则重新引入维度内的稀释风险。
18.3 分诊机制(go-review-lead Skill 在主会话中执行)¶
两级分诊¶
分诊分两个层次,层次之间成本差异悬殊:
Level 1:文件类型分诊(无需 LLM,用 grep 即可)
# 有 .go 文件变更? → 进入 Level 2
# 有 _test.go 变更? → 派发 go-test-reviewer
# 有 go.mod 变更? → 派发 go-security-reviewer(依赖审查)
# 有 .sql / migration? → 派发 go-security-reviewer
Level 2:内容分诊(Haiku 快速扫描 diff,约 $0.001/次)
diff 包含 go func / channel / sync → Concurrency Agent
diff 包含 make([] + 零容量 → Performance Agent
diff 包含 sql.Rows / tx.Begin → Error + Security + Performance Agent
函数名含 Batch / Multi / GetAll → Performance Agent
Level 1 不消耗 token。两级合计每次分诊成本可忽略不计。
四阶段分诊逻辑(Phase 1–4)¶
| Phase | 扫描对象 | 典型触发规则 |
|---|---|---|
| Phase 1:Import 扫描 | 所有变更文件的 import 块 | "sync" → Concurrency;"database/sql" → Security + Error + Performance |
| Phase 2:Diff Pattern 扫描 | 仅新增/修改行 | make(\[\] 零容量 + append( 共现 → Performance;go func → Concurrency |
| Phase 3:文件路径 heuristic | 变更文件的路径和函数名 | auth/、handler/ → Security;函数名含批量语义 → Performance |
| Phase 4:变更范围评估 | diff 整体结构 | 新增 .go 文件 → 强制派发 Error;go.mod 变更 → 对新依赖重跑 Phase 1 |
无兜底派发原则:若某 Agent 未被任何阶段触发,则跳过并明确记录原因——而不是无差别地全量启动。这是分诊机制最核心的价值。
成本对比¶
| 方案 | 简单风格 PR | 复杂并发 PR | 全方位重构 |
|---|---|---|---|
| 全量 7 Agent(无分诊) | ~$0.16 | ~$0.16 | ~$0.16 |
| 分诊 + 按需派发 | ~$0.02 | ~$0.07 | ~$0.10 |
| 原始单 Skill | ~$0.03 | ~$0.03(但漏报) | ~$0.03(但漏报) |
按需调度在简单 PR 上节省约 80% 成本,在复杂 PR 上成本与全量启动持平,但审查质量显著优于单 Skill 方案。
注:以上成本为近似估算,基于 Claude Haiku 4.5 / Sonnet 4.6 的 2026-03 官方定价,实际成本还受代码量(token 数)影响,仅作数量级参考。
18.4 Grep-Gated 执行协议(核心创新)¶
问题本质的重新认识¶
首轮 Multi-Agent 架构(§18.5 轮次 2)暴露了一个根本性的设计失误:把模型当成了人类代码审查员。人类审查员读 checklist,然后用"眼睛"扫代码,靠注意力和经验发现问题。模型也在被迫做同样的事——用"注意力"扫描 checklist,然后在代码中寻找匹配。这种方式的问题在于,模型的注意力是概率性分配的;而 grep 对显式模式的检出更接近规则驱动的机械扫描。
模型不是人,它有工具可以用。
核心解法:工具辅助检测(tool-assisted detection)+ 模型判断(model judgment)。对于有明确语法特征的 checklist 项,让模型先用 grep 机械扫描,再对 HIT 结果做语义确认。只有真正需要推理的语义项,才交给模型全量分析。
执行流程(分步说明)¶
对每个 sub-agent,执行流程变为:
1. 通过 Skill 工具加载对应领域 Skill(checklist + 规则 + grep pattern)
2. 识别目标文件(或将裸代码片段写入 $TMPDIR/review_snippet.go)
3. 对所有 grep-gated checklist 项,按 Skill 中提供的 pattern 执行 grep
4. grep HIT → 模型做语义确认(true positive vs false positive)
5. grep MISS → 自动标记 NOT FOUND,跳过语义分析,不上报主会话
6. 无 grep pattern 的项(纯语义项)→ 模型全量推理
7. 只上报 FOUND 项
8. Execution Status 中包含审计行:Grep pre-scan: X/Y items hit, Z confirmed
主会话汇总各 sub-agent 的报告后,根据审计行核查覆盖率,而不是盲目信任"没报告 = 没问题"。
覆盖率统计¶
7 个 Skill、86 条 checklist 项,其中 65 条(75%)可 grep 化:
| Skill | 总条数 | Grep 化 | 纯语义 |
|---|---|---|---|
| go-concurrency-review | 14 | 13 | 1 |
| go-performance-review | 12 | 10 | 2 |
| go-error-review | 12 | 12 | 0 |
| go-security-review | 16 | 14 | 2 |
| go-quality-review | 12 | 8 | 4 |
| go-test-review | 10 | 8 | 2 |
| go-logic-review | 10 | 0 | 10 |
| 合计 | 86 | 65 (75%) | 21 (25%) |
在当前设计中,75% 的检查项转化为了规则驱动的预筛选,模型的注意力可以更多集中在剩余 25% 的语义项上。
宽门槛设计原理¶
Grep-Gated 协议的 pattern 设计采用宽门槛策略:宁有 HIT 假阳性,不漏 MISS 假阴性。
go\s+func这一 pattern 同时触发 6 个并发审查项,产生大量 HIT- false positive 交给模型在语义确认阶段过滤,成本可接受
- MISS 会直接跳过语义分析,一旦漏检就不再有任何机会补救
这种不对称性决定了 pattern 宁宽勿严:漏检的代价(遗漏真实 bug)远大于误触发的代价(多一次语义确认)。
复合 pattern 设计:缺失保护检测¶
对于"应该有 A 但没有 B"的缺失类问题,使用复合 pattern:
# CONC-14: 无界 goroutine 创建(有并发但无限流控制)
grep pattern:go\s+func
AND NOT:SetLimit|semaphore|maxConcurrency|worker.*pool
# PERF-01: Slice 未预分配(有 make 但无容量参数)
grep pattern:make\(\[\][^]]+,\s*0\) → 检测零容量
AND NOT:第三个参数存在
复合 pattern 使"缺少防护"类问题可被 grep 机械检出,而不再依赖模型注意力去发现"不存在的东西"——这恰恰是注意力最容易疏漏的场景。
go-logic-review 的特殊处理¶
go-logic-review 覆盖业务逻辑、边界条件、合同违反、nil 安全等问题,这些问题没有稳定的语法特征,无法用 grep 预筛选。该 Skill 的所有 10 条 checklist 项均为纯语义分析,使用专用执行模板:
## Execution Order
After invoking the skill:
1. Identify target files (from dispatch prompt)
2. All checklist items are semantic-only — no grep pre-scan applicable
3. Apply full model reasoning to each item
4. Report FOUND items only
5. Include: `Semantic-only skill: 10/10 items evaluated`
这是协议的合理边界:grep 只适用于有语法特征的问题,强行 grep 化语义项会产生大量无意义 MISS,反而降低覆盖率的可信度。
18.5 三轮迭代验证¶
用同一段 getBatchUser 代码(§17.1 所示)进行三轮完整验证,每轮在上一轮的架构基础上改进。
三轮对比总览¶
| 指标 | 轮次 1:单 Skill | 轮次 2:Multi-Agent v1 | 轮次 3:Multi-Agent + Grep-Gated |
|---|---|---|---|
| 架构 | 1 Agent + 重度 Skill | 8 Agent 误配(Lead 作为 agent,并行派发受阻) | 7 Worker Agent + 主会话 Skill 编排 + Grep-Gated 协议 |
| 派发 Agent 数 | 1 | 4(跳过 performance) | 5(含 performance) |
| High Findings | 4 | 7 | 7 |
| Medium Findings | 1(漏报 1) | 2(漏报 4+) | 6 |
| Slice Pre-allocation | ❌ 未发现 | ❌ 未发现(performance 未被分诊) | ✅ REV-009 正式上报 |
| Unbounded Goroutines | ❌ 仅在 Residual Risk | ⚠️ 有时遗漏 | ✅ REV-008 正式上报 |
| 总 Findings 捕获 | 8/9(漏 1) | 不稳定 | 13/13 |
轮次 1:单 Skill 的失效¶
单 Skill 调用发现了 4 个 High 并发缺陷,但 Slice Pre-allocation 漏报。模型事后承认原因是 Performance checklist 的注意力被 High Findings 挤压。这是本次改造的起点。
轮次 2:Multi-Agent v1 的新问题¶
完成 1 Skill → Multi-Agent 的初步改造后(此阶段 Lead 误配为 agent 定义,并行派发受平台约束而受阻),验证发现两个新问题:
问题一:分诊盲区。go-review-lead 的 Phase 2 原始触发条件只对"已有 capacity 参数的 make"触发,而 make([]*User, 0) 恰好是没有 capacity 的情况——规则反向匹配失败,go-performance-reviewer 被直接跳过。代码以裸片段提交也导致 Phase 3 的文件路径 heuristic 无效。
问题二:维度内注意力稀释。即便 go-concurrency-reviewer 被正确分诊并派发,当上下文中存在多个 High 级别的编译错误和数据竞争时,"无界 goroutine 创建"这类 Medium 级别的问题仍会被模型降低优先级,最终只出现在 Residual Risk 中,而不是作为正式 Finding 上报。
架构已经将不同审查维度隔离到独立上下文,但在同一个 Agent 的上下文内,多个 High 级别 Findings 仍然会压制 Medium 级别的项。注意力稀释问题在垂直维度内部依然存在。第一轮架构改造的汇总报告如下(摘录关键差异部分):
- Skipped skills: go-performance-reviewer (no hot-path loops or DB patterns)
← 分诊盲区导致跳过
Residual Risk:
2. Unbounded goroutine spawning: ... Not flagged as a finding since expected
batch size is unknown ... ← 未正式上报,藏在 Residual Risk 中
Summary: 7 High / 2 Medium / 1 Low.
轮次 3:Multi-Agent + Grep-Gated 的验证通过¶
针对分诊盲区,修正 Phase 2 触发条件(同时检测零容量 make),并在 Phase 3 补充批量语义函数名 heuristic(getBatchUser 直接命中)。针对维度内注意力稀释,引入 Grep-Gated 执行协议。
验证结果:在当前基准案例中,13 个预期发现均被捕获,未观察到新的遗漏。
slice pre-allocation 的完整轨迹:
| 轮次 | 状态 | 原因 |
|---|---|---|
| 轮次 1(单 Skill) | 未发现 | Performance checklist 注意力被 4 个 High 挤压 |
| 轮次 2(Multi-Agent v1) | 未发现 → Residual Risk | performance Agent 未被分诊;维度内仍有注意力竞争 |
| 轮次 3(Multi-Agent + Grep-Gated) | REV-009 [Medium] 正式上报 | make([]*User, 0) 被 grep pattern 机械命中,无法被注意力稀释 |
最终报告(摘录):
- Dispatched: go-concurrency-reviewer, go-performance-reviewer,
go-error-reviewer, go-quality-reviewer, go-logic-reviewer
- Triage: make([]*User, 0) + append( + getBatchUser 批量语义命中 Phase 2+3
[Medium] Missing Slice Pre-allocation — Repeated Reallocation in Batch Hot Path
- ID: REV-009 (original: PERF-001)
- Evidence: userList := make([]*User, 0) — zero capacity, no second argument.
Grep hit: make([]*User, 0) at L10. Function name getBatchUser signals batch hot path.
- Recommendation: userList := make([]*User, 0, len(userKeys))
[Medium] Unbounded Goroutine Spawning — Resource Exhaustion Under Large Batches
- ID: REV-008 (original: CONC-005)
- Evidence: goroutine count scales linearly. No SetLimit, semaphore, or worker pool
present. Grep: go\s+func HIT AND NOT SetLimit|semaphore MISS.
Summary: 7 High / 6 Medium — 13/13 expected findings captured.
至此,改进闭环完整成立:单 Skill 注意力稀释 → Multi-Agent 架构改造 → 分诊盲区修复 → Grep-Gated 协议引入 → 13/13 全部捕获。
18.6 完整实现参考¶
本章描述的 Multi-Agent 架构已作为可运行文件发布在本仓库,可直接部署到 Claude Code 环境:
| 内容 | 路径 | 说明 |
|---|---|---|
| Orchestrator Skill | skills/go-review-lead/SKILL.md | 主会话编排逻辑:分诊规则、汇总格式、报告规范(以 Skill 形式运行,不在 agents/ 目录中) |
| 7 个垂直审查 Skill | skills/go-{concurrency,performance,error,security,quality,test,logic}-review/SKILL.md | 各维度的 checklist、Grep-Gated pattern、输出格式 |
| 7 个 Agent 定义文件 | outputexample/go-review-lead/agents/ | 可直接复制到 .claude/agents/ 的垂直 Worker Agent 定义文件(不含 go-review-lead) |
| 部署指引 | outputexample/go-review-lead/README.md | 安装步骤、前置条件、用法说明(英文) |
18.7 常见问题¶
Q:跨维度问题(如无界 goroutine = 并发 + 性能)如何处理?
允许两个 Agent 从各自角度同时报告同一问题。主会话在汇总时去重合并,取较高严重度,合并证据。交叉报告比遗漏好——去重的成本远低于漏报的代价。REV-008(无界 goroutine)正是由 Concurrency Agent 从并发维度正式上报,兼有 Performance 语义,两者合并为一条 Finding,严重度取较高的 Medium。
Q:所有重度 Skill 都应该拆分吗?
不是。判断标准:覆盖 3 个以上独立维度、单次经常产生 5+ 个 High Findings、或用户反复反馈漏报,才值得拆分。如果 Skill 只有单个维度且 checklist < 15 条,上下文负担不大,单 Agent 足够,不需要引入 Multi-Agent 的设计和维护成本。
Q:go-review-lead Skill 应该让主会话用什么模型运行?
Sonnet 足够。分诊(模式匹配)和汇总(合并排序)不需要深度推理。用 Opus 做分诊是过度配置。垂直审查 Agent 用 Sonnet,特别复杂的架构级审查可以考虑 Opus。
Q:Lead 应该配置为 Skill 还是 .claude/agents/ 中的 Agent 文件?
必须是 Skill,不能是 agent 定义文件。原因是平台的硬约束。
Claude Code 官方文档在多处明确规定:子代理不能生成子代理("Subagents cannot spawn other subagents. If your workflow requires nested delegation, use Skills or chain subagents from the main conversation.")。其后果是:
| 调用方式 | Lead 运行在 | 能否派发 Worker | 实际结果 |
|---|---|---|---|
主会话加载 go-review-lead Skill | 主对话(非子代理) | ✅ 可以 | 7 个 Worker 并行运行 |
主会话启动 go-review-lead Agent | 子代理 | ❌ 不可以 | Agent 工具调用被平台忽略,并行步骤跳过 |
正确的部署方式:不要在 .claude/agents/ 中创建 go-review-lead.md。主对话通过 Skill 加载 go-review-lead 后,由主对话本身执行分诊和 Worker 派发。7 个垂直审查 Agent(.claude/agents/go-*-reviewer.md)保留为 agent 定义,它们是被主对话派发的 Worker,自身不再派发子任务。
Q:Grep-Gated 的 grep MISS 会不会漏掉真实问题?
会,这是协议的已知权衡。grep MISS 代表 pattern 未命中,自动标记 NOT FOUND 并跳过语义分析。因此 pattern 的设计至关重要——宽门槛原则(宁多 HIT 不漏 MISS)和复合 pattern(有 A 且无 B)是两个核心设计手段,用于最大化覆盖率同时保持 pattern 的稳定性。
18.8 降级与错误处理¶
Multi-Agent 架构引入了额外的故障点——单 Skill 只会整体失败,而 7 个 Worker Agent 并行时,任何一个都可能出现超时、Skill 加载失败或返回格式错误。
| 故障类型 | 主会话处理方式 |
|---|---|
| sub-agent 超时(> 120s) | 标记该维度为 SKIPPED (timeout),继续汇总其他维度结果 |
| sub-agent 返回空 Findings | 正常,视为该维度无发现,在 Execution Status 中记录 0 findings |
| sub-agent 返回格式错误 | 标记为 PARSE_ERROR,在 Residual Risk 中注明"X 维度未完成,建议单独重跑" |
| Skill 文件缺失(加载失败) | sub-agent 自行报告错误,主会话在 Execution Status 中注明 |
核心原则:部分成功优于全量失败。 主会话应始终输出当前已有的发现,而不是因为一个 Agent 失败就放弃整份报告。
如果关键维度(如 Concurrency)的 Agent 失败,在报告尾部加注:
[Residual Risk] go-concurrency-reviewer did not complete (timeout).
Concurrency dimension not covered in this review — recommend re-running
with: "使用 go-concurrency-reviewer agent 审查 <file>"
18.9 成本模型与适用范围¶
适用范围:
| 场景 | 推荐架构 | 原因 |
|---|---|---|
| 单维度 Skill,checklist < 15 条 | 单 Skill | 无注意力竞争,无需多 Agent 开销 |
| 多维度 Skill,已观察到漏报 | Multi-Agent + 垂直 Skill | 跨维度注意力竞争,需要隔离上下文 |
| 高频轻量审查(如变量名修改) | 分诊后按需派发(2–3 Agent) | 成本约 $0.02,远低于全量启动 |
| 关键路径全量审查 | 全量 7 Agent | 成本约 $0.10–0.16,质量最优 |
成本结构:
- 分诊成本(Level 1 grep + Level 2 Haiku):约 $0.001/次,可忽略
- 每个 Worker Agent(Haiku,单文件):约 $0.005–0.015
- 主会话汇总(Sonnet):约 $0.01–0.02
- 典型完整审查(5 个 Worker):约 $0.05–0.10
适用范围的边界:
本文的结论强度应限定在以下范围内:Go 代码审查场景;以 getBatchUser(并发/goroutine 类)为主案例,以 ListLayout(安全/ORM/设计类)为跨域追加案例;当前 7 个垂直 Skill + go-review-lead Skill(主会话编排)实现;当前 Grep-Gated checklist 覆盖率(65/86,约 75%)。
尚未充分验证的场景包括:其他编程语言、超大 diff、跨文件复杂依赖、不同模型版本下的稳定性,以及多案例上的误报率和漏报率统计曲线。
如果 Skill 只有单个维度且 checklist < 15 条,不必升级为 Multi-Agent 架构——单 Agent 在上下文负担可控时,是更简单、更低成本的选择。架构升级的触发条件是可观察的漏报症状,而不是维度数量的绝对阈值。
本篇关键结论回顾:注意力稀释是 LLM 在单上下文多维度场景下的结构性限制,提示词强化只能缓解,无法根本解决。Skill-Agent 协作架构通过两个正交手段解决这一问题:Multi-Agent(Orchestrator-Workers 模式)消除跨维度注意力竞争;Grep-Gated 协议将 75% 的检查项转为规则驱动的预扫描,降低维度内的概率性遗漏。两者结合,在
go-code-reviewer的基准案例中实现了 13/13 的完整捕获。五种编排模式(§17.4)为不同任务结构提供了系统性的架构选型参考,Orchestrator-Workers 只是其中最适合"内容驱动、动态子任务"场景的一种。