Q11RAG 检索增强RAGAgentAlpha 社区约 6 分钟更新 2026-09-14

RAG 为什么越用越慢?反向调优的排查顺序

上线时很快的 RAG,一年后高峰期开始超时,期间没人改过代码。慢不是单一 bug,是索引膨胀、数据倾斜、缓存退化、重排加码接力恶化的结果,排查要按固定顺序逐段归因。

面试官原题

为什么 RAG 越用越慢?如何反向调优?

面试官 · Agent 岗面试现场

一个真实的时间线:RAG 系统上线时,检索段延迟控制得很好,团队很满意。半年后,同样的查询要等明显更久;一年后,高峰期开始超时。期间没有人动过链路代码——动的是数据:文档量翻了不止一倍,增量导入跑了几百次,reranker 候选数为了效果从几十条加到上百条。

「越用越慢」很少是单一 bug,是每个当时都合理的小决定叠加出的系统性退化。反向调优的关键不是知道多少种优化手段,而是按正确顺序排查。

先给一个能复述的答案

RAG 变慢的来源随规模转移:索引膨胀让图搜索路径变长,数据倾斜和脏数据让无效搜索变多,缓存命中率随长尾查询占比升高而下滑,重排候选数随质量要求一路加码。排查按固定顺序:先分段埋点确认哪段退化,再查索引(规模、参数、分区),然后查数据(重复、倾斜、冷热),最后查缓存和重排。每次只动一个变量,动完用同一套评测集验证。

退化四格:按顺序排查,别平均用力 图:小蓝图解——退化四格:按顺序排查,别平均用力。

慢不是常数,是随规模恶化的函数

阶段主导因素典型症状第一刀切哪里
上线期配置不当从第一天就慢分段埋点,找配置错误
成长期索引膨胀检索段延迟缓慢爬升分区、重建索引、重标参数
成熟期数据倾斜 + 缓存退化高峰期抖动,长尾查询拖垮整体冷热分层、缓存治理
后期重排与生成成本失控延迟和成本一起涨候选数回收、上下文瘦身

四个阶段不严格串行,但退化的大方向一致:先慢在检索,再慢在数据,最后慢在链路后端。

索引膨胀:HNSW 参数的取舍开始变味

主流向量库的索引大多是 HNSW(分层可导航小世界图):向量被组织成多层图,上层稀疏、负责快速远距离导航,底层稠密、负责精细搜索。

三个参数决定它的行为。M 是每个节点保留的连边数,边越密图越好走、召回越稳,但内存和搜索开销越高;efConstruction 控制建图时的候选队列长度,决定图建得结不结实;efSearch 是查询时的候选队列长度,直接决定单次查询要探索多少节点。

库小的时候,默认参数毫无压力。库大了之后,两件事开始变味:

其一,同样的 efSearch 覆盖不住了。图变大后,固定的候选队列能探索的比例下降,要么调大 efSearch(延迟上涨),要么接受召回下滑。这个取舍必须用评测集重新标定,而不是沿用上线时的值。

其二,增量插入让图结构劣化。HNSW 对批量建库友好,对长期高频的增量更新不友好——删除留下空洞,插入让局部密度失衡,同样的参数下召回悄悄下降。工程对策是定期全量重建索引,配合新索引预热、原子切换流量。

AgentAlpha 面试题库 · 腾讯篇 RAG 部分的真题「向量数据库了解过吗,常见向量索引的实现细节」,答到最后一定要落在这组参数的取舍上,这才是面试官想听的部分。

HNSW 的多层跳表式结构:上层长程连接加速检索 图:HNSW 的多层图结构(上层节点更少、连线更长,搜索从顶层出发逐层下降缩小范围,把全库暴力比对的开销降到对数级别——向量库毫秒级召回的基础)

数据侧:慢的一半,花在没必要查的东西上

索引膨胀还有一个更隐蔽的推手:数据本身。

重复内容霸占索引容量。爬虫页面、模板化文档、同一份材料的多个版本,都以向量的形式住在库里。它们不带来信息,却让每次搜索穿过更多节点,还在结果里刷屏。去重瘦身往往能让索引规模降一截,这一步的收益比调任何参数都直接。

