RAG 性能优化:缓存、批量与并发
RAG 系统跑起来容易,扛住并发难。用户多了响应慢、成本高怎么办?这篇讲 RAG 系统的性能优化:检索加速、Embedding 优化、大模型调用优化、缓存策略、并发处理,从延迟和成本两个维度优化。
大家好,我是黒漂技术佬。
demo 阶段一个人用,怎么都快。上线后几百人同时用,问题就来了:
- 检索慢,用户等半天
- Embedding 算不过来,队列堵了
- 大模型调用贵,流量上来成本爆炸
- 并发高了系统崩
RAG 系统的性能优化,要从延迟和成本两个角度入手。
这篇讲各个环节的优化手段:缓存、批量、并发、模型选型、架构优化。
一、先搞清楚瓶颈在哪
优化之前先测速,找到最慢的环节。
RAG 各环节耗时(大概)
| 环节 | 耗时 | 说明 |
|---|---|---|
| 问题 Embedding | 10-50ms | 看模型大小和部署方式 |
| 向量检索 | 5-30ms | 看数据量和索引 |
| 关键词检索 | 5-20ms | BM25 很快 |
| Rerank | 50-200ms | CrossEncoder 慢,是瓶颈之一 |
| 大模型生成 | 500-2000ms+ | 通常是最大瓶颈 |
| 查询改写 | 300-1000ms | 多调一次大模型 |
一般来说,大模型生成是最大的瓶颈,其次是 Rerank 和查询改写。
成本构成
- 大模型 API:占主要成本,按 token 收费
- Embedding:便宜很多
- 向量库/服务器:固定成本
优化也要看是优化延迟还是优化成本,或者两者都要。
二、缓存:最简单有效的优化
相同的问题反复问,不用每次都重新算。
1. 问题检索缓存
同样的问题,直接返回缓存的检索结果,不用再 embedding + 检索。
用户问题 → 查缓存 → 命中 → 直接返回检索结果
→ 未命中 → 正常检索 → 写入缓存
缓存 Key
- 精确匹配:问题完全一样才命中(简单,但命中率低)
- 归一化匹配:去标点、统一大小写、去空格后匹配(命中率高一点)
- 语义缓存:语义相似就命中(效果最好,但复杂)
缓存 TTL
- 知识库更新了要失效
- 一般几小时到几天,看更新频率
2. 答案缓存
常见问题直接缓存答案,不用每次都生成:
- FAQ 类问题,答案固定
- 热门问题预生成答案
命中率高的话,能省大量大模型调用。
3. Embedding 缓存
相同文本的 embedding 结果缓存,建索引或重复查询时不用重复算。
4. 语义缓存(进阶)
不是完全一样才命中,语义相近就命中:
「怎么退货」和「退换货流程」语义接近 → 命中缓存
用向量相似度判断,命中率更高,但实现复杂。
缓存收益
热门问题占比高的场景,缓存命中率能到 30-70%,大幅降低延迟和成本。
三、Embedding 优化
1. 选轻量模型
- 效果够的话,优先用 small/base 版本,不用 large
- bge-small 比 bge-large 快 2-3 倍,效果差得不多
- 建库慢一点没关系,查询快就行
2. 批量处理
建索引的时候批量 encode,比一条条快很多:
python
# 慢
for text in texts:
emb = model.encode(text)
# 快
embs = model.encode(texts, batch_size=64)
3. GPU 加速
数据量大一定要上 GPU,速度快 10-100 倍。
4. 量化部署
INT8 量化,速度更快、内存更少,精度损失很小。
5. 专用推理框架
- vLLM:大模型推理加速,也支持 embedding
- Text Embeddings Inference (TEI):HuggingFace 出品,专门部署 embedding
- ONNX Runtime:模型转 ONNX,CPU 上也快不少
生产环境别直接用 sentence-transformers 裸跑,用专用推理服务。
四、检索优化
1. 向量库参数调优
- ef / nprobe 不用设太大,满足召回率要求就行
- 追求极限速度的话,牺牲一点召回率换速度
- 量化索引(SQ/PQ),内存更小,缓存命中率更高
2. 减少召回数量
Rerank 前召回 20 条够了就别召 50 条,检索和重排都省时间。
根据数据量和召回率要求找最小值。
3. 过滤下推
带元数据过滤的检索,尽量在向量库内部完成,别查出来再自己过滤。
选过滤优化好的向量库(Qdrant 这方面不错)。
4. 分片与冷热分离
- 热数据(常用)存高性能节点
- 冷数据(历史)存低成本节点
- 查询先查热数据,不够再查冷的
5. 关键词检索优化
BM25 一般很快,但数据量大也要优化:
- 用 ES 的话,合理设置分片
- 只检索标题和正文关键字段,别全字段搜
- 缓存热门查询结果
五、Rerank 优化
Rerank 经常是第二大瓶颈(第一是大模型生成)。
1. 控制重排数量
召回 20 条去重排就够了,别召 100 条去排,慢死。
2. 选轻量 Rerank 模型
- base 版本够用就不用 large
- 或者用更快的蒸馏版本
3. 批量重排
多个查询可以批量处理,提升吞吐。
4. 降级策略
高并发时可以跳过 Rerank,直接用粗排结果,保证可用性。
5. 缓存
相同 query + doc 的 rerank 结果缓存,不过命中率一般不高。
六、大模型生成优化
最大的开销,也是优化空间最大的地方。
1. 选合适的模型
- 简单问答:用小模型(GPT-3.5-Turbo、通义千问 turbo),便宜快
- 复杂推理:才用大模型
- 别什么都上 GPT-4,贵还慢
2. 控制输出长度
Prompt 里要求回答简洁,控制在 N 句话以内。输出越短越快越便宜。
3. 精简 Prompt
- 参考资料去重,别塞重复内容
- 历史记录只留必要的
- 系统提示词精简,别写一堆废话
每轮省一点,积少成多。
4. 流式输出
用户体验优化:边生成边返回,不用等全部生成完。
不减少总时间,但用户感觉快了。
5. 批量生成
多个请求批量处理,提升吞吐,降低成本。
6. 本地模型部署
流量大的话,部署开源模型(Qwen、Llama 等),成本比 API 低很多。
- 小流量:API 划算,不用运维
- 大流量:自部署划算,单价低
7. 答案缓存
前面说过,FAQ 类问题直接缓存答案,省掉整个生成环节。
七、并发与架构优化
1. 异步处理
- Embedding、检索、Rerank、大模型调用,都是 IO 密集型
- 用 async 异步框架,单机能扛更多并发
2. 队列削峰
请求进队列,worker 慢慢处理,防止突发流量打垮系统。
3. 读写分离
- 建索引和查询分开
- 批量更新索引,别实时一条一条更
4. 水平扩展
- 向量库集群部署
- Embedding 和 Rerank 服务多实例
- 无状态的服务直接加机器扩容
5. 多级降级
高并发时逐级降级,保证核心功能可用:
正常:混合检索 + Rerank + 大模型生成
一级降级:跳过 Rerank
二级降级:只用向量检索
三级降级:返回缓存的热门答案
极限:返回「系统繁忙,请稍后再试」
八、成本优化
1. 选型成本
| 方案 | 开发成本 | 运行成本 | 适合 |
|---|---|---|---|
| 全用 API | 低 | 高(按调用量) | 小流量、快速上线 |
| 开源自部署 | 高 | 低(固定服务器) | 大流量、长期运行 |
| 混合 | 中 | 中 | 高峰用 API,平时自部署 |
2. 向量库成本
- 小数据量:FAISS/Chroma 免费,自己维护
- 中数据量:Qdrant/Milvus 单机,一台服务器搞定
- 大数据量:集群 + 运维成本
3. 减少不必要的调用
- 查询改写不是必须的,简单场景可以省
- Rerank 效果够了就不用每次都跑
- 缓存命中就跳过计算
4. 监控用量
- 统计每天的 token 消耗、调用次数
- 找出异常的高消耗请求
- 优化 top 消耗的场景
九、性能监控
优化要有数据支撑,监控各个环节的耗时:
关键指标
- 端到端延迟(用户提问到返回答案)
- 各环节耗时(embedding、检索、rerank、生成)
- 缓存命中率
- 并发数、QPS
- 错误率、超时率
慢查询日志
记录耗时超过阈值的请求,分析为什么慢:
- 是检索慢?
- 还是大模型生成慢?
- 哪个环节异常?
成本监控
- 每天大模型 token 消耗
- embedding 调用量
- 服务器资源使用率
十、优化优先级建议
按性价比从高到低排:
第一梯队(简单有效)
- 答案缓存:热门问题直接返回,省最多
- 检索缓存:相同问题不用重复检索
- 精简 Prompt:省 token,还能快点
- 选合适大小的模型:别杀鸡用牛刀
第二梯队(中等投入)
- Embedding 服务优化:ONNX/TEI 部署,批量处理
- Rerank 控制数量:够用就好,别排太多
- 流式输出:体验优化
- 异步架构:提升并发
第三梯队(进阶优化)
- 语义缓存:命中率更高,实现复杂
- 本地模型部署:大流量成本优化
- 向量库集群:大数据量高并发
- 多级降级:稳定性保障
十一、常见坑
坑 1:过早优化
还没几个人用就搞分布式集群,纯属浪费。先跑起来,有瓶颈再优化。
坑 2:只优化速度不优化成本
速度很快,但大模型账单爆炸。两个维度都要考虑。
坑 3:缓存不失效
知识库更新了,缓存还是旧答案。要有缓存失效机制。
坑 4:并发上来全崩了
没有队列和降级,突发流量直接打挂。要有保护机制。
坑 5:Rerank 召太多
觉得召回越多越准,召 100 条去重排,慢得要死。20-30 条足够了。
十二、本篇小结
- 先测瓶颈,再针对性优化,别瞎调
- 大模型生成通常是最大瓶颈,也是最大成本项
- 缓存是性价比最高的优化:答案缓存 > 检索缓存 > embedding 缓存
- Embedding 优化:选轻量模型、批量、GPU、专用推理框架
- 检索优化:参数调优、减少召回数、过滤下推
- Rerank 优化:控制数量、轻量模型、降级策略
- 大模型优化:选对模型、控制输出、精简 Prompt、流式、缓存
- 架构优化:异步、队列、水平扩展、多级降级
- 成本和延迟都要关注,平衡两者
下一篇是本系列最后一篇:企业知识库实战------从 0 到 1 落地全记录,把整个系列串起来。
我是黒漂技术佬。