一家连锁餐厅的生意做得红火,老板却发现:每个客人都让后厨从洗菜切菜开始现做,食材、燃气、人力账单越来越高,出餐还慢得像蜗牛。RAG 系统的处境与它一模一样——每次用户提问,都要先做 Embedding(把问题翻译成向量),再请大模型现场生成答案。单次成本看着不高,可用户量一上来,总成本几乎线性飙升。 聪明的餐厅该怎么办?把招牌菜提前做成半成品冷藏,点单直接加热上桌(语义缓存);把厚达 200 道的菜单精简成爆款,去掉重复备料(检索结果压缩);让前厅服务员先分流,家常菜走家常做法,硬菜才请大厨出马(粗筛精排与模型分级)。这篇就用这家餐厅的经营哲学,把 RAG 降本增效的整套思路讲透——先看成本账,再依次掌握缓存、压缩、双阶段排序、模型分级,最后讲清工程落地的监控与迭代方法。

岗位关联

对 AI 从业者:掌握这些策略,你能在大规模 RAG 服务中把单请求成本降低 50% 以上,把系统从「能跑通」推到「能规模化盈利」,这是 AI 应用工程师与架构师的必修课。

目录
  1. 可视化演示
  2. 成本问题分析
  3. 语义缓存原理
  4. 检索结果压缩
  5. 粗筛精排架构
  6. 模型分级调用
  7. 工程落地实践
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

展示语义缓存命中、检索结果压缩、级联排序粗筛精排及多级模型成本路由四大降本增效策略,交互切换理解优化原理。

本节配有交互动效(进入视口后自动加载,约 3KB)。

语义缓存:embedding相似度匹配 新查询与历史查询做向量相似度匹配,命中则直接返回缓存结果 similarity = cos(emb(q_new), emb(q_cache)) 避免重复LLM调用,命中率越高成本节省越显著。

成本问题分析

开餐厅的头一件事,不是研究新菜,而是把账本摊开:钱花在哪道菜、哪道菜不赚钱、哪个环节在磨洋工。RAG 系统的降本同理,先拆解成本结构,才能知道该往哪儿下刀。

RAG 查询链条里有两个躲不掉的开销:Embedding 和 LLM 生成。Embedding 就像把客人的口味偏好翻译成“甜辣咸淡”的标签组合,便宜但逃不掉;LLM 生成则像大厨从洗菜切菜到颠勺出锅全程亲力亲为,又贵又慢。把单次成本记为 $C_{emb}$ 与 $C_{llm}$,查询次数记为 $N$,总成本就是二者之和再乘上 N。

看清账单后,餐厅老板的目标就很明确了:不是把某一道菜砍掉,而是改变“每个客人点菜都让大厨从头做”的模式,让该备的备好、该省的省下。这正好引出后面的四招省钱术。

Ctotal=N×(Cembedding+Cllm)\displaystyle C_{total} = N \times \left( C_{embedding} + C_{llm} \right)
总成本 = 查询次数 ×(单次向量化成本 + 单次生成成本)。查询越多,这个乘法放大镜越明显。
  1. 查询次数 N一段时间内用户发起的请求总数,相当于一天里客人点的菜数。
    NN
  2. 向量化成本 C_embedding把文本变成向量的开销,固定且便宜。
    CembeddingC_{embedding}
  3. 生成成本 C_llm大模型逐字输出答案的开销,与答案长度正相关,是整个链条最贵的一环。
    CllmC_{llm}
  4. 乘法放大单次成本看似微小,乘以海量查询后变成惊人账单。
    N×(Cembedding+Cllm)N \times \left( C_{embedding} + C_{llm} \right)

语义缓存原理

为了不让大厨累死在灶台前,聪明餐厅的做法是:把点击率高的招牌菜提前做成半成品冷藏,客人一点单,加热三十秒就上桌。RAG 里的语义缓存,就是给高频问题准备一份“半成品答案”。

