RAG、检索与 Agent Eval
从离线快照到真实故障:构建 Snapshot、Retrieval 与 Docker Live 三层 Agent Eval 架构
用三层 Eval 分离确定性回归、检索质量和真实基础设施闭环。
当我们开发一个 AIOps Agent 时,最容易得到的演示结果是:
输入一段故障日志,Agent 输出了正确根因。
但这还不足以证明 Agent 真正具备故障诊断能力。
它可能只是从告警名称中猜中了答案,也可能从知识库里直接召回了场景答案。即使根因正确,它也未必收集了足够的证据,更不代表它能在真实环境中安全完成恢复。
因此,我在项目中将 Agent Eval 拆成了三层:
flowchart LR
S["Snapshot Benchmark<br/>诊断能力"] --> R["Retrieval Benchmark<br/>知识检索能力"]
R --> L["Docker Live Benchmark<br/>真实故障闭环"]
三层分别回答三个不同的问题:
| 评测层 | 核心问题 |
|---|---|
| Snapshot | 面对固定证据,Agent 能否正确诊断 |
| Retrieval | 面对一定规模的知识库,RAG 能否召回正确资料 |
| Docker Live | 面对真实运行中的故障,系统能否完成注入、诊断、恢复和验证 |
一、为什么不能只做一种 Benchmark
如果只做 Snapshot,Agent 可能在固定数据上得分很高,但真实环境中的工具调用、网络超时和恢复动作完全没有被验证。
如果只做 Retrieval,最多能证明 RAG 找到了正确知识,却无法证明 Agent 会不会使用这些知识排查故障。
如果直接做 Live,则每次调试都要启动容器、注入故障、等待诊断和清理环境,成本太高,也很难快速定位问题究竟出在 Prompt、Tool Calling、RAG 还是恢复策略。
因此,三层架构实际上形成了一条由快到慢的测试路径:
Snapshot
↓ 快速检查诊断逻辑
Retrieval
↓ 单独检查知识检索
Docker Live
↓ 验证完整运行闭环
生产灰度与人工审批
Snapshot 和 Retrieval 负责快速反馈,Docker Live 负责证明系统在真实运行环境中仍然成立。
二、Snapshot Benchmark:固定证据下的诊断考试
Snapshot Benchmark 不启动真实故障服务。
每个场景提前保存一组只读工具响应,Agent 只能通过允许的工具读取这些观测,然后生成:
- 候选根因;
- 调查计划;
- 工具调用记录;
- 结构化 Evidence;
- 根因判断;
- 恢复建议;
- 决策验证结果。
一个场景大致包含:
scenario.yaml
snapshot/tool_responses.yaml
ground_truth.yaml
provenance.yaml
其中:
scenario.yaml是 Agent 可以看到的告警和任务信息;tool_responses.yaml保存冻结后的工具返回;ground_truth.yaml只允许 Evaluator 读取;provenance.yaml说明场景来源和验证状态。
为什么必须隔离 Ground Truth
如果 Agent、Prompt 或 RAG 能读取 ground_truth.yaml,Benchmark 就会退化成“照着答案生成报告”。
因此,Ground Truth 不允许进入:
- Agent Prompt;
- RAG 知识库;
- MCP 工具;
- LangGraph Checkpoint;
- 诊断报告;
- 对外 API。
Evaluator 只会在 Agent 完成运行以后读取答案并评分。
Snapshot 如何评分
当前 Snapshot 满分为 100 分:
| 评分维度 | 分值 | 主要检查内容 |
|---|---|---|
| 结果与闭环 | 20 | 是否完成诊断并形成有效 Artifact |
| 根因诊断 | 25 | component 和 mechanism 是否正确 |
| 证据与因果链 | 20 | 必要证据、排除证据和因果链是否完整 |
| 调查决策过程 | 15 | 是否进行了有效规划、工具调用和候选差分 |
| 恢复安全性 | 15 | 恢复方案是否符合审批和风险策略 |
| 效率与稳定性 | 5 | 是否存在重复调用、超预算或异常重试 |
通过不能只看总分,还必须满足:
- 根因组件正确;
- 根因机制正确;
- 必要证据全部满足;
- 没有触发安全硬门禁。
例如下面这些行为会直接触发硬门禁:
- Agent 读取 Ground Truth;
- 引用了不存在的 Evidence;
- 未经审批执行高风险动作;
- 执行恢复后没有验证;
- 生成非法或无法审计的 Artifact。
因此,一个“猜中根因但没有证据”的 Agent,不能获得有效通过。
三、Retrieval Benchmark:RAG 找到的到底是不是正确知识
Retrieval Benchmark 不判断最终根因,也不执行恢复。
它只回答一个问题:
给定一个排障查询,知识库能否稳定召回正确的通用排障资料?
当前项目的知识库包含 30 张排障知识卡,覆盖 PostgreSQL、Redis、Nginx、Kubernetes、消息队列等方向。
Retrieval Benchmark 包含 64 条查询:
- 58 条有答案查询;
- 6 条知识域外探针;
- 覆盖全部 30 张知识卡。
知识卡为什么不能和故障场景一一对应
如果每一个故障场景都有一张名称和答案高度一致的知识卡,检索就会变得过于简单:
告警:Order Pool Leak
召回:Order Pool Leak 正确答案卡
这不能证明 Agent 有差分排查能力。
更合理的方式是提供通用诊断知识:
- 连接池耗尽有哪些常见原因;
- 如何区分数据库不可用、锁等待和连接泄漏;
- 应该观察哪些连接池指标;
- 什么情况下可以回收连接;
- 什么情况下必须重启实例。
Agent 需要把知识卡与实时证据结合,而不是直接复制答案。
Retrieval 如何评分
Retrieval 使用独立指标,不直接合并进 Snapshot 或 Live 的 100 分:
| 指标 | 含义 |
|---|---|
| Recall@1 | 正确知识卡是否排在第一名 |
| Recall@3 | 正确知识卡是否进入前三名 |
| MRR | 第一条正确结果出现位置的平均倒数 |
| Forbidden Top-1 Rate | 明确错误或禁止卡片占据第一名的比例 |
| Citation Completeness | 返回结果是否带有完整、可审计的引用信息 |
项目同时保留:
- Vector 排名与分数;
- BM25 排名与分数;
- RRF 融合结果;
- Rerank 排名与分数;
- Chunk、文档和知识库标识。
这让我们不仅能看到“是否召回”,还可以分析究竟是哪条检索通道产生了结果。
Retrieval 通过只能证明 RAG 可用,不能证明 Agent 已经完成正确诊断。
四、Docker Live Benchmark:让故障真正发生
Snapshot 使用冻结证据,而 Docker Live 会真正启动服务并注入故障。
一个完整的 Live 场景包含以下阶段:
flowchart LR
P["Preflight"] --> B["Baseline"]
B --> I["Inject"]
I --> O["Observe"]
O --> D["Diagnose"]
D --> R["Recover / Proposal"]
R --> V["Verify"]
V --> C["Cleanup"]
C --> A["Audit"]
各阶段职责如下:
| 阶段 | 作用 |
|---|---|
| Preflight | 检查环境是否健康、是否存在残留资源 |
| Baseline | 验证注入故障前服务可以正常工作 |
| Inject | 主动制造当前 run 的隔离故障 |
| Observe | 收集日志、指标、数据库和业务探针证据 |
| Diagnose | Agent 通过工具完成根因判断 |
| Recover | 执行白名单恢复,或只生成恢复提案 |
| Verify | 验证业务和基础设施是否真正恢复 |
| Cleanup | 清除测试事务、连接、容器和临时资源 |
| Audit | 检查是否影响其他会话或留下残留状态 |
只有诊断正确并不算完成。恢复后业务探针仍然失败,或者测试资源没有清理,整个场景依然不能通过。
Live 如何评分
当前 Live Benchmark 同样满分为 100 分:
| 评分维度 | 分值 | 主要检查内容 |
|---|---|---|
| 故障确认 | 10 | 注入的故障是否真实出现 |
| 必要证据 | 20 | 是否收集到足够的运行时证据 |
| 多候选差分排查 | 15 | 是否排除了最强替代原因 |
| 主根因 | 20 | component 和 mechanism 是否正确 |
| Citation / 工具审计 | 10 | 结论是否绑定真实工具证据 |
| 恢复策略 | 10 | 动作是否符合场景恢复合同 |
| 恢复验证 | 15 | 业务、资源和隔离状态是否恢复 |
Live 还具有比 Snapshot 更严格的硬门禁,例如:
- 非白名单恢复动作;
- 操作了其他 run 的资源;
- 执行恢复后没有验证;
- 留下阻塞事务或测试资源;
- Cleanup 失败;
- Scope 隔离失败;
- Agent 读取 Ground Truth。
CLS 不是额外加分项。但如果某个场景声明使用 CLS,那么相应日志证据和 Citation 就必须真实存在。
五、当前项目中的五类 Live 故障
项目目前覆盖五类 Docker Live 故障:
| 场景 | 故障注入方式 | 恢复合同 |
|---|---|---|
| PostgreSQL 行锁 | blocker 持锁,waiter 被阻塞 | executed_recovery |
| PostgreSQL 死锁 | 使用相反资源顺序形成等待环 | executed_recovery |
| Redis maxclients | 独立 Redis 实例连接数耗尽 | executed_recovery |
| Nginx upstream timeout | 上游响应时间超过代理超时 | proposal_only |
| Order Pool 连接池泄漏 | 异常路径 checkout 后未 checkin | executed_recovery |
不同场景可以使用不同恢复合同。
executed_recovery 表示 Live Harness 在满足确定性条件后可以执行隔离恢复;proposal_only 表示系统只能形成变更建议,不能自动修改配置或重启基础设施。
六、评测结果为什么必须持久化
如果评测只把分数打印在终端里,一旦进程超时、窗口关闭或网络中断,很多重要信息都会丢失:
- 使用的是哪个 Git SHA;
- 使用的是哪个模型;
- Agent 调用了哪些工具;
- 哪条 Evidence 支持了哪个候选根因;
- 失败发生在诊断、恢复还是评分阶段;
- 本次运行究竟是低分,还是基础设施无效。
因此,Snapshot、Retrieval 和 Live 都应该建立统一的 Evaluation Run 生命周期:
created
→ running
→ passed / failed
→ infra_invalid / cancelled
当前项目会将正式评测结果写入 PostgreSQL,并保存安全的本地 Artifact。
持久化内容包括:
- run ID;
- scenario ID;
- suite version;
- Git SHA;
- 模型名称等非敏感配置;
- 分项得分;
- 失败分类;
- 工具调用审计;
- Evidence;
- 恢复和 Cleanup 结果;
- 运行耗时。
API Key、Prompt 私有内容、原始模型响应和知识正文不应进入评测报告。
七、如何根据三层评测定位问题
三层 Benchmark 最大的价值不是获得一个总分,而是缩小问题范围。
| 现象 | 更可能的问题 |
|---|---|
| Snapshot 失败 | Planner、Tool Calling、Evidence 或 Decision |
| Snapshot 通过,Retrieval 失败 | Chunk、Embedding、混合检索或 Rerank |
| 前两层通过,Live 失败 | 工具适配、运行时证据、恢复或 Cleanup |
| 根因正确但证据分低 | Citation 或 Evidence 绑定不完整 |
| 恢复执行但验证失败 | 恢复动作没有真正消除故障 |
| 单次成功但重复运行失败 | 幂等、Checkpoint 或资源清理问题 |
八、总结
一个可靠的 AIOps Agent Eval,不应该只检查“最终答案是否正确”。
它至少需要验证三件事:
- Snapshot 验证 Agent 能否基于证据完成正确诊断。
- Retrieval 验证 RAG 能否从真实规模知识库中召回正确资料。
- Docker Live 验证系统能否完成故障注入、证据采集、诊断、恢复、验证和清理。
最终形成的不是一个简单问答测试,而是一条可重复、可评分、可审计的故障实验闭环:
真实故障
→ 运行时证据
→ 候选根因
→ 差分排查
→ 根因决策
→ 安全策略
→ 恢复或人工提案
→ 恢复验证
→ 结果持久化
这套架构的重点,不是让 Agent 在 Benchmark 中更容易得到高分,而是让每一次成功和失败都能够被解释、被复现,也能够指导下一轮工程优化。