老张在市中心开了一家“汤鲜面馆”。开业三个月,他发现一个规律:翻来覆去卖得最好的,就是红烧牛肉面、番茄鸡蛋面和酸菜鱼面这三样。于是他想了个办法——早上开门前,先把这三样的汤底熬好、浇头备齐、小料分装;顾客一落座,报了菜名,一分钟内面就端上桌了。偶尔有顾客点菜单上没有的新面,老张也会现做,但做完之后他会把配料记在“点单记录本”上,如果这道新面卖得好,明天就进入“预先备料”名单。 前端里的 RAG 缓存策略,和老张的经营智慧如出一辙:用户反复问相似的问题,没必要每次都让大模型重新检索、重新生成,把热门问题的答案“提前备好、快速上菜”就是查询缓存;把切配工作标准化,就是 Embedding 缓存;听出“牛肉面”和“红烧牛肉面”是同一个需求,就是语义去重;开门前先备好最受欢迎的菜,就是预热策略。本文就用面馆的故事,把 RAG 缓存策略与性能优化的门道讲清楚。
掌握 RAG 缓存策略,意味着你能显著降低大模型调用成本与响应延迟,在检索效果和系统性能之间做出理性取舍,这是衡量 AI 工程化能力的重要分水岭。
可视化演示
演示查询缓存命中流程、Embedding向量缓存与语义去重、预热策略三种RAG缓存优化方案,交互切换查看前端RAG性能优化策略。
本节配有交互动效(进入视口后自动加载,约 3KB)。
查询缓存命中流程 用户查询先查缓存命中则直接返回结果 未命中则走完整RAG检索链路并回填缓存 latency = hit ? cache : retrieve + LLM 查询缓存可将首次请求延迟从2秒降至50毫秒
查询缓存机制
老张的“点单记录本”不只是记流水账,它还是一本“备料指南”。每天打烊后,老张会在本子上数一数:今天哪几样面点得最多?点得多的,明天就提前把料备好;点得少的,等客人点了再临时切配。这样一来,最忙的午餐时段,热销面的出餐时间硬是从 15 分钟压到了 1 分钟。
前端 RAG 系统面临的困境一模一样。用户通过聊天组件提问时,很多问题其实高度相似,比如“怎么开通会员”和“会员怎么开通”。如果每次都走一遍完整的 RAG 链路——把问题转成向量、去向量库检索、把文档拼给大模型生成——一次回答的延迟动辄两三秒,成本也高。查询缓存的做法是:把“问题→答案”直接存进一个高速存储里,下次遇到同一个问题,直接取答案返回。
实现查询缓存有几个关键决策。第一是缓存键设计:原始问题文本不能直接当键,因为“ 怎么开通会员 ”和“怎么开通会员”要去空格、统一大小写后再做键。第二是命中判定:完全一致就算命中。第三是淘汰策略:缓存空间有限,最常用的是 LRU(最近最少使用)——像老张每天看记录本一样,把最久没被点过的条目请出去。第四是失效机制:给每条缓存设置 TTL(生存时间),到期自动作废,避免知识库更新后用户拿到旧答案。
老张每天睡前翻记录本,其实就是一次“LRU 扫描”——把最久没点的面从备料清单里划掉。查询缓存也在每一次访问中感知热度,把最热的问题留在高速区,冷门问题让位出去。
- 命中次数 $N_{\text{命中}}$用户提问后,在缓存里直接找到现成答案的次数。就像顾客点“红烧牛肉面”,后厨端起早已备好的浇头就上菜,一分钟出餐。
- 总请求数 $N_{\text{总请求}}$所有用户提问的总次数,包含命中和未命中。对应面馆一天接到的所有点单,不管热销还是冷门。
- 比值乘以 100%把比例换算成百分数,方便和行业基准对比。命中率 80% 意味着五分之四的提问不需要重新检索、重新生成。
Embedding缓存
面馆后厨有个“配菜间”:葱段、姜丝、蒜末、香菜,都按标准分量洗好切好,装进保鲜盒。不管哪位师傅掌勺,炒菜用的配料规格完全一样,谁都不用临时洗菜切菜。这份标准化,就是出餐速度稳定的秘密。
RAG 链路里,把“自然语言问题”变成“机器能计算的向量”这一步,就是最费时的“洗菜切菜”。Embedding 模型一次调用往往要跑几十毫秒甚至更久,同一个问题被 10 个用户各问一遍,就白算了 10 次同样的向量。Embedding 缓存的办法:以问题的语义指纹为 key,把算好的向量存起来,下次直接取向量,跳过 Embedding 模型的推理。
具体实现时,先用哈希函数给问题算一个“语义指纹”作为缓存键——这是从“大段的字”到“定长字符串”的映射。缓存条目里除了向量本身,还带上答案、知识库版本号和时间戳。存储格式上,向量是浮点数数组,需要计算维度乘字节数来估算内存占用。比如 1536 维、float32(4 字节)的一条向量占约 6KB,缓存 1 万条就是 60MB,这个成本需要在设计之初就心里有数。
配菜间让任何一位师傅出餐速度都稳定,Embedding 缓存让任何一次查询的响应时间都稳定。更重要的是,保鲜盒用完要补、过期要扔,Embedding 缓存的条目也要按 TTL 和版版号及时刷新。
- 向量维度 $D$Embedding 模型输出的维度,常见的有 384、768、1536。维度越高,表示越精细,占内存也越多,就像一碗面的浇头越丰富,备料越占地方。
- 单值字节数 $B$每个浮点数在内存中占 4 字节(float32)。如果对精度要求不高,也可以换成 2 字节的 float16,用一半内存换轻微精度损失。
- 缓存条目数 $M$缓存里存了多少条向量。条目越多,覆盖面越广,但内存压力也越大,需要和 LRU 淘汰配合控制上限。
语义去重策略
面馆里有个耳朵特别灵的服务员小刘。客人喊“来碗牛肉面”或者“我要红烧牛肉面”,他都知道是同一道招牌面,直接向后厨报同一个单号。要是每次都让客人重新解释一遍“牛肉面是红烧还是清炖”,客人早就不耐烦了。
查询缓存要求问题完全一致才能命中,可真实用户说话千奇百怪:“怎么开通会员”“会员怎么开通”“帮忙开通一下会员”——意思相同,文本却完全不同。语义去重就是为了解决这个问题:不比较字面,比较“意思”。先给问题算 Embedding 向量,再用余弦相似度衡量两个向量在语义空间里离得有多近。
余弦相似度的取值范围是 -1 到 1,越接近 1 表示方向越一致,也就是语义越接近。实际操作中会设定一个阈值,比如 0.92 以上判定为“同一个问题”,直接复用缓存结果;低于阈值则当作新问题处理。为了提高精度,通常还要做归一化处理——把向量缩放到单位长度,让余弦值只反映方向差异,避免文本长度干扰。阈值设太高,去重效果差;设太低,会把不同问题误判成同一个,给出驴唇不对马嘴的答案。
小刘的“顺风耳”不是把所有菜都当成牛肉面,而是有分寸:相似度够高才算同一道菜。语义去重的阈值就是这个分寸——调好了,顾客觉得自己被记住了;调过头,顾客会觉得这店连点啥都分不清。
- 向量点积 $\mathbf{a} \cdot \mathbf{b}$把两个向量的对应分量相乘再求和,得到一个标量,衡量两个向量在方向上的“共鸣”程度。
- 向量模长 $\lVert \mathbf{a} \rVert$把向量每个分量平方求和再开方,得到向量的长度。归一化就是让每个向量长度变成 1。
- 点积除以模长乘积把长度影响消掉,只保留角度信息——这正是“只看意思、不看长短”的关键一步。
预热策略
面馆每天早上 10 点开门,但老张 9 点就到店了。他会翻出昨天和前天的点单记录,挑出排名前 12 的热卖面,先把汤底熬上、浇头炖上、配菜摆好;遇到周末,再加备 3 道游客爱点的特色面。
RAG 系统也可以“不等客来就备菜”。预热(Warm-up)策略的核心是:从历史访问日志中挖掘高频问题,在系统空闲时段(比如凌晨)批量预计算这些问题的检索结果和答案,写进缓存。这样早高峰一上来,最热的问题几乎是零延迟响应。
实现预热需要三步。第一步是热门问题识别:统计请求日志里每个问题的出现频次,按近一周加权汇总出热门榜单;第二步是批量预计算:把榜单上的问题逐条送进 RAG 链路,得到答案后写入缓存,这一步可以并行执行,充分利用夜间闲置资源;第三步是定时刷新机制:知识库每周更新,热门问题的答案也需要跟着刷新,通常用定时任务(比如每天凌晨 2 点)重新跑一遍。热度公式中,近一周权重 α 和近一天权重 β 的配比,决定了榜单是“看长期口碑”还是“追当下热点”。
老张的备菜不是乱备,依据就是那本点单记录本——这就是“日志驱动”的预热。游客一多,周末特色面自动加量;RAG 系统里,热搜一出现,定时任务也会把新话题自动纳入第二天的预热清单。
- 近一周频次 $f_{\text{week}}(q)$问题 $q$ 在过去 7 天出现的总次数,代表长期热度,像面馆的“镇店招牌面”。
- 近一天频次 $f_{\text{day}}(q)$问题 $q$ 在过去 24 小时出现的次数,捕捉短期突发热度,比如新功能上线后用户集中询问。
- 权重 $\alpha$ 和 $\beta$控制两类频次的占比。$\alpha$ 取大,榜单偏稳健;$\beta$ 取大,榜单对突发话题更敏感。一般满足 $\alpha + \beta = 1$。
性能指标评估
老张店里挂着三块白板:一块写出餐时间,一块写翻台率,一块写当日食材损耗。媳妇笑他“开个面馆还像做审计”,他说:“不看数据,我怎么知道明天该多备牛肉还是多备番茄?”
RAG 缓存加没加、加了多少,不能凭感觉拍板,要用指标说话。最核心的三个数字是:缓存命中率、响应延迟和存储成本。命中率决定多少请求能“抄近道”;延迟决定用户等多久;存储成本决定这个“近道”修不修得起。
延迟对比要在相同条件下测:分别统计加缓存前后的 P50、P95 延迟。P95 指 95% 的请求能在多少毫秒内完成,比平均值更能反映最差体验。存储成本要算总账:内存缓存条数乘每条体积,加上刷新的计算开销。这三个指标不是孤立看的——命中率很高但延迟没降,说明缓存键设计有漏洞;延迟降了但内存爆了,说明淘汰策略太保守。
三块白板让老张第二天备菜有了依据,三个指标让 RAG 系统的缓存策略有了方向盘。数据不会说谎:命中率、延迟、成本摆在一起,是加缓存、减缓存还是改阈值,一目了然。
- 无缓存平均耗时 $T_{\text{no-cache}}$完全没有缓存时,一次完整 RAG 检索和生成的耗时,比如 2500ms。相当于面馆从洗菜切菜到端面上桌的全流程。
- 有缓存平均耗时 $T_{\text{cache}}$加上缓存后,命中的请求直接返回答案的耗时,比如 300ms。相当于浇头备好、汤已烧开,直接煮面装碗。
- 1 减比值把节省比例算出来。若 $T_{\text{cache}}$ 是 $T_{\text{no-cache}}$ 的 12%,节省率就是 88%;若缓存没起作用,比值接近 1,节省率趋近 0。
方案选型对比
街角的快餐车和商场里的连锁面馆,后厨逻辑完全不同。快餐车一个灶台一口锅,老板自己就是出餐系统;连锁面馆有中央厨房,向十几家分店统一配送半成品。规模一变,备菜方案就要变。
RAG 缓存也存在“快餐车”和“中央厨房”的差别。小型项目、单实例部署,用一个 JavaScript 的 Map 或者 Python 的 dict 就能当缓存,零依赖、零运维。中大型项目,需要重启不丢数据的本地持久化存储;多实例部署时,还得让所有实例共享同一份缓存,避免每个实例各备各的菜、互相不知道。
目前主流是三条路线。第一,内存缓存(如 JS Map / Python dict):读写最快,微秒级,但进程重启即丢失,内存上限受限,适合个人工具或原型验证。第二,本地持久化(如 SQLite、LMDB):重启不丢,读取速度中等,适合单机应用。第三,外部缓存服务(如 Redis):多实例共享、支持 TTL 和 LRU 等高级策略,吞吐量高,但要引入网络开销和运维成本,适合高并发生产环境。选型时画一条决策线:先看 QPS——低于 100 用 Map 就够;再看实例数——多实例必须上 Redis。
快餐车没必要建中央厨房,连锁面馆也不能靠一口锅打天下。方案选型的本质,是让“备菜体系”匹配“客流规模”——QPS 和实例数就是 RAG 系统的客流数据。
- 缓存层容量 $Q_{\text{cache}}$缓存服务每秒钟能处理的查询次数。Redis 轻松上万,Map 取决于单机内存和事件循环能力。
- RAG 链路容量 $Q_{\text{rag}}$底层检索和生成服务每秒能支撑的请求数。大模型推理通常是瓶颈,可能只有几十到几百。
- 取两者较小值 $\min$短板决定上限。就算缓存能扛 5 万 QPS,RAG 链路只能扛 200,整体也就是 200——备菜再快,灶眼不够多也没用。
权衡与优化
老张最近添了烦恼:牛肉备多了,卖不完的隔夜肉口感差;备少了,中午最忙时两小时就断货。他试了几周,终于找到一个折中方案——牛肉这种“基本盘”多备两天量,时令浇头每天只备当天量,高汤则从早到晚一直小火煨着,随时能加。
RAG 缓存优化的本质也是“备多备少的艺术”。缓存加得猛,命中率高、响应快,但知识库一更新,旧答案就像隔夜牛肉——吃着没事,味道不对,甚至可能给用户错误信息。缓存加得少,答案新鲜,但延迟和成本都上去了。优化的核心是三件事:一致性保障、存储开销控制和分层缓存。
一致性保障指知识库内容更新后,缓存里的旧答案必须及时失效。常见做法是版本号机制:知识库每次更新,版本号加 1,缓存的条目记录自己对应的版本号,对不上就视为过期。存储开销控制包括:限制缓存容量、压缩向量精度(float32 降 float16)、给相似答案去重合并。分层缓存则是把最热的 20% 问题放内存(最快)、中温问题放本地磁盘、冷门问题完全不缓存——对应老张的“牛肉多备、时令少备、高汤常备”。
老张的折中方案没有完美答案,只有每天的微调。RAG 缓存也是一样:一致性、成本、延迟三个目标天然互斥,成熟的团队不是追求某个指标登顶,而是像老张那样,找到自己客流和菜单下最舒服的那个平衡点。
- 命中率收益缓存命中带来的延迟和成本节省,越高越好。对应老张多备牛肉带来的高峰出餐速度。
- 存储成本率缓存占用的内存、磁盘和刷新计算开销占总资源的比例,越高越差。对应备料占用的冰箱空间和采购成本。
- λ 权重系数在 0 到 1 之间调节。λ 取 0.7 表示更看重响应速度,可以容忍多占内存;λ 取 0.3 表示更心疼成本,宁可慢一点。
AI 应用场景
企业客服知识库机器人
阶段:检索增强生成(RAG)的缓存与性能层
解决的问题:传统客服系统遇到重复问题也要完整走一遍检索-生成链路,响应 3-5 秒,大模型 API 费用高昂。AI 助手加一层查询缓存和预处理后,Top 100 热门问题命中率达到 70%,P95 延迟从 3 秒降到 400ms,月 API 账单腰斩。
具体案例:某银行在线客服上线 RAG 缓存后,“信用卡怎么还款”这类高频问题在每日 2 万次咨询中占四成,全部由缓存直接回复;知识库每周更新后,版本号机制自动让约 1% 的条目标记过期,下一轮预热任务在凌晨重新填充。
企业文档问答助手
阶段:向量化与检索优化
解决的问题:团队协作工具里,“Q3 报表在哪里”和“第三季度报表链接”其实是同一个问题,每次都单独调用 Embedding 模型就是浪费。用语义指纹做 Embedding 缓存,配合余弦相似度去重,相似问题复用同一份向量和答案。
具体案例:某互联网公司内部文档机器人上线前 500 次提问中,语义重复率高达 35%。应用语义去重后,实际调用底层模型次数减少三成;由日志挖掘出的“登录问题”“报销流程”等 80 个热门问题在每晚定时预热,早晨上班高峰全部秒回。
电商导购 Chatbot
阶段:全链路缓存架构设计
解决的问题:大促期间流量是平时的 20 倍,如果所有提问都实时调用大模型,成本不可控。方案选型上,会话级查询缓存用 Redis 承载多实例共享,商品答案用本地 SQLite 持久化,做到“热数据共享、温数据落盘”。
具体案例:某电商平台 618 大促前,用上一年大促的日志挖掘出“满减规则”“发货时间”等 200 个高频问题做预热。活动当天缓存命中率 85%,RAG 后端压力仅为无缓存方案的六分之一,整体响应保持在 800ms 以内。
Python 演示
import hashlibimport timefrom collections import OrderedDict class SemanticDedupCache: """带语义去重的RAG缓存""" def __init__(self, capacity=100, threshold=0.92, ttl=300): self.capacity = capacity self.threshold = threshold self.ttl = ttl self._cache_map = OrderedDict() @staticmethod def _normalize(text): """规范化: 去空白并统一小写""" return "".join(text.split()).lower() @staticmethod def _semantic_fingerprint(text): """用哈希模拟语义指纹(演示用)""" return hashlib.md5(text.encode("utf-8")).hexdigest() @staticmethod def _cosine_similarity(a, b): """基于字符bigram的近似相似度""" set_a = set(a[i:i + 2] for i in range(len(a) - 1)) set_b = set(b[i:i + 2] for i in range(len(b) - 1)) if not set_a or not set_b: return 0.0 return len(set_a & set_b) / (len(set_a) * len(set_b)) ** 0.5 def get(self, question): """查询缓存: 精确键匹配加语义去重""" key = self._normalize(question) for cached in reversed(list(self._cache_map)): if self._cosine_similarity(key, cached) >= self.threshold: answer, ts = self._cache_map[cached] if time.time() - ts < self.ttl: self._cache_map.move_to_end(cached) return answer, key if key == cached else cached del self._cache_map[cached] return None, None def put(self, question, answer): """写入缓存并按LRU淘汰最久未使用条目""" key = self._normalize(question) self._cache_map[key] = (answer, time.time()) self._cache_map.move_to_end(key) while len(self._cache_map) > self.capacity: self._cache_map.popitem(last=False) def warm_up(self, questions, retrieve_fn): """预热: 对热门问题批量预计算答案""" for q in questions: ans, _ = self.get(q) if ans is None: self.put(q, retrieve_fn(q)) if __name__ == "__main__": cache = SemanticDedupCache(capacity=50, threshold=0.9) def fake_rag(query): return "答案:" + query[:6] + "..." hot = ["什么是RAG缓存", "RAG缓存策略", "缓存性能优化"] cache.warm_up(hot, fake_rag) for q in ["什么是RAG缓存", "RAG 缓存策略", "今天天气怎么样"]: ans, hit_key = cache.get(q) if ans is not None: print("命中: " + q + " -> " + ans + " (对应键: " + hit_key + ")") else: ans = fake_rag(q) cache.put(q, ans) print("未命中, 已写入: " + q + " -> " + ans) print("缓存条目数: " + str(len(cache._cache_map)))
self._cache_map = OrderedDict()用有序字典实现 LRU,插入和访问都会调整条目顺序,淘汰时直接弹最前端。return "".join(text.split()).lower()规范化文本:去掉所有空白并统一小写,保证“同一个问题”永远生成同一个键。if self._cosine_similarity(key, cached) >= self.threshold语义去重的核心判断:意思相近就当作同一问题复用缓存。self._cache_map.move_to_end(cached)刚被命中的条目挪到末尾,作为“最近使用”的证据,供 LRU 排序使用。self._cache_map.popitem(last=False)弹出最前面的条目,也就是最久没被访问的,完成 LRU 淘汰。cache.warm_up(hot, fake_rag)预热入口:批量把热门问题算好并写入,对应面馆开门前备菜。ans, hit_key = cache.get(q)命中时同时返回答案和命中的缓存键,方便调试语义去重是否误判。
常见误区
误区我把命中率从 70% 调到了 98%,以为性能已经拉满了。结果用户反馈答案越来越旧,知识库明明更新了,机器人还在念旧文档。
正解命中率过高往往意味着缓存条目长期不失效、TTL 设得太长,或者问题集僵化。就像面馆每天的菜单永远是那十道菜,客人早就吃腻了。正确做法是为命中率设定“健康区间”,同时监控缓存新鲜度——新知识上线后,应有一定比例的缓存自然过期并重新计算,保证答案“既快又对”。
为何常见:性能优化时,人天然盯着“越大越好”的指标,忽略了命中率高背后的数据陈旧问题,把手段当成了目的。
误区我以为语义去重就是把问题里的语气词去掉、把同义词替换成统一的词,然后直接字符串比较就行。结果“我今天想退款”和“退款流程”完全匹配不上。
正解真正的语义去重要把文本映射到向量空间,用余弦相似度判断距离,靠的是模型对语义的理解,而不是简单的字面替换。面馆小刘能听懂“牛肉面”和“红烧牛肉面”是同一道菜,靠的不是背菜单,而是对店里菜品的整体理解。
为何常见:字符串处理是大多数人最先接触的文本技术,容易把一切文本问题都往“字符串替换”上想,低估了语义模型的作用。
误区我做了个预热任务,把所有 FAQ 的几千条问题一次性全部塞进缓存,结果内存直接爆掉,冷门问题占了大半空间,热门问题反而被挤出去了。
正解预热的前提是“热”——必须基于历史访问日志或业务预判,只挑高频问题。老张备菜只备排名前 12 的热卖款,绝不会把食材库里的每种菜都做成成品。无差别预热等于缓存污染,不仅浪费存储,还会挤占真正热门的条目,反而拉低命中率。
为何常见:新手容易从“越多越好”出发,认为缓存数据多一定好,忽略了缓存是稀缺资源、有容量边界,需要和淘汰策略统筹设计。
误区我在项目里加了 Redis 缓存,结果响应时间反而慢了几十毫秒,还不如不用缓存的时候。缓存不是万能药吗?
正解缓存有命中成本(查缓存)和未命中成本(查缓存加查底层加回填)。如果业务里 90% 的请求都是全新的、几乎不重复的问题,那么大部分请求都在付“额外的未命中成本”——查一次缓存的网络开销白白浪费了。RAG 缓存适合“重复度高、单次计算贵”的场景,就像面馆只对回头客多的招牌菜备料,一次性顾客点的新菜,现做反而划算。
为何常见:市面上讲缓存总是强调收益,忽略了“缓存也有查询成本”这一面;没有做场景判断就直接套用,自然适得其反。
误区我把缓存 TTL 设成 7 天,想着这样可以减少重新计算。但知识库更新后,用户连续一周拿到旧答案,差评率直线上升。
正解TTL 本质是“新鲜度”和“计算成本”的开关:设太长,陈旧数据长期存活;设太短,缓存频繁失效,命中率暴跌,等于白做。更稳妥的是“版本号加短 TTL”组合:知识库变更时主动失效对应条目,没变更时让缓存活得久一点。就像面馆的隔夜菜:冰箱里分层管理,标记日期的先吃,而不是一刀切全放七天。
为何常见:TTL 的语义是“时间到就删”,容易让人以为设长一点只是懒得刷新,忽视了知识型业务中“内容会变”这个前提。
面试题
Q1. RAG 查询缓存的缓存键通常由什么生成?
- A.用户浏览器型号
- B.规范化后的问题文本← 正确答案
- C.前端组件 DOM 节点
- D.后端随机数种子
答案:B。缓存键必须稳定且可重复。规范化后的问题文本(去空格、统一大小写)能保证“同一个问题”每次都生成同一个键。浏览器型号、DOM 节点、随机数种子都不具备这种稳定性,会导致命中率极低。
Q2. 缓存命中率的计算公式是?
- A.命中次数除以总请求次数← 正确答案
- B.未命中次数除以总请求次数
- C.缓存条目数除以总请求数
- D.缓存容量除以磁盘容量
答案:A。命中率 = 命中次数 ÷ 总请求次数 × 100%,衡量缓存的价值。未命中率是命中率的补数;条目数除以请求数没有业务含义;容量除以磁盘容量是存储使用率,与请求行为无关。
Q3. 语义去重通常使用哪种相似度指标?
- A.编辑距离加权求和
- B.余弦相似度阈值判断← 正确答案
- C.字符频率差分对比
- D.词频逆文档频率排序
答案:B。语义去重把文本映射成向量,用余弦相似度判断意思远近。编辑距离算的是字面改动次数,字符频率和词频统计都无法捕捉同义表达之间的语义关系。
Q4. Embedding 缓存主要降低哪部分开销?
- A.向量模型重复推理计算← 正确答案
- B.前端页面渲染的性能
- C.浏览器网络请求次数
- D.用户登录鉴权的延时
答案:A。Embedding 缓存把算好的向量存起来复用,省去同一问题反复调用向量模型的推理开销。页面渲染、网络请求、登录鉴权与向量计算无关,不是它优化的对象。
Q5. 预热策略的问题来源通常是?
- A.开发者脑补的随机问题
- B.历史日志中的高频问题← 正确答案
- C.测试用例里的固定问题
- D.竞争对手的公开问题
答案:B。预热要的是“真实的热”。历史日志记录了用户实际问过的问题,统计出的高频项最接近第二天的请求分布。开发者猜测、测试用例、竞品问题都无法代表真实流量。
Q6. LRU 淘汰策略的核心思想是什么?
- A.淘汰最近最少被访问的条目← 正确答案
- B.淘汰最早写入缓存的条目
- C.淘汰数据体积最大的条目
- D.淘汰内容最不相似的条目
答案:A。LRU 的核心假设是“刚被访问过的条目更可能再次被访问”,所以淘汰最久未使用的,对应老张每天把最久没点的面从备料清单里划掉。“最早写入”是 FIFO;“体积最大”和“内容不相似”都与访问热度无关。
Q7. 一条 1536 维 float32 向量占多少内存?
- A.约 3KB
- B.约 6KB← 正确答案
- C.约 12KB
- D.约 24KB
答案:B。1536 维 × 4 字节 = 6144 字节,约 6KB。这个数字直接决定缓存容量规划:1 万条向量就占约 60MB 内存,需要提前评估是否可接受。
Q8. 分层缓存策略通常包括哪些层级?
- A.内存级热数据缓存← 正确答案
- B.磁盘级温数据缓存← 正确答案
- C.Redis 共享缓存层← 正确答案
- D.大模型权重参数缓存
答案:ABC。分层缓存让热数据走内存、温数据走磁盘、跨实例走 Redis,命中率和成本兼顾,对应老张“牛肉多备、时令少备、高汤常备”。大模型权重属于模型服务层,不属于 RAG 缓存范畴。
Q9. 知识库更新后保证缓存一致的手段有?
- A.版本号比对自动失效← 正确答案
- B.主动删除旧缓存条目← 正确答案
- C.设置合理 TTL 兜底← 正确答案
- D.永久保留全量历史缓存
答案:ABC。知识库更新后,版本号比对、主动删除旧条目、合理 TTL 兜底都是常用的失效手段。永久保留全量历史缓存会让旧答案无限期存活,违背一致性目标,就像隔夜牛肉一直摆在冰箱里,迟早吃坏肚子。
Q10. 关于权衡打分公式 Score = λ × 命中率 − (1−λ) × 存储成本率的理解,正确的是?
- A.λ 越大越看重响应速度← 正确答案
- B.λ 取 0 时收益权重归零← 正确答案
- C.存在全局最优的 λ 配置
- D.λ 取 1 时忽略存储成本← 正确答案
答案:ABD。λ 调节收益与成本的偏好:λ 越大越看重响应速度,λ=1 时收益权重满、存储成本被完全忽略,λ=0 时收益权重归零。但 λ 表达的是业务偏好而非可优化的系统参数,不存在对所有人都最优的固定配置——这正是权衡取舍的本质。