难点在于用户提问千变万化:“怎么申请发票”和“发票如何开”字面长得不一样,意思却相同。字面精确匹配会漏掉大量可复用请求,所以要用向量语义匹配:把查询 q 转成向量,和缓存库里每个缓存问题 c 的向量算余弦相似度,高于阈值就判定命中,直接复用现成答案。

缓存不是存了就不管,半成品也有保质期:知识库更新后,相关缓存要主动作废;缓存体积太大时,用 TTL 或 LRU 淘汰低频项目。这样“厨房的冷柜”才能始终放最新鲜的料。

sim(q,c)=q⃗⋅c⃗∥q⃗∥×∥c⃗∥\displaystyle sim(q, c) = \frac{ \vec{q} \cdot \vec{c} }{ \|\vec{q}\| \times \|\vec{c}\| }
命中判据:$sim(q, c) \ge \theta$。相似度超过阈值,就认为两个问题“口味一样”,可以共用同一种半成品。
  1. 点积两个向量对应元素相乘后累加,反映它们在方向上的重合程度。
    q⃗⋅c⃗\vec{q} \cdot \vec{c}
  2. 模长向量自身的长度,用来做归一化分母。
    ∥q⃗∥×∥c⃗∥\|\vec{q}\| \times \|\vec{c}\|
  3. 归一化除法消除向量长度的影响,只看方向夹角,夹角越小越相似。
    q⃗⋅c⃗∥q⃗∥×∥c⃗∥\frac{ \vec{q} \cdot \vec{c} }{ \|\vec{q}\| \times \|\vec{c}\| }
  4. 阈值门槛相似度大于等于 $\theta$ 才允许复用答案,太低会拿错菜、太高会漏接单。
    sim(q,c)≥θsim(q, c) \ge \theta

检索结果压缩

菜单厚达 200 道菜,客人看得眼花,后厨备料浪费严重。RAG 从向量库捞回的相关文档,也常常又长又啰嗦、充满重复段落,直接塞给大模型,既浪费 token 又干扰判断。

压缩的三条路径可以一起上:去重是把内容高度重复的文档合并成一份;摘要压缩是请小模型把长文提炼成要点;截断取舍是只保留与问题最相关的段落,无关内容坚决不要。压缩率衡量省了多少:

压缩的底线是信息保真:菜单可以砍到 30 道爆款,但客人必点的招牌菜绝不能删。实践中用去重相似度(如 Jaccard)判断重复,用相关性排序决定先留谁——压缩掉噪音,反而让大模型更容易抓住重点。

r=1−∣compressed∣∣original∣\displaystyle r = 1 - \frac{ |compressed| }{ |original| }
压缩率 = 1 − 压缩后长度 / 压缩前长度。压缩率越高,喂给大模型的 token 越少,单次调用越便宜。
  1. 原始长度压缩前文档的字符数,相当于一份菜的全套原材料清单。
    ∣original∣|original|
  2. 压缩后长度精简后剩余的字符数,去掉的是水分,留下的是干货。
    ∣compressed∣|compressed|
  3. 比值压缩后占压缩前的比例,越小说明砍得越狠。
    ∣compressed∣∣original∣\frac{|compressed|}{|original|}
  4. 取补用 1 减去比例得到“省了多少”,省得越多越接近 1。
    1−∣compressed∣∣original∣1 - \frac{|compressed|}{|original|}

粗筛精排架构

一个有经验的前厅经理,会先扫一眼客人需求快速分流:赶时间的客人去吃简餐,讲究的客人领到包间。如果所有菜都让大厨从头做,大厨早累垮了。RAG 检索同样要分层。

初始检索可能捞回几百上千条候选文档,如果全让大模型阅读排序,成本无法接受。于是先让小模型(或轻量检索器)做粗筛:从海量文档里快速挑出 TopK 个候选,不求精确,但求不遗漏;再让大模型对候选做精排,逐个评估相关性,选出真正进入上下文的少量片段。

前厅分流的价值在于:大厨的精力和时间只花在最值得的菜上。粗筛保证召回,精排保证精准,两者配合把“质量-成本”这个天平端平。

