RAG、检索与 Agent Eval

我如何为 AIOps Agent 构建 10 个 Snapshot 与 5 个 Live Benchmark

说明 Snapshot 与 Live 场景的边界、证据来源、评分和正式基线管理。

SnapshotLive EvalAIOps

本文介绍当前项目中的 10 个 Snapshot 场景和 5 个 Live 场景,包括每个场景模拟的故障、Agent 可使用的工具,以及必须获得的关键证据。

一、Snapshot 和 Live 有什么区别?

两者使用相同的 Agent 诊断链路,但数据来源不同。

维度Snapshot BenchmarkLive Benchmark
故障来源预先冻结的工具响应Docker 隔离环境中真实注入
工具调用tool_responses.yaml 回放查询真实 PostgreSQL、Redis、Nginx、Order API
稳定性高,适合 CI 回归受服务状态和网络影响
执行速度较快较慢
恢复验证主要评估诊断与方案可真实恢复并验证
CLS不需要可通过 SearchLog 查询真实日志
主要用途测试根因辨别和证据推理测试完整生产链路和安全闭环

整体链路如下:

故障告警
   ↓
Planner 生成调查计划
   ↓
调用诊断工具
   ↓
获得 Observation
   ↓
Evidence Evaluation
   ↓
假设排除与根因决策
   ↓
Validator 核验
   ↓
恢复执行或生成恢复提案
   ↓
独立 Verify + Cleanup
   ↓
Benchmark 评分

这里有一个非常重要的区别:

工具输出只是 Observation,并不会自动成为有效 Evidence。

工具结果还必须经过证据评估,判断它:

  • 是否与当前假设相关;
  • 支持还是反驳某个假设;
  • 是否来自独立的数据源;
  • 是否能够支撑 trigger、mechanism 和 impact 因果链;
  • 是否存在重复证据或来源污染。

二、10 个 Snapshot 场景

APY-002:PostgreSQL 慢事务导致连接池耗尽

告警现象

应用大量出现数据库连接获取超时,连接池已经没有可用连接。

诊断工具

  • InspectPostgres
  • InspectDatabasePool
  • GetServiceMetrics
  • GetDeploymentChanges

关键证据

  • 存在持续约 428 秒的长事务;
  • 11 个数据库会话被阻塞,等待类型为 transactionid
  • 连接池 20 个连接全部借出,37 个请求等待连接;
  • 连接的主要持有者正在等待数据库锁;
  • 流量只小幅增加,不足以解释连接池突然耗尽。

正确根因

component: postgresql
mechanism: slow_transaction_pool_exhaustion

这里的关键不是“池满了”,而是继续向下追问:连接为什么一直没有归还?答案是连接被数据库慢事务和锁等待占用。

APY-003:应用进程退出导致 Nginx 502

告警现象

Nginx 返回 502,无法连接 checkout 服务。

诊断工具

  • InspectContainer
  • InspectNginx

关键证据

  • checkout 容器状态为 exited,退出码为 137;
  • 应用端口 8080 没有监听;
  • Nginx upstream 正确指向 8080;
  • Nginx 请求 upstream 时收到 connection refused

正确根因

component: checkout-service
mechanism: process_unavailable

APY-006:Nginx upstream 端口配置错误导致 502

这个场景和 APY-003 的外部现象几乎相同,但根因完全不同。

诊断工具

  • InspectContainer
  • InspectNginx

关键证据

  • checkout 容器健康;
  • 应用正常监听 8080;
  • Nginx upstream 却配置成 8081;
  • 访问 8081 返回 connection refused

正确根因

component: nginx-gateway
mechanism: upstream_port_mismatch

APY-003 和 APY-006 构成一组差分场景:

场景表面现象应用状态Nginx 配置根因
APY-003502进程退出正确应用不可用
APY-006502健康端口错误网关配置错误

它可以判断 Agent 是真正综合证据,还是看到 502 就机械地回答“应用挂了”。

APY-007:Redis 服务进程停止