数据倾斜拖垮共享资源。多租户系统里,一个超大租户的查询会占掉检索集群的算力,表现为其他租户的延迟跟着抖动。对策是配额与隔离:大租户独立分区,查询加并发上限。

冷热分布被忽略。绝大多数查询集中在最近更新的文档上,但索引对所有文档一视同仁。冷热分层——热数据用高性能索引,冷数据走低成本检索——是规模化之后的必选项。

AgentAlpha 面试题库 · 阿里篇系统设计部分问过:「线上成功率突然下降时,怎样按版本、租户、模型和工具快速归因?」同样的按维度归因思路用在延迟上:把 P95 按租户、分区、时间段切开看,倾斜问题会立刻现形。

!小 A 拿着小扫帚整理落灰的书架,给文件夹换上崭新的紫色索引签 图:越用越慢不是单一 bug,是索引、数据、缓存几处慢性失血的叠加——先分段埋点确认退化位置,再按顺序下刀。

缓存与重排:后端的两处慢性失血

缓存命中率会自然下滑。上线初期查询高度集中,精确缓存躺着命中;用户规模上来后,长尾查询占比升高,命中率回落是正常现象。要做的是收紧归一化、给高频前缀做语义缓存灰度,并接受命中率有上限——别为了拉命中率放宽 key,那是在重蹈越权和陈旧的覆辙。

重排成本随质量要求一路加码。为了压 badcase,reranker 候选从几十条加到上百条,每次加码单独看都合理,累计起来重排段延迟翻了几倍。要定期回收:用评测集验证「砍回一部分候选,质量指标掉不掉」,多数系统能砍掉两成左右候选而效果基本不动。

一张按顺序执行的排查清单

被告知「系统变慢了」,按这个顺序走:

  1. 分段埋点对比:拿当前 P95 和历史基线比,确认是哪一段退化,不靠猜。
  2. 索引体检:规模曲线、efSearch 是否被改过、距上次全量重建多久、删除标记比例。
  3. 数据体检:重复内容占比、最大租户的查询份额、冷热分布。
  4. 缓存体检:三层命中率曲线,陈旧投诉是否同步上升。
  5. 重排体检:候选数量 × 单条耗时,对比历史配置。
  6. 生成体检:注入上下文的总长度曲线,确认不是检索结果越塞越多。

每一步只动一个变量,动完跑同一套评测集。AgentAlpha 面试题库 · 腾讯篇系统设计部分有一道相邻的题:「用户量从 100 增长到 10 万时,Agent 服务的主要扩展瓶颈在哪里?」——它和「越用越慢」考的是同一种能力:说清楚瓶颈如何随规模转移。

面试现场:追问怎么接

「为什么不直接加机器?」 扩容买回来的是吞吐,不是退化修复。索引结构劣化、参数失配这些问题,加机器只是把爆发点往后推,成本曲线还在原地。

「多久重建一次索引?」 不按时间定,按指标定:监控删除标记比例和召回抽检值,劣化到阈值就重建。固定周期重建是在为省心付浪费。

「反向调优和正向优化冲突吗?」 不冲突,顺序不同。正向优化面对「怎么更快」,反向调优面对「为什么变慢」。后者必须先归因再动手,跳过归因的优化经常把好配置改坏。

参考答案要点

  • 越用越慢不是单一 bug:索引膨胀、数据倾斜、缓存命中率下滑、重排加码,四个因素随规模接力恶化。
  • 排查按顺序:分段埋点找退化段,再依次体检索引、数据、缓存、重排、生成。
  • 关键机制:HNSW 的 efSearch 要随库规模重新标定,增量插入会劣化图结构,定期重建加原子切换。
  • 主动说坑:为效果悄悄加码重排候选,是延迟失控最常见的推手。
  • 收在取舍:扩容买吞吐不修退化;先归因再动手,每次只动一个变量并用评测集验证。
—— 本场面试完 ——