Crerank=Ncand×Csmall+K×Clarge\displaystyle C_{rerank} = N_{cand} \times C_{small} + K \times C_{large}
粗筛阶段用便宜的小模型处理 N_cand 个候选,精排阶段只用大模型评估 K 个,总成本远低于直接让大模型全量排名。
  1. 候选数量粗筛放行的文档数,$N_{cand}$ 远小于全量文档库大小。
    NcandN_{cand}
  2. 小模型单价粗筛模型处理一个候选文档的成本。
    CsmallC_{small}
  3. 精排数量真正进入大模型深度评估的条数,通常取 Top-2 到 Top-5。
    KK
  4. 大模型单价精排模型处理一个候选的成本。
    ClargeC_{large}
  5. 两部分相加粗筛与精排的成本之和,就是双阶段漏斗的总账单。
    Ncand×Csmall+K×ClargeN_{cand} \times C_{small} + K \times C_{large}

模型分级调用

餐厅分快餐、家常菜、宴席三档,各有各的定价和做法。RAG 也不该让所有问题都去请旗舰大模型——回答“今天星期几”和“推导傅里叶变换”的成本显然不该一样。

分级策略的核心是把请求按难度路由到匹配的模型:简单的事实性问答交给便宜小模型,复杂推理和长文总结才动用大模型。路由可以用规则(如分类器、关键词、用户请求长度)或信号模型自动判断。整体成本按各档请求占比加权计算:

分级不是一刀切省钱,还要留“效果回退保障”:如果小模型给出的答案置信度过低,自动升级到旗舰模型重答。就像砂锅粥不够时立刻换佛跳墙,客人始终满意,餐厅也保住了招牌。

Ctotal=∑iNiN×Cmodel_i\displaystyle C_{total} = \sum_{i} \frac{N_i}{N} \times C_{model\_i}
总成本 = Σ(第 i 档请求占比 × 第 i 档模型单次成本)。简单请求占得越多,总账单越低。
  1. 分档数量分给第 i 档模型的请求个数。
    NiN_i
  2. 请求总量所有请求的总数。
    NN
  3. 占比第 i 档请求占总请求的份额,权重越大对成本影响越大。
    NiN\frac{N_i}{N}
  4. 分档单价第 i 档模型的单次调用成本。
    Cmodel_iC_{model\_i}
  5. 加权求和各档占比乘单价再加起来,得到混合后的期望成本。
    ∑iNiN×Cmodel_i\sum_{i} \frac{N_i}{N} \times C_{model\_i}

工程落地实践

方案再好,也要用账本验证:备的半成品卖了多少、上菜速度提了多少、客人投诉有没有变多。RAG 优化上线之前,先搭好监控与评估体系,再用灰度逐步放量。

核心指标有两组:一是效率指标,包括缓存命中率、p95 延迟、单请求成本;二是质量指标,用人工抽评和评测集给答案的准确性、完整性、格式打分。成本优化如果让质量明显下滑,省的钱总有一天会以用户流失的方式还回去。

上线路径建议从 10% 流量灰度开始:切一小部分流量观察指标无异常,再逐步放大。随后持续调优——降低缓存阈值提高召回、换更好的粗筛模型、调整分级路由规则,形成“监控-评估-调优”的迭代闭环,让成本曲线一路向下。

hit_rate=HhitHhit+Mmiss,Ceff=Cquery×(1−hit_rate)\displaystyle hit\_rate = \frac{H_{hit}}{H_{hit} + M_{miss}}, \qquad C_{eff} = C_{query} \times (1 - hit\_rate)
命中率是缓存健康度的体温计;有效成本 = 单次原始成本 × 未命中率,只有没命中的请求才需要支付全价。
  1. 命中数缓存直接给出答案的请求数,相当于从冷柜直接上菜的订单。
    HhitH_{hit}
  2. 未命中数必须完整走一遍 LLM 的请求数。
    MmissM_{miss}
  3. 命中率命中数占总请求数的比例,越高说明缓存越有用。
    HhitHhit+Mmiss\frac{H_{hit}}{H_{hit} + M_{miss}}
  4. 有效成本原始单次成本乘以未命中率,得到优化后的期望成本。
    Cquery×(1−hit_rate)C_{query} \times (1 - hit\_rate)

