用户连续问两次"退款规则是什么",RAG系统没有必要每次都重新召回相同的文档。但是,另一个租户问同样的问题,或者退款制度刚更新,这个"相同问题"就不再对应同一份证据。
RAG检索缓存复用的是检索结果。设计它时,真正要确定的是:什么条件下,两次检索可以视为同一次计算?回答这个问题,才能决定缓存键、失效策略和权限检查的位置。
本文从缓存层次开始,用一个可运行的Python示例验证租户隔离、知识版本、权限变化和过期行为,再讨论接入真实检索链路时的取舍。
一、先确定缓存的是哪一层
RAG链路中,至少有三种不同的可复用结果:
| 缓存层 | 输入与输出 | 命中后省掉什么 |
|---|---|---|
| 向量缓存 | 文本及模型配置→向量 | 重复的Embedding计算 |
| 检索缓存 | 查询及检索上下文→证据片段列表 | 重复召回,以及纳入缓存范围的重排 |
| 答案缓存 | 问题及回答上下文→最终答案 | 检索和生成中的更多计算 |
例如,LangChain的CacheBackedEmbeddings针对文本向量做缓存,并提供命名空间隔离。它不会自动保证检索结果随文档权限、知识版本一起更新。给Embedding加缓存,不等于已经完成RAG结果缓存。 LangChain:Embedding缓存
本文把缓存放在检索完成之后、答案生成之前。缓存内容保存文档标识、版本与证据文本;命中时仍然进行本次回答的生成。这样可以独立观察检索复用是否正确,而不把答案生成策略混在一起。
二、缓存键应描述一次完整的检索
只使用hash(question),会把不同用户环境中的检索结果混到一起。一个更完整的键应包含:
text
租户
授权范围与权限版本
知识库或索引版本
检索配置版本
过滤条件与top_k
实际送入检索器的查询
其中,授权范围来自服务端认证和授权系统 。不能让客户端传一个tenant-a或admin字符串,就把它当成访问凭据。
如果答案受对话上下文影响,应先得到本次实际检索查询,再生成键。例如"它支持退款吗"需要先明确"它"指哪种产品。对原始短句直接缓存,会把不同对话的话题混在一起。
检索配置也不仅是模型名字。切分策略、召回方式、重排模型、阈值和过滤规则变化,都可能改变结果。可以把这些配置固化成一个版本标识,避免把所有细节都拼成长字符串。分布式存储中使用规范化序列化再计算摘要,需保留相同字段顺序和明确的类型编码。

图中的证据抽屉只有在上下文标识吻合时才打开。这个隐喻对应的是缓存分区与键匹配;实际读取结果前仍需进行权限判断。
三、TTL控制存活时间,版本控制内容变化
设缓存保留30秒,第5秒文档被撤回。如果只检查TTL,系统还会在后面的25秒继续返回撤回前的内容。
TTL限制缓存能活多久,不能代替知识更新和权限撤回 。Redis的过期机制根据超时使键失效,不会主动理解某篇业务文档已经变更。Redis:键过期机制
针对不同变化,应使用不同措施:
| 变化 | 处理方式 |
|---|---|
| 新知识索引发布 | 切换知识版本,让新请求进入新命名空间 |
| 检索规则调整 | 更新检索配置版本 |
| 用户权限收回 | 获取当前权限,更新权限版本,并检查缓存证据是否仍可访问 |
| 文档删除或紧急撤回 | 根据文档状态拒绝旧证据,配合主动清理或版本切换 |
| 普通缓存老化 | TTL到期后重新检索 |
知识版本必须与实际索引一致。正确顺序是:构建新索引、确认可用、切换索引与版本。不能先把版本号加一,却仍用旧索引检索,再把旧内容存进新版本的缓存。

