1. 為什麼 ChatGPT App 需要指標與 SLO
想像團隊有兩種狀態。
第一種大家都按照「看起來能動」在過日子。只要使用者沒去投訴、也沒有在推特上抱怨——似乎就一切安好。 偶爾有人打開日誌,翻翻一長串文字,點點頭就關掉分頁。
第二種,團隊有幾個簡單的面板:
- 主要 MCP 工具的 p95 延遲。
- MCP 與 checkout 的 error‑rate。
- webhook 的可用性。
- 漏斗中的付款轉換率。
並且有 3–5 個 SLO: 「工具 recommend_gifts 的 95% 呼叫——快於 2 秒」、 「MCP‑tools 的錯誤占比 < 1%」、 「checkout 可用性 ≥ 99.5%」、 「從小工具到成功付款的轉換率 ≥ 10%」。
在第二種狀態下,你可以:
- 在出現抱怨之前就能快速知道應用出了點問題;
- 量化任何變更的效果(新推薦演算法、遷移 SDK、供應商新資費);
- 等到走到 Store 與審核的模組時,能坦然說:「我們有品質標準,也知道自己符合到什麼程度」。
我們會討論一些很直觀的事情:什麼是 p95、它為什麼比平均值更好,如何計算 error‑rate 與 availability,對含 webhook 的電商部分有哪些重要指標,以及如何把這些拼成簡單但有用的 SLO。 我們將以教學應用 GiftGenius 為例——一個包含 MCP 推薦工具、checkout 與付款 webhook 的電商情境。
2. ChatGPT App 的基礎指標:到底要量什麼
延遲:用 p50/p95/p99,而不是「平均」
延遲是從操作開始到其邏輯結束的時間。在我們的堆疊中有幾類這樣的操作:
- 呼叫 MCP 工具 recommend_gifts(挑選禮物);
- 呼叫在 ACP 中建立 checkout intent 的工具;
- 處理「付款成功」的 webhook。
重要的是,使用者在 ChatGPT 端看到的整體延遲我們只能部分控制。 有平臺的因素(模型推理、OpenAI 網路延遲),也有我們的部分——工具、後端、資料庫、支付服務商。 對於延遲的 SLI(Service Level Indicator——可量測的服務品質指標),通常量的就是我們這一段:從請求進入 App/MCP 到我們的伺服器給出回應。
平均回應時間在這裡很迷惑。若 90% 的請求在 100 毫秒內返回,而 10% 要花 5 秒,平均大約是半秒,圖表看起來「綠油油」。 但每十個使用者就有一個會遇到 5 秒的卡頓——UX 明顯受損。
因此業界習慣用百分位數:p50(中位數)、p95、p99。 p95 是指有 95% 的請求延遲低於這個值。 SRE 指南強調,百分位數「不會讓離群值藏在平均數裡」,能讓那 5–10% 常常落在分佈尾端的使用者的實際體驗被看見。
最簡單的理解是:p50 反映「典型」使用者的體驗,而 p95/p99 告訴你那些耐心的人到底有多痛苦,因為他們總是在「卡卡的」狀態。
Error‑rate:不成功請求的占比
Error‑rate 是某段期間內不成功請求數量占總請求數量的比例。 主要的資料來源通常是結構化日誌,或帶有標籤的指標資料 status="success" | "error"。
在我們的堆疊中,自然有幾種 error‑rate:
- MCP‑tools 層級:recommend_gifts 呼叫以錯誤結束的占比(例外、外部 API HTTP 5xx、逾時);
- ACP/checkout 層級:結帳嘗試不成功的占比(API 錯誤、支付服務不可用);
- webhook 處理層級:以失敗結束的 webhook 占比。
有個微妙之處:在 ChatGPT App 中會有「靜默」錯誤。 例如 MCP 工具回傳了錯誤,模型道歉後繼續對話,沒有把技術錯誤顯示在頂部。 形式上 ChatGPT 仍給使用者一個人類可讀的回應,但就可靠性而言,你的堆疊出了問題。 因此計算 error‑rate 時,重點是統計工程層面的狀態,而不是「GPT 的最終 UX 回覆」。
Availability:服務可用性
Availability 是某段期間內成功處理的請求百分比。 概念上它就是 error‑rate 的反向:看「成功了多少」,而不是「失敗了多少」。 典型公式:availability = successful_requests / total_requests * 100%。
在我們的堆疊中,可這樣套用:
- MCP 伺服器可用性:最近一小時 ChatGPT 發起的 JSON‑RPC 呼叫中,有多少得到正確回應;
- checkout‑API 可用性:對 /api/checkout 的請求中,HTTP 2xx 的占比;
- webhook 端點可用性:支付服務商送來的 webhook 中,有多少得到我們的正確回應(通常 HTTP 200)。
若支付提供商文件中承諾的可用性是 99.9%,而你只有 97%,那多半問題不在他們,而在你。
電商指標:轉換率與漏斗
GiftGenius 是電商情境。不僅要看技術面(回應快、錯誤少),還要看商業結果——推薦究竟多常轉成已付款訂單。
這裡就輪到轉換漏斗上場:
- 顯示了小工具的使用者(view);
- 選擇了禮物的使用者(selection);
- 點擊「開始結帳」的使用者(checkout started);
- 訂單狀態變成「已付款」的使用者(paid)。
由此可定義「從小工具到付款」的轉換率,這也屬於 SLI——可量測的服務品質指標。 例如:「每日成功付款數 / 看見小工具的使用者 = 7%」。 如果延遲突然升高或 checkout 有時會逾時,漏斗就會在意料之外的地方變窄。
如果你使用 Instant Checkout
上述電商指標同樣適用於基於 Agentic Commerce Protocol 的 Instant Checkout。 此時你不是用自有的 /api/checkout,而是用標準化的 Agentic Checkout API: ChatGPT 會呼叫你的 REST 端點 POST /checkout_sessions、 POST /checkout_sessions/{id}、 POST /checkout_sessions/{id}/complete (可選的還有 cancel 與 GET), 每次都從你這裡取得購物車與結帳的「真實」狀態。
對指標而言沒有任何改變:p95 延遲、error-rate 與 availability 不再針對任意的 /api/checkout 計算,而是針對這些標準 endpoint。 像「p95 checkout 延遲 < 3 秒、error-rate < 2%」的 SLO 直接套用到 checkout_sessions 呼叫,而不是自製 API。
另一個世界:webhook 指標
Webhook 是非同步事件(例如支付服務商的 payment_succeeded),推動訂單走完生命週期。 如果 webhook 處理不好,應用也許推薦得很漂亮,但訂單會停留在「等待付款」或某種不明確的狀態。
如果你不是直接整合 Stripe/支付,而是透過 Instant Checkout,那「支付的 webhook」這個角色就由 Agentic Checkout 的 order events 來承擔: 你的後端會把 order.created、order.updated 之類的事件,發送到 OpenAI 指定的 webhook URL。 這是同一類型的實體:決定訂單最終狀態的非同步事件,只是接收方不是你的前端,而是 ChatGPT。
因此,同樣的指標——success rate、latency、error-rate——你將不是算 Stripe webhook,而是算你發往 OpenAI 的 order‑event webhooks。 在 SLO 中可以直接寫:「至少 99% 的 order.* 事件在 7 天內送達並成功處理,p95 處理延遲 < 500 毫秒」——這對 Instant Checkout 來說是正確的 SLI/SLO。
對於 webhooks,通常會看:
- webhook success rate——包含重試在內,最終業務邏輯成功的 webhook 占比;
- webhook latency——從 webhook 進入到處理結束的時間;
- webhook error rate——處理 webhook 以錯誤結束的占比(驗證失敗、資料庫不可用、逾時等)。
例如,可以設定 SLO: 「至少 99% 的 webhook 在 7 天內成功處理」 以及「webhook 處理延遲的 p95 < 500 毫秒」。
3. 在 GiftGenius 中如何技術性地量測指標
從理論走向程式。我們需要弄清楚在哪裡加上量測,以便後續彙總成 p95、error‑rate 等指標。
為了不把特定的 Prometheus 或 Datadog 拉進講座,先假設我們有個簡單的 logMetric 函式,或是記錄 JSON 事件。任何觀測系統都能在此之上建出所需的圖表。
量測 MCP 工具的延遲
假設我們有一個用 TypeScript 寫的 GiftGenius MCP 伺服器,以及工具 recommend_gifts。 用計時器把商業邏輯包起來:
// mcp/tools/recommendGifts.ts
import { logMetric } from "../observability/metrics"; // 假想的 helper
export async function recommendGiftsTool(input: RecommendInput) {
const startedAt = performance.now(); // 開始時間
try {
const result = await recommendGifts(input); // 商業邏輯
const duration = performance.now() - startedAt;
logMetric("tool_latency_ms", duration, {
tool: "recommend_gifts",
status: "success",
});
return result;
} catch (error) {
const duration = performance.now() - startedAt;
logMetric("tool_latency_ms", duration, {
tool: "recommend_gifts",
status: "error",
error_type: "exception",
});
throw error;
}
}
這裡 logMetric 可以只是把 JSON 日誌寫到 stdout:
// observability/metrics.ts
export function logMetric(
name: string,
value: number,
labels: Record<string, string | number>
) {
// 實際上這裡會是 Prometheus/DataDog 用戶端
console.log(
JSON.stringify({
type: "metric",
name,
value,
labels,
timestamp: new Date().toISOString(),
})
);
}
用這種方式你會得到一串 tool_latency_ms 事件流,藉由 tool 與 status 這些 label,就能只針對成功呼叫計算 p95,或反過來觀察以錯誤結束的請求通常要跑多久。
計算 error‑rate
用相似方式可以記錄獨立的錯誤指標:
// 在同一個工具處理器裡
logMetric("tool_error_total", 1, {
tool: "recommend_gifts",
error_type: "external_api_timeout",
});
對於成功的請求:
logMetric("tool_success_total", 1, {
tool: "recommend_gifts",
});
接著在指標系統中建立 error_rate = tool_error_total / (tool_error_total + tool_success_total) 在某一期間的比值。 這部分由指標系統聚合;在應用中重點是穩定地丟出事件。
如果想要更極簡,也可以只用日誌而不單獨記 error_total。 這樣 error‑rate 就由 status 欄位來計算。
Checkout/ACP 的指標
對於 Next.js 的 checkout 端點,邏輯相同:用計時器包住處理器並統計狀態。
// app/api/checkout/route.ts
import { NextRequest, NextResponse } from "next/server";
import { logMetric } from "@/observability/metrics";
export async function POST(req: NextRequest) {
const startedAt = performance.now();
try {
const body = await req.json();
const result = await createCheckoutSession(body); // 呼叫 ACP/Stripe
const duration = performance.now() - startedAt;
logMetric("checkout_latency_ms", duration, { status: "success" });
logMetric("checkout_total", 1, { status: "success" });
return NextResponse.json(result, { status: 200 });
} catch (error) {
const duration = performance.now() - startedAt;
logMetric("checkout_latency_ms", duration, { status: "error" });
logMetric("checkout_total", 1, { status: "error" });
return NextResponse.json(
{ error: "Checkout failed" },
{ status: 500 }
);
}
}
現在可以查看 checkout_latency_ms 的 p95,以及 checkout_total 的 error‑rate。 基於這些 SLI,很容易設定 SLO,例如「p95 < 3 秒,error‑rate < 2%」。
Webhook 的指標
當然還有 webhooks。前面(第 2 節)說了哪些指標很重要,現在看看在程式裡要如何量。 這裡不只時間重要,還要記錄是否成功處理:否則使用者付了款,訂單卻沒有轉為「paid」。
// app/api/webhooks/payment/route.ts
import { NextRequest, NextResponse } from "next/server";
import { logMetric } from "@/observability/metrics";
export async function POST(req: NextRequest) {
const startedAt = performance.now();
try {
const payload = await req.text(); // 原始資料
const sig = req.headers.get("stripe-signature") || "";
const event = verifyStripeSignature(payload, sig); // 驗證
await handlePaymentEvent(event); // 更新訂單
const duration = performance.now() - startedAt;
logMetric("webhook_latency_ms", duration, {
type: event.type,
status: "success",
});
logMetric("webhook_total", 1, {
type: event.type,
status: "success",
});
return new NextResponse("ok", { status: 200 });
} catch (error) {
const duration = performance.now() - startedAt;
logMetric("webhook_latency_ms", duration, {
type: "unknown",
status: "error",
});
logMetric("webhook_total", 1, {
type: "unknown",
status: "error",
});
return new NextResponse("error", { status: 500 });
}
}
基於這些事件,可以定義 SLI:
- webhook success rate = success / (success + error);
- payment_succeeded 的 webhook_latency_ms p95。
然後為它們設定 SLO,例如「99% 的 webhooks 在 7 天內成功處理,p95 < 500 毫秒」。
4. 百分位數統計:再深入一點
我們已多次用到 p50/p95/p99,現在稍微更正式地看看它們的定義。 實務上百分位數會由指標系統來算,但理解背後在做什麼仍然很有幫助。
百分位數 pX 是指有 X% 的量測值位於該值之下。 若你把延遲的陣列由小到大排序,p95 會在「尾端」,接近最大值。 在程式中(例如在 Node 上,如果你想在本地對一組數值算 p95)大概可以這麼寫:
// 簡單的百分位數計算函式
export function percentile(values: number[], p: number): number {
if (values.length === 0) return 0;
const sorted = [...values].sort((a, b) => a - b);
const index = Math.ceil((p / 100) * sorted.length) - 1;
return sorted[Math.max(0, Math.min(index, sorted.length - 1))];
}
這種函式可用於測試或小腳本,玩玩資料、看看 p95 和平均值究竟差多少。 在生產環境,這件事交給 Prometheus、Datadog、New Relic 等成熟系統就好。
5. SLI、SLO 與 SLA:白話版
三個看起來可怕的縮寫,其實很簡單。
SLI — Service Level Indicator
SLI 是具體可量測的指標與公式。例如:
- 過去 24 小時內,工具 recommend_gifts 的延遲 p95;
- 過去 7 天內,MCP 工具的 error‑rate;
- 小工具 → 成功付款的週轉換率。
SLI 不是目標也不是承諾,它只是「溫度計」。
SLO — Service Level Objective
SLO 是針對 SLI 設定的目標,本質上是服務「健康條件」。例如:
- 「p95(latency recommend_gifts) < 2 秒,視窗為 7 天」;
- 「所有 MCP‑tools 的 error‑rate < 1%,視窗為 30 天」;
- 「checkout API 可用性 ≥ 99.5%,視窗為一季」;
- 「從小工具到成功付款的轉換率 ≥ 15%,視窗為一個月」。
好做法是先量出當前水位,再把 SLO 設得比現狀稍嚴一些,不然要嘛成了「不可能任務」,要嘛是「反正已經夠好」。
SLA — Service Level Agreement
SLA 不是內部目標,而是對使用者或合作方的外部協議。 在 SLA 中會寫清楚義務(例如「99.9% uptime」)與違反後果(補償、罰金、延長訂閱等)。 SLO 通常比 SLA 更嚴,以留出「錯誤預算」的空間。
在教學用的 GiftGenius 中你多半不需要 SLA,但要理解這個階梯:
SLI → SLO → SLA
指標 → 目標 → 對外承諾
Error budget(錯誤預算)
Error budget 簡而言之,就是可接受的「不完美」容量。 若你的 SLO 是「30 天內可用性 99.9%」,那 0.1% 就是錯誤預算,可以「花」在:
- 有停機的計劃性釋出;
- 實驗;
- 不可預期的事故。
當預算「燒完」時(例如實際上該月可用性只有 99.5%),就該暫緩新功能、優先修穩定性。
6. GiftGenius 的特殊指標:電商 + webhooks
把所有東西放在一起,從整體產品角度看 GiftGenius。
漏斗與轉換率
想像一個簡單的使用者旅程:
flowchart TD A[打開含有 GiftGenius 小工具的 App] --> B[收到推薦] B --> C[選擇禮物] C --> D[點擊「前往付款」] D --> E[付款成功]
對每個步驟,我們可以記錄事件:
logMetric("funnel_step_total", 1, {
step: "widget_view",
});
logMetric("funnel_step_total", 1, {
step: "gift_selected",
});
logMetric("funnel_step_total", 1, {
step: "checkout_started",
});
logMetric("funnel_step_total", 1, {
step: "checkout_paid",
});
接著,知道 widget_view 與 checkout_paid 的事件數,就能計算轉換率: paid / view * 100%。 並設定 SLO:「轉換率 ≥ 10%」。 若轉換率突然掉到 3%,而技術 SLI(latency/error‑rate)都正常,那可能是 UX、模型指示或商品 feed 品質的問題,而不是基礎設施。
把 webhook 指標納入轉換
我們已經談過 webhook 的技術指標與實作。現在要把它們和轉換串起來:在電商情境中,webhook 是關鍵。 使用者看到「付款完成」,但訂單最終狀態取決於你的後端多快接收並處理 payment_succeeded。
SLI(webhooks):
- webhook success rate;
- webhook latency 的 p95;
- 粗略的 webhook_endpoint_availability 可用性。
如果 webhook 的 success rate 下降,你就在實打實地流失訂單。
7. 基於 SLO 的簡易告警
完整的告警系統更偏運維主題,但現在可以先畫出基本面。
重點是針對SLO 的違反發送告警,而不是每一個單獨錯誤。 這常被稱為 symptom‑based alerts(基於症狀的告警)——聚焦在服務劣化的症狀:你關心的不是「發生一個錯誤」,而是「服務開始系統性地低於承諾」。
常見例子:
- 最近 5 分鐘 MCP‑tools 的 error‑rate > 2%,而 SLO 是 < 1%;
- 最近 10 分鐘 p95(latency recommend_gifts) > 3 秒,而 SLO 是 2 秒;
- 最近 15 分鐘沒有任何成功的 checkout_paid——懷疑整合掛了;
- 最近 10 分鐘 webhook success rate < 95%。
告警內容應該是人話,而不是「Alert: metric 123 > 456」。例如 GiftGenius 的 Slack 通知:
[ALERT][GiftGenius] High error rate on MCP tools:
error_rate = 3.2% (>1% SLO) for last 5 minutes.
Impact: part of users cannot receive gift recommendations.
Actions: check MCP logs and external gift API health.
這種訊息和 SLO 綁在一起,能幫 on‑call 開發者迅速判斷嚴重程度。
8. 小練習:替 GiftGenius 擬定 SLO
試著為我們的應用擬一組 SLO。即使沒有完整的指標系統,也可以先在紙上完成。
「起步」範例:
- 對主要 MCP 工具 recommend_gifts:
- SLI:過去 7 天成功呼叫的延遲 p95。
- SLO:p95(latency) < 2 秒。
- 對 MCP 工具的錯誤:
- SLI:error‑rate = errors / (errors + successes),視窗 30 天。
- SLO:error‑rate < 1%。
- 對 checkout API:
- SLI:availability = 所有請求中 HTTP 2xx 的占比。
- SLO:availability ≥ 99.5%,視窗一個月。
- 對付款 webhooks:
- SLI:webhook success rate。
- SLO:7 天內至少 99% 成功處理 webhooks;webhook 處理延遲的 p95 < 500 毫秒。
- 對商業成果:
- SLI:月度小工具 → 已付款訂單的轉換率。
- SLO:轉換率 ≥ 10–15%(視品類而定)。
就算只有這麼一小組,也足以提供決策的「骨架」: 如果你上線新模型、修改 prompt 或推薦演算法,看到 p95 與 error‑rate 仍在 SLO 範圍內,而轉換率上升——大概就算是成功的實驗。
如果你不是用自有的 checkout 端點,而是使用 Instant Checkout,那「checkout API」其實就是 Agentic Checkout 的呼叫(/checkout_sessions create/update/complete),而「付款 webhooks」就是你發送給 OpenAI 的 order events(order.created、order.updated)。指標與 SLO 的表述不變,只是協定不同。
9. 使用指標與 SLO 的常見錯誤
錯誤 №1:只量平均回應時間。
平均值方便但危險。它很容易掩蓋慢請求的尾巴。 在 ChatGPT App 中這點尤其致命:就算大部分使用者很快拿到結果,對那小部分人來說,固定的 5–10 秒延遲會被感知為「這 App 總是在卡」。 因此,延遲請至少用 p50 與 p95,不要只看 mean。
錯誤 №2:在腦中與文件裡混淆 SLI、SLO 與 SLA。
有時開發者會寫「我們的 SLA——p95 < 2 秒」,但其實這既未對外承諾,也沒有任何配套。 事實上那是 SLO。 SLA 是與客戶簽的協議,包含違規後果。 如果把一切混在一起,就沒人說得清到底你對誰承諾了什麼。
錯誤 №3:告警與 SLO 沒有關聯。
典型陷阱是「每個錯誤都告警」、每個逾時都吵、任何 0.01 的偏差都通知。 結果 on‑call 工程師活在通知地獄,最後乾脆不看了。 更好的做法是基於 SLO 的違反來告警:當 error‑rate 顯著超出目標、或 p95 超過界線時,再去打擾人。
錯誤 №4:忽視 webhook 與非同步部分的指標。
雖然單獨提出,但這問題我們已見過——忽略 webhook 與非同步部分的指標。 許多團隊只看主要 API 的 HTTP 回應,不關注 webhooks 與背景處理。 在電商情境,最討厭的 bug 常躲在那裡:付款完成了,webhook 沒被處理,訂單「卡住」。 沒有 webhook 的 success rate 與 latency 指標,你可能會長期以為「一切正常」,直到帳務數字與資料庫嚴重對不上。
錯誤 №5:不切實際的 SLO,或完全沒有。
有時 SLO 會被寫成「100% uptime」或「完全沒有錯誤」。 現實做不到,會讓團隊挫折。 另一個極端是完全不訂 SLO,一直活在「應該還行」。 黃金中道是:先量當前的 SLI,設定稍嚴但可達成的目標,隨著系統成熟逐步收緊。
錯誤 №6:只為了「有指標」而有指標,與產品脫節。
也常見這樣的情況:指標系統裡滿是圖表、p95、p99、數十個儀表板,但沒人能回答一個簡單問題: 「這條線如果跳起來——會影響什麼?使用者?收入?名譽?」 在 LLM 產品中特別要把技術指標(latency、error‑rate)和商業指標(轉換率、成功付款)串起來。 否則,可觀測性就只是漂亮但無用的電視機。
GO TO FULL VERSION