API 可用率測試怎麼做:自己測 AI API 的指標、指令碼與統計口徑

部落格 / 效能

API 可用率測試怎麼做:自己測 AI API 的指標、指令碼與統計口徑

做 API 可用率測試,最簡單可靠的辦法是:每隔固定時間向介面發一個最小請求,記下狀態碼和耗時,按“成功 /(成功 + 服務端失敗)”算比例。難點不在指令碼,而在口徑:哪些錯誤算服務的、哪些算你自己的,樣本夠不夠,測的是入口還是真實推理。本文給出一個能直接跑的指令碼,再用 cdnping 和 AGI Plan 兩份公開資料說明,同一個服務換一種口徑,結論可能差很多。

合成探測和真實請求統計,測的是同一件事嗎?

不是。兩種常見做法:

  • 合成探測:由監控方定時發請求,例如每 5 分鐘訪問一次 API 入口。優點是間隔均勻,夜裡沒人用也有資料;缺點是請求很輕,往往只驗證到閘道器能響應,未必走到模型推理。
  • 真實請求統計:服務方把使用者真實請求的成功、失敗計數彙總出來。它反映的是使用者實際碰到的情況,但請求量隨作息起伏,凌晨樣本很少,一小時只有兩三個請求時,比例沒有統計意義。

cdnping 的 API 狀態頁 屬於前一種:從 Cloudflare 邊緣每 5 分鐘探測各官方 API 入口,具體做法寫在 資料方法。AGI Plan 公開的逐小時資料屬於後一種。AGI Plan 是 cdnping 的商業合作方,正好可以把兩種口徑放在一起看。

兩種口徑放在一起,差別有多大?

先看合成探測。cdnping 在 2026 年 10 月 17 日 18:05(北京時間)的快照,探測點為丹佛(DEN)。cdnping 當天才開始採集,欄位名雖然叫 24 小時,實際只覆蓋 16:40 到 18:05 約 85 分鐘、242 條探測記錄:

服務入口中位耗時 p50p95視窗內可用率
api.anthropic.com73 ms84 ms100%
api.openai.com96 ms194 ms100%
api.deepseek.com353 ms414 ms100%
api.moonshot.cn375 ms1125 ms約 94.4%
agiplan.dev883 ms883 ms100%

15 個入口裡只有 Kimi 開放平臺在這段時間出現過失敗,其餘都是 100%。

再看真實請求。AGI Plan 公開的逐小時計數,取 10 月 15 日 19 時到 10 月 17 日 18 時(北京時間)共 48 個小時,合計成功 13,963 次、平臺失敗 2,177 次,按公式算出來約 86.5%。失敗高度集中:10 月 16 日 14 時和 15 時這兩個小時分別有 722 次和 877 次失敗,單小時成功率約 48% 和 34%;凌晨 4 點到 6 點每小時只有 2 個請求,成功率 100% 也說明不了什麼。

同一快照裡 AGI Plan 按能力組給出的 30 天可用率也不一樣:快速組約 81.7%(44,729 次請求),前沿模型組約 94.4%,均衡組約 95.0%,國產模型組約 98.0%。

把兩邊對上:合成探測視窗內 agiplan.dev 入口 100% 可用,而同一時段(10 月 17 日 16 時到 18 時)的真實請求每小時都有 1 到 7 次失敗。這不矛盾,入口能響應只說明閘道器線上;上游模型返回 5xx 時,入口探測看不到。反過來,只看真實請求資料,又會在請求稀少的時段失去判斷依據。所以自己測的時候,兩種都要有,至少要清楚手上的數字屬於哪一種。

哪些錯誤應該算進不可用?

可用率的分母怎麼定,決定了結果。下面是一個可以直接沿用的分類表:

結果例子是否計入可用率說明
2xx200計為成功流式介面要確認讀到了結束事件
5xx500、502、503、504計為失敗服務方或閘道器的問題
超時、連線失敗DNS 失敗、TLS 握手失敗、讀超時單獨記錄,再判斷可能是服務,也可能是你的網路
429限流單獨統計和你的額度、併發有關,不宜直接算故障
其他 4xx400、401、403、404不計入引數、金鑰或許可權問題,是呼叫方的錯

AGI Plan 公開資料採用的就是“只有 5xx 算平臺失敗”的口徑。自己測的時候也建議把 4xx 排除在分母之外,但一定要把它們記下來:一個突然大量出現的 401 可能是金鑰被輪換,403 可能和地區或賬號狀態有關,這些要按服務條款處理,不是可用率問題。

超時最難歸因。比較實用的辦法是同時探測一個對照目標,例如 cdnping 自己的入口。對照目標也超時,多半是本機網路;對照正常、只有 AI 介面超時,再算到服務頭上。網路層的排查順序可以參考 Claude Code 連線超時和報錯怎麼排查。

動手:一個最小可執行的探測指令碼

下面的 Python 指令碼只用標準庫,相容 OpenAI 格式的介面(官方 API、雲廠商託管或聚合閘道器都可以)。每次執行發兩個請求:一個 GET /models 檢查入口,一個 max_tokens=1 的對話請求檢查推理鏈路,結果追加到 CSV。

#!/usr/bin/env python3
# probe.py: 每次執行探測一次,結果追加到 probe.csv
import csv, json, os, time, urllib.request, urllib.error