告警现象

应用无法连接 Redis,请求出现 connection refused。

诊断工具

  • InspectRedis
  • InspectRedisClientPool
  • GetServiceMetrics
  • GetDeploymentChanges

关键证据

  • Redis 进程已经停止,端口没有监听;
  • PING 不可用;
  • 客户端最近错误为 connection refused
  • 连接池中没有 stale connection;
  • 没有明显的连接池 waiter。

正确根因

component: redis
mechanism: service_process_stopped

APY-011:异常路径没有归还 PostgreSQL 连接

告警现象

连接池耗尽,新的 checkout 请求无法获得数据库连接。

诊断工具

  • InspectPostgres
  • InspectDatabasePool
  • GetServiceMetrics
  • GetDeploymentChanges

关键证据

  • PostgreSQL 没有长事务,也没有数据库锁等待;
  • 连接 checkout 次数为 9130,checkin 次数为 9047;
  • 20 个连接被应用持续保留;
  • 保留连接的路径为 checkout-discount-exception

正确根因

component: checkout-service
mechanism: borrowed_connection_not_returned

APY-002 和 APY-011 同样构成差分场景:

  • APY-002:连接因为数据库慢事务无法释放;
  • APY-011:连接因为应用异常路径遗漏 checkin 无法释放。

因此,“连接池满”只是结果,不是根因。

APY-012:Redis 恢复后,应用仍保留旧连接

告警现象

Redis 已经恢复,但应用请求仍然失败。

诊断工具

  • InspectRedis
  • InspectRedisClientPool
  • GetServiceMetrics
  • GetDeploymentChanges

关键证据

  • Redis 进程已经运行,PING=PONG,网络连接正常;
  • 新建直连可以成功;
  • 应用连接池仍保留 24 个 stale connections;
  • 有 26 个请求等待连接;
  • Redis 恢复后,连接池 generation 没有变化。

正确根因

component: checkout-service
mechanism: stale_connections_retained_after_recovery

APY-007 和 APY-012 用于区分 Redis 服务真的停止,与 Redis 已恢复但应用客户端没有完成连接恢复。

APY-013:相反资源顺序导致 PostgreSQL 死锁

告警现象

并发订单事务发生回滚,但数据库整体仍然可达。

诊断工具

  • InspectPostgresErrors
  • InspectTransactionResourceOrder
  • InspectPostgresWaitGraph
  • GetDatabaseMetrics

关键证据

  • PostgreSQL 返回 SQLSTATE 40P01deadlock detected
  • 事务 A 先更新 order row,再更新 inventory row;
  • 事务 B 以相反顺序更新资源;
  • wait graph 中出现长度为 2 的环;
  • 数据库 CPU、连接数和整体延迟正常。

正确根因

component: order-service
mechanism: opposite_order_transaction_deadlock

完整因果链应当是:

两个并发事务以相反顺序获取资源
→ 形成循环等待
→ PostgreSQL 选择一个事务作为 victim
→ 返回 40P01 并回滚事务

APY-014:Redis maxclients 被耗尽

告警现象

已经建立的 Redis 连接还能使用,但新连接被拒绝。

诊断工具

  • InspectRedisServer
  • GetRedisConnectionMetrics
  • ListRedisClients
  • InspectHostLimits

关键证据

  • Redis 进程仍在运行,已有连接 PING=PONG
  • connectedClients == maxclients == 16
  • rejectedConnections 增加 83;
  • 其中 14 个连接属于当前 Benchmark run;
  • 宿主机文件描述符仍然充足。

正确根因

component: live-eval-redis
mechanism: benchmark_clients_exhausted_maxclients

这组证据排除了 Redis 进程停止和宿主机文件描述符耗尽两种常见误判。

APY-015:上游响应超过 Nginx read timeout

告警现象

Nginx 返回 504 Gateway Timeout。

诊断工具

  • InspectGatewayRequestTimeline
  • InspectGatewayErrors
  • ProbeUpstreamHealth
  • GetGatewayMetrics