权限检查失败的结果不能继续送进模型。模型生成之前就应完成证据筛选;提示模型"不要泄露"无法替代后端访问控制。
四、写一个可运行的检索缓存
下面的例子使用Python标准库,模拟证据检索,并通过显式时钟测试过期。Context代表服务端构造的可信检索上下文;Hit保存不可变的证据记录。检索函数和授权函数通过参数传入,便于观察缓存与业务规则的边界。
python
from dataclasses import dataclass, replace
@dataclass(frozen=True)
class Context:
tenant: str
scope: tuple[str, ...]
policy_version: int
corpus_version: int
retriever: str = "hybrid-v1"
top_k: int = 3
@dataclass(frozen=True)
class Hit:
doc_id: str
revision: int
text: str
class RetrievalCache:
def __init__(self, ttl=30):
self.ttl = ttl
self.entries = {}
def get(self, ctx, query, now, retrieve, allowed):
# ctx comes from trusted server-side authentication and version state.
key = (ctx, query)
entry = self.entries.get(key)
if entry is not None:
expires, hits = entry
if now < expires and all(allowed(ctx, h) for h in hits):
return "HIT", hits
del self.entries[key]
# Exceptions propagate: a failed retrieval is not an empty result.
hits = tuple(retrieve(ctx, query))
if not all(allowed(ctx, h) for h in hits):
raise PermissionError("retrieval returned inaccessible evidence")
# Keep empty-result policy separate; this example does not cache it.
if hits:
self.entries[key] = (now + self.ttl, hits)
return "MISS", hits
cache = RetrievalCache()
calls = 0
active = True
def retrieve(ctx, query):
global calls
calls += 1
if not active:
return ()
return (Hit("guide-1", ctx.corpus_version, "Example evidence"),)
def allowed(ctx, hit):
return active and "docs:read" in ctx.scope
ctx = Context("tenant-a", ("docs:read",), 1, 7)
cases = [
("first", ctx, 0, "MISS"),
("repeat", ctx, 1, "HIT"),
("other_tenant", replace(ctx, tenant="tenant-b"), 2, "MISS"),
("new_corpus", replace(ctx, corpus_version=8), 3, "MISS"),
("new_policy", replace(ctx, policy_version=2), 4, "MISS"),
("expired", ctx, 31, "MISS"),
]
for label, context, now, expected in cases:
state, hits = cache.get(context, "refund rules", now, retrieve, allowed)
assert state == expected
print(f"{label}: {state}, documents={len(hits)}")
active = False
state, hits = cache.get(ctx, "refund rules", 32, retrieve, allowed)
assert state == "MISS" and not hits
print(f"revoked: {state}, documents={len(hits)}")
assert calls == 6
print(f"retrieval_calls={calls}")
保存为cache_demo.py,执行:
bash
python cache_demo.py
运行结果:
text
first: MISS, documents=1
repeat: HIT, documents=1
other_tenant: MISS, documents=1
new_corpus: MISS, documents=1
new_policy: MISS, documents=1
expired: MISS, documents=1
revoked: MISS, documents=0
retrieval_calls=6
第一次请求建立缓存,第二次复用结果。租户、知识版本和权限版本变化后,键都不同,因此重新检索。第31秒超过首条记录的TTL,再次检索;第32秒即使新缓存还没过期,撤回状态也使旧证据无法通过检查。
这里的六次检索是示例计数,不是性能测试。模拟检索器始终生成一个固定形式的文档,目的是验证控制流程。接入真实检索器时,retrieve必须在对应租户、权限过滤条件和知识版本上检索;allowed则要检查当前用户是否能访问该文档及其版本。
五、把示例接到服务之前,补齐四件事
1. 容量与清理
示例字典只在同键被访问时清掉失效记录。线上需要容量限制和回收策略,避免旧知识版本的键持续占用空间。TTL负责过期语义,容量策略负责控制内存,两者应同时考虑。
2. 同一查询的并发合并
热门键失效后,多个请求可能一起落到向量数据库。使用按键合并的在途任务,让同一上下文中的请求等待同一次检索,减少重复工作。锁或任务协调也必须按完整缓存键分组,不能只按问题文本分组。
3. 版本切换期间的竞态
请求开始时读取版本,检索期间知识库又切换了,这时不能把混合结果写回缓存。应让请求绑定一个可读取的索引快照;写回和生成前再判断该快照是否仍允许使用。需要立即生效的撤权,应在最终证据使用点检查当前授权状态。
4. 错误与空结果分开
数据库超时、网络失败和"成功查询但没有匹配文档"是三种不同状态。不能捕获所有异常后统一返回空列表,再把这个空列表长期缓存。示例让检索异常向上传递,并且不缓存空结果。若业务需要缓存空结果,应单独设置较短有效期,避免新文档出现后仍持续返回"没有资料"。
六、为什么先做精确缓存,再考虑语义缓存
精确缓存要求完整键一致。语义缓存根据问题相似度寻找可复用条目,能覆盖更多不同问法,也增加了误命中的机会。
"基础版能否退款"和"企业版能否退款"措辞很近,业务答案却可能不同。因此,语义相似度只能在已经完成租户、权限、知识版本和业务过滤的候选范围内使用。相似不是等价,更不是授权。
实践中先建立精确缓存,观察命中率、检索耗时、缓存证据失效率与权限拒绝次数,再决定是否引入语义匹配。命中率升高但返回旧证据的比例也升高,说明系统复用了不该复用的结果。
七、知识结构回顾
#mermaid-svg-CshHjSTP86vBsudB{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-CshHjSTP86vBsudB .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-CshHjSTP86vBsudB .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-CshHjSTP86vBsudB .error-icon{fill:#552222;}#mermaid-svg-CshHjSTP86vBsudB .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-CshHjSTP86vBsudB .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-CshHjSTP86vBsudB .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-CshHjSTP86vBsudB .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-CshHjSTP86vBsudB .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-CshHjSTP86vBsudB .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-CshHjSTP86vBsudB .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-CshHjSTP86vBsudB .marker{fill:#333333;stroke:#333333;}#mermaid-svg-CshHjSTP86vBsudB .marker.cross{stroke:#333333;}#mermaid-svg-CshHjSTP86vBsudB svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-CshHjSTP86vBsudB p{margin:0;}#mermaid-svg-CshHjSTP86vBsudB .edge{stroke-width:3;}#mermaid-svg-CshHjSTP86vBsudB .section--1 rect,#mermaid-svg-CshHjSTP86vBsudB .section--1 path,#mermaid-svg-CshHjSTP86vBsudB .section--1 circle,#mermaid-svg-CshHjSTP86vBsudB .section--1 polygon,#mermaid-svg-CshHjSTP86vBsudB .section--1 path{fill:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-CshHjSTP86vBsudB .section--1 text{fill:#ffffff;}#mermaid-svg-CshHjSTP86vBsudB .node-icon--1{font-size:40px;color:#ffffff;}#mermaid-svg-CshHjSTP86vBsudB .section-edge--1{stroke:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-CshHjSTP86vBsudB .edge-depth--1{stroke-width:17;}#mermaid-svg-CshHjSTP86vBsudB .section--1 line{stroke:hsl(60, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-CshHjSTP86vBsudB .disabled,#mermaid-svg-CshHjSTP86vBsudB .disabled circle,#mermaid-svg-CshHjSTP86vBsudB .disabled text{fill:lightgray;}#mermaid-svg-CshHjSTP86vBsudB .disabled text{fill:#efefef;}#mermaid-svg-CshHjSTP86vBsudB .section-0 rect,#mermaid-svg-CshHjSTP86vBsudB .section-0 path,#mermaid-svg-CshHjSTP86vBsudB .section-0 circle,#mermaid-svg-CshHjSTP86vBsudB .section-0 polygon,#mermaid-svg-CshHjSTP86vBsudB .section-0 path{fill:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-CshHjSTP86vBsudB .section-0 text{fill:black;}#mermaid-svg-CshHjSTP86vBsudB .node-icon-0{font-size:40px;color:black;}#mermaid-svg-CshHjSTP86vBsudB .section-edge-0{stroke:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-CshHjSTP86vBsudB .edge-depth-0{stroke-width:14;}#mermaid-svg-CshHjSTP86vBsudB .section-0 line{stroke:hsl(240, 100%, 83.5294117647%);stroke-width:3;}#mermaid-svg-CshHjSTP86vBsudB .disabled,#mermaid-svg-CshHjSTP86vBsudB .disabled circle,#mermaid-svg-CshHjSTP86vBsudB .disabled text{fill:lightgray;}#mermaid-svg-CshHjSTP86vBsudB .disabled text{fill:#efefef;}#mermaid-svg-CshHjSTP86vBsudB .section-1 rect,#mermaid-svg-CshHjSTP86vBsudB .section-1 path,#mermaid-svg-CshHjSTP86vBsudB .section-1 circle,#mermaid-svg-CshHjSTP86vBsudB .section-1 polygon,#mermaid-svg-CshHjSTP86vBsudB .section-1 path{fill:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-CshHjSTP86vBsudB .section-1 text{fill:black;}#mermaid-svg-CshHjSTP86vBsudB .node-icon-1{font-size:40px;color:black;}#mermaid-svg-CshHjSTP86vBsudB .section-edge-1{stroke:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-CshHjSTP86vBsudB .edge-depth-1{stroke-width:11;}#mermaid-svg-CshHjSTP86vBsudB .section-1 line{stroke:hsl(260, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-CshHjSTP86vBsudB .disabled,#mermaid-svg-CshHjSTP86vBsudB .disabled circle,#mermaid-svg-CshHjSTP86vBsudB .disabled text{fill:lightgray;}#mermaid-svg-CshHjSTP86vBsudB .disabled text{fill:#efefef;}#mermaid-svg-CshHjSTP86vBsudB .section-2 rect,#mermaid-svg-CshHjSTP86vBsudB .section-2 path,#mermaid-svg-CshHjSTP86vBsudB .section-2 circle,#mermaid-svg-CshHjSTP86vBsudB .section-2 polygon,#mermaid-svg-CshHjSTP86vBsudB .section-2 path{fill:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-CshHjSTP86vBsudB .section-2 text{fill:#ffffff;}#mermaid-svg-CshHjSTP86vBsudB .node-icon-2{font-size:40px;color:#ffffff;}#mermaid-svg-CshHjSTP86vBsudB .section-edge-2{stroke:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-CshHjSTP86vBsudB .edge-depth-2{stroke-width:8;}#mermaid-svg-CshHjSTP86vBsudB .section-2 line{stroke:hsl(90, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-CshHjSTP86vBsudB .disabled,#mermaid-svg-CshHjSTP86vBsudB .disabled circle,#mermaid-svg-CshHjSTP86vBsudB .disabled text{fill:lightgray;}#mermaid-svg-CshHjSTP86vBsudB .disabled text{fill:#efefef;}#mermaid-svg-CshHjSTP86vBsudB .section-3 rect,#mermaid-svg-CshHjSTP86vBsudB .section-3 path,#mermaid-svg-CshHjSTP86vBsudB .section-3 circle,#mermaid-svg-CshHjSTP86vBsudB .section-3 polygon,#mermaid-svg-CshHjSTP86vBsudB .section-3 path{fill:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-CshHjSTP86vBsudB .section-3 text{fill:black;}#mermaid-svg-CshHjSTP86vBsudB .node-icon-3{font-size:40px;color:black;}#mermaid-svg-CshHjSTP86vBsudB .section-edge-3{stroke:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-CshHjSTP86vBsudB .edge-depth-3{stroke-width:5;}#mermaid-svg-CshHjSTP86vBsudB .section-3 line{stroke:hsl(120, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-CshHjSTP86vBsudB .disabled,#mermaid-svg-CshHjSTP86vBsudB .disabled circle,#mermaid-svg-CshHjSTP86vBsudB .disabled text{fill:lightgray;}#mermaid-svg-CshHjSTP86vBsudB .disabled text{fill:#efefef;}#mermaid-svg-CshHjSTP86vBsudB .section-4 rect,#mermaid-svg-CshHjSTP86vBsudB .section-4 path,#mermaid-svg-CshHjSTP86vBsudB .section-4 circle,#mermaid-svg-CshHjSTP86vBsudB .section-4 polygon,#mermaid-svg-CshHjSTP86vBsudB .section-4 path{fill:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-CshHjSTP86vBsudB .section-4 text{fill:black;}#mermaid-svg-CshHjSTP86vBsudB .node-icon-4{font-size:40px;color:black;}#mermaid-svg-CshHjSTP86vBsudB .section-edge-4{stroke:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-CshHjSTP86vBsudB .edge-depth-4{stroke-width:2;}#mermaid-svg-CshHjSTP86vBsudB .section-4 line{stroke:hsl(150, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-CshHjSTP86vBsudB .disabled,#mermaid-svg-CshHjSTP86vBsudB .disabled circle,#mermaid-svg-CshHjSTP86vBsudB .disabled text{fill:lightgray;}#mermaid-svg-CshHjSTP86vBsudB .disabled text{fill:#efefef;}#mermaid-svg-CshHjSTP86vBsudB .section-5 rect,#mermaid-svg-CshHjSTP86vBsudB .section-5 path,#mermaid-svg-CshHjSTP86vBsudB .section-5 circle,#mermaid-svg-CshHjSTP86vBsudB .section-5 polygon,#mermaid-svg-CshHjSTP86vBsudB .section-5 path{fill:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-CshHjSTP86vBsudB .section-5 text{fill:black;}#mermaid-svg-CshHjSTP86vBsudB .node-icon-5{font-size:40px;color:black;}#mermaid-svg-CshHjSTP86vBsudB .section-edge-5{stroke:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-CshHjSTP86vBsudB .edge-depth-5{stroke-width:-1;}#mermaid-svg-CshHjSTP86vBsudB .section-5 line{stroke:hsl(180, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-CshHjSTP86vBsudB .disabled,#mermaid-svg-CshHjSTP86vBsudB .disabled circle,#mermaid-svg-CshHjSTP86vBsudB .disabled text{fill:lightgray;}#mermaid-svg-CshHjSTP86vBsudB .disabled text{fill:#efefef;}#mermaid-svg-CshHjSTP86vBsudB .section-6 rect,#mermaid-svg-CshHjSTP86vBsudB .section-6 path,#mermaid-svg-CshHjSTP86vBsudB .section-6 circle,#mermaid-svg-CshHjSTP86vBsudB .section-6 polygon,#mermaid-svg-CshHjSTP86vBsudB .section-6 path{fill:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-CshHjSTP86vBsudB .section-6 text{fill:black;}#mermaid-svg-CshHjSTP86vBsudB .node-icon-6{font-size:40px;color:black;}#mermaid-svg-CshHjSTP86vBsudB .section-edge-6{stroke:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-CshHjSTP86vBsudB .edge-depth-6{stroke-width:-4;}#mermaid-svg-CshHjSTP86vBsudB .section-6 line{stroke:hsl(210, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-CshHjSTP86vBsudB .disabled,#mermaid-svg-CshHjSTP86vBsudB .disabled circle,#mermaid-svg-CshHjSTP86vBsudB .disabled text{fill:lightgray;}#mermaid-svg-CshHjSTP86vBsudB .disabled text{fill:#efefef;}#mermaid-svg-CshHjSTP86vBsudB .section-7 rect,#mermaid-svg-CshHjSTP86vBsudB .section-7 path,#mermaid-svg-CshHjSTP86vBsudB .section-7 circle,#mermaid-svg-CshHjSTP86vBsudB .section-7 polygon,#mermaid-svg-CshHjSTP86vBsudB .section-7 path{fill:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-CshHjSTP86vBsudB .section-7 text{fill:black;}#mermaid-svg-CshHjSTP86vBsudB .node-icon-7{font-size:40px;color:black;}#mermaid-svg-CshHjSTP86vBsudB .section-edge-7{stroke:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-CshHjSTP86vBsudB .edge-depth-7{stroke-width:-7;}#mermaid-svg-CshHjSTP86vBsudB .section-7 line{stroke:hsl(270, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-CshHjSTP86vBsudB .disabled,#mermaid-svg-CshHjSTP86vBsudB .disabled circle,#mermaid-svg-CshHjSTP86vBsudB .disabled text{fill:lightgray;}#mermaid-svg-CshHjSTP86vBsudB .disabled text{fill:#efefef;}#mermaid-svg-CshHjSTP86vBsudB .section-8 rect,#mermaid-svg-CshHjSTP86vBsudB .section-8 path,#mermaid-svg-CshHjSTP86vBsudB .section-8 circle,#mermaid-svg-CshHjSTP86vBsudB .section-8 polygon,#mermaid-svg-CshHjSTP86vBsudB .section-8 path{fill:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-CshHjSTP86vBsudB .section-8 text{fill:black;}#mermaid-svg-CshHjSTP86vBsudB .node-icon-8{font-size:40px;color:black;}#mermaid-svg-CshHjSTP86vBsudB .section-edge-8{stroke:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-CshHjSTP86vBsudB .edge-depth-8{stroke-width:-10;}#mermaid-svg-CshHjSTP86vBsudB .section-8 line{stroke:hsl(330, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-CshHjSTP86vBsudB .disabled,#mermaid-svg-CshHjSTP86vBsudB .disabled circle,#mermaid-svg-CshHjSTP86vBsudB .disabled text{fill:lightgray;}#mermaid-svg-CshHjSTP86vBsudB .disabled text{fill:#efefef;}#mermaid-svg-CshHjSTP86vBsudB .section-9 rect,#mermaid-svg-CshHjSTP86vBsudB .section-9 path,#mermaid-svg-CshHjSTP86vBsudB .section-9 circle,#mermaid-svg-CshHjSTP86vBsudB .section-9 polygon,#mermaid-svg-CshHjSTP86vBsudB .section-9 path{fill:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-CshHjSTP86vBsudB .section-9 text{fill:black;}#mermaid-svg-CshHjSTP86vBsudB .node-icon-9{font-size:40px;color:black;}#mermaid-svg-CshHjSTP86vBsudB .section-edge-9{stroke:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-CshHjSTP86vBsudB .edge-depth-9{stroke-width:-13;}#mermaid-svg-CshHjSTP86vBsudB .section-9 line{stroke:hsl(0, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-CshHjSTP86vBsudB .disabled,#mermaid-svg-CshHjSTP86vBsudB .disabled circle,#mermaid-svg-CshHjSTP86vBsudB .disabled text{fill:lightgray;}#mermaid-svg-CshHjSTP86vBsudB .disabled text{fill:#efefef;}#mermaid-svg-CshHjSTP86vBsudB .section-10 rect,#mermaid-svg-CshHjSTP86vBsudB .section-10 path,#mermaid-svg-CshHjSTP86vBsudB .section-10 circle,#mermaid-svg-CshHjSTP86vBsudB .section-10 polygon,#mermaid-svg-CshHjSTP86vBsudB .section-10 path{fill:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-CshHjSTP86vBsudB .section-10 text{fill:black;}#mermaid-svg-CshHjSTP86vBsudB .node-icon-10{font-size:40px;color:black;}#mermaid-svg-CshHjSTP86vBsudB .section-edge-10{stroke:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-CshHjSTP86vBsudB .edge-depth-10{stroke-width:-16;}#mermaid-svg-CshHjSTP86vBsudB .section-10 line{stroke:hsl(30, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-CshHjSTP86vBsudB .disabled,#mermaid-svg-CshHjSTP86vBsudB .disabled circle,#mermaid-svg-CshHjSTP86vBsudB .disabled text{fill:lightgray;}#mermaid-svg-CshHjSTP86vBsudB .disabled text{fill:#efefef;}#mermaid-svg-CshHjSTP86vBsudB .section-root rect,#mermaid-svg-CshHjSTP86vBsudB .section-root path,#mermaid-svg-CshHjSTP86vBsudB .section-root circle,#mermaid-svg-CshHjSTP86vBsudB .section-root polygon{fill:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-CshHjSTP86vBsudB .section-root text{fill:#ffffff;}#mermaid-svg-CshHjSTP86vBsudB .section-root span{color:#ffffff;}#mermaid-svg-CshHjSTP86vBsudB .section-2 span{color:#ffffff;}#mermaid-svg-CshHjSTP86vBsudB .icon-container{height:100%;display:flex;justify-content:center;align-items:center;}#mermaid-svg-CshHjSTP86vBsudB .edge{fill:none;}#mermaid-svg-CshHjSTP86vBsudB .mindmap-node-label{dy:1em;alignment-baseline:middle;text-anchor:middle;dominant-baseline:middle;text-align:center;}#mermaid-svg-CshHjSTP86vBsudB :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} RAG检索缓存
选择缓存层
向量
检索证据
最终答案
完整缓存键
租户与权限
知识版本
检索配置
查询与过滤
正确失效
TTL
版本切换
撤权与撤回
服务化
容量限制
并发合并
快照一致性
区分错误与空结果
总结要点
检索缓存复用的是某个上下文中的证据。问题文本相同,只能说明输入的一部分相同;租户、权限、知识版本和检索配置共同决定结果能否复用。
TTL解决时间上的老化,版本切换和权限复核解决业务状态变化。缓存命中之后,证据仍然要满足当前访问要求,才能进入生成阶段。
先用精确缓存建立可验证的复用规则,再考虑语义缓存扩大命中范围。节省一次检索的前提,是没有改变这次检索应有的结果边界。
下一篇继续讨论RAG的语义缓存:如何判断两个问题是否足够等价,以及怎样用反例验证命中阈值。
👉 如果你觉得这篇文章对你有所帮助,欢迎点赞、收藏、分享!😊