1. 什么是 ChatGPT Apps 世界里的事件
在经典 Web 场景中,事件通常类似于“服务器宕了”“500 错误明显增多”“延迟翻倍”。ITIL 的形式化定义:事件是服务的非计划性中断或服务质量的下降。
在 ChatGPT Apps 与 GiftGenius 的世界里,情况更复杂。我们引入了模型这一层,它们可能会:
- 不调用需要的 tool,尽管一切都可用;
- 用错误的参数调用 tool;
- 忽略你的 MCP,“幻想”出结果。
因此,事件不仅是 HTTP 500,也可能是在所有后端指标都为绿色时,用户却大量抱怨:“机器人卡住了,不展示礼物”——原因是模型不再调用 suggest_gifts 或混淆了参数。这就是质量类事件(Quality incident)。
把事件按类别来思考会更方便:
| 类别 | 症状示例 | 指标示例(SLI) |
|---|---|---|
| Availability(可用性) | MCP 无响应,ChatGPT 中出现 “Error talking to app” | % 成功响应 /mcp |
| Latency(延迟) | 礼物筛选耗时超过 10 秒 | suggest_gifts 调用时间的 p95 |
| Quality(质量) | 模型不调用所需的 tool,或把货币搞混 | 在明确需要时未发起 tool-call 的请求占比 |
| Commerce(交易) | 结账无法完成,资金不流转 | checkout_success_rate |
当实际指标超出事先约定的 SLO 边界时,就构成了事件。例如:
- 我们约定:礼物筛选的 p95 < 4 秒。现在变成了 9 秒;
- 我们希望每周 99% 的 checkout 成功,但现在只有 94%;
- 我们期望在购买场景中,模型几乎总会调用 create_checkout_session,但从日志中看到“漏调”突然增多。
重要:事件并不是“有人在群里抱怨”。抱怨是触发器,而“这确实是事件”的判断需要基于 SLO/SLI 和仪表盘来做出。
2. SLO/SLI 如何触发事件
在可观测性模块里,你已经设定了关键指标:latency、availability、error-rate、checkout 成功率。现在把它们当作“门口的守卫”来用。
最简单的场景:我们针对 checkout_success_rate 设定了 SLO。我们记录结构化的事件日志:
// MCP 服务器中的 checkout 日志事件示例
logger.info({
event: 'checkout_result',
request_id,
user_id,
checkout_session_id,
status: 'success', // 或 'failed'
error_code: null,
});
在这些日志之上构建指标:最近 N 分钟/小时里,所有 checkout_result 中 status = "success" 的占比。当该占比低于阈值(例如 10 分钟内低于 95%)时,监控会向 on-call 通道发送告警。这就是事件检测:SLI 超出了 SLO 的范围。
同样地,还可能触发以下告警:
- suggest_gifts、search_products 等工具的 error_rate 上升;
- p95/p99 延迟上升;
- workflow_completed 数量异常下降(用户未走完整流程);
- 在流量不变的情况下,LLM 成本异常上升(经济类事件)。
这一切的前提是我们采用结构化日志,而不是在日志里写“checkout 又不对劲了”。当指标与告警就绪后,我们就具备了“发现异常”的能力。接下来:检测之后会发生什么?谁来响应?如何响应?
3. 事件生命周期:从检测到事后复盘
为了不一直处于“救火模式”,最好描述一个标准流水线。许多 SRE 团队会把它形式化为一条链:
flowchart TD
D["Detection (检测)"] --> T["Triage (严重性评估)"]
T --> M["Mitigation (快速止血)"]
M --> R["Resolution (最终修复)"]
R --> P["Post-mortem (复盘与改进)"]
我们以 GiftGenius 为例拆解各阶段。
Detection —— 如何判断状况变糟
问题的发现既可以是自动的,也可以是人工的。
自动发现——来自基于 SLO/SLI 的监控告警:
- PagerDuty / Opsgenie / 邮件 / Slack 机器人在叫:SEV-1: checkout_success_rate < 60% 持续 10 分钟;
- 延迟告警:p95(suggest_gifts) > 10 秒;
- 成本异常:“在 workflow_completed 数量不变的情况下,LLM 成本翻倍”。
人工发现——当支持渠道(或者直接在你的 Telegram)里涌入大量消息:“支付失败”“小部件一直在转圈”。有时这会先于监控信号把问题暴露出来。
实践结论:即便你还没有完美的监控体系,遇到用户的集中抱怨,也要尝试用指标视角来看——“背后对应哪条指标?如何量化?”。
Triage —— 分类与优先级
检测之后要回答两个问题:问题有多严重,以及由谁来修。
采用一套简明的严重性分级很有用:
- SEV-1:致命——用户无法完成购买,App 的关键流程失效(例如有真实流量时 checkout=0)。
- SEV-2:严重但可降级——部分用户无法完成流程,延迟显著升高但非完全不可用。
- SEV-3:次要缺陷——某个附加 tool 偶发报错,仅影响边缘场景。
对于 GiftGenius,交易类事件几乎总是SEV-1:一旦资金不流转,问题不仅技术层面严重,也会直接影响营收与信任。
在这一步还需要指定 on-call(如果是一人团队,那就是你自己),并做决定:“是的,这是正式的 SEV‑1 事件,按第 N 个 Runbook 执行”(Runbook 是预先写好的分步操作手册;结构我们会在后文单独讲)。
Mitigation —— 快速“止血”
Mitigation 不是为了寻找根因,而是用快速措施降低用户受影响的程度。示例:
- 回滚最近的 MCP/Agents/ACP 发布;
- 关闭有问题的功能开关(feature flag);
- 把 GiftGenius 切到“只读/浏览”模式:仍展示推荐,但不允许下单;
- 临时降低负载(rate limiting)或关闭重型工具。
以下是我们 MCP 中“降级模式”的典型伪代码:
// 伪代码:可快速切换的全局开关
let checkoutDisabled = false;
export function setCheckoutDisabled(value: boolean) {
checkoutDisabled = value;
}
export async function createCheckoutSession(args: CheckoutArgs) {
if (checkoutDisabled) {
// 告诉模型,支付暂时不可用
return {
error: 'checkout_temporarily_disabled',
message: '支付暂时不可用,请向用户展示说明。',
};
}
// 常规的会话创建逻辑
}
在功能开关系统中,你可以在缓解阶段调用 setCheckoutDisabled(true):用户至少不会再遇到 500 或卡住的支付,而是看到明确的提示。
Resolution —— 最终修复
当“止血”完成后,你就有时间去定位根因并修复它:
- MCP/ACP 代码中的缺陷;
- 第三方服务提供商问题(Stripe、支付网关);
- OpenAI API 限流(429,过载);
- Prompt 损坏或模型更换导致不再调用 tool。
Resolution 通常包括:
- 修复(补丁/回滚/配置);
- 先部署到 staging,再到 production;
- 核对所有 SLI/SLO;
- 把各类开关恢复到正常状态。
Post-mortem —— 从错误中学习
在事件之后,尤其是 SEV‑1/SEV‑2,要做事后复盘(post-mortem):一份文档,诚实回答以下问题:
- 发生了什么(事实与时间线);
- 如何被发现;
- 如何响应;
- 哪些做得好、哪些不足;
- 你会做哪些改变以避免复发。
Post-mortem 不是“找替罪羊”,而是改进系统与流程。基于它可以更新 Runbook、告警,甚至架构。
4. 角色与职责:即便你是“一人团队”
要让上述事件流水线在现实中有效运行,关键是预先约定“火灾”期间谁对哪些决策负责。即便你们的团队很小,也值得把事件中的角色形式化,这能显著降低混乱。
通常会划分以下角色:
- On-call 工程师——第一时间接收告警,做出稳定性相关的技术决策(回滚、功能开关、临时挡板)。
- Incident commander(事件指挥官)——主导流程:记录时间线,确定任务优先级,避免团队四处乱撞。在小团队里这可能与 on-call 是同一人,只是“换一顶帽子”。
- 沟通负责人——对外沟通:在 Slack、状态页、App(小部件/聊天)以及 ChatGPT 商店中发布信息。
- Scribe(记录员)——记录关键步骤与事实,之后据此撰写 post-mortem。
在一人团队中,这四个角色都是你自己,但最好有意识地切换模式:“现在我在修”“现在我在沟通”“现在我在记录时间线”。
5. Runbook:让制度替代记忆
Runbook 是一份文档,分步骤说明遇到某类事件时该怎么做:看哪些图、按哪些按钮、可以牺牲什么。它能显著减少临场发挥与压力。
Runbook 的结构
通常 Runbook 包含:
- 事件的简要描述与检测方式。例如:“ACP checkout 错误 > 5% 持续 5 分钟”或“超过 20% 的请求出现 Error talking to app”。
- Scope —— 影响范围:全量流量、特定区域、还是具体某个 tool。
- 观测入口:仪表盘链接(checkout SLO、MCP error-rate、tool_name = create_checkout_session 的日志)、MCP Inspector 等。
- 快速缓解步骤:“检查 Stripe 状态”“回滚最近的 ACP 发布”“开启只推荐不购买的模式”。
- 最终排查与修复步骤。
- 事后需要更新的内容:告警、代码、文档。
GiftGenius 的 Runbook 迷你示例(checkout 失败)
我们用结构化数据来描述它,更贴近代码:
type Severity = 'SEV-1' | 'SEV-2' | 'SEV-3';
interface RunbookStep {
title: string;
description: string;
}
interface Runbook {
id: string;
title: string;
severity: Severity;
detection: string;
steps: RunbookStep[];
}
export const checkoutFailureRunbook: Runbook = {
id: 'rb-checkout-failure',
title: 'GiftGenius 中 checkout 错误增长',
severity: 'SEV-1',
detection: '告警:checkout_success_rate < 60% 持续 10 分钟',
steps: [
{
title: '检查外部状态',
description: '打开 Stripe 与 ACP backend 的状态页,确认没有全局性故障。',
},
{
title: '检查近期发布',
description: '确认过去 30 分钟内是否有 MCP/ACP 部署。如有必要进行回滚。',
},
],
};
在真正的 Runbook 里,你会补充更多步骤:开启只读功能开关、在小部件中展示横幅、为 post-mortem 收集日志等。
commerce 事件时的小部件文案示例
提前把用户可见的文案写进 Runbook 很有用。例如,GiftGenius 的小部件可以展示:
“我们目前遇到支付方面的临时技术问题。你仍然可以保存喜欢的礼物灵感,我们稍后再完成购买。”
随后可把文案固化为 UI 状态:
// 小部件的伪代码状态
const [checkoutAvailable, setCheckoutAvailable] = useState(true);
if (!checkoutAvailable) {
return (
<Alert>
支付暂时不可用。你仍然可以浏览和保存礼物灵感。
</Alert>
);
}
6. GiftGenius 实操:围绕事件的代码
为了不让这部分停留在组织流程层面,我们来看几段直接有助于事件管理的代码。
MCP/Backend 的健康检查(Health-check)端点
最简单但很重要的工具——健康检查。在 Next.js 16 中可以通过 route handler 来实现:
// app/api/health/route.ts
import { NextRequest, NextResponse } from 'next/server';
export function GET(_req: NextRequest) {
// 可在此加入数据库、队列等检查
return NextResponse.json({
status: 'ok',
mcp: 'healthy',
timestamp: new Date().toISOString(),
});
}
监控系统会定期轮询 /api/health。如果不再返回200 OK,而是超时或 5xx,就明确地提示为可用性事件(MCP 不可用)。
基于指标的事件分级
在分析服务或管理后台脚本中,可以保留一段简单的严重性判断逻辑:
type Severity = 'SEV-1' | 'SEV-2' | 'SEV-3';
interface IncidentContext {
checkoutSuccessRate: number; // 0..1
giftSearchErrorRate: number; // 0..1
p95GiftSearchMs: number;
}
export function classifyIncident(ctx: IncidentContext): Severity | null {
if (ctx.checkoutSuccessRate < 0.6) return 'SEV-1'; // 资金不流转
if (ctx.giftSearchErrorRate > 0.3 || ctx.p95GiftSearchMs > 8000) return 'SEV-2';
return null; // 暂不构成事件
}
这段逻辑可以通过定时任务运行,或由监控触发:一旦返回 SEV‑1,就自动在你的系统中创建事件并向 on-call 发送通知。
记录事件的关键状态变更
事件不仅是指标曲线,还有关键事件:创建、缓解、关闭。把它们记录到独立日志中会很方便。
function logIncidentEvent(event: {
incidentId: string;
type: 'created' | 'mitigated' | 'resolved';
severity: Severity;
requestId?: string;
message: string;
}) {
logger.warn({
level: 'WARN',
service: 'incident-manager',
...event,
timestamp: new Date().toISOString(),
});
}
例如,当为 GiftGenius 开启“只读”模式:
setCheckoutDisabled(true);
logIncidentEvent({
incidentId: 'inc-2025-11-21-001',
type: 'mitigated',
severity: 'SEV-1',
message: 'Checkout disabled, app switched to recommendations-only mode',
});
之后就能很容易将这些事件与时间序列指标进行对照。
7. 运营日历:不是“修好就万事大吉”
事件管理不仅是“救火”,还包括规律性的预防。在 SRE 实践中,运营周期常以运营日历呈现,定期回顾 SLO、成本与安全。
可以按周期性大致划分活动。
每周
每周(或每两周)可以:
- 查看核心 SLO:latency、error-rate、checkout 成功率、各类事件占比;
- 回顾一周内是否有会自行恢复的告警,并决定是否需要调整阈值强度;
- 简要复盘至少一个事件(哪怕是 SEV‑3)——锻炼 post-mortem 的“肌肉”。
每月
每月建议:
- 做一次成本复盘(LLM、ACP/Stripe 手续费、基础设施)并与收入对比——关联第 19 模块的 1–2 个主题;
- 查看产品指标:activation、retention、workflow_completed → checkout_success 的转化——关联营销与增长模块;
- 快速扫描安全日志是否有异常:异常登录模式、授权错误、请求的异常峰值(与安全模块呼应)。
每季度
每季度你可以:
- 轮换密钥:OpenAI、Stripe 的 API key,OAuth 客户端等;
- 检查 SLO 是否过时:也许 App 成长后 p95 从 1 秒到 2 秒是新常态;或相反,你可以收紧目标;
- 审视 Runbook:加入新的事件类型,更新依赖(SDK、MCP 规范等)。
运营日历可以简单地放在 Wiki 页面或 GiftGenius 仓库的 README 中;关键是保持“活文档”,持续更新。
8. 事件、金钱与产品:为什么交易类“火情”最急
第 19 模块整体讨论 App 的经济与“运营生命”,事件与金钱高度相关。交易类事件——例如结账无法完成、资金被冻结或重复扣款——往往优先级高于偶发的礼物搜索超时。
原因很简单:
- 即时的营收损失;
- 信任风险(被扣款却拿不到商品的用户很难再回来);
- 潜在的法律与声誉后果。
因此,在 GiftGenius 的事件目录中,交易类事件应明确标注为SEV‑1,并设定严格的响应 SLO(例如“on-call 15 分钟内响应,1 小时内完成缓解”)。
经济性异常(例如在收入不变的情况下 LLM 成本突然飙升)同样是事件,但通常为SEV‑2:它不会立刻破坏 UX,但若不发现可能“吃掉”全部利润。
从产品角度看,任何重大事件都是反思的契机:
- 流程是否过于复杂(更简单也许更可靠);
- 是否需要加入后备方案:例如 MCP 不可用时,模型至少给出不依赖外部数据的建议;
- 是否需要修改 UX,以诚实地告知问题,而不是掩盖它。
9. 迷你练习(供自学)
虽然这是讲座而非实操课,但强烈建议你在自己的 GiftGenius 上真正做以下事情:
- 在一份文档中描述至少两个 Runbook:
- “支付(checkout)大量失败”;
- “MCP 无响应 / ChatGPT 显示 Error talking to app”。
- 制定一个月的运营日历:
- 每周你要看哪些 SLO;
- 月底要做怎样的成本复盘;
- 要纳入哪些安全检查(哪怕是基础项)。
这些事情只需几个小时,但会极大改变你看待自己应用的方式:它不再只是代码,而是一个活的服务。
ChatGPT Apps 事件管理中的常见错误
错误 №1:“只有彻底挂了才算事件”
很多人习惯只把 MCP 或数据库的完全宕机视为事件。在 AI Apps 中,更“温和”的质量类事件往往更致命:模型不再调用需要的 tool,checkout 流程变得混乱,用户无法走到终点,尽管 HTTP 指标一片绿色。如果你不把这类情况当作事件去复盘,App 质量会在无形中持续下降。
错误 №2:没有明确的 SLO 与“正常工作”边界
缺少形式化的 SLO,关于事件的讨论就会沦为“我觉得很慢” vs “我本机很快”。这正是 SLO 成为事件管理基石的原因:它让严重性变得客观。
错误 №3:用即兴发挥代替 Runbook
常见场面:告警来了,大家慌忙上产,有人回滚,有人改配置,一个小时后“好像修好了”,但没人记得到底什么起了作用。没有 Runbook,每次事件都是一次小型混乱,团队也得不到学习。哪怕只为 checkout 写一个简单的 Runbook,也能显著降低压力。
错误 №4:忽视与用户的沟通
工程师在默默修,用户却只看到“转圈”和“出错了”。对交易场景尤为致命:人们担心钱款。因此要预先准备好在小部件、App 描述,以及必要时外部渠道上的消息模板,坦诚说明问题与预计恢复时间。
错误 №5:把锅甩给 OpenAI,而不检视自己的责任
把一切归咎于“OpenAI 不稳定”很容易,但实践表明,即便上游有问题,你仍可以在自己的一侧做很多事:正确处理超时与错误、在 MCP 不可用时切换到降级模式、减少重试次数避免雪上加霜。共享责任(shared responsibility)的理念意味着,即使某个供应商不稳定,你也要对自己这段链路负责。
错误 №6:没有 post-mortem,也没有运营周期
如果一个事件以“行了,继续干”收尾,而文档、告警与代码都不更新——系统注定会重蹈覆辙。post-mortem、定期的 SLO/成本/安全回顾并非官僚主义,而是与你的“未来的自己与团队”达成契约,让一年后的 GiftGenius 更可靠,而非更脆弱。
GO TO FULL VERSION