保存时间:2026/3/29 21:47:24
| 配件 | 推荐型号 | 价格 (元) | 备注 |
|---|---|---|---|
| CPU | Intel i5-14600K | 1,600 | 中端足够,瓶颈不在 CPU |
| 主板 | 微星 Z790-A WIFI | 1,500 | 支持 PCIe 4.0 x16 全速 |
| 内存 | DDR5 6000MHz 32GB (16×2) | 1,200 | 双通道起步,64GB 更好 |
| 固态硬盘 | 1TB NVMe M.2 (三星 990 Pro) | 700 | 保证模型加载速度 |
| 电源 | 1200W 金牌全模组 ATX3.0 | 600 | 原生 12VHPWR 接口,必须 |
| 散热 | 360mm 一体式水冷 | 600 | 压制 CPU,为显卡留风道 |
| 机箱 | 中塔(支持 4090 + 360 水冷) | 400 | 保证散热和空间 |
| 合计 | 6,600 |
后续的计算就只需要 kv cache,然后一个 token 一个 token 的产生。
KV Cache 大小 ≈层数 × 头数 × head_dim × 上下文长度 × 2(K+V) × 精度字节
所有人问题大同小异,先算一个公共 Base KV,每个人只传增量 Delta,很小。
用户:你好(2 个 token)云端传回这 2 个 token 的 KV Cache之后我再说任何话,都只在本地增量加新 KV
You are a helpful assistant...上回书说到...以下是对话历史...--cache-prompt把固定前缀的 KV 存下来,重复使用系统提示是标准的,存起来不就完了,何必傻傻重复计算?
--ctx-size 4096下次用 --ctx-size 2048→ KV 位置、长度、偏移全对不上。git pull
make
./main \
-m your_model.gguf \
--ctx-size 2048 \
--prompt "You are a helpful assistant." \
--cache-prompt save \
--cache-file system_prompt.kvcache
system_prompt.kvcache。./main \
-m your_model.gguf \
--ctx-size 2048 \
--cache-prompt load \
--cache-file system_prompt.kvcache \
--prompt "Hello!"
部署时就把「模型权重 + 固定系统提示 KV Cache」绑在一起一起发布, inference 参数全部锁死,不让用户乱改。
./main \
-m model.gguf \
--ctx-size 2048 \
-p "You are a helpful assistant. You answer concisely." \
--cache-prompt save \
--cache-file sys_prompt.kvcache
./main \
-m model.gguf \
--ctx-size 2048 \
--cache-prompt load \
--cache-file sys_prompt.kvcache \
-p "Hello."
系统提示:你是一个专业助手……(很长,100~300 token)
用户:你好
为什么不把系统提示算好存起来?这不就是 0 预热吗?
超长上下文 Prefill
KV Cache 大小 =层数 × 头数 × head_dim × 长度 × 2(K+V) × 2(字节)
长坂坡赵云发生了什么?
赵云怀抱阿斗,七进七出曹营,斩将五十余员…
三国里有个人救了小孩。
有一位英雄救了孩子。
三国里有个人救了孩子
我需要更多信息…
赵云怀抱后主,直透重围…
这是赵云在长坂坡救阿斗…
后续的 token 生成都会有这部分记忆,不需要重复输入。
L = 32head_dim = 128×2KV Cache 大小(MB) ≈ 上下文长度 × 0.015625
上下文长度 ≈ KV 大小(MB) × 64
模型权重显存 ≈ 8B × 0.5Byte = 4GB
6GB - 4.5GB = 1.5GB ≈ 1536MB
上下文长度 ≈ 1536MB × 64 ≈ 98304 token
| 模型 | 量化 | 显存占用 | 最大上下文 | 速度 | 适合场景 |
|---|---|---|---|---|---|
| Qwen3.5-2B-Instruct | Q4_K_M | 2.0GB | 128K+ | 60–80t/s | 日常对话、摘要、轻量RAG |
| DeepSeek-V2-3B | GPTQ-4bit | 2.1GB | 128K+ | 50–70t/s | 中文知识库、本地问答 |
| Phi-3-mini-4K | Q4_K_M | 1.8GB | 128K+ | 70–90t/s | 代码、短文本、快速响应 |
| 模型 | 量化 | 显存占用 | 最大上下文 | 速度 | 适合场景 |
|---|---|---|---|---|---|
| Qwen2.5-7B-Instruct | Q4_K_M | 4.0GB | 96K | 30–50t/s | 全能主力、长对话、RAG、代码 |
| Llama 3.1-8B-Instruct | Q4_K_M | 4.2GB | 96K | 25–45t/s | 通用对话、逻辑推理、英文优先 |
| Qwen3.5-9B-Instruct | Q4_K_M | 4.8GB | 80K | 20–35t/s | 强中文、复杂指令、长文本 |
| 模型 | 量化 | 显存占用 | 最大上下文 | 速度 | 备注 |
|---|---|---|---|---|---|
| Llama 3.1-13B | Q4_K_M | 5.8GB | 16K | 5–15t/s | 显存吃满、易爆、仅短对话 |
| Qwen2.5-14B | Q4_K_M | 6.0GB | 8K | 3–10t/s | 几乎无KV空间、不适合长记忆 |
ollama run qwen2.5:7b-instruct-q4_k_m上下文翻 2 倍 → 速度大约慢 2 倍
新Q × 所有历史K → 得到注意力权重
权重 × 所有历史V → 得到输出
计算量是不是越来越大?越来越慢?
字典就 32768 个 token每个 token × Wq / Wk / Wv 结果固定做成大表存起来不就行了?
4096 × 4096上一轮的隐藏层输出 → 经过 LayerNorm → 乘 Wq → 才是 Q
new_state = F(old_state, current_token)
KV Cache 是状态模型权重是固定函数那能不能不用 KV Cache 存状态,而是用另一个模型去“计算”这个状态?
state = [] # KV Cache,无限变长
def next_token(new_token):
q, k, v = model(new_token)
state.append( (k,v) )
output = attention(q, state) # O(N)
return output
state = fixed_size_vector # 永远不变大
def next_token(new_token):
# 用一个函数(模型)计算新状态
state = state_model(state, new_token)
# 直接用状态预测下一个 token
output = predict(state)
return output
KV Cache 本质也是一种函数,那能不能用另一个模型去算这个状态?
state = initial_state
def step(input_token):
global state
# 状态由模型计算,不是存储
state = state_model(state, input_token)
return predict_token(state)
从多的信息变成少的信息,没有逆运算,就是有损,必然丢失细节。