AI 应用场景

智能客服知识库问答

阶段:RAG 在线推理时的成本治理

解决的问题:客服场景 70% 的问题是重复的(退换货政策、物流查询等),传统做法每次都要 embedding + LLM 全部走一遍,账单高、响应慢。用语义缓存直接命中常见问题的答案,配合粗筛精排缩短上下文,只对“这怎么走迷宫”这类复杂问题启用大模型。

具体案例:某电商客服机器人上线语义缓存后,缓存命中率达到 68%,单次对话成本下降 55%,p95 延迟从 3.2 秒降到 1.1 秒。日常问题秒回,复杂退款投诉转入大模型精细处理,满意度不降反升。

企业内部文档检索助手

阶段:检索与上下文构建阶段

解决的问题:企业知识库文档动辄几十万篇,直接向量检索返回 top-10 再全量喂给大模型,token 消耗巨大。通过检索结果去重 + 摘要压缩 + 粗筛精排,把送入大模型的上下文压缩到原来的 40%。

具体案例:一家法律咨询公司的案例库问答系统,用 Jaccard 相似度去重合并了 30% 重复段落,并用小模型粗筛 500 条候选、大模型精排 Top-3。合同条款问答精度保持 91% 不变,单请求 token 消耗下降 60%。

在线教育答疑平台

阶段:模型路由与成本预算控制

解决的问题:上万名学生同时提问,问题难度天差地别。统一使用旗舰大模型既浪费又不必要,按复杂度分级路由可让简单题走小模型,难题自动升级。

具体案例:某在线教育平台按题目类型和长度路由:常识题(小模型成本 0.003 元/次)、知识点解释(中型模型 0.01 元/次)、高难度压轴题(旗舰 0.05 元/次)。混合后平均单次成本从 0.05 元降到 0.015 元,且答错率变化不超过 1 个百分点。

Python 演示

python66 行
import difflib  class SemanticCache:    def __init__(self, threshold=0.55):        self.threshold = threshold        self.cache_map = {}        self.hit_count = 0        self.miss_count = 0     def _similar(self, q1, q2):        # 教学简化版: 用字符相似度近似语义相似        return difflib.SequenceMatcher(None, q1, q2).ratio()     def lookup(self, query):        for cached_q, answer in self.cache_map.items():            if self._similar(query, cached_q) >= self.threshold:                self.hit_count += 1                return answer        self.miss_count += 1        return None     def store(self, query, answer):        self.cache_map[query] = answer  def llm_call(query):    # 模拟一次昂贵的大模型生成    return f"关于[{query}]的完整答案(LLM生成)"  def main():    cache = SemanticCache(threshold=0.5)    questions = [        "如何申请发票",        "发票怎么申请",        "请问怎样开增值税发票",        "退款流程是什么",        "退货怎么操作",        "取消订单后怎么退钱",    ]    llm_cost = 10   # 大模型调用单价    emb_cost = 1    # 向量化查询单价    total_cost = 0     for q in questions:        ans = cache.lookup(q)        if ans is None:            ans = llm_call(q)            cache.store(q, ans)            total_cost += llm_cost + emb_cost            print(f"[MISS] {q} -> 全价 {llm_cost + emb_cost}")        else:            total_cost += emb_cost            print(f"[HIT ] {q} -> 成本 {emb_cost}")     n = len(questions)    hits = cache.hit_count    baseline = n * (llm_cost + emb_cost)    print(f"\n命中率: {hits}/{n} = {hits / n:.1%}")    print(f"优化后成本: {total_cost}, 无缓存成本: {baseline}")    print(f"节省比例: {1 - total_cost / baseline:.1%}")  if __name__ == "__main__":    main()
目的:用 20 行核心逻辑演示语义缓存的查缓存、算相似度、命中复用、未命中调 LLM 的完整流程,并统计命中率与成本节省。
  1. self.cache_map = {}初始化缓存仓库,相当于餐厅的半成品冷柜
  2. difflib.SequenceMatcher(None, q1, q2).ratio()计算两个问题文本的相似比例,工业界会换成 embedding 余弦相似度
  3. if self._similar(query, cached_q) >= self.threshold:相似度超过阈值就判定命中并复用答案
  4. cache.lookup(q)点餐前先翻冷柜,命中就免去 LLM
  5. llm_call(q)模拟一次全价的大模型生成,像大厨从头做一道菜
  6. total_cost += llm_cost + emb_cost未命中才支付全价
  7. total_cost += emb_cost命中只需要付向量化的轻量成本

