2026-09-02 · 原文发布日
KPI 异常自动检测并生成 AI 调查报告
数据库驱动的 KPI 异常监控模板:夜里把各指标 SQL 跑出的观测值写入 Postgres,用 28 天中位数加 MAD 构建稳健基线,早上计算 z 分数识别异常并抑制重复告警;Claude 代理带 Postgres 和 GitHub 工具自动调查成因,按严重度分别推 Slack、建 GitHub issue 和发 Gmail,还提供反馈 webhook 和每周精准度报告。
原文要点
原模板为免费 n8n 工作流,以 Postgres 为中心:夜里 01:00(或手动)从 kpi_metrics 读取启用的指标定义,执行各 metric_sql 把昨日观测值写入 kpi_observations;用 28 天中位数加 MAD(外加星期几分组中位数)重算基线,历史不足的指标不评分并发 Slack 警告;每天 07:00 计算稳健 z 分数与严重度,检查近期未关闭/已确认事故做重复抑制并限制单次事故数;新事故由 OpenRouter(Claude)代理带 Postgres 与 GitHub 工具调查并校验解释;按严重度路由:critical 和 warning 发 Slack,critical 另建 GitHub issue 并发 Gmail 确认请求;提供带 header 鉴权的处置 webhook(confirmed/false_positive/wont_fix,非法负载返回 400);每周一 08:00 统计精准度与阈值建议,发 HTML 邮件和 Slack 摘要。
这次做成什么
搭一条“夜间采集 KPI→MAD 稳健基线→早晨 z 分数检测并去重→Claude 代理调查→按严重度路由 Slack/GitHub/Gmail→webhook 收集处置→每周精准度报告”的监控系统。完整模板涉及六张以上 Postgres 表与多个外部凭据,本站设计一个可先做通的独立练习:只建 kpi_metrics、kpi_observations 两张表 + 一个指标 + 本地 z 分数计算 + Slack 告警,跑通后再按原文 Setup 补齐 Claude 调查代理、GitHub issue、处置 webhook 和周报。
准备什么
- 一个 Postgres 实例及 n8n 可用的凭据(练习可用本地 Docker 起的隔离测试库,勿连生产库)
- OpenRouter API 凭据(走 Claude 模型,练习第一阶段可暂缓,接入后按用量计费)
- Slack 工作区及 n8n 凭据,替换模板中 ALERT_SLACK_CHANNEL 占位的告警频道
- GitHub 凭据与 Gmail 凭据(仅完整流程需要,用于 critical 事故建 issue 与发确认邮件)
- 至少 14 天历史数据(星期几基线需 21 天),不足时指标不会被评分
- 一个 DATA_ONCALL_EMAIL 值班邮箱地址
具体怎么做
建练习用表与指标定义
在测试库执行下方材料一的建表 SQL(本站简化版,仅两张表)。往 kpi_metrics 插入一个指标:metric_key=daily_signups、metric_sql=返回单个数值的 SQL、z_threshold=3.5、direction=both、owner_email=你的测试邮箱。注意原文要求每条 metric_sql 必须返回单个数值,带多行多列会让采集失败。
夜间采集:01:00 写入观测
Schedule Trigger 设每天 01:00(可先手动执行)。Postgres 节点查 kpi_metrics 中 enabled=true 的行,逐条用另一个 Postgres 节点执行其 metric_sql,把(metric_key、obs_date=昨天、value)插入 kpi_observations。重复执行时用唯一约束或先 DELETE 当日再 INSERT,避免重复行污染基线。
回填历史并重算基线
用下方合成数据一次性 INSERT 28 天历史观测。加一个 Postgres 节点按指标计算近 28 天中位数与 MAD(中位数绝对偏差),以及可选的星期几分组中位数;历史不足 14 天的指标跳过并记日志,完整模板此时会向 Slack 发“基线过薄”警告。本站练习 SQL 用 percentile_cont 算中位数,具体基线表结构与原文不同,以原模板查询为准。
早晨检测:07:00 z 分数与去重
07:00 触发:取昨日观测与其基线,用 Code 节点算稳健 z 分数(本站示例采用常见做法 z=0.6745×(观测值-中位数)/MAD,模板实际公式与系数请导入后核对)。|z|≥z_threshold 且绝对变化超过 min_abs_change 判定为异常。随后查近期 open/acknowledged 事故,同一指标已有未关闭事故则抑制告警并记日志,单次运行事故数设上限。
告警路由与(可选)Claude 调查
IF 节点按严重度分流:warning 仅发 Slack;critical 发 Slack + GitHub issue + Gmail 确认请求。练习阶段先把 Slack 通路做通:消息含指标名、昨日值、基线中位数、z 分数、owner。跑通后再接入 OpenRouter Claude 代理节点,挂上 Postgres(查相关观测)与 GitHub(查近期提交)两类工具,用下方材料二的系统提示词调查成因,并把结论连同证据校验结果写回事故记录。
处置 webhook 与周报
完整流程收尾:建 Webhook 节点(生产 URL),校验请求头中的鉴权字段与负载(incident_id、disposition∈confirmed/false_positive/wont_fix、note、actor),非法返回 400,合法则更新事故状态。再加周一 08:00 的 Schedule:统计已处置事故中 confirmed 占比得到精准度,生成阈值调整建议,发 HTML 邮件(Gmail)与 Slack 摘要。这两步依赖前文事故表,练习方案不实现,字段以原模板为准。
可直接复制的材料
练习用建表与合成数据 SQL
本站独立设计的练习脚本,在隔离测试库执行;为可读性 MAD 写法做了简化,正式用应子查询中位数。表结构非原模板真实 schema,导入原模板后以模板内查询为准。signups 表名需换成你测试库里的真实表。
CREATE TABLE kpi_metrics (
metric_key text PRIMARY KEY,
metric_sql text NOT NULL,
z_threshold numeric NOT NULL DEFAULT 3.5,
min_abs_change numeric NOT NULL DEFAULT 0,
direction text NOT NULL DEFAULT 'both',
owner_email text,
enabled boolean NOT NULL DEFAULT true
);
CREATE TABLE kpi_observations (
metric_key text NOT NULL,
obs_date date NOT NULL,
value numeric NOT NULL,
PRIMARY KEY (metric_key, obs_date)
);
INSERT INTO kpi_metrics VALUES
('daily_signups','SELECT count(*) FROM signups WHERE created_at::date = current_date - 1',3.5,50,'both','oncall@example.com',true);
-- 28 天历史观测(中位数约 1200,MAD 约 80,昨日 760 为异常低值)
INSERT INTO kpi_observations (metric_key, obs_date, value)
SELECT 'daily_signups', current_date - g,
1200 + (CASE WHEN g % 7 = 0 THEN -150 WHEN g % 7 = 6 THEN 180 ELSE (g * 37) % 60 - 30 END)
FROM generate_series(2, 29) AS g;
INSERT INTO kpi_observations VALUES ('daily_signups', current_date - 1, 760);
-- 基线计算(本站练习版)
SELECT metric_key,
percentile_cont(0.5) WITHIN GROUP (ORDER BY value) AS median,
percentile_cont(0.5) WITHIN GROUP (ORDER BY abs(value - 1200)) AS mad
FROM kpi_observations
WHERE metric_key='daily_signups' AND obs_date >= current_date - 29 AND obs_date <= current_date - 2
GROUP BY metric_key;Claude 调查代理系统提示词
本站编写的代理提示词,可粘贴进 n8n 的 AI Agent 节点系统提示;工具命名需与你在节点里实际挂的工具一致。OpenRouter 调用按用量计费。
你是数据值班调查员。一个 KPI 异常已确认:
指标:{{metric_key}},昨日值:{{value}},28 天中位数基线:{{median}},稳健 z 分数:{{z}},方向:{{direction}}。
你可以使用两个工具:
1. Postgres 查询工具:只允许只读 SELECT,用于查看该指标近 30 天观测、相关维度拆分和上游表的当日数据量。
2. GitHub 工具:查看该指标 owner 对应仓库近 48 小时的提交与发布记录。
调查要求:
- 先判断是数据管道问题(如上游表当日行数为 0、采集任务失败)还是真实业务变化。
- 每条结论必须附带证据(具体查询结果数字或提交哈希),没有证据的假设标为"未证实"。
- 输出 JSON:{"probable_cause": "...", "evidence": ["..."], "confidence": "high|medium|low", "suggested_action": "..."}
- 不要修改任何数据,不要猜测你没有查询过的系统状态。webhook 处置请求与 Slack 告警消息示例
本站设计的练习示例;共享密钥仅为演示占位,请生成独立测试密钥,不要复用任何真实密钥。webhook 的鉴权字段名以原模板节点配置为准。
处置 webhook 请求(POST 到生产 webhook URL):
Header: x-disposition-token: <在 n8n 中配置的共享密钥>
Body:
{"incident_id": 1042, "disposition": "false_positive", "note": "昨日为已知促销活动后的回落,属预期", "actor": "oncall@example.com"}
缺少 token 或 disposition 不在 confirmed/false_positive/wont_fix 时应返回 400。
Slack 告警消息模板(Text 字段):
:warning: KPI 异常 [{{severity}}] {{metric_key}}
昨日值 {{value}} | 基线中位数 {{median}} | z={{z}}
Owner: {{owner_email}}
调查结论:{{probable_cause}}(置信度 {{confidence}})
处置:回复 webhook 标记 confirmed / false_positive / wont_fix输入与输出示例
本站虚构演示,z 分数公式为本站练习采用的常见稳健算法,数字按输入推算,未真实运行模板;原模板实际系数请核对。
输入
指标 daily_signups:近 28 天中位数 1200、MAD 80,昨日观测 760;z_threshold=3.5,min_abs_change=50,direction=both;该指标当前无未关闭事故。对应输出
z = 0.6745 × (760-1200) / 80 ≈ -3.71,|z|=3.71 ≥ 3.5 且绝对变化 440 > 50,判定异常,severity=warning(未达 critical 档)。无重复事故,不抑制。Slack 收到::warning: KPI 异常 [warning] daily_signups 昨日值 760 | 基线中位数 1200 | z=-3.71,Owner: oncall@example.com。事故表新增 incident_id=1042。值班人员 POST 处置 {"incident_id":1042,"disposition":"false_positive","note":"促销后回落","actor":"oncall@example.com"},返回 200;若 disposition 写成 "ignore" 则返回 400。做完检查这些
- 01:00 采集后 kpi_observations 出现昨日行,且重复执行不会产生同指标同日期的第二行
- 历史不足 14 天的指标当日不被评分,日志中有跳过记录(完整流程还应收到基线过薄的 Slack 警告)
- 同一指标存在未关闭事故时新异常被抑制并有 suppressed 日志,单次运行事故数不超过上限
- webhook 缺鉴权头或 disposition 非法时返回 400,合法负载返回成功且事故状态被更新
- critical 事故同时产生 Slack 消息、GitHub issue 和 Gmail 确认请求三条记录,warning 只有 Slack
容易卡住的地方
- 必须先回填或连续采集至少 14 天(星期几基线 21 天),否则检测期什么都评不出来,这是最容易误判为模板坏了的点
- 每条 metric_sql 必须返回单个数值,返回多行多列会在采集节点直接报错
- MAD 为 0(指标长期不变)时 z 分数除零,需要对极小 MAD 做下限保护,练习 SQL 未处理此边界
- OpenRouter/Claude、Gmail、GitHub、Slack 四类凭据缺一不可跑完整流程,练习阶段可先只做 Postgres+Slack
- webhook 鉴权 token 要放 n8n 侧配置而非写死在消息里,泄漏后应能在凭据处直接更换
- 检测时间为模板设定的 01:00/07:00/周一 08:00,可按需改,但改动后注意采集要先于检测完成
本站借助AI整理来源事实,独立编写中文操作指南与示例。示例不代表实际运行结果;来源效果尚未由本站独立复现。付费模板与模型、服务费用分别计算。
- 原文标题
- Detect and explain KPI anomalies with Postgres, Slack, GitHub, Gmail and Claude
- 原作者
- Mina Saad
- 原始发布日期
- 2026-09-02T10:27:28.292Z
- 来源
- https://n8n.io/workflows/19059