营销仪表盘的异常检测:用 Gemini + Slack 在 CAC 飙升时告警
目录
三月的某个周二凌晨 4:11,我的 Slack 响了。Meta 渠道的 CAC(Customer Acquisition Cost, 获客成本)比 14 天基线高 47%,Gemini 在告警正文里把原因写了出来:一个广告组的 CPM(Cost Per Mille, 千次曝光成本)涨了 4 倍,原因是 Meta 的"自动扩展受众"功能在夜里悄悄把定向放宽了。8 点活动负责人被叫醒,暂停了那个广告组,11 点 CAC 恢复正常。整件事浪费的广告费:大约 2,400 美元。如果还是老办法,这个故障要跑 96 小时,损失会到 9,600 美元。
这就是 AI 异常检测的全部价值。阈值告警("CPA 超过 50 美元就报警")抓不到这件事,因为 47 美元这个数字本身看起来很正常。AI 抓得到,是因为它能把今天和过去 14 天的基线对比,做标准差检验,再——这是阈值做不到的部分——给出一个合理的原因。把原因写出来,告警才从"可以忽略"变成"必须看一眼"。
为什么阈值告警会失效
三种失效方式,都来自真实项目:
- 静态阈值不识别季节性。 黑色星期五 CPA 本来就该高 60%。$50 的阈值在每年 11 月都会触发,到了 12 月就被关静音。
- 阈值没有上下文。 SaaS 免费试用阶段 $42 的 CPA 算优秀,电商结算页 $42 的 CPA 算灾难。同一个数字,相反的含义。
- 阈值永远不解释原因。 "CPA > $50" 是一个事实。"CPA 涨了 47%,原因是一个广告组的 CPM 因自动扩展受众涨了 4 倍"是一个决定。Slack 里第二条会被点开,第一条会被 snooze 掉。
AI 异常检测不是要替换阈值,是补一层:和基线做统计对比,加上一条"命名原因"的指令,把数字变成故事。
数据准备(90 天、日级、三个来源)
把过去 90 天的日级 KPI 拉到一个 Google Sheet 的同一个标签页里。一行一天,一列一个指标。最少需要这些列:
date | channel | spend | impressions | clicks | conversions | revenue | cpm | ctr | cpa | roas数据来源:
- GA4——用 GA4 Data API 或 Supermetrics 拉,带 source/medium 维度
- Meta Ads——用 Marketing API,日级 + 广告组粒度(粒度一定要到广告组,只到渠道级别太粗,定位不到原因)
- Google Ads——同上,日级 + 广告系列粒度
设定每天 23:55 拉取。"今天"这一行会一直是不完整的当天,没关系——基线窗口用的是前 14 个完整的日子,对比也在当天结束之后才跑。
Gemini 提示词(真正干活的这一段)
这就是我每天晚上跑的那段提示词。把每个渠道过去 14 天的数据喂给 Gemini 当基线,把最近 3 天作为"候选窗口",问三件事:有没有异常、异常多大、最可能的原因是什么。
You are a marketing analytics assistant. Today is {TODAY_DATE}.
Below is the last 14 days of daily CAC values for each channel, with the most
recent 3 days marked as [CANDIDATE].
For each channel:
1. Compute mean and standard deviation over the 14-day baseline.
2. Compute the day-over-day change for the most recent [CANDIDATE] day.
3. Flag as ANOMALOUS if:
- the candidate value is more than 2 standard deviations from the
baseline mean, OR
- the day-over-day change is more than ±30%.
4. If ANOMALOUS, return:
- severity: red (>=2.5σ OR >=50% DoD) or yellow (2-2.5σ OR 30-50% DoD)
- metric and value
- delta vs baseline (%)
- one-sentence plausible cause, drawn from: channel mix shift,
audience saturation, creative fatigue, tracking/pixel break,
bid strategy change, auction pressure, audience auto-expansion
- one-sentence remediation suggestion
Output strictly as JSON. Do not summarize. Do not editorialize.
DATA:
{CHANNEL_DATA_JSON}提示词里有三处细节不能省:
- "from" 那个原因清单——把假设空间限定住,这样 Gemini 不会编出"推特爆红"或者"柠檬季节到了"这种原因。
- "remediation suggestion"——这是告警不被静音的关键。后面会讲"无修复建议不告警"的硬规则。
- "strictly as JSON"——不写这句,Gemini 偶尔会回一封客气的邮件,Slack 节点根本解析不了。
n8n 工作流(一个定时、三个节点、一个 Slack)
json{
"nodes": [
{
"name": "Nightly Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"parameters": { "rule": { "hour": 0, "minute": 5 } }
},
{
"name": "Read Sheet",
"type": "n8n-nodes-base.googleSheets",
"parameters": {
"operation": "read",
"sheetId": "YOUR_SHEET_ID",
"range": "A1:K2000"
}
},
{
"name": "Detect Anomalies",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"method": "POST",
"url": "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-pro:generateContent",
"headers": { "x-goog-api-key": "={{$env.GEMINI_API_KEY}}" },
"body": {
"contents": [{
"parts": [{
"text": "={{$json.prompt}}"
}]
}]
}
}
},
{
"name": "Parse + Filter",
"type": "n8n-nodes-base.code",
"parameters": {
"jsCode": "const out = JSON.parse($input.first().json.candidates[0].content.parts[0].text); return out.alerts.filter(a => a.severity === 'red' || a.severity === 'yellow');"
}
},
{
"name": "Slack Alert",
"type": "n8n-nodes-base.slack",
"parameters": {
"channel": "#marketing-alerts",
"text": "={{$json.severity.toUpperCase()}} — {{$json.channel}} {{$json.metric}} {{$json.delta}}%\nCause: {{$json.cause}}\nFix: {{$json.remediation}}"
}
}
]
}Parse + Filter 这个节点是真正的主角。少了它,工作流每天都会往 Slack 推一条"今天没有异常"。加上它,平时安静,只在有人需要看的时候才响。安静的日子才是这个系统该有的状态。
硬规则:没有修复建议,就不告警
这条规则决定系统能活过第三个月,还是被全员静音。每条告警都必须带一句修复建议。如果 Gemini 给不出有把握的建议,这条告警不发——改成进每日摘要。
账很好算:一条写"Meta CAC 涨了 47%"的告警,会教团队忽略这个频道。一条写"Meta CAC 涨了 47%——广告组 X 的 CPM 涨了 4 倍,大概率是自动扩展受众触发的,先暂停这个广告组,再回去看 Advantage+ 受众设置"的告警,是另一个东西。团队能在 30 秒内做完决定,他们就会去做。我跑这套系统的头 30 天里,14 条告警里团队处理了 11 条。同样数据上跑纯阈值系统,触发了 47 次,处理了 4 次。AI 版本被点开的原因只有一个:有严重等级、有命名原因、有修复建议。
这条规则的另一面也要看:发出来但没人能动手的告警,说明数据层有问题,不是告警系统的问题。回去改数据层。
这套系统能抓到什么
4 点钟的 Meta CPM 暴涨只是最简单的案例。过去半年里它还抓到过:
- 一个周五下午 Google Ads 的转化追踪断了,如果不告警,周末报表会显示"业绩超好"
- iOS 归因模型的一次调整,一夜之间让 Meta 报告的转化掉了 22%
- 一次落地页改版,把付费社交的 CPA 悄悄拉到了 3 倍
- 一个竞品进入某个关键词组的竞价,在某个广告系列上只表现为 CPM 偏移 2.3σ
这些没有一个长得像"CPA > $50"。它们都是被"统计基线 + 命名原因"这个组合抓到的。这就是整个系统。