常见误区

误区语义缓存不就是把问过的问题存起来,下次遇到相同问题直接取答案吗?用户换个说法就命中不了,没啥用。

正解语义缓存的关键在“语义相似”而非“字符串相等”。它把问题转成向量后算余弦相似度,“怎么退款”和“钱能退回来吗”在向量空间里距离很近,照样命中同一份答案。就像半成品冷柜按“菜的味道”分类,不按菜名逐字匹配。

为何常见:大家习惯了浏览器缓存按 URL 精确匹配的运作方式,把“缓存必须精确命中”的惯性思维带到了 RAG 缓存设计里。

误区压缩就是把内容砍掉,砍掉信息后大模型看不到完整资料,答案质量肯定会变差。

正解RAG 检索回来的文档里大量段落是重复、跑题或低相关的噪音。压缩去掉的是冗余而不是关键信息,配合截断取舍和精排把最相关的 TopK 保留下来,上下文反而更聚焦。就像 200 道菜的菜单精简成 30 道爆款后,客人更容易选中真正想吃的菜。

为何常见:看到“压缩”就联想到有损压缩(图片变糊、音乐变闷),忽略了文本压缩可以只删冗余、保留语义核心。

误区小模型这么笨,粗筛时把正确答案划到候选池外,后面精排再准也无力回天。

正解粗筛只承担“高召回、低成本”的初选职责,候选池故意放宽到百条量级,漏掉正解的概率很低。真正做最终选择的是大模型精排阶段,小模型的定位是“海选”而不是“定音”。

为何常见:用精排的精度标准去要求粗筛,混淆了两个阶段各自的目标函数,放大对小模型的担忧。

误区既然小模型又便宜又快,那把所有请求都切到小模型不就彻底降本了吗?

正解分级调用的精髓是“该省则省,该花则花”。简单任务用便宜模型,复杂推理必须升级到旗舰,否则答案质量崩塌导致用户流失,流失的营收远大于省下的 token 钱。餐厅也不会因为想省钱就把宴席菜全换成快餐。

为何常见:只盯着成本公式里显性的单价,忽略了质量下降带来的隐性长期成本,陷入“省钱省掉了客户”的陷阱。

面试题

Q1. RAG 系统每次查询中,成本占比通常最高的环节是?

单选题 · easy

  • A.用户登录鉴权开销
  • B.大模型生成回答← 正确答案
  • C.日志存储与监控
  • D.前端页面展示渲染

答案:B。LLM 生成按 token 计费且输出阶段计算量大,是 RAG 链路中最贵的环节。登录鉴权、日志、前端渲染都不是推理主链路的大头,成本占比很小。

Q2. 语义缓存判断两个问题语义是否相似,主要依据是?

单选题 · easy

  • A.两个问题的长度一致
  • B.向量空间中的余弦相似度← 正确答案
  • C.两个问题首字母相同
  • D.两个问题的标点符号相同

答案:B。语义缓存把文本转成向量,用余弦相似度衡量方向夹角。“如何退款”与“钱怎么退回”字面不同但向量方向接近,能命中同一份缓存答案;而长度、首字母、标点都是表面特征,无法反映语义。

