关于 anomaly-investigation
anomaly-investigation 是用于通过数据检验候选原因、诊断已知异常的 Skill。它排除被数据否定的解释,只有在候选原因经受反驳检验并通过正向验证后才予以确认。
主要功能
- 01对照基线描述异常
- 02检验并排除候选原因
- 03通过预测结果确认原因
- 04在台账中追踪候选项与证据
- 05报告未决解释及所需数据
适用场景
- 01调查意外的指标变化
- 02缩小峰值或骤降的可能原因
- 03区分已确认原因与合理猜测
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ gaasher/ agent-loop-skills --skill anomaly-investigation安装后在 Claude Code 中输入/anomaly-investigation确认已加载。
附带文件examples/run.example.yaml
详细介绍
异常调查循环
一个构建 → 测试 → 排除 → 确认的循环——把根因分析当作搜索。产物是一份调查日志;反馈信号是有效候选解释的数量,并将其逐步缩减到一个已确认的原因,而非仅仅与数据一致的原因。每次迭代都针对数据测试一个候选原因,并剔除被数据反驳的候选原因,逐步缩小范围,直到只剩一个。
这一流程要求遵守的准则是:只有当某个原因既经受住了诚实的反驳尝试,又做出了得到验证的正向预测(例如:“如果这是原因,移除它就能恢复正常”——而事实也确实如此),它才是“根因”。一个只是可能解释异常的说法只是一个假设,并非结论。
适用场景
当你已经发现异常——大致知道哪里不对,并希望通过对照数据逐一排除来诊断原因时,使用此流程。默认先列出一组较广泛、彼此可区分的候选原因,然后测试能最快缩小范围的那个;如果异常描述模糊,首先要把它具体化(第 0 次迭代)。不适用于没有待追查异常、对数据集进行开放式探索的场景(使用 data-analysis);也不适用于对照文献核实外部说法的场景(使用 claim-verify)。
设置
以交互方式确定绑定值。如果工作目录中存在 loop.run.yaml,则加载它,用一行确认各项值,然后跳转到循环。否则:在 Claude Code 中(可使用 AskUserQuestion 工具),推断每项绑定可能的值,并将其作为推荐选项呈现;在其他宿主中,逐项以纯文本提问。然后写入 loop.run.yaml(格式:examples/run.example.yaml),并在创建任何其他文件之前确认各项值。
| 绑定 | 含义 | 默认值 | 推断方法 |
|---|---|---|---|
<dataset> | 待调查的数据(或日志);只读的真实依据 | — | 扫描工作目录,查找数据或日志文件 |
<anomaly> | 异常情况:指标、发生位置/时间,以及偏差幅度 | — | 询问用户;在第 0 次迭代中具体化 |
<analysis_cmd> | 在用户环境中运行分析代码片段的解释器 | python3 | 检查工作目录中的 pyproject.toml/.venv/uv |
<log> | 调查日志的输出路径 | <sandbox_root>/investigation.md | — |
<sandbox_root> | 代码片段和台账的存放位置 | ./sandbox | — |
<budget> | 最大迭代次数 | 8 | — |
分析代码片段通过 <analysis_cmd> 在用户的环境中运行,因此可以使用用户已安装的任意工具。辅助代码优先使用标准库(csv、statistics):如果代码片段需要 pandas/numpy,则通过 try/except ImportError 检查,并退回到标准库方案;或者在征得同意后提供 uv pip install "pandas==<ver>"——绝不假设相关包已经安装。
分析循环
复制此检查清单并逐项勾选:
- 第 0 轮迭代——精确描述异常;在
<log>中列出初步候选原因。 - 选择一个候选原因进行测试(选择其测试最能清晰区分剩余候选原因的那一个)。
- 进行测试:编写
<sandbox_root>/iter<N>/test.py,使用<analysis_cmd>运行,并将输出重定向到out.txt。 - 排除或保留(数据证伪 → 从当前候选集中移除;数据支持 → 保留在候选集中)。
- 确认最终候选原因:当一个候选原因领先时,在尝试证伪后,运行一项只有它能预测的正向测试。
- 追加一行台账记录;确认一个原因或达到
<budget>时停止。
第 0 轮迭代——描述异常。 精确量化异常:编写并运行代码片段,确定偏离了什么、何时何地发生偏离,以及偏离幅度有多大;并以正常基线作为参照(即相邻时段/区段的同一指标)。然后列出初步候选原因——这些解释彼此可区分,范围足以涵盖真实原因(实际变化、构成/混合比例变化、数据质量缺陷、测量方式变化、季节性、离群区段)。将它们作为当前候选原因列在 <log> 中。此时不要记录任何已确认的原因。
然后,持续迭代,直至停止(确认一个原因或达到预算):
- 选择一个候选原因进行测试。 理想情况下,选择其测试最能清晰区分剩余候选原因的那一个,这样每轮迭代都能尽可能多地排除候选原因。
- 进行测试。 编写
<sandbox_root>/iter<N>/test.py,计算能够证伪或支持该候选原因的内容(按区段/来源/时间切片、重新计算指标、比较分布)。使用<analysis_cmd>运行,并将输出重定向到<sandbox_root>/iter<N>/out.txt(切勿让上下文被输出内容淹没)。 - 排除或保留。
- 数据证伪该候选原因 → 在
<log>中记录证据并标记为已排除;将其从当前候选集中移除。 - 数据支持该候选原因 → 将其保留在候选集中;如果它现在是领先候选原因,则运行一项确认性测试,检验它所独有的正向预测(例如:“移除/进行季节性调整,消除疑似影响因素后,异常消失”)。同时尝试证伪它——领先候选原因经受住真正的证伪尝试,并通过确认性测试后,即为根本原因。
- 数据证伪该候选原因 → 在
- 记录一行台账,然后继续缩小候选范围。
观察等价性。 两个机制不同的候选原因,可能会对现有数据作出完全相同的预测(例如,在按日聚合的数据中,机器人流量激增和管道重复计数都会表现为“会话数激增,转化数持平”)。遇到这种情况,你无法在此区分它们——不要武断地选择其中一个。应在现有数据的分辨率范围内将它们作为一个已确认原因报告,并指出哪些额外数据可以将它们区分开来(更细粒度的日志、原始事件记录、上游检查)。此外,还要区分机制(指标如何变化)和根本原因(输入数据为何有误)——确认机制是进展,但机制本身不是原因。
台账
<sandbox_root>/ledger.tsv,以制表符分隔,文本中不得使用逗号。表头:
iter candidate_tested verdict live_candidates
verdict ∈ {characterize,refuted,supported,confirmed}。示例:
iter candidate_tested verdict live_candidates
0 characterize anomaly + slate characterize 5
1 real drop across all segments refuted 4
2 one segment's conversions fell refuted 3
3 one source's sessions inflated supported 2
4 removing that source restores normal confirmed 1
报告已确认的根本原因及其确认性证据、各项替代解释及其排除方式;如果停止时尚无单一的已确认原因,则报告剩余的当前候选原因,以及能够区分它们的测试。
约束
- 确认,不要只求拟合。 根因必须经得起诚实的反驳尝试,并且通过正向确认测试;“与数据一致”还不够,因为通常有多种说法都符合。
- 用数据检验,而非凭直觉判断——每次排除和最终确认都必须有你运行的计算作为依据,并记录在
<log>中。 - 保持候选项可区分,并优先选择能最快缩小范围的测试,让存活候选数量减少;不要只追着一个偏爱的理论,而不检验其他可能性。
- 只读取
<dataset>——绝不修改它,因为每次测试都要以它为真实依据。沙箱是独立的(不能通过../越界)。 - 不要暂停循环询问是否继续;持续运行,直到确认某个原因或达到预算上限。
停止条件
- 已确认——恰好有一个候选项经受住反驳并通过正向确认测试。
- 预算耗尽——达到
<budget>次迭代,但仍未确认任何原因;报告当前存活的候选项。