1. 什麼是 ChatGPT Apps 世界中的事件
在傳統 Web 中,事件通常像是「伺服器掛了」、「500 錯誤暴增」、「latency 翻倍」。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 呼叫的請求占比 |
| Commerce | 結帳無法完成,款項不流動 | checkout_success_rate |
所謂事件,是指實際指標超出預先約定的 SLO 範圍的時刻。比如:
- 我們約定:禮物推薦的 p95 < 4 秒。現在變成 9 秒;
- 我們希望每週 99% 的 checkout 成功,結果只有 94%;
- 我們預期在購買情境中,模型幾乎都會呼叫 create_checkout_session,但從日誌看到「漏叫」急遽上升。
重要:事件不是「有人在聊天室抱怨」。抱怨只是觸發器;是否認定為事件,需依據 SLO/SLI 與儀表板。
2. SLO/SLI 如何轉變為事件
在 observability 模組中,你已經設定了關鍵指標: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 範圍。
同樣地,警報也可能因以下而觸發:
- error_rate 在 suggest_gifts、search_products 等工具上升;
- p95/p99 latency 上升;
- 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:10 分鐘內 checkout_success_rate < 60%;
- 延遲警報:p95(suggest_gifts) > 10 秒;
- 成本異常:「在 workflow_completed 數量相同的情況下,LLM 成本翻倍」。
手動偵測——當客服(或直接在你的 Telegram)收到大量訊息:「無法付款」、「小工具一直在轉圈」。有時正是這些訊息在監控反應之前就凸顯了問題。
實務結論:即便尚未有完美的監控,也請養成一個習慣——遇到大量用戶抱怨時,用指標的視角去看:「背後對應的是哪個指標?要如何量測?」
Triage — 分類與優先順序
偵測後要回答兩個問題:有多糟,以及誰要去修。
可以用一個簡單的嚴重性等級:
- SEV-1:嚴重——使用者無法購買,App 的關鍵流程無法運作(例如有流量時 checkout=0)。
- SEV-2:嚴重但為降級狀態——部分使用者無法完成流程,延遲大幅上升,但非完全不可用。
- SEV-3:次要缺陷——某個附加 tool 偶爾會掛,只影響邊界案例。
對 GiftGenius 而言,commerce 事件幾乎總是 SEV-1:只要錢不動,不只是技術問題,還會直接打擊營收與信任。
同一步也會指派 on-call(或如果你是單人團隊,就是你自己),並做出決定:「是的,這是正式的 SEV‑1 事件,依 runbook N 執行」(runbook 是事先寫好的逐步指引;其結構在後文說明)。
Mitigation — 先止血
Mitigation 不是尋找根因,而是採取快速措施,讓使用者少受影響。例子:
- 回滾最近的 MCP/Agents/ACP 版本;
- 關閉有問題的功能旗標;
- 將 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) 當作 mitigation 的一部分:至少讓使用者看到真實的說明訊息,而不是 500 或卡住的付款。
Resolution — 最終修復
當「出血止住」後,你就有時間找出根因並修復它:
- MCP/ACP 代碼中的 bug;
- 外部供應商問題(Stripe、支付閘道);
- OpenAI API 的限制(429、過載);
- prompt 損壞或更換了模型,以致不再呼叫 tool。
Resolution 通常包含:
- 修復(patch/rollback/設定調整);
- 先部署到 staging,之後再到 production;
- 檢查所有 SLI/SLO;
- 將旗標恢復為正常狀態。
Post-mortem — 從錯誤學習
事件之後,特別是 SEV‑1/SEV‑2,要做 post-mortem:一份文件,誠實回答:
- 發生了什麼(事實與時間線);
- 如何發現;
- 如何回應;
- 哪些做得好、哪些做得不好;
- 要做哪些變更避免再犯。
Post-mortem 不是找戰犯,而是改進系統與流程。根據它更新 runbook、警報,有時甚至是架構。
4. 角色與責任:即使你是「一人團隊」
要讓上述事件管線在現實中運作,必須預先約定:在失火期間,到底是誰對哪些決策負責。即使你的團隊小到能擠進同一部電梯,也值得在事件期間形式化角色,降低混亂。
常見的分工:
- On-call 工程師——第一時間接到警報,並對穩定性相關的技術決策負責(回滾、feature flags、暫時性遮罩)。
- 事件指揮官(Incident commander)——主導流程:記錄時間線、決定任務優先順序、避免團隊瞎忙。在小團隊中,可能就是同一位 on-call 換上不同「帽子」。
- 對外溝通——負責與使用者與業務利害關係人的溝通:Slack、狀態頁、App 介面(widget/聊天)、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 等。
- 快速 mitigation 步驟:「檢查 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: '警報:10 分鐘內 checkout_success_rate < 60%',
steps: [
{
title: '檢查外部服務狀態',
description: '查看 Stripe 與 ACP backend 的狀態,確認沒有全域性故障。',
},
{
title: '檢查最近的發佈',
description: '確認過去 30 分鐘內是否有 MCP/ACP 部署;必要時回滾。',
},
],
};
在真正的 runbook 裡,你會加入更多步驟:開啟唯讀旗標、在 widget 顯示橫幅、收集日誌以備 post-mortem。
Commerce 事件時給 widget 的文案範例
在 runbook 中預先設計使用者訊息很有幫助。例如,GiftGenius 的 widget 可以顯示:
«我們目前遇到付款的臨時技術問題。您仍可先保存喜歡的禮物點子,稍後再完成購買。」
之後就能把這段文案綁定到 UI 狀態:
// Widget 狀態的偽代碼
const [checkoutAvailable, setCheckoutAvailable] = useState(true);
if (!checkoutAvailable) {
return (
<Alert>
付款暫時無法使用。您仍可瀏覽並保存禮物點子。
</Alert>
);
}
6. 在 GiftGenius 的實作:環繞事件的程式碼
為了不讓主題只停留在流程,來看幾段直接協助事件管理的程式碼。
MCP/Backend 的 health-check 端點
最簡單但重要的工具——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。若開始出現逾時或 5xx,而非 200 OK,這就是 Availability 事件的明確信號(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 的轉換——呼應行銷與成長的模組;
- 瀏覽 security 日誌找異常:奇怪的登入模式、授權錯誤、異常的請求高峰(銜接安全模組)。
每季
每季你會:
- 輪換密鑰:OpenAI、Stripe、OAuth client 等 API 金鑰;
- 檢查 SLO 是否過時:也許 App 成長後 p95 2 秒而非 1 秒是合理,或相反地可以收緊目標;
- 檢視 runbook:新增事件類型、更新相依(SDK、MCP 規格等)。
行事曆可以只是 Wiki 頁或 GiftGenius 儲存庫裡的 README:重點是要「活著」並持續更新。
8. 事件、金錢與產品:為何 commerce 的火最燙
第 19 模組整體談的是 App 的經濟與「營運生命」,事件在此與金錢緊密相連。Commerce 事件——例如結帳失敗、款項被凍結或重複扣款——幾乎總是比隨機的禮物搜尋逾時更高優先級。
原因很簡單:
- 此刻的直接營收損失;
- 信任風險(被扣款卻拿不到商品的使用者很難回來);
- 潛在的法律與聲譽後果。
因此,在你的 GiftGenius 事件目錄中,commerce 事件應明確標示為 SEV‑1,且要有嚴格的反應 SLO(例如「on-call 需在 15 分鐘內回應,1 小時內完成 mitigation」)。
經濟異常(例如 LLM 成本在流量不增的情況下突然上升)也是事件,但通常屬於 SEV‑2:它不會立刻破壞 UX,但若忽視,可能吃掉所有毛利。
從產品角度看,任何大型事件都是思考的契機:
- 流程是否過於複雜(也許更簡單就更可靠);
- 是否需要加入 fallback 情境:例如 MCP 無回應時,模型至少回傳無外部資料的建議;
- 是否需要調整 UX,以誠實告知問題,而非隱藏它們。
9. 迷你練習(自行完成)
雖然是講座,但強烈建議你在自己的 GiftGenius 上實際完成以下步驟:
- 在同一份文件中描述至少兩個 runbook:
- 「大量付款(checkout)錯誤」;
- 「MCP 無回應/ChatGPT 顯示 Error talking to app」。
- 制定一個月的營運行事曆:
- 每週要看哪些 SLO;
- 月底要做哪些成本檢視;
- 要涵蓋哪些基本的 security 檢查。
這只花幾個小時,但會徹底改變你看待自己應用的方式:它不再只是程式碼,而是活生生的服務。
ChatGPT Apps 事件管理中的常見錯誤
錯誤 №1:「事件只有在全部掛掉時才算」
許多人習慣只把 MCP 或資料庫完全掛掉算作事件。在 AI‑Apps 中,往往更痛的是「柔性」的品質事件:模型不再呼叫所需的 tool、checkout 流程變得混亂、使用者到不了終點,雖然 HTTP 指標一片綠。如果你不把這些情況視為事件並加以檢討,App 的品質會在不知不覺中退化。
錯誤 №2:缺乏明確的 SLO 與「正常運作」邊界
沒有正式的 SLO,關於事件的爭論就會變成「我覺得很慢」對上「我本機很快」。這就是為什麼 SLO 被視為事件管理的基礎:它讓嚴重性變得客觀。
錯誤 №3:用即興代替 runbook
常見畫面:警報一來大家就慌了衝上線上環境,有人回滾版本,有人改設定;一小時後「好像修好了」,卻沒人記得究竟是什麼奏效。沒有 runbook,每個事件都是小型混亂,團隊也無從學習。就算只有一份簡單的 checkout 事件 runbook,也能大幅降低壓力。
錯誤 №4:忽視與使用者的溝通
有時工程師默默修系統,使用者此時只看到「轉圈圈」與「發生未知錯誤」。對 commerce 情境尤其有害:人們會為金錢著急。請事先備好 widget、App 說明,以及必要時對外管道的訊息模板,誠實說明問題與預計修復時間。
錯誤 №5:沒頭沒腦地怪「OpenAI 的錯」,卻不檢討自己那一段
把一切歸咎為「OpenAI 在當機」很容易,但實務上,即使上游出狀況,你仍可在自己的區塊做很多事:正確處理逾時與錯誤、切換到無 MCP 的模式、降低重試次數避免雪上加霜。Shared responsibility 的概念意味著,即便某個供應商不穩,你仍需對你負責的那段負責。
錯誤 №6:沒有 post-mortem 與營運循環
如果事件以「嗯,差不多好了,繼續」結束,而文件、警報、程式碼都不改——系統註定重蹈覆轍。Post-mortem、定期的 SLO/成本/安全檢視,這不是官僚主義,而是與未來的自己與團隊訂定合約,讓一年後的 GiftGenius 更可靠,而不是更脆弱。
GO TO FULL VERSION