Q3. 缓存命中率越高,对 RAG 系统意味着?

单选题 · easy

  • A.大模型调用次数越少← 正确答案
  • B.向量库越来越大
  • C.答案质量越来越低
  • D.网络带宽消耗越高

答案:A。命中率高说明大量请求直接复用缓存答案,不需要再触发昂贵的 LLM 调用,成本和延迟都会下降。命中率与向量库大小、质量、带宽没有直接必然联系。

Q4. 余弦相似度 sim(q,c) 的数值越接近 1,表示两个向量?

单选题 · mid

  • A.方向越一致夹角越小← 正确答案
  • B.长度差异越来越大
  • C.维度数量完全相同
  • D.出现顺序完全相反

答案:A。余弦相似度只关注向量夹角,夹角越接近 0,相似度越接近 1,表示两个问题的语义方向越一致。它与向量长度、维度数量无关,也不反映顺序信息。

Q5. 检索结果压缩最重要的原则是?

单选题 · mid

  • A.压缩后的字节越小越好
  • B.保留核心信息不丢失← 正确答案
  • C.全部转成纯文本格式
  • D.删除所有长难句与修饰语

答案:B。压缩的目的是在省 token 的同时保持信息保真,回答问题的关键事实不能丢。只追求体积小会伤及质量,转纯文本和删长句都是手段而非原则。

Q6. 下列哪些做法属于 RAG 降本增效策略?

多选题 · mid

  • A.语义缓存复用相似查询← 正确答案
  • B.压缩检索结果的冗余信息← 正确答案
  • C.小模型粗筛加大模型精排← 正确答案
  • D.每次请求都加大 max_tokens

答案:ABC。A、B、C 分别是语义缓存、结果压缩、粗筛精排,都是 RAG 降本核心手段。D 增大输出上限会抬高单次生成成本,与降本目标背道而驰。

Q7. 粗筛精排架构中,粗筛阶段的首要目标是?

单选题 · mid

  • A.最高精确率放行极少结果
  • B.高召回率不遗漏相关文档← 正确答案
  • C.用大模型逐一精读全文
  • D.对海量文档做最终排序

答案:B。粗筛负责“海选”,要求把可能相关的文档都捞进候选池,宁可多留也不漏掉;精确的最终选择交给大模型精排。如果粗筛就追求高精确,容易把正确答案挡在门外。

Q8. 关于语义缓存的失效与淘汰策略,合理做法包括?

多选题 · hard

  • A.知识库更新后清理相关缓存← 正确答案
  • B.给缓存条目设置 TTL 过期时间← 正确答案
  • C.缓存一旦写入永不删除
  • D.按 LRU 淘汰低频访问条目← 正确答案

答案:ABD。知识更新后旧答案要失效,TTL 保证数据时效,LRU 控制缓存体积并保留热点。缓存永不清理会导致陈旧答案长期驻留,并让存储成本不断膨胀。

Q9. 模型分级调用的路由依据可以包括?

多选题 · hard

  • A.问题的复杂程度评估← 正确答案
  • B.用户所在地区的地理位置
  • C.上下文长度与成本预算← 正确答案
  • D.输出结果的质量要求高低← 正确答案

答案:ACD。路由应依据任务复杂度、上下文长度和期望质量来匹配模型档次,达到成本与效果的平衡。用户地理位置与技术路由无关,不应作为模型分级的核心依据。

Q10. 某 RAG 系统优化前单请求成本 0.1 元,引入语义缓存后命中率 80%,再配合粗筛精排节省剩余开销的 50%,优化后单请求成本约为?

单选题 · extreme

  • A.0.01 元← 正确答案
  • B.0.02 元
  • C.0.04 元
  • D.0.08 元

答案:A。命中率 80% 意味着只有 20% 请求走完整链路:0.1 × 0.2 = 0.02 元;粗筛精排在此基础上再省 50%:0.02 × 0.5 = 0.01 元。注意“剩余开销”的基准是未命中部分,不可从原始成本直接除倍率。