QwenPaw 在 Mac Studio 上 KV Cache 命中率归零的排查与根因

最近给 QwenPaw 配置 LM Studio 时,发现一个现象:LLM 请求的 KV Cache 命中率始终为 0

排查了一圈配置和代理链路,最终发现这不是 bug,而是 Apple Silicon (MLX) 与 NVIDIA CUDA 在 KV Cache 实现上的根本性差异。记录一下排查过程和实验数据。

架构与现象

我们的请求链路如下:

QwenPaw (Linux) → Docker(cli-proxyapi:8317) → LM Studio (Mac M2 Max, 100.100.100.11:1234)

在 LM Studio 的 Web UI 中,我已经开启了 KV缓存量化 (Experimental),上下文长度设为 262144。但 QwenPaw 的 token 用量日志显示,每次请求都是全新的 prompt,缓存从未命中。

排查过程

Step 1: 排除代理层干扰

首先怀疑是 cli-proxyapi 在转发时注入了动态 header(如 X-Request-Id、时间戳等),导致每次请求的 HTTP 头不一致。

curl -sv ... http://cli-proxyapi.sh4.local:8317/v1/chat/completions 2>&1 | grep -E "^[<>]"

结果:两次请求的 header 完全一致,代理层干净。

Step 2: 排除多实例负载均衡

如果 LM Studio 背后有多台机器轮询,缓存自然无法复用。我是单实例运行,无负载均衡。

Step 3: KV Cache 压力测试

我构造了两组对比实验:

实验 A:完全相同的 prompt 重复发送

{"model":"qwen3.6-35b-a3b@8bit","messages":[{"role":"system","content":"You are a test bot."},{"role":"user","content":"What is 1+1?"},{"role":"assistant","content":"2"},{"role":"user","content":"And 2+2?"}],"max_tokens":5,"temperature":0}
  • Req1: 1011ms
  • Req2: 444ms (↓ 56% 加速)

实验 B:相同前缀(100K chars) + 不同后缀(模拟 Agent 多轮对话)

PREFIX=$(python3 -c "print('A'*100000)") # 约 25K tokens
# Req1: system="$PREFIX", user="Say ONE word: test"
# Req2: system="$PREFIX", user="Say ONE word: test" (完全相同)
  • Req1: 632ms
  • Req2: 753ms (反而更慢,缓存未生效)

核心结论:MLX vs CUDA 的 KV Cache 差异

实验数据说明了原因:

场景 CUDA (vLLM/TGI) Apple Silicon (MLX/LM Studio)
完全相同的 prompt ✅ 命中,复用 KV Cache ✅ 命中,复用 KV Cache
相同前缀 + 不同后缀 ✅ 自动前缀缓存 (Prefix Caching) 不支持,必须逐字节完全匹配

QwenPaw 的 Agent 场景每轮发送的 prompt 结构如下:

[固定 System Prompt (~15K tokens)] + [变化的对话历史] + [新的 User Message]
         ↑ 前缀固定                          ↑ 每轮变化

在 CUDA 推理框架中,vLLM/TGI 会自动提取相同的前缀进行 KV Cache 复用,Agent 场景的缓存命中率通常能达到 30%~50%

但在 Apple Silicon 上,LM Studio 底层使用 MLX 框架。MLX 的 KV Cache 实现较为朴素,仅支持精确匹配(Exact Match),不支持前缀缓存 (Prefix Caching)。Apple Silicon 的 KV Cache 优化目前仍处于实验阶段,前缀复用功能尚未稳定。

踩坑记录

  1. Apple Silicon 的 MLX 框架限制:MLX 在推理速度上已经非常优秀,但在企业级特性(如 Prefix Caching、Continuous Batching)上仍落后于 CUDA 生态。选型时需明确场景需求。
  2. 实验设计:用 date +%s%N 记录毫秒级耗时,配合完全相同的 prompt vs 前缀相同后缀不同的对比,能最快定位缓存生效边界。

Mac Studio 接入 Prometheus + Grafana 监控实践