关键证据

  • Nginx 连接 upstream 只用了约 4ms;
  • 请求约 752ms 后返回 504;
  • 错误发生在 reading response header 阶段;
  • upstream health endpoint 返回 200;
  • 慢接口 first byte 约为 1500ms;
  • Nginx read deadline 为 750ms;
  • Nginx 本身没有明显资源压力。

正确根因

component: live-eval-upstream
mechanism: upstream_response_exceeded_proxy_read_timeout

这说明连接已经成功,问题发生在“等待响应”阶段,而不是 upstream 端口不可达。

APY-016:客户端忽略 Retry-After 导致重试风暴

告警现象

接口收到大量 429,整体流量突然放大。

诊断工具

  • InspectHttpAttempts
  • InspectRateLimitTimeline
  • InspectClientRetryPolicy
  • InspectTrafficAndDependencyHealth

关键证据

  • 每个逻辑请求的尝试次数从 1.08 上升到 4.92;
  • 429 比例达到 61%;
  • 总请求量增长约 310%;
  • 服务返回 Retry-After: 2,但客户端没有遵守;
  • 没有 exponential backoff,也没有 jitter;
  • 实际重试间隔接近 0;
  • 恶意流量比例较低,下游依赖整体健康。

正确根因

component: checkout-client
mechanism: retry_after_ignored_without_backoff

它测试的是 Agent 能否识别“客户端重试放大”,而不是把 429 简单归因于恶意流量或服务容量不足。

三、5 个 Live 场景

与 Snapshot 不同,Live 场景会在隔离 Docker 服务中真实构造故障。Agent 获得的是经过脱敏的实时证据,而不是 ground_truth.yaml 中的答案。

APY-LIVE-PG-LOCK-001:PostgreSQL 行锁阻塞

故障注入

一个合成事务锁住当前测试订单行,另一个订单状态更新被阻塞,最终业务探针超时。

运行时工具

  • InspectPostgresSessions
  • InspectPostgresLockGraph
  • VerifyServiceHealth
  • SearchLog:启用 CLS 模式时使用

关键证据

  • waiter 的 waitEventType=Lock
  • 阻塞图存在 blocker → waiter 边;
  • 被锁资源是当前测试订单行;
  • PostgreSQL 本身仍然可达;
  • 业务更新探针超时;
  • CLS 日志记录对应 run 的 request timeout。

需要排除

  • 数据库不可达;
  • SQL 自身计算过慢;
  • 不存在 blocker 的普通慢查询。

恢复闭环

终止当前 run 的合成 blocker
→ waiter 解除阻塞
→ 业务探针重新成功
→ PostgreSQL 健康
→ 锁图清空
→ 确认未影响无关会话

恢复动作只能作用于当前 Benchmark 创建并确认所有权的 blocker。

APY-LIVE-PG-DEADLOCK-001:真实 PostgreSQL 死锁

故障注入

两个并发事务以相反顺序更新两条业务记录,形成真实等待环。

运行时工具

  • InspectPostgresDeadlockAudit
  • InspectPostgresTransactionResult
  • VerifyPostgresHealth
  • SearchLog

关键证据

  • SQLSTATE 为 40P01
  • PostgreSQL 确认发生死锁;
  • 两个事务的资源获取顺序相反;
  • 审计中存在 deadlock cycle;
  • 其中一个事务被回滚;
  • PostgreSQL 整体仍然健康。

需要排除

  • 普通的长时间锁等待;
  • 没有锁环的慢 SQL;
  • 数据库整体不可用。

恢复闭环

只重试被 PostgreSQL 回滚的 Benchmark 事务,而不是终止未知数据库会话。验证条件包括:

  • victim 事务重试成功;
  • 两条业务记录均更新成功;
  • 当前 run 没有遗留事务;
  • PostgreSQL 保持健康。

APY-LIVE-REDIS-MAXCLIENTS-001:Redis 连接槽耗尽

故障注入