BASE  = os.environ["API_BASE"].rstrip("/")   # 例如 https://api.example.com/v1
KEY   = os.environ["API_KEY"]
MODEL = os.environ["API_MODEL"]              # 你實際在用的模型 id
OUT   = os.environ.get("PROBE_OUT", "probe.csv")

def call(kind, method, path, body=None):
    req = urllib.request.Request(BASE + path, method=method,
        data=json.dumps(body).encode() if body else None,
        headers={"Authorization": f"Bearer {KEY}",
                 "Content-Type": "application/json"})
    t0 = time.time(); status, err = 0, ""
    try:
        with urllib.request.urlopen(req, timeout=30) as r:
            r.read(); status = r.status
    except urllib.error.HTTPError as e:
        status = e.code
    except Exception as e:                    # 超時、DNS、TLS 等
        err = type(e).__name__
    ms = int((time.time() - t0) * 1000)
    return [int(t0), kind, status, ms, err]

rows = [
    call("entry", "GET", "/models"),
    call("infer", "POST", "/chat/completions",
         {"model": MODEL, "max_tokens": 1,
          "messages": [{"role": "user", "content": "ping"}]}),
]
with open(OUT, "a", newline="") as f:
    csv.writer(f).writerows(rows)

用 cron 每 5 分鐘跑一次:

# crontab -e
*/5 * * * * API_BASE=https://api.example.com/v1 API_KEY=sk-xxx API_MODEL=your-model PROBE_OUT=$HOME/probe.csv /usr/bin/python3 $HOME/probe.py

推理請求會消耗少量 token。每 5 分鐘一次、每次輸出 1 個 token,一天 288 次,成本可以忽略,但仍建議用單獨的金鑰,方便在賬單裡區分。不同介面地址的寫法可以對照 Claude Code 自定義 API 與 Codex、OpenCode 介面地址配置。

彙總時按上面的口徑計算,4xx 不進分母,429 和超時單獨列出:

awk -F, '$2=="infer"{
  if($3>=200 && $3<300) ok++;
  else if($3>=500) fail++;
  else if($3==429) rl++;
  else if($3==0) to++;
  else c4++
} END{
  if (ok+fail==0) { print "沒有可統計的樣本"; exit }
  printf "成功 %d  5xx %d  可用率 %.3f%%\n", ok, fail, 100*ok/(ok+fail);
  printf "429 %d  超時/連線失敗 %d  其他4xx %d\n", rl, to, c4
}' ~/probe.csv

如果超時最後確認是服務方的問題,把它併入 fail 再算一遍,兩個數字都留著。

要測多久,樣本才夠?

可以用算術估一下。每 5 分鐘一次,一天 288 個樣本,一次失敗就讓當天可用率掉 0.35 個百分點。想區分 99.9% 和 99.5%,樣本至少要上千個:1,000 個樣本里,前者約對應 1 次失敗,後者約 5 次,再少就分不開。按每 5 分鐘一次算,要三到四天起步;按月看需要約 8,640 個樣本,這時一次失敗約佔 0.01%。

幾條經驗:

  1. 只跑一天,只能看出有沒有大問題,別用來比較兩個服務誰更穩。
  2. 按小時出圖,比只看一個總百分比有用。上面 AGI Plan 的 48 小時資料,總數 86.5% 掩蓋了一件事:失敗主要集中在兩個小時裡。
  3. 請求很少的小時不要單獨下結論,可以設一個門檻,例如當小時樣本少於 10 個就標灰。
  4. 探測點要和你的使用者處在相近的網路環境。從境外機房測出來的結果,不代表國內辦公網的情況,延遲差異的成因可以看 AI API 延遲拆解。

怎麼拿公開資料和自己的資料對照?

自測最大的問題是不知道失敗是自己的網路還是服務方。可以拿幾份公開資料交叉看:

curl -s 'https://agiplan.dev/api/status/requests?month=2026-10' -o agiplan-2026-10.csv
curl -s 'https://agiplan.dev/api/status/requests?month=2026-10&format=json'

cdnping 的 /status/agiplan 頁面會映象展示這份資料。拿到後和自己的 probe.csv 按小時對齊:兩邊同時出現失敗,基本可以歸到服務方;只有你這邊失敗,先查本地網路和出口。

如果你測的是中轉站或聚合閘道器,可用率只是其中一項,計費方式、資料政策和模型一致性同樣要查,完整清單見 AI API 中轉站怎麼選:可用率、計費、資料政策 8 項檢查。經過 OpenRouter 這類路由時,同一模型在不同供應商上的可用率也會不同,參考 同一模型換個 OpenRouter 供應商,可用率能差多少。

上線前的檢查表

  • 探測分兩類:入口(/models)和推理(最小對話請求)
  • 2xx 計成功,5xx 計失敗,429、超時、其他 4xx 分開記錄
  • 同時探測一個對照目標,用來區分本地網路問題
  • 探測點和真實使用者處在相近的網路環境
  • 至少積累 3 到 4 天資料再做比較,報告時寫明視窗和樣本數
  • 按小時彙總,樣本過少的小時不單獨下結論
  • 使用獨立金鑰,遵守服務條款,不用探測去試探限流或地區限制

引用任何可用率數字時,都把來源、視窗和口徑寫在旁邊。本文的 cdnping 資料只有約 85 分鐘,AGI Plan 的逐小時資料是 48 小時,它們說明的是方法上的差別,不是長期結論。

相關文章

繼續閱讀