ScholarMind 高级缓存加速方案
本文档补充原有 4 级缓存体系,新增 7 层缓存机制,覆盖从应用层语义缓存到 GPU KV Cache 硬件层的全栈加速。
缓存全景图
┌──────────────────────────────────────────────────────────────────────────────────┐
│ ScholarMind 7层缓存加速栈 │
├──────────────────────────────────────────────────────────────────────────────────┤
│ │
│ Layer 1 ─── 语义缓存 (GPTCache) │
│ "What is SnapKV?" ≈ "Explain SnapKV" → 同一缓存命中 │
│ 延迟: ~5ms (缓存命中) vs ~1500ms (LLM调用) │
│ 节省: ~100× 延迟, ~100% API成本 │
│ │
│ Layer 2 ─── 检索结果缓存 (语义级) │
│ 相似query复用检索结果, 跳过向量搜索+图谱遍历+重排 │
│ 延迟: ~2ms vs ~300ms │
│ 节省: 避免重复检索计算 │
│ │
│ Layer 3 ─── API Provider 提示缓存 │
│ OpenAI: 自动, ≥1024 tokens → 90%输入token折扣 │
│ Anthropic: cache_control 标记 → 90%折扣 │
│ DeepSeek: 自动磁盘KV → 90%折扣 │
│ 节省: 50-90% API成本, 最高80%延迟降低 │
│ │
│ Layer 4 ─── vLLM 前缀缓存 (APC) │
│ 共享 system prompt + 文档chunk 的 KV Cache │
│ 节省: 2-8× TTFT (首Token延迟) 降低 │
│ │
│ Layer 5 ─── RAG KV Cache 复用 (LMCache/CacheBlend) │
│ 预计算每个文档chunk的KV状态, 组合时选择性重算5-15% │
│ 节省: 2.2-3.3× TTFT, 2.8-5× 吞吐提升 │
│ │
│ Layer 6 ─── KV Cache 压缩 (SnapKV/Quest) │
│ 长文档场景: 只保留注意力关键的20% KV位置 │
│ 节省: 3.6× 解码加速, 8.2× 显存效率 │
│ │
│ Layer 7 ─── 多轮对话状态缓存 │
│ 缓存Agent中间状态 + 检索上下文 + 部分答案 │
│ 追问时跳过路由+检索+图谱查询 │
│ 节省: 追问响应 ~60% 延迟降低 │
│ │
└──────────────────────────────────────────────────────────────────────────────────┘
请求完整路径:
User Query
→ [L1 语义缓存] 命中? → 直接返回 (~5ms)
→ [L2 检索缓存] 命中? → 跳过检索, 直接生成
→ [L7 对话缓存] 追问? → 复用上下文
→ Retriever (向量+图谱+RAPTOR)
→ Prompt组装 (static prefix + retrieved chunks + query)
→ [L3 Provider缓存] 系统提示+文档chunk已缓存 → 90%折扣
→ [L4 vLLM APC] 共享前缀KV命中 → 跳过prefill
→ [L5 CacheBlend] 非前缀chunk KV复用 → 部分重算
→ [L6 SnapKV] 长上下文KV压缩 → 加速decode
→ Response → 写入 L1 + L2
Layer 1: 语义缓存 (GPTCache)
原理
传统 Redis 缓存只能精确匹配 key。但学术问答中,同一个问题有多种表达方式:
- "SnapKV 是什么?" ≈ "解释一下 SnapKV 的原理" ≈ "What does SnapKV do?"
语义缓存将查询编码为向量,通过相似度搜索查找语义等价的历史查询,命中则直接返回缓存答案。
查询 → Embedding → 向量相似度搜索 → 相似度 > 阈值?
├── 是: 返回缓存答案 (~5ms)
└── 否: 调用LLM → 存入缓存
实现
# ===== 方案A: GPTCache (推荐, 7k⭐) =====
# pip install gptcache
from gptcache import cache
from gptcache.adapter import openai
from gptcache.embedding import Onnx
from gptcache.manager import CacheBase, VectorBase, get_data_manager
from gptcache.similarity_evaluation.distance import SearchDistanceEvaluation
from gptcache.processor.pre import get_prompt
# 初始化: FAISS向量索引 + SQLite存储 (开发)
onnx = Onnx()
data_manager = get_data_manager(
CacheBase("sqlite"),
VectorBase("faiss", dimension=onnx.dimension)
)
cache.init(
pre_embedding_func=get_prompt, # 只用user query做缓存key (排除检索上下文)
embedding_func=onnx.to_embeddings,
data_manager=data_manager,
similarity_evaluation=SearchDistanceEvaluation(),
)
# 使用: 直接替换 openai 调用
response = openai.ChatCompletion.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "You are ScholarMind..."},
{"role": "user", "content": "What is attention mechanism?"}
]
)
# 第二次语义相似查询 → 缓存命中, ~5ms返回
# ===== 方案A (生产版): Milvus/Redis后端 =====
from gptcache.embedding import OpenAI as OpenAIEmbedding
from gptcache.manager import CacheBase, VectorBase, get_data_manager
# 使用 Qdrant 作为向量后端 (复用已有基础设施)
data_manager = get_data_manager(
CacheBase("postgresql", sql_url="postgresql://user:pass@localhost/gptcache"),
VectorBase("milvus", host="localhost", port=19530, dimension=1536)
# 也可用 VectorBase("qdrant", url="http://localhost:6333", collection_name="gptcache")
)
# 使用 OpenAI Embedding (与检索管道同模型, 一致性最高)
openai_emb = OpenAIEmbedding()
cache.init(
pre_embedding_func=get_prompt,
embedding_func=openai_emb.to_embeddings,
data_manager=data_manager,
similarity_evaluation=SearchDistanceEvaluation(),
)
# ===== 方案B: LangChain SemanticCache (更简洁) =====
from langchain_community.cache import RedisSemanticCache
from langchain_openai import OpenAIEmbeddings
import langchain
langchain.llm_cache = RedisSemanticCache(
redis_url="redis://localhost:6379",
embedding=OpenAIEmbeddings(),
score_threshold=0.85, # 学术领域建议较严格
)
# 所有 LangChain LLM 调用自动走语义缓存
关键参数调优
| 参数 | 推荐值 | 说明 |
|---|---|---|
| 相似度阈值 | 0.85 (学术) | 太低→错误答案; 太高→命中率低; 通用场景可用0.75 |
| 嵌入模型 | text-embedding-3-small | 与检索管道一致, 避免语义偏差 |
| TTL | 24h | 学术知识相对稳定 |
| 淘汰策略 | LRU | 最近最少使用 |
| 缓存key | 仅user query | 排除检索context, 否则同一问题不同检索结果无法命中 |
效果预估
| 场景 | 命中率 | 延迟节省 |
|---|---|---|
| 同一用户追问变体 | ~70% | ~300× (5ms vs 1.5s) |
| 多用户热门问题 | ~30-40% | ~300× |
| 全新问题 | 0% | 无节省 (还多~10ms嵌入开销) |
| 加权平均 | ~35% | 总QPS提升~50% |
Layer 2: 语义检索结果缓存
原理
混合检索 (向量+图谱+RAPTOR+重排) 耗时约 300ms。如果两个查询语义相似,它们的检索结果往往也相似。
class SemanticRetrievalCache:
"""语义级检索结果缓存 — 相似query复用检索结果"""
def __init__(self, qdrant_client, collection="retrieval_cache", threshold=0.90):
self.client = qdrant_client
self.collection = collection
self.threshold = threshold
self.embed_model = load_embedding_model()
# 创建缓存collection
self.client.create_collection(
collection_name=collection,
vectors_config=models.VectorParams(size=1536, distance=models.Distance.COSINE),
)
async def get_or_fetch(self, query: str, retriever) -> list:
"""查缓存, 没有则检索并缓存"""
query_vec = self.embed_model.encode(query)
# 1. 在缓存中搜索语义相似的历史查询
hits = self.client.search(
collection_name=self.collection,
query_vector=query_vec,
limit=1,
score_threshold=self.threshold,
)
if hits and hits[0].score >= self.threshold:
# 缓存命中 — 直接返回历史检索结果
cached = hits[0].payload["results"]
return cached
# 2. 缓存未命中 — 执行完整检索
results = await retriever.retrieve(query, mode="hybrid")
# 3. 存入缓存
self.client.upsert(
collection_name=self.collection,
points=[models.PointStruct(
id=hash(query) % (2**63),
vector=query_vec,
payload={
"query": query,
"results": results,
"timestamp": time.time(),
}
)]
)
return results
缓存失效
async def invalidate_on_new_papers(self, paper_ids: list):
"""新论文导入时, 清除可能受影响的缓存"""
# 策略1: 全量清除 (简单但激进)
self.client.delete_collection(self.collection)
# 策略2: 精准失效 (复杂但精确)
# 检索包含这些paper_id的缓存条目并删除
for paper_id in paper_ids:
self.client.delete(
collection_name=self.collection,
points_selector=models.FilterSelector(
filter=models.Filter(
must=[models.FieldCondition(
key="results[].metadata.paper_id",
match=models.MatchValue(value=paper_id),
)]
)
)
)
Layer 3: API Provider 提示缓存
核心原理
Prompt 结构:
┌─────────────────────────────────────────┐
│ System Prompt (固定, ~500 tokens) │ ← 这部分每次都一样
│ "You are ScholarMind, a research..." │ Provider 自动缓存
├─────────────────────────────────────────┤
│ 检索到的论文片段 (半固定, ~2000 tokens) │ ← 热门论文反复被检索到
│ Paper chunk A: "Attention is..." │ 高概率命中缓存
│ Paper chunk B: "We propose BERT..." │
├─────────────────────────────────────────┤
│ 用户问题 (动态, ~50 tokens) │ ← 每次不同
│ "Compare BERT and GPT-2 on GLUE" │ 不被缓存
└─────────────────────────────────────────┘
关键: 固定内容放前面, 动态内容放最后!
OpenAI — 全自动 (零配置)
from openai import OpenAI
client = OpenAI()
# 技巧: 构造≥1024 tokens的静态前缀, OpenAI自动缓存
SYSTEM_PROMPT = """You are ScholarMind, an expert academic research assistant.
You have access to a knowledge base of 1000+ academic papers spanning NLP,
computer vision, and machine learning. When answering questions:
1. Always cite specific papers with [Author, Year] format
2. Include quantitative results where available
3. Compare methods objectively
4. Acknowledge limitations and open questions
... (填充到≥1024 tokens)
"""
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": SYSTEM_PROMPT}, # ~1200 tokens, 自动缓存
{"role": "user", "content": f"""
Based on these papers:
{retrieved_chunks}
Question: {user_question}
"""}
]
)
# 检查缓存效果
usage = response.usage
cached = usage.prompt_tokens_details.cached_tokens
total = usage.prompt_tokens
print(f"Cache hit: {cached}/{total} tokens ({cached/total:.0%})")
# 首次: 0%, 后续相同前缀: ~70-90%
成本节省:
| 场景 | 正常价格 | 缓存命中价格 | 节省 |
|---|---|---|---|
| GPT-4o input | $2.50/M | $1.25/M | 50% |
| GPT-4o-mini input | $0.15/M | $0.075/M | 50% |
| GPT-4o 长前缀 (>128K) | — | 高达 90% off | 90% |
Anthropic — 显式标记 (精细控制)
import anthropic
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=2048,
system=[
{
"type": "text",
"text": SYSTEM_PROMPT, # 系统指令
"cache_control": {"type": "ephemeral"} # ← 缓存断点1
}
],
messages=[{
"role": "user",
"content": [
{
"type": "text",
"text": retrieved_chunks, # 检索到的论文片段
"cache_control": {"type": "ephemeral"} # ← 缓存断点2
},
{
"type": "text",
"text": user_question # 动态部分, 不缓存
}
]
}]
)
# 查看缓存统计
print(f"Cache write: {response.usage.cache_creation_input_tokens} tokens")
print(f"Cache read: {response.usage.cache_read_input_tokens} tokens")
# 首次: 全部write; 5分钟内再次调用相同前缀: 全部read → 90%折扣
Anthropic 缓存定价:
| 类型 | Sonnet 4 | Haiku 3.5 |
|---|---|---|
| 正常输入 | $3/M | $0.80/M |
| 缓存写入 (首次) | $3.75/M (+25%) | $1.00/M (+25%) |
| 缓存读取 (命中) | $0.30/M (-90%) | $0.08/M (-90%) |
| TTL | 5分钟 (每次命中刷新) | 5分钟 |
DeepSeek — 自动磁盘缓存
from openai import OpenAI
client = OpenAI(api_key="sk-xxx", base_url="https://api.deepseek.com")
response = client.chat.completions.create(
model="deepseek-chat",
messages=[
{"role": "system", "content": LONG_SYSTEM_PROMPT},
{"role": "user", "content": user_question}
]
)
# DeepSeek 自动缓存到磁盘, 无需配置
usage = response.usage
print(f"Cache hit: {usage.prompt_cache_hit_tokens} tokens @ 10% price")
print(f"Cache miss: {usage.prompt_cache_miss_tokens} tokens @ 100% price")
# 磁盘缓存持续时间 > Anthropic的5分钟, 更适合低流量场景
Layer 4: vLLM 前缀缓存 (APC)
原理
vLLM 的 Automatic Prefix Caching 将 KV Cache 按 block (16-32 tokens) 分割,每个 block 通过 hash(tokens + position) 索引。新请求到来时,从头匹配已缓存的 blocks,跳过已有 blocks 的 prefill 计算。
请求1: [System 500 tokens] + [Chunk A 200 tokens] + [Query 1]
↓ 全部计算 KV, 缓存所有blocks
请求2: [System 500 tokens] + [Chunk A 200 tokens] + [Query 2]
↓ 前700 tokens 命中缓存! 只需计算 Query 2 的KV
→ prefill 从 ~700 tokens 降到 ~50 tokens → 14× TTFT降低
配置
# vLLM serving — APC默认开启 (v1+)
vllm serve meta-llama/Llama-3.1-8B-Instruct \
--enable-prefix-caching \
--gpu-memory-utilization 0.95 \
--max-model-len 32768
# 查看缓存统计
curl http://localhost:8000/metrics | grep prefix_cache
# vllm_prefix_cache_hit_rate: 0.73
# vllm_prefix_cache_queries_total: 10000
# Python API
from vllm import LLM, SamplingParams
llm = LLM(
model="meta-llama/Llama-3.1-8B-Instruct",
enable_prefix_caching=True,
gpu_memory_utilization=0.95,
)
# 关键: 所有请求共享相同的长前缀
SHARED_PREFIX = f"""<|begin_of_text|><|start_header_id|>system<|end_header_id|>
You are ScholarMind, an expert academic research assistant with access to
1000+ research papers. Answer precisely with citations.
<|eot_id|><|start_header_id|>user<|end_header_id|>
Based on the following paper excerpts:
{FREQUENTLY_RETRIEVED_CHUNKS}
"""
# 每次请求只改变 query 部分 — 前缀全部缓存命中
responses = llm.generate([
SHARED_PREFIX + "What is the main contribution of BERT?<|eot_id|>",
SHARED_PREFIX + "Compare BERT and GPT-2 on GLUE<|eot_id|>",
])
⚡ 优化技巧: 文档chunk排序一致化
def order_chunks_for_cache(chunks: list, query: str) -> list:
"""
将检索到的chunk按确定性顺序排列, 最大化前缀缓存命中率
策略: 按chunk_id排序 (而非按相关性排序)
→ 不同查询检索到相同chunk集合时, 前缀完全一致 → 缓存命中
"""
# 按paper_id + page_idx 确定性排序
return sorted(chunks, key=lambda c: (c["metadata"]["paper_id"], c["metadata"]["page"]))
# 注意: 这会牺牲一点"最相关chunk排前面"的优势
# 折中方案: 前N个按相关性, 后面按ID排序
Layer 5: RAG KV Cache 复用 (LMCache / CacheBlend)
问题
标准前缀缓存要求 chunks 以完全相同的顺序出现。但 RAG 检索结果的顺序经常变化:
- Query 1 → [Chunk A, B, C]
- Query 2 → [Chunk B, A, D] ← Chunk A, B 都出现了, 但前缀不同
CacheBlend 解决这个问题: 预计算每个chunk的独立KV状态, 组合时只选择性重算 5-15% 的 tokens。
实现
# 安装 LMCache (CacheBlend 的生产实现)
pip install lmcache lmcache-vllm
# LMCache 集成 vLLM 的示例
import lmcache_vllm
from vllm import LLM, SamplingParams
# LMCache 在 vLLM 之上透明地管理 KV 缓存
# 支持 GPU VRAM → Host RAM → SSD 三级缓存层次
llm = LLM(
model="meta-llama/Llama-3.1-8B-Instruct",
# LMCache 通过环境变量或配置文件集成
)
# 预热: 将所有高频文档chunk的KV预计算并缓存
for chunk in top_1000_chunks:
llm.encode(chunk["text"]) # 预计算KV → 缓存到GPU+RAM
# 推理: 组合时自动复用已缓存的chunk KV, 只重算5-15%
response = llm.generate(
system_prompt + chunk_a + chunk_b + user_query
)
# chunk_a 和 chunk_b 的 KV 从缓存加载, 仅选择性重算跨chunk注意力
效果
| 指标 | 无缓存 | vLLM APC | CacheBlend |
|---|---|---|---|
| TTFT (首token) | 基准 | 2-8× 降低 (仅限相同前缀) | 2.2-3.3× 降低 (任意chunk组合) |
| 吞吐 | 基准 | 1.5× 提升 | 2.8-5× 提升 |
| 适用场景 | — | 固定前缀 | 任意RAG检索结果 |
论文: CacheBlend (arxiv:2405.16444), LMCache GitHub:
github.com/LMCache/LMCache
Layer 6: KV Cache 压缩 (长文档场景)
SnapKV — 关注度投票压缩
当输入很长(多篇论文全文)时,保留完整 KV Cache 会耗尽显存。SnapKV 只保留每个注意力头真正关注的 20% 位置。
完整KV: [tok1, tok2, tok3, ..., tok10000] → 160GB VRAM (70B模型)
SnapKV: [tok3, tok45, tok202, ..., tok9998] → 32GB VRAM (仅保留20%)
~5× 显存节省, ~3.6× 解码加速
# pip install snapkv
# 核心参数
config = {
"compression_ratio": 0.2, # 保留20%的KV位置
"observation_window": 32, # 用最后32个token投票决定保留哪些位置
"kernel_size": 5, # 投票时的池化窗口
}
# SnapKV 集成方式: 修改 attention 层
# 适用: 处理多篇完整论文时 (>16K tokens)
# 结果: 单A100可处理380K token上下文 (原本~32K)
Quest — 查询感知的稀疏注意力
每个KV页面维护元数据 (K向量的min/max值)
→ 新query来了, 用Q和元数据估算每页的重要性
→ 只加载Top-K重要的页面
→ 7× self-attention加速
论文: SnapKV (arxiv:2404.14469, GitHub:
fasterdecoding/snapkv) 论文: Quest (arxiv:2406.10774, GitHub:mit-han-lab/quest)
Layer 7: 多轮对话状态缓存
原理
学术问答常见多轮追问:
- "BERT在GLUE上表现如何?" → 检索+推理+生成
- "和GPT-2相比呢?" → 不需要重新检索BERT的信息!
from langgraph.checkpoint.memory import MemorySaver
class ConversationCache:
"""多轮对话缓存 — 避免追问时重复检索"""
def __init__(self):
self.checkpointer = MemorySaver() # LangGraph 内置状态持久化
self.context_cache = {} # session_id → {retrieved_docs, entities, graph_context}
async def handle_query(self, session_id: str, query: str):
# 检查是否是追问
if session_id in self.context_cache:
prev = self.context_cache[session_id]
# 追问检测: 如果query引用了上一轮的实体, 复用上下文
if self._is_followup(query, prev["entities"]):
# 直接复用之前的检索结果 + 图谱上下文
return await self._generate_with_cached_context(
query=query,
retrieved_docs=prev["retrieved_docs"],
graph_context=prev["graph_context"],
history=prev["history"],
)
# 非追问: 完整检索流程
result = await full_retrieval_and_generation(query)
# 缓存上下文供追问使用
self.context_cache[session_id] = {
"retrieved_docs": result["retrieved_docs"],
"graph_context": result["graph_context"],
"entities": result["entities"],
"history": result["messages"],
"timestamp": time.time(),
}
return result
def _is_followup(self, query: str, prev_entities: list) -> bool:
"""检测是否是追问: 包含代词、比较词、或引用上一轮实体"""
followup_signals = ["compared to", "和...比", "那", "它", "this method", "上面提到的"]
has_pronoun = any(s in query.lower() for s in followup_signals)
references_entity = any(e["name"].lower() in query.lower() for e in prev_entities)
return has_pronoun or references_entity
LangGraph 内置检查点
from langgraph.graph import StateGraph
from langgraph.checkpoint.postgres import PostgresSaver
# 使用 PostgreSQL 持久化 Agent 状态
checkpointer = PostgresSaver.from_conn_string("postgresql://...")
# 编译时传入 checkpointer
agent = build_agent_graph().compile(checkpointer=checkpointer)
# 每次调用使用 thread_id 标识会话
config = {"configurable": {"thread_id": session_id}}
# 第一次: 完整执行
result1 = await agent.ainvoke({"query": "BERT在GLUE上表现如何?"}, config)
# 追问: LangGraph 自动恢复之前的状态
result2 = await agent.ainvoke({"query": "和GPT-2相比呢?"}, config)
# → Agent 已有上一轮的 retrieved_docs, 只需补充检索GPT-2信息
集成架构: 完整缓存流水线
class CachedQAEngine:
"""集成7层缓存的问答引擎"""
def __init__(self):
# L1: 语义缓存
self.semantic_cache = GPTCacheWrapper(threshold=0.85, ttl_hours=24)
# L2: 检索结果缓存
self.retrieval_cache = SemanticRetrievalCache(qdrant, threshold=0.90)
# L7: 对话状态缓存
self.conversation_cache = ConversationCache()
# L3-L6: 由 LiteLLM / vLLM / Provider 自动处理
async def query(self, session_id: str, query: str) -> dict:
# === L1: 语义缓存检查 ===
cached_answer = await self.semantic_cache.get(query)
if cached_answer:
return {"answer": cached_answer, "cache": "L1_semantic", "latency_ms": 5}
# === L7: 追问检查 ===
if self.conversation_cache.is_followup(session_id, query):
result = await self.conversation_cache.handle_followup(session_id, query)
if result:
return {**result, "cache": "L7_followup"}
# === L2: 检索缓存检查 ===
retrieved = await self.retrieval_cache.get_or_fetch(query, self.retriever)
# === 组装 Prompt (L3/L4/L5友好的结构) ===
prompt = self._build_prompt(
system=STATIC_SYSTEM_PROMPT, # → L3 Provider缓存
chunks=order_chunks_for_cache(retrieved), # → L4 vLLM APC缓存
query=query # → 动态部分
)
# === LLM调用 (L3/L4/L5/L6 自动生效) ===
answer = await self.llm.complete(prompt, task="generation")
# === 写入缓存 ===
await self.semantic_cache.set(query, answer)
self.conversation_cache.update(session_id, query, retrieved, answer)
return {"answer": answer, "cache": "miss", "retrieved": retrieved}
def _build_prompt(self, system: str, chunks: list, query: str) -> list:
"""
Prompt结构优化:
1. 固定系统提示放最前 (Provider缓存 + vLLM前缀缓存)
2. 检索chunks按确定性排序 (最大化vLLM前缀命中)
3. 用户query放最后 (动态部分)
"""
return [
{"role": "system", "content": system}, # ≥1024 tokens → OpenAI自动缓存
{"role": "user", "content":
"Based on these paper excerpts:\n\n" +
"\n---\n".join([c["text"] for c in chunks]) +
f"\n\nQuestion: {query}"
}
]
性能收益汇总
┌───────────────────────────────────────────────────────────────────┐
│ 7层缓存预估收益 (1000篇论文, 日均500查询) │
├──────────┬──────────┬──────────────┬──────────────┬──────────────┤
│ 缓存层 │ 命中率 │ 延迟节省 │ 成本节省 │ 实现复杂度 │
├──────────┼──────────┼──────────────┼──────────────┼──────────────┤
│ L1 语义 │ ~35% │ 300×(5ms) │ ~100%(命中时) │ ⭐⭐ 中 │
│ L2 检索 │ ~25% │ ~60×(5ms) │ 检索计算 │ ⭐⭐ 中 │
│ L3 API │ ~70% │ 最高80% │ 50-90% │ ⭐ 低 │
│ L4 APC │ ~60% │ 2-8× TTFT │ GPU算力 │ ⭐ 低 │
│ L5 Cache │ ~40% │ 2-3× TTFT │ GPU算力 │ ⭐⭐⭐ 高 │
│ Blend │ │ │ │ │
│ L6 SnapKV│ N/A │ 3.6×解码 │ 5×显存 │ ⭐⭐ 中 │
│ L7 对话 │ ~20% │ ~60%(追问) │ 检索+推理 │ ⭐⭐ 中 │
├──────────┼──────────┼──────────────┼──────────────┼──────────────┤
│ 综合 │ — │ P50: 1.5s │ API成本 │ │
│ 效果 │ │ → ~400ms │ 降低60%+ │ │
│ │ │ P99: 4s │ │ │
│ │ │ → ~1.5s │ │ │
└──────────┴──────────┴──────────────┴──────────────┴──────────────┘
实施优先级
| 优先级 | 缓存层 | 理由 | 工作量 |
|---|---|---|---|
| P0 (立即) | L3 Provider缓存 | 零代码改动, 只需调整prompt结构 | 2小时 |
| P0 (立即) | L4 vLLM APC | 默认已开启, 确认配置即可 | 1小时 |
| P1 (本周) | L1 语义缓存 | GPTCache几十行代码, 收益最高 | 1天 |
| P1 (本周) | L7 对话缓存 | LangGraph checkpointer, 追问体验质变 | 1天 |
| P2 (下周) | L2 检索缓存 | 复用Qdrant基础设施 | 2天 |
| P3 (后续) | L6 SnapKV | 仅长文档场景需要 | 3天 |
| P3 (后续) | L5 CacheBlend | 需要LMCache集成, 侵入性较大 | 1周 |
相关论文
| 论文 | ArXiv ID | 核心贡献 |
|---|---|---|
| GPTCache | ACL 2023 NLPOSS | 语义缓存框架 |
| GPT Semantic Cache | 2411.05276 | 语义缓存基准评测 |
| PagedAttention (vLLM) | 2309.06180 | 分页KV Cache管理 |
| RAGCache | 2404.12457 | RAG专用多级KV缓存 |
| CacheBlend | 2405.16444 | 非前缀KV复用 |
| SnapKV | 2404.14469 | 注意力投票KV压缩 |
| Quest | 2406.10774 | 查询感知稀疏注意力 |
| StreamingLLM | 2309.17453 | 注意力sink+滚动窗口 |
| Prompt Cache | 2311.04934 | 模块化KV状态复用 |
| KV Cache Survey | 2412.19442 | KV Cache管理全面综述 |
开源项目
| 项目 | GitHub | Stars | 用途 |
|---|---|---|---|
| GPTCache | zilliztech/GPTCache | 7k+ | 语义缓存 |
| LMCache | LMCache/LMCache | — | CacheBlend生产实现 |
| SnapKV | fasterdecoding/snapkv | 311 | KV压缩 |
| Quest | mit-han-lab/quest | 382 | 稀疏注意力 |
| vLLM | vllm-project/vllm | 45k+ | APC前缀缓存 |
| KV Cache Survey | TreeAI-Lab/Awesome-KV-Cache-Management | 314 | 综述索引 |