使用带有当前 run 标识的 Benchmark 客户端,占满隔离 Redis 的连接上限。

运行时工具

  • InspectRedisServerInfo
  • ListBenchmarkRedisClients
  • VerifyRedisPing
  • SearchLog

关键证据

  • connectedClients == maxclients
  • rejectedConnectionsDelta 增加;
  • 新连接被拒绝;
  • 已有控制连接仍能 PING;
  • 占用连接的是当前 run 的命名 Benchmark clients;
  • CLS 中存在对应的新连接拒绝事件。

需要排除

  • Redis 进程停止;
  • 宿主机文件描述符耗尽;
  • 应用只保留了少量 stale connections。

恢复闭环

只关闭当前 run 的命名客户端
→ connectedClients 降到限制以下
→ 新连接恢复成功
→ 原有控制连接仍然健康
→ 无关客户端不受影响

这里不能使用“关闭所有 Redis 客户端”这样的高风险动作。

APY-LIVE-NGINX-TIMEOUT-001:上游响应超时

故障注入

隔离 upstream 可以正常建立连接,但业务响应时间超过 Nginx 的 proxy_read_timeout,网关返回真实 504。

运行时工具

  • InspectNginxRequestTimeline
  • ProbeLiveEvalUpstream
  • ReadNginxTimeoutSummary
  • ProposeNginxTimeoutMitigation
  • SearchLog

关键证据

  • 网关返回 504;
  • upstream connection 已成功建立;
  • 请求耗时达到 read deadline;
  • upstream 独立健康检查返回 200;
  • 网关自身健康检查返回 200;
  • CLS 中存在对应的 upstream timeout 日志。

需要排除

  • upstream 端口关闭;
  • 路由到错误地址;
  • Nginx 自身资源耗尽。

恢复合同

这是 proposal_only 场景。Agent 不能直接修改或 reload Nginx,只能生成结构化方案:

  • 修改目标;
  • 风险说明;
  • 回滚方法;
  • 至少两项可执行验证步骤;
  • 明确要求人工审批。

最终还要验证 Nginx 配置哈希没有变化、Agent 没有执行写操作,以及网关和 upstream 仍保持健康。

APY-LIVE-ORDER-POOL-LEAK-001:Order API 异常路径连接泄漏

故障注入

Order API 使用固定容量的 asyncpg pool。特定订单更新路径在 checkout 数据库连接后抛出异常,但没有执行对应 release。

运行时工具

  • InspectOrderPoolState
  • InspectOrderDatabaseSessions
  • VerifyOrderDatabaseReachability
  • SearchLog

在 Multi-Agent 模式下,这些工具可以分为两个调查域:

Runtime Specialist
├── InspectOrderPoolState
├── InspectOrderDatabaseSessions
└── VerifyOrderDatabaseReachability

Log Specialist
└── SearchLog

关键证据

运行时证据:

  • 连接池达到容量上限;
  • freeConnections=0
  • 出现等待连接的请求;
  • 当前 run 的数据库会话仍然存在;
  • PostgreSQL 可以正常连接;
  • 没有数据库 lock wait;
  • 业务探针因为无法获取连接而超时。

CLS 生命周期证据:

connection_checkout
→ order_update_exception
→ request_timeout

并且缺少与 checkout 匹配的 connection_checkin

需要排除

  • 正常流量超过容量;
  • PostgreSQL 不可达;
  • 慢 SQL 长时间持有连接;
  • 数据库锁等待。

正确根因

component: order-api
mechanism: exception_path_connection_not_released

恢复闭环

隔离 Live Harness 可以重启当前测试的 Order API 实例,使旧 pool generation 释放并创建新连接池,然后验证:

  • 旧 generation 会话已经清除;
  • 新 generation 已就绪;
  • 业务探针恢复;
  • PostgreSQL 健康;
  • 无关数据库会话仍然存在;
  • 测试订单和残留会话完成清理。

陈涛 · Agent Application Developer

杭州 · 2026