Hal-Hanami/incident-triage-agent

GitHub: Hal-Hanami/incident-triage-agent

基于 Claude Agent SDK 与 MCP 的只读事件分诊 Agent,对告警进行分类、检索 runbook 并给出带引用的建议,低置信度时主动弃权上报人工。

Stars: 0 | Forks: 0

# incident-triage-agent **基于 Claude Agent SDK + MCP 的只读首轮事件分诊。** 输入告警或事件工单 → 它会对**严重程度 + 类型**进行分类,检索 匹配的 **runbook**,并提出**带引用的首次响应建议** — 或者,当置信度较低或情况超出范围时,它会**弃权并 上报给人类**。它绝不执行修复。 [![tests](https://static.pigsec.cn/wp-content/uploads/repos/cas/6b/6b52945adbf8d9e421fe243515ae54cfbd3da263f16b1eabda37cdc0b797b8eb.svg)](https://github.com/Hal-Hanami/incident-triage-agent/actions/workflows/ci.yml) 一个能够采取行动的 agent,其可信度仅取决于它*不*采取行动的意愿。因此, 这个仓库衡量的不是 agent 有多准确——而是 它拒绝行动的可靠程度。在一组固定的 32 个合成事件中,经过三次 完整的 pipeline 运行: | | 测量值 | 含义 | |---|---|---| | 弃权率 | **100%** (15/15 必须弃权) | 它从未对需要人类介入的事件提出过行动建议 | | **遗漏的上报** | **0** | 在任何测量运行中均未发生过此类危险错误 | | 错误弃权 | **17 个可回答问题中的 2 个** | 它*过度*上报了——见下文 | | 行动正确率 | **93.3%** (14/15 PROPOSE,关键指标匹配) | LLM 裁判同意率为 15/15 | | 成本 | 每个事件 **$0.0140** | Opus 起草器约占其中的 93% | | 延迟 | **p50 5.22秒 / p95 10.80秒** | 起草是关键杠杆:p50 3.55秒 | **错误弃权是诚实的一部分。** 有两个本可回答的事件被不必要地 上报了,并且该数值在其他方面完全相同的运行之间发生了波动(1,然后是 2,然后是 2)——这是 LLM 的方差,而不是固定属性。这两种 错误都偏向保守方向,对于这项工作来说,这是宁可犯的错误类型,但设计目标是 0,并未达到。 [`docs/EVALUATION.md`](docs/EVALUATION.md) 包含了每一个数字、日期、其 复现命令,以及它未能展示的内容。 Runbook 搜索**没有在这里重新实现**:它复用了来自 [tech-docs-rag](https://github.com/Hal-Hanami/tech-docs-rag) 的检索包,这是一个基于源文件的 RAG,如果其源文件不支持,它会拒绝回答。这个项目将这种 态度在自主性阶梯上提升了一级——从*不回答*变为**不行动**——在这里,错误的代价是一个行动而不是一句话。 - **可衡量** — 严重程度/类型准确率、检索召回率,以及在版本化的合成事件集上的**弃权率 / 错误弃权 / 遗漏的上报**。 - **护栏约束** — **构造上即为只读**:未给 agent 提供任何可以 修改系统的工具;其唯一的副作用是向人类上报。 - **成本上限** — 设有严格的**单事件 USD 预算**,一旦超出即触发弃权,而不是 超支。 - **可观测** — 每次分诊均有**分阶段延迟 + 分模型 $ 统计**,以及整个事件集的 p50/p95 数据。 ## 工作原理 ``` incident → classify → retrieve → draft → decide → TriageResult (+ trace) sev+type runbook cited PROPOSE | ABSTAIN→escalate haiku-4-5 (reused) opus-4-8 (deterministic rule) ``` 这四个阶段是一个可衡量的 pipeline;**Claude Agent SDK** 将它们封装为 **进程内 MCP 工具**,并在只读权限策略下对它们进行编排。 这个安全关键的汇合点 —— PROPOSE 或 ABSTAIN —— **完全不运行任何模型**:它是一个 确定性规则,因此该决策不会在不同运行之间发生偏移。完整规范,包括 PROPOSE/ABSTAIN 合约和 SEV1 规则: [`docs/design.md`](docs/design.md)。 ## 快速开始(离线 — 无需密钥) ``` # 列出合成 incident set(22 个 in-scope + 10 个 abstention 测试) python -m triage incidents python -m triage incidents --scope out # just the must-abstain cases # 重放五次真实的 measured triage 运行 — 无 key,无网络 python -m triage demo # 检查 fixture 完整性 python -m triage validate # offline test suite — 137 项测试:pricing math(含 cache tokens)、schema # invariants、fixtures、完整的 PROPOSE/ABSTAIN decision table、budget/skip # wiring、read-only guardrail red-team,以及使用 fakes 的 pipeline eval loop uv run --with pytest python -m pytest -q # or: pip install -e '.[dev]' && pytest -q ``` ## 测量(需要密钥) ``` # classify:severity/type 准确率 + 每模型成本 + p50/p95 (claude-haiku-4-5) export ANTHROPIC_API_KEY=... # or put it in .env (gitignored) uv run --with anthropic python -m triage eval --classify-only # --limit N bounds spend # retrieve:构建 runbook index,然后测量 recall@1/@3/@k + MRR export VOYAGE_API_KEY=... # shares .env with the Anthropic key uv run --with sqlite-vec python -m triage index-runbooks uv run --with sqlite-vec python -m triage eval --retrieval-only # --no-rerank ablates the rerank # 完整 pipeline(两个 key + 已构建的 index):classify → retrieve → draft # (claude-opus-4-8) → decide,评估 abstention / false-abstention / missed-escalation uv run --with anthropic --with sqlite-vec python -m triage eval # --no-draft = no Opus spend # 一个 incident 的 end to end,包含 per-stage latency + per-model $ trace + §8 budget verdict uv run --with anthropic --with sqlite-vec python -m triage triage INC-0003 # §8 cost ceiling,实时:微小的 budget 使 classify 触发上限,Opus # draft 永不会被购买,且 decision 降级为 ABSTAIN(cost_budget_exceeded) uv run --with anthropic --with sqlite-vec python -m triage triage INC-0001 --budget 0.0005 # 通过 Agent SDK shell 的同一 incident:read-only MCP tools、 # 每次运行的 tool/deny audit,以及 orchestrator cost cross-check(SDK vs token-priced) uv run --with claude-agent-sdk --with anthropic --with sqlite-vec python -m triage agent INC-0001 ``` 检索功能复用了同级目录的 tech-docs-rag 检出,用于 `import rag`(默认为 `../tech-docs-rag`,可通过 `TECH_DOCS_RAG_PATH` 覆盖)。 ## 目录结构 ``` docs/design.md the spec (numbered §, cited from code) docs/EVALUATION.md every measured number: date, set, reproduce command, limits triage/schema.py Incident / TriageResult / Severity / IncidentType / Outcome triage/classify.py classify stage — Classifier Protocol + claude-haiku-4-5 triage/runbooks.py runbook corpus adapter — chunks fixtures/runbooks → rag index rows triage/retrieve.py retrieve stage — Retriever Protocol + RagRetriever (reuses tech-docs-rag) triage/draft.py draft stage — Drafter Protocol + claude-opus-4-8 cited recommendation triage/decide.py decide stage — deterministic PROPOSE/ABSTAIN rule; no model triage/agent.py Agent SDK shell — stages as in-process MCP tools, read-only guardrails triage/eval.py eval harness — accuracy + recall@1/@3/@k + MRR + abstention / missed-escalation + per-stage p50/p95 triage/observe.py sourced per-model pricing (cache-aware), Trace, the §8 cost ceiling triage/__main__.py CLI — incidents / validate / index-runbooks / eval / triage / agent / demo fixtures/incidents/ synthetic incident set (JSONL) — no real/secret data fixtures/runbooks/ synthetic runbooks the RAG indexes tests/ offline test suite (no key, no network) ``` ## 非目标 不是一个自动修复系统(它只建议 + 上报,从不执行)。没有真实 事件、遥测数据或机密——一切都是合成的,因此它可以独立构建 并且可以安全地公开。见 [`docs/design.md`](docs/design.md) §11。 ## 贡献 提交约定和范围列表位于 [`CONTRIBUTING.md`](CONTRIBUTING.md)。许可证:[MIT](LICENSE)。
标签:LLM Agent, MCP, 告警分诊, 安全规则引擎, 自动化运维, 运维, 逆向工具