Ollama 提示词缓存——改在哪里,决定账单大小
同一台全新虚拟机上跑了六个探针:完全重复的请求只重估 1,539 个 token,耗时 0.2 s,而冷启动那次为 75.6 s 买单——可一个词被挪到提示词中部,就又收回 49 s。缓存不是开关,它是一座边境关卡:你改在哪里,账单就开在哪里。六张账单摆在一起,差距 370×,而开关从未被碰过。
verify: 六个探针、一台全新虚拟机、seed 42 · temp 0 · ollama 0.40.16 · 回执在下方,日志 promptcache-2026-11-12.log
Fig 1 — 六个探针,同一条提示词。变暗的柱子就是回执:提示中部的编辑付掉了冷账单的 65%,而重排开出的价码比冷加载本身还高。
ollama 的提示词缓存到底存了什么?
不是你的文本。ollama 评估提示词时,会为每个 token 算一个 KV 张量——该 token 对其之前所有内容的注意力足迹——模型驻留期间,runner 把这些张量留在 RAM 里。新提示会与这份库存从头部开始、逐 token 比对。凡是精确延续旧前缀的 token 都免费。第一个不同的 token 就是边境:从那里到结尾的一切都按全价重读。这正是我们 KV-cache 那篇讲卸载时机时的同一份 KV 驻留——服务速度的缓存,就是占住 RAM 的缓存(而 keep_alive 决定两者各自活多久——账单里算尺寸的那一半归上下文窗口那篇)。
keep_alive。为什么完全重复只花 0.2 秒?
探针是:一条 1,539 token 的提示词——八个编号章节的 fixture 日志事实,加一个问题——在全新虚拟机上冷启动提问。引擎以 20.4 tok/s 读完全部 1,539 个 token,提示评估计费 75.6 s。同一问题,模型仍驻留时原样重发:0.2 s。同一个 endpoint,同一个 body,什么都没拨动——ollama 不需要 flag、不需要 cache: true、不需要预热咒语就做到了。你每次重复提问都在享受这笔折扣;这篇讲的是怎么别把它交回去。
curl http://localhost:11434/api/generate -d '{
"model": "qwen3:4b",
"prompt": "<your 1,500-token prompt>",
"keep_alive": "45m",
"think": false,
"options": {"seed": 42, "temperature": 0, "num_predict": 128}
}'
verify: P1 冷启动 75.6 s → P2 重复 0.2 s,探针 body 逐字节一致,模型驻留 · promptcache-2026-11-12.log
你改在哪里,决定你付多少
我们保住 1,539 token 的正文,只挪一个词,挪三种地方。改最后一句里的词:4.2 s——共享的头部活了下来,只有尾部被重读。在问题之后追加一句:1.4 s——近乎全中,五个新 token 按边际计费。改第 41/96 条事实里的一个词,正文中部:49.2 s——冷账单的 65%,只为挪动一个形容词。缓存有大象的记忆、海关关员的恕道:它记得一切,而一份填错的表格就作废小本子里所有印章——对错表格之后的一切作废。
| 探针 | 改了什么 | prompt-eval | 整次请求 | 对冷启动 |
|---|---|---|---|---|
| P1 冷启动 | 无——全新虚拟机,首次提问 | 75.6 s | 111.8 s | 基准 |
| P2 重复 | 无——body 完全一致 | 0.2 s | 26.6 s | 快 370× |
| P3 尾部 | 问题后 +1 句 | 1.4 s | 27.2 s | 快 54× |
| P4 中部编辑 | 第 41/96 条事实里 1 个词 | 49.2 s | 75.2 s | 冷账单的 65% |
| P5 重排 | 章节 1–2 ↔ 7–8 对调 | 79.9 s | 135.5 s | 比冷启动还糟 |
| P6 近尾部 | 最后一句里 1 个词 | 4.2 s | 34.0 s | 快 18× |
1539 token 提示词 · prompt-eval 是重读的账单;“整次请求”另加 128 token 的生成,全程稳在 ~25–29 s。
为什么重排比冷加载还贵?
因为边境在第 ~1 个 token。把头两章和末两章对调,共享前缀就是空的——匹配当场死亡,每个 token 重新计费。但 P5 计的是 79.9 s,不是 75.6 s:比它为之扔掉折扣的冷加载还高 5.7%。我们不打算假装抓到了元凶——诚实的备注是:那次探针的生成过程也慢了 2.1×(55.4 s,其余每次请求都是 25.5–29.4 s,同 seed、同预算)。热机状态会以缓存示意图画不出的方式加入账单;确定性那篇已在 temp 0 下领教过这位证人,翻车的是一个 token。我们能作为回执声明的是:重排过的提示词不是“同一条提示词,换个顺序”。它是一张全新的账单,外加噪声。
修正清单
| 症状 | 正在发生什么 | 修正 |
|---|---|---|
| 每次请求都像冷加载 | 模型在请求之间被卸载——缓存随之死亡 | 调高 keep_alive;查看回复里的 load_duration |
| 提示词改动极小,延迟巨大 | 编辑落在提示中部;尾部从分歧点起重新计费 | 把易变部分挪到提示词尾部 |
| “同一条提示词”每次 run 计费不同 | 顺序或模板内容在请求间漂移了 | 把头部逐字节冻结;diff 提示词本身,别 diff 直觉 |
P1 cold-full-ask prompt_eval 75,646 ms (1,539 tok · 20.4 tok/s) wall 111.8 s P2 exact-repeat prompt_eval 203 ms wall 26.6 s P3 suffix-only prompt_eval 1,402 ms (+5 tok) wall 27.2 s P4 mid-edit-kill prompt_eval 49,176 ms (1 word, fact 41/96) wall 75.2 s P5 reorder-full-miss prompt_eval 79,878 ms (secs 1–2 ↔ 7–8) wall 135.5 s P6 edit-near-end prompt_eval 4,189 ms (1 word, last sentence) wall 34.0 s
一条提示词。六张账单,从 0.2 到 79.9 秒——370× 的落差,没动任何设置,没拨任何 flag。缓存一直开着。唯一的变量,是我们敢在哪里下笔修改。
最后测试 2026-11-12
qwen3:4b · 2,497,293,931 B · sha256 359d7dd4…74e7 · ollama 0.40.16 · 一台全新 Arch 虚拟机,2 vCPU——CPU 实测,不对 VRAM 作任何断言