怎么自己测大模型 API 的延迟
直接回答
用你真实的提示词发几十个流式请求,记下第一个内容 token 到达的时间和流结束的时间,报告中位数和 95 分位数,不要报平均值。开源脚本 llm-latency 一条命令就能对任意 OpenAI 兼容或 Anthropic 原生接口做这件事,只需要 Python 3.9,不用装依赖。
公开的延迟数据,包括我们自己公开的那份,用的都是别人的提示词、别人的地区和网络。能描述你的用户的,只有从你的代码运行的地方测出来的数字。这一页讲怎么测。
1. 跑起来
git clone https://github.com/amdmsz/llm-latency && cd llm-latency
export LLM_API_KEY=sk-...
# OpenAI 兼容接口(Chat Completions)
python3 llm_latency.py --base-url https://api.openai.com/v1 --model gpt-6.1-sol -n 20
# Anthropic Messages API
python3 llm_latency.py --api anthropic --base-url https://api.anthropic.com --model claude-opus-5-5 -n 20任何支持这两种格式之一的网关或自建服务都一样用,把 --base-url 指过去就行。重复写 --model 可以一次对比多个模型。
输出是每个模型一行:
model n success ttft p50 ttft p95 total p50 total p95 tok/s p502. 换成你自己的提示词
默认的提示词很短。延迟和输入长度、模型要思考多久关系很大,所以要用有代表性的内容来测:
python3 llm_latency.py --base-url https://api.openai.com/v1 --model gpt-6.1-sol \
--prompt-file prompt.txt --max-tokens 1024 -n 50 --json run.json --csv run.csv--json 和 --csv 会保留每个请求的结果,方便回头看慢的那几个。
3. 各列是什么意思
| 列 | 含义 | 注意 |
|---|---|---|
ttft | 从发出请求到第一个可见内容 token 的秒数 | 推理模型包含思考时间,这正是用户实际等待的时间 |
total | 到流结束的秒数 | 随 max_tokens 和输出长度增长 |
tok/s | 输出 token 数除以生成时间 | 前面带 ~ 表示服务端没返回 usage,token 数是估算的 |
success | HTTP 2xx、至少有一个内容 token、流正常结束 | 流被截断、没有结束标记的请求,即使状态码是 200 也算失败 |
4. 三个会让数字失真的错误
报平均值。 少数几个特别慢的请求会把平均值拉离大多数请求的样子,同时又掩盖慢的那些到底有多慢。要报 p50 和 p95。
高估推理模型的输出速度。 服务端返回的 token 数通常包含思考 token,如果计时从第一个可见 token 才开始,就等于用全部 token 除以一部分时间。脚本分两种情况处理:OpenAI 格式下,服务端报告了思考 token 数就把它减掉;Anthropic 格式下,从 message_start 开始计时。如果你自己写测量代码,要先弄清你的 token 数包含了哪些。
相信 20 个请求算出来的 p95。 20 个样本的 p95 基本就是「最慢的那一个」。用来发现问题够了;要拿来定超时或告警阈值,得跑几百个。
5. 变成例行检查
只要有一个请求失败,脚本的退出码就不是 0,所以可以放进发布流程或定时任务:
python3 llm_latency.py --base-url "$BASE" --model "$MODEL" -n 10 --json "latency-$(date +%F).json" \
|| echo "LLM endpoint check failed"把 JSON 文件留着。攒一周的结果,比任何单次测量都更说明问题。
局限
- 每个请求都会被服务商计费。
-n别设太大,--max-tokens按实际情况设。 -c大于 1 时,测到的还包括限流和排队。这有用,但那是另一个数字。- 客户端计时包含你的网络。这正是目的所在,但也意味着在笔记本上和在服务器上测出来的结果不一样。
