长上下文实测:4k / 8k / 16k,没有独显能开多长
上下文长度是本地跑模型时最容易被忽视的成本。很多人以为「开大一点又不花钱」,我把同一段材料分别塞成 3.5k、7.1k、14.2k tokens,在同一台没有独显的机器上测了处理耗时、生成速度和内存。
一、结论先说
| 模型 | 上下文 | 材料 tokens | 读完材料 | 生成速度 | 内存峰值 | 暗号找到 |
|---|---|---|---|---|---|---|
| Qwen2.5 7B | 4k | 3561 | 83 秒 | 7.1 tok/s | 4.9 GB | ✅ |
| Qwen2.5 7B | 8k | 7117 | 184 秒 | 5.7 tok/s | 5.3 GB | ✅ |
| Qwen2.5 7B | 16k | 14170 | 437 秒 | 3.2 tok/s | 5.7 GB | ✅ |
| Qwen2.5 3B | 8k | 7117 | 94 秒 | 12.3 tok/s | 2.4 GB | ✅ |
| Qwen2.5 3B | 16k | 14170 | 241 秒 | 8.0 tok/s | 2.7 GB | ✅ |
一句话:能读进去,但读完太慢。16k 上下文在 7B 上光是"读材料"就要 7 分钟,还没开始回答。
二、怎么测的
- 机器:i5-12400、32GB 内存、无独显,Ollama 0.40.13
- 材料:站内一篇文章正文反复拼接,分别做到约 3.5k / 7.1k / 14.2k tokens
- 测试方法:在材料 30% 的位置埋一个暗号「紫色立方体-7429」,材料末尾问「暗号是什么」,看能否答对(检验长上下文召回)
- 记录:读材料耗时、生成速度、内存峰值,每个模型每次先卸载再加载
- 生成上限 24 token、温度 0,避免生成阶段把时间差拉大
三、四个发现
1. 读材料的代价远大于生成。 生成 24 个 token 只要几秒,而读 14k tokens 要 437 秒。长上下文的成本几乎全在「预填充」阶段。
2. 上下文翻倍,速度掉得比想象中快。 7B 读材料的速度:43.1 → 38.6 → 32.4 tok/s;生成速度:7.1 → 5.7 → 3.2 tok/s。生成速度掉了一半,因为注意力要扫过更长的缓存。
3. 内存增长比预期温和,但不是没成本。 7B 从 4.9GB 涨到 5.7GB,涨的是 KV 缓存;3B 只要 2.4–2.7GB。也就是说:模型本体占大头,上下文只是加法——但加法在 16 位精度下会越加越明显。
4. 暗号 5 组全中。 说明这批模型的「长上下文召回」本身没问题,瓶颈是速度,不是「读不懂」。这一点和网上说的「长上下文必丢信息」不太一样——至少在这个长度上还好。
四、那什么时候该开大上下文
| 场景 | 建议 |
|---|---|
| 日常问答、改错字、写短文 | 4k 足够,别开 16k |
| 总结一篇文章、整理材料 | 8k 可以接受,但要等 2–3 分钟 |
| 整本书、十几个文件一起喂 | 不要用长上下文,改用检索(见下) |
| 离线批量任务(睡前跑) | 16k 随便开,反正不等人 |
五、比长上下文更划算的做法
同一台机器上,我之前做过的 RAG 召回实验:156 个分块建索引 40 秒,单次查询 50ms。按 3B 模型算,检索到 500 token 的材料只需要约 7 秒就能开始回答——比硬塞 14k 上下文的 437 秒快约 60 倍。
所以结论很直接:需要「看很多资料」时,用检索把资料压缩到 500–1000 token,而不是把上下文开到 16k。
六、想自己复现
ollama run qwen2.5-7b
curl http://127.0.0.1:11434/api/generate -d "{\"model\":\"qwen2.5-7b\",\"prompt\":\"...\",\"stream\":false,\"options\":{\"num_ctx\":16384,\"num_predict\":24}}"看返回里的 prompt_eval_count 和 prompt_eval_duration:前者是材料 tokens,后者是读完耗时。
本文脚本:editor\_bench-longctx.mjs、_bench-longctx-one.mjs;原始数据 editor\logs\longctx-final.json。
七、局限
- 每组只跑了一次,没有取平均
- 材料是重复文本,比真实文章更容易处理,真实材料可能更慢
- 暗号测试只测了最简单的「找一句话」,不代表复杂推理
- 不同量化版本、不同 Ollama 版本,数字会变