Ollama API 用量
Ollama 的每个推理响应都带性能指标:耗时、token 数、缓存命中情况。这些字段既能算吞吐量,也能定位性能瓶颈。
版本基线 v0.40.12,官方
docs.ollama.com/api/usage。
一、七个指标字段
| 字段 | 含义 | 单位 |
|---|---|---|
total_duration |
整个响应耗时 | 纳秒 |
load_duration |
模型加载耗时 | 纳秒 |
prompt_eval_count |
输入 token 数 | 个 |
prompt_eval_cached_count |
从缓存读取的输入 token 数 | 个 |
prompt_eval_duration |
评估未缓存输入 token 的耗时 | 纳秒 |
eval_count |
输出 token 数 | 个 |
eval_duration |
生成输出 token 的耗时 | 纳秒 |
所有时间单位都是纳秒(1 ms = 1,000,000 ns)。忘了换算会得到离谱的结论。
二、完整响应示例
{
"model": "gemma4",
"created_at": "2025-10-17T23:14:07.414671Z",
"response": "Hello! How can I help you today?",
"done": true,
"done_reason": "stop",
"total_duration": 174560334,
"load_duration": 101397084,
"prompt_eval_count": 11,
"prompt_eval_cached_count": 8,
"prompt_eval_duration": 13074791,
"eval_count": 18,
"eval_duration": 52479709
}
读一下这组数据就能看出不少信息:
- 总耗时 174.6 ms,其中模型加载占 101.4 ms——大头是冷启动
- 输入 11 token,其中 8 个命中缓存——前缀复用生效了
- 输出 18 token 用了 52.5 ms,约 2.9 ms/token
三、流式响应的指标在哪
流式模式下,这七个字段只出现在最后一个 chunk 里(done: true 那一行)。中间行只有 response 和 done: false。
所以想统计用量必须读到流结束,中途断开就拿不到指标。
四、三个实用计算
生成速度(tokens/s)
eval_count / (eval_duration / 1e9)
用示例数据:18 / (52479709 / 1e9) ≈ 343 tok/s。
这是最硬的性能指标——只算生成部分,不掺加载和输入处理。
首 token 延迟(估算)
(load_duration + prompt_eval_duration) / 1e6 # 毫秒
示例:约 114 ms。这个值决定用户点击到看到第一个字之间的等待感。
缓存命中率
prompt_eval_cached_count / prompt_eval_count
示例:8/11 ≈ 73%。
这个指标值得单独盯。多轮对话里前缀(系统提示 + 历史消息)是重复的,缓存命中率高意味着每次请求实际要重算的 token 少,响应快、成本低。命中率突然掉到 0,通常说明提示词前缀结构被改了(比如在开头插了变化的时间戳)。
五、指标的局限
- token 数是模型 tokenizer 的结果,不同模型对同一段文字计数不同,不能跨模型比较
- 纳秒精度不代表纳秒准确度,测量值受系统负载影响,做基准测试要多次取中位数
load_duration在模型已加载时为 0(或极小),所以冷启动和热调用要分开测
六、代码示例
import requests
r = requests.post("http://localhost:11434/api/generate", json={
"model": "gemma4",
"prompt": "用一句话解释什么是向量",
"stream": False,
})
d = r.json()
tok_s = d["eval_count"] / (d["eval_duration"] / 1e9)
print(f"输出 {d['eval_count']} tokens,{tok_s:.1f} tok/s")
print(f"模型加载 {(d['load_duration'])/1e6:.0f} ms")
if d["prompt_eval_count"]:
hit = d["prompt_eval_cached_count"] / d["prompt_eval_count"]
print(f"缓存命中率 {hit:.0%}")
动手试
连跑两次同一条命令,看 load_duration 的变化:
## 第一次:冷启动
curl -s http://localhost:11434/api/generate -d '{"model":"gemma4","prompt":"hi","stream":false}'
## 第二次:模型已在内存
curl -s http://localhost:11434/api/generate -d '{"model":"gemma4","prompt":"hi","stream":false}'
第二次的 load_duration 会接近 0,total_duration 大幅下降——这个对比能让你直观感受到 Keep-Alive 的价值。