- RAG(检索增强生成)完整详解,覆盖索引、检索、生成与评估全链路
- 对应面试问答速查见 RAG(面试版)
- 相关主题:大模型基础、大模型训练与微调、大模型推理与部署、AI Agent、LangChain 与 LangGraph
- 当前覆盖:动机与对比微调、三段式流程、分块与语义分块、embedding 选型/微调/不对称、dense/sparse 与 BM25/TF-IDF、多向量(ColBERT)、向量库与索引(HNSW/IVF/PQ/参数调优)、相似度、混合检索与多路召回、rerank、元数据过滤与文档新鲜度、query 改写/意图识别与 routing、GraphRAG/Self-RAG/CRAG/RAPTOR、agentic/conversational 与多轮检索、上下文组织与引用溯源、幻觉控制、评估(RAGAS/recall@k/A-B)、成本与语义缓存、权限多租户、增量索引与 CDC
什么是 RAG?它解决什么问题?和微调有什么区别?
定义
Retrieval-Augmented Generation:在生成前先从外部知识库检索相关文档,把检索结果作为上下文注入 LLM,再生成回答。核心是「先查再用」。
解决什么问题
- 幻觉:用外部事实锚定生成,减少编造。
- 知识时效:知识库可随时更新,无需重训模型。
- 知识私有化:接入企业内部/私有数据。
- 可溯源:回答可标注引用来源。
vs 微调
| 维度 | RAG | 微调(SFT) |
|---|---|---|
| 知识更新 | 即时(改库即可) | 需重训 |
| 成本 | 低 | 高(数据+算力) |
| 能力改变 | 不改模型能力,只补知识 | 改变行为/风格 |
| 可溯源 | 强 | 弱 |
| 幻觉控制 | 好 | 一般 |
- 实践常组合:RAG 补知识 + 微调改行为/风格。
一句话「检索外部知识再生成」,并说清「RAG 补知识、微调改行为」,点出「知识更新快、成本低、可溯源」三优势。
RAG 的完整流程包含哪几个阶段?
三段式流程
- 索引(Indexing)离线:文档 → 分块(chunking)→ embedding 向量化 → 存入向量库(建索引)。
- 检索(Retrieval)在线:用户 query → 向量化 → 向量库相似度检索 top-k →(可选)rerank 重排。
- 生成(Generation)在线:把检索到的片段拼进 prompt → LLM 生成回答(可带引用)。
关键点
- 索引与检索分离:离线建库、在线查询。
- 每段质量(分块、embedding、检索)都会影响最终答案,检索质量是 RAG 效果的上限。
完整说出「索引 → 检索 → 生成」三段,并强调「检索质量决定 RAG 上限」这句共识。
RAG 中如何做文本分块(chunking)?
分块目标
把长文档切成语义完整的块(chunk),兼顾「块过大 → 检索不准、噪声多」与「块过小 → 上下文破碎、语义缺失」。
分块策略
| 策略 | 做法 | 特点 |
|---|---|---|
| 固定大小 | 按 N 字符/token 切 + overlap | 简单,最常用 |
| 递归分块 | 按段落/句子层级递归切 | 保持结构 |
| 语义分块 | 按 embedding 相似度找语义边界 | 质量高,成本高 |
| 结构分块 | 按标题/表格/代码块结构切 | 适合结构化文档 |
关键参数
- chunk size:常见 256~1024 token;语义粒度决定检索精度。
- overlap:块间重叠(如 10%~20%),避免语义被切断。
- 需匹配 embedding 模型与任务类型(问答用小块、摘要可大块)。
说明「size 与 overlap 权衡语义完整与检索精度」,并提「按标题结构切 + 语义分块」等进阶做法。
如何选择和评估 embedding 模型?
选择要点
- 语言:中英文能力匹配(中文选 BGE、bge-large-zh 等)。
- 维度:维度越高表达越强但存储/计算越贵,常见 768/1024。
- 检索 vs 通用:检索专用模型(BGE、E5、Cohere)优于通用 embedding。
- 上下文长度:能否处理长 chunk。
- 成本/延迟:本地部署 vs API。
评估方法
- MTEB 基准:综合评估检索/分类/聚类等任务。
- 检索指标:Recall@k、MRR、NDCG(针对具体语料实测)。
- 用真实业务数据评测比通用榜单更可靠。
注意
- 查询与文档可能需不同模型或不同 prompt 模板(不对称检索)。
- embedding 需与分块策略、向量库配合调优。
强调「按语言选模型、用 MTEB + 业务数据实测」,并点出「query 与 doc 可用不对称模型」的细节。
常用的向量数据库有哪些?HNSW 索引的原理是什么?
常用向量库
| 向量库 | 特点 |
|---|---|
| FAISS | Meta 开源,库而非服务,高性能 |
| Milvus | 分布式向量库,生产级 |
| pgvector | PostgreSQL 扩展,与关系库同源 |
| Chroma | 轻量,适合原型 |
| Weaviate/Qdrant | 开源向量库,功能全 |
HNSW 原理
Hierarchical Navigable Small World(分层可导航小世界图):
- 建多层图,上层稀疏、下层稠密,节点按「近邻」连接。
- 检索从顶层贪心跳跃快速逼近目标区域,再在底层精细搜索。
- 特点:近似最近邻(ANN),检索快(对数级),内存占用较大,召回率/速度可调(efSearch、M)。
讲清「HNSW = 多层小世界图 + 贪心搜索,近似最近邻,速度/内存权衡」,并知道「召回率与速度靠 efSearch 调」。
向量检索的相似度度量有哪些?余弦、内积、欧式距离怎么选?
三种度量
| 度量 | 公式思想 | 适用 |
|---|---|---|
| 余弦相似度 | 夹角余弦,只看方向 | 文本语义(embedding 常用) |
| 内积 | 向量点积 | 归一化后等价余弦,检索快 |
| 欧式距离 | 空间直线距离,看大小 | 向量需考虑模长时 |
怎么选
- 文本 embedding 普遍用余弦:语义由方向决定,模长无关。
- 向量已归一化时,内积 = 余弦(点积更省计算),向量库常用内积加速。
- 欧式距离在「向量模长本身有意义」的场景(如图像特征)更合适。
注意
- 度量必须与 embedding 模型训练时用的度量一致(模型用余弦训练,检索就用余弦),否则召回差。
强调「embedding 已归一化时内积等价余弦、更快」,并点出「度量要与模型训练一致」这个常被忽略的点。
什么是混合检索?BM25 和向量检索如何融合?
为什么混合
- 向量检索:语义匹配强,但对专有名词、精确匹配(型号、错误码)弱。
- BM25(关键词):精确词匹配强,但不理解同义/语义。
- 二者互补,混合检索同时取两类结果融合,召回更全。
融合方法
- RRF(Reciprocal Rank Fusion):对每个文档按在两个列表中的排名取倒数求和
score = Σ 1/(k + rank),简单有效、无需调权。 - 加权融合:
score = α·向量分 + β·BM25分,需调权。 - 融合后再接 rerank 精排。
落地
- 典型链路:BM25 + 向量 → RRF 融合 → rerank,是生产 RAG 的标准组合。
讲清「向量管语义、BM25 管精确词」互补,并报出 RRF 排名倒数融合这个主流做法,再接 rerank。
什么是 rerank(重排)?双编码器和交叉编码器有什么区别?
rerank 是什么
初检索(双编码器)为速度只做粗排,召回 top-k(如 50~100)后,用更强的模型对「query + 文档」精排,取最终 top-N 进 prompt,显著提升相关性。
双编码器 vs 交叉编码器
| 维度 | 双编码器(Bi-Encoder) | 交叉编码器(Cross-Encoder) |
|---|---|---|
| 结构 | query、doc 分别编码再算相似度 | query+doc 拼接一起编码 |
| 精度 | 低(无交互) | 高(全交互) |
| 速度 | 快(doc 可预存) | 慢(需逐对算) |
| 用途 | 初检索(海量) | 重排(top-k 小集合) |
- 代表 rerank 模型:bge-reranker、Cohere Rerank、cross-encoder。
- 组合:双编码器粗召回 + 交叉编码器重排,兼顾速度与精度。
讲清「双编码器快但粗、交叉编码器准但慢」,标准架构「双编码器粗排 + 交叉编码器重排」。
检索质量差有哪些常见原因?如何优化?
常见原因
- 分块不当:chunk 过大/过小、语义被切断。
- embedding 不匹配:模型语言/领域不符、度量不一致。
- query 与文档表述鸿沟:用户口语 query vs 文档术语。
- 单路召回:只靠向量,漏掉精确词匹配。
- 索引/库问题:参数(efSearch)不当、数据未更新。
优化手段
- Query 改写:用 LLM 把口语 query 改写/扩展为检索友好表述(HyDE、多 query)。
- 多路召回:BM25 + 向量 + 元数据过滤。
- rerank:召回后精排。
- 调分块与 embedding:语义分块、领域 embedding。
- HyDE:先让 LLM 生成假设答案再拿它检索,缩小 query-doc 鸿沟。
按「分块 → embedding → 召回 → 重排」链路逐段排查,并重点提 query 改写/HyDE + 混合检索 + rerank 三板斧。
有哪些高级 RAG 技术?
主要进阶方案
| 技术 | 思路 | 解决什么 |
|---|---|---|
| Parent-Document Retriever | 检索小块、返回其父块大上下文 | 检索精度与上下文完整性兼顾 |
| HyDE | 先假设答案再检索 | query-doc 语义鸿沟 |
| Self-RAG | 模型自判「要不要检索、检索好不好」 | 按需检索、反思 |
| CRAG | 检索结果评估 + 纠正(重写/再检索) | 检索结果差时兜底 |
| GraphRAG | 用知识图谱做实体关系检索/社区摘要 | 多跳推理、全局问题 |
| 多路召回 + rerank | BM25/向量/多 query 融合 | 召回不全 |
选型
- 通用问答:多路召回 + rerank + query 改写即可。
- 多跳/全局问题:GraphRAG。
- 上下文碎片化:Parent-Document。
能报出 Parent-Document、HyDE、Self-RAG、CRAG、GraphRAG 并各用一句话说清用途,体现广度。
如何组织检索到的上下文?如何做引用溯源?
上下文组织
- 去重与截断:去重复片段,按相关性排序,控制总 token 在上下文窗口内。
- 排序:相关片段放前面(LLM 对前部更敏感)。
- 结构化拼接:给每个片段加编号/来源标签,如
[1] ... [2] ...。 - 保留元数据:来源、标题、时间,便于溯源。
- 压缩/摘要:片段过多时先用 LLM 压缩,避免上下文过载(lost in the middle)。
引用溯源
- 生成时要求模型引用片段编号(如
[1][3])。 - 结构化输出 + 约束解码,强制引用格式。
- 用「片段 → 原文位置」映射,前端渲染可点击引用。
- 评估忠实度(答案是否被检索内容支撑)来检验溯源质量。
提「编号 + 排序 + 截断」的组织法,以及「lost in the middle」现象与引用编号约束。
如何评估 RAG 系统的效果?
三组指标(RAGAS 框架)
| 维度 | 指标 | 含义 |
|---|---|---|
| 检索质量 | 上下文相关度(Context Relevance)、Recall | 检索到的内容相关吗 |
| 生成质量 | 忠实度(Faithfulness)、答案相关性 | 答案是否忠于上下文、切题 |
| 端到端 | 准确率、用户满意度 | 整体效果 |
具体方法
- RAGAS:用 LLM 自动评估忠实度/上下文相关度/答案相关性。
- 检索指标:Recall@k、MRR、NDCG(有标注时)。
- 忠实度:答案的每个断言是否被检索片段支撑(防幻觉)。
- 人工评估:端到端问答质量。
注意
- 评估要分层(检索与生成分开定位问题)。
- 用真实业务数据集,而非只跑通用 benchmark。
报出 RAGAS 与「忠实度 / 上下文相关度 / 答案相关性」三指标,强调分层评估定位检索还是生成问题。
RAG 系统生产落地有哪些工程要点?
工程要点
- 增量更新:知识库数据变更的实时/定时同步与重建索引。
- 缓存:热门 query 结果缓存、embedding 缓存,降成本延迟。
- 成本控制:embedding/LLM 调用计费、缓存、小模型分工。
- 安全与权限:文档级权限过滤,防止越权检索(多租户)。
- 可观测性:日志/监控检索命中率、延迟、失败率。
- 容错与降级:检索失败兜底、LLM 超时重试、限流。
- 质量迭代:用线上反馈回流,持续优化分块/embedding/rerank。
关键难点
- 权限隔离(企业场景最易踩坑)、知识库新鲜度、成本与延迟平衡。
突出「权限过滤、增量更新、缓存、可观测」这几个生产级要点,体现不只是「搭 demo」而是「能上线」。
dense 检索和 sparse 检索有什么区别?各有什么优劣?
dense 检索
把 query 和文档都编码为稠密向量(如 768 维),用语义相似度(余弦/内积)匹配。代表:embedding 向量检索。
sparse 检索
把文本表示为稀疏向量(绝大多数维度为 0),本质是词项权重。代表:BM25、TF-IDF、SPLADE(学习型稀疏)。
对比
| 维度 | Dense(稠密) | Sparse(稀疏) |
|---|---|---|
| 匹配方式 | 语义相似 | 词项精确匹配 |
| 同义/改写 | 强(能召回「车」vs「汽车」) | 弱 |
| 精确词(型号/错误码/专名) | 弱 | 强 |
| 领域迁移 | 依赖训练语料 | 通用、免训练 |
| 可解释性 | 差 | 好(能看到命中词) |
| 存储/算力 | 需向量库+算力 | 倒排索引,轻量 |
优劣与结论
- 二者互补,生产常混合检索(dense + sparse → RRF/加权融合)。
- 无训练数据或强词匹配场景用 sparse;语义泛化场景用 dense。
用「dense 管语义、sparse 管精确词」一句话点透,并落到「生产混合检索」的结论。
BM25 和 TF-IDF 有什么区别?
TF-IDF
词项权重 = TF(词频)× IDF(逆文档频率)。思想:在本文中出现多、在整个语料少见的词越重要。
BM25
TF-IDF 的工程改良,打分公式 BM25(q,d) = Σ IDF(qi) · [f(qi,d)·(k1+1) / (f(qi,d) + k1·(1-b+b·|d|/avgdl))]:
- 词频饱和:TF 非线性,
k1控制(词出现 5 次和 10 次差别不大,TF-IDF 线性放大)。 - 文档长度归一化:
b控制长度惩罚(长文档不再被无脑高估)。 - IDF 修正:常用变体
IDF = ln(1 + (N-n+0.5)/(n+0.5)),避免极端值。
对比
| 维度 | TF-IDF | BM25 |
|---|---|---|
| 词频处理 | 线性 | 饱和(k1) |
| 长度归一化 | 弱/无 | 有(b) |
| 可调参数 | 无 | k1、b |
| 效果 | 基准 | 检索标配、更优 |
点出 BM25 的词频饱和与长度归一化两个关键改进,能报出 k1、b 两个参数。
query 和 document 的不对称问题如何解决?
什么是非对称问题
query 是短、口语化的提问,document 是长、正式的文本,二者分布不同。若用同一个对称模型在同空间编码,会出现语义鸿沟,检索变差。
解决方案
- 非对称双塔模型:query 编码器和 document 编码器参数不共享/结构不同,各自适配。
- 不同 prompt/instruction:同模型但 query 侧加「为检索生成表示」指令、doc 侧加「为被检索生成表示」,如 E5/BGE 的
query:/passage:前缀。 - query 改写:把口语 query 改写成文档风格(见 query rewriting)。
- HyDE:先让 LLM 生成假设文档再拿它检索,直接对齐 doc 分布。
- 训练侧:用对比学习让「query 向量靠近其正例 doc 向量」。
说清「query 短口语、doc 长正式」的分布差异,并给出「非对称双塔 + 不同 prompt 前缀(query:/passage:)」这个主流做法。
ColBERT 多向量检索的原理是什么?
单向量 vs 多向量
- 传统双塔把整段文本压成一个向量,长文信息被压缩损耗。
- ColBERT 为每个 token 生成一个向量(多向量),保留细粒度语义。
ColBERT 原理(Late Interaction 后期交互)
- query 的每个 token 编码为向量
Q = [q1,...,qn],document 每个 token 编码为D = [d1,...,dm]。 - 打分用 MaxSim:query 每个 token 在 document 所有 token 中找最相似的向量求最大相似度,再求和:
score(Q, D) = Σ_i max_j (q_i · d_j)- document token 向量离线预存,检索时只需编码 query,用近似索引加速 MaxSim。
优势与代价
- 精度高:token 级交互,接近交叉编码器效果。
- 可离线预存:比交叉编码器快得多。
- 代价:存储量大(token 级向量)、需要多向量索引(如 PLAID、ColBERTv2 残差压缩)。
说清「token 级多向量 + MaxSim 后期交互」两个关键词,点出「精度接近交叉编码器但可离线预存」的核心优势。
如何对 embedding 模型做领域微调?
目标
让通用 embedding 适配领域(医疗、法律、金融)词汇与语义,提升召回。
数据构建(最关键)
- 正例:真实 query 及其点击/命中文档(日志挖掘)。
- 负例:随机负例、同 batch 内负例(in-batch negatives)、难负例(相似但不相关的文档)。
- 形式:
(query, doc+, doc-)三元组。
训练方式
- 对比学习:InfoNCE / triplet loss,拉近正例、推远负例。
- 参数高效微调:LoRA/QLoRA,只训部分参数。
- 非对称结构:query/doc 用不同 prompt 前缀。
评估
- 用领域标注集测 Recall@k / MRR / NDCG,对比微调前后。
- 防止灾难性遗忘:混入部分通用数据。
强调「难负例」对 embedding 微调的决定性作用,并提「对比学习 + LoRA + 领域集测 recall@k」的完整链路。
什么是元数据过滤?如何实现?
定义
检索时先按文档的结构化字段(时间、部门、文档类型、权限标签、语言)过滤,再在过滤后的子集里做向量检索。也叫 filtered search。
实现方式
- Pre-filter(先过滤后检索):先用倒排/标量索引筛出符合条件文档,再向量检索。语义准,但过滤条件宽时性能差。
- Post-filter(先检索后过滤):先向量召回 top-k,再按条件过滤。快,但可能过滤后不足 k 条。
- 混合/单遍过滤(single-stage filtering):向量索引内嵌过滤(如 HNSW 遍历时跳过不满足条件节点),兼顾两者。
场景
- 多租户权限隔离、按时间范围查、按部门/文档类型查。
报出 pre-filter / post-filter 两种方式及其「语义准 vs 性能」的取舍,并提「single-stage filtering」这一进阶做法。
如何处理文档新鲜度?时间加权检索怎么做?
问题
知识库文档新旧并存,旧文档可能已过时;纯语义检索无法感知时间。
时间加权检索(Recency Weighting)
把文档时间作为一个打分因子,与语义分加权融合:
final_score = α · semantic_score + β · recency_score- recency_score:常用指数/高斯衰减,如
exp(-λ · (now - doc_time)),越新越高。 - 或按时间桶分段赋权(近 7 天 / 近 1 月 / 更早)。
其它手段
- 时间过滤:query 解析出时间意图,用元数据过滤限定时间窗。
- 新鲜度重排:检索后把过时文档降权/丢弃。
- 有效期标记:文档标注
valid_until,过期自动下架。 - 区分「时效性 query」:只对新闻/法规等时效敏感 query 启用时间加权,技术文档则不必要。
给「语义分 + 时间衰减分加权融合」的公式思路,并强调「按 query 是否时效敏感选择性启用」这一工程细节。
多路召回如何实现?各路结果如何融合?
为什么多路
单路(纯向量)易漏:精确词、实体、同义改写、结构化字段各自需要不同的匹配方式。
多路召回源
- 向量检索:语义匹配。
- BM25 / 关键词:精确词匹配。
- 多 query 改写:同一 query 生成多个变体各自检索。
- 实体/知识图谱召回:实体链接后的关系召回。
- 结构化/元数据召回:字段精确命中。
融合方法
- RRF(Reciprocal Rank Fusion):
score = Σ 1/(k + rank_i),对各路排名取倒数求和,免调权、鲁棒。 - 加权融合:各路分数归一化后加权(需调权重)。
- 合并去重 → 统一 rerank:各路结果并集去重后,交给 reranker 精排(生产最常用)。
result = rerank( dedup( R_vector ∪ R_bm25 ∪ R_entity ... ) )说出「多路(向量+BM25+多 query)→ 并集去重 → rerank」的标准链路,并报出 RRF 免调权融合。
HNSW 的三个关键参数(M、efConstruction、efSearch)分别是什么?
参数含义
| 参数 | 作用阶段 | 含义 | 影响 |
|---|---|---|---|
| M | 建图 | 每个节点最大近邻连接数 | 越大召回越高、内存越大、建图越慢 |
| efConstruction | 建图 | 建图时贪心搜索的候选宽度 | 越大图质量越高、建图越慢 |
| efSearch | 查询 | 查询时搜索的候选宽度 | 越大召回越高、查询越慢 |
调参经验
- efSearch ≥ k(至少取 top-k),要更高召回则调大到 100~500。
- M 常用 16~64,efConstruction 常用 100~200(一次建图成本可接受)。
- 召回率与查询延迟是一对矛盾:
efSearch是上线后最常调的旋钮。
分「建图(M、efConstruction)vs 查询(efSearch)」两组讲清,并指出 efSearch 是上线后调召回/延迟平衡的主旋钮。
IVF 和 HNSW 有什么区别?如何选择?
IVF(倒排文件索引)
- 先对全量向量做 k-means 聚类,得到 nlist 个聚类中心(倒排桶)。
- 查询时先算 query 与各中心的距离,选最近的 nprobe 个桶,再在桶内暴力算距离。
- 特点:内存小、构建快,召回依赖 nprobe(nprobe 越大越准越慢)。
HNSW(图索引)
- 多层小世界图 + 贪心搜索(见前文)。
- 特点:召回高、查询快,但内存占用大、构建慢。
对比
| 维度 | IVF | HNSW |
|---|---|---|
| 结构 | 聚类倒排 | 多层图 |
| 查询速度 | 快(nprobe 控制) | 更快(对数级) |
| 内存 | 小 | 大 |
| 构建 | 快 | 慢 |
| 精度 | 依赖 nprobe | 高 |
| 适用 | 超大规模、内存受限 | 中小规模、追求高召回 |
选择
- 千万级以内、内存充足 → HNSW。
- 亿级超大规模 / 内存受限 → IVF(+PQ 压缩);磁盘场景用 DiskANN 等。
用「IVF=聚类倒排省内存、HNSW=图索引高召回快但吃内存」对比,并给「大规模选 IVF+PQ、中小规模选 HNSW」的选型结论。
乘积量化(PQ)的原理是什么?
背景
向量维度高(768/1024)时,存储与距离计算成本高。PQ 用有损压缩换内存与速度。
原理(三步)
- 切分:把 d 维向量切成 m 个子段,每段 d/m 维。
- 聚类建码本:对每个子段分别做 k-means,得到 m 个码本,每个码本 256 个中心(8bit 编码)。
- 量化编码:每段用最近中心点的 8bit 编号代替,整个向量压成 m 个字节。
距离计算(ADC)
- 预计算 query 每段到各中心的距离查表(Lookup Table),检索时对候选文档查表求和,避免逐维计算。
特点
- 内存压缩:768 维 float32(≈3KB)→ m×8bit(如 96 字节),压缩约 30 倍。
- 有损:量化引入误差,召回略降,常配合 IVF-PQ / IVF-PQ + 重排(粗筛后对候选用原始向量精算)。
讲清「切分→聚类码本→8bit 编码」三步与「查表求距离」,并点出「有损压缩、常配 IVF + 重排精算」的落地姿势。
如何选择向量数据库?选型要点有哪些?
选型维度
- 功能:是否支持元数据过滤、多向量(ColBERT)、标量+向量混合查询、权限/多租户。
- 性能与规模:支持的索引类型(HNSW/IVF/PQ/DiskANN)、数据量级(百万/亿)、QPS 与延迟。
- 一致性与可用性:副本、分片、故障切换、备份。
- 部署与运维:自托管 vs 托管云服务、K8s 支持、监控。
- 成本:内存/磁盘占用、License、云服务计费。
- 生态与集成:SDK 语言、与 LangChain/LlamaIndex 集成。
常见库定位
| 库 | 定位 |
|---|---|
| FAISS | 高性能库,非服务,需自建 |
| Milvus/Qdrant/Weaviate | 生产级服务,功能全 |
| pgvector | 嵌入 PostgreSQL,适合已有 PG 架构 |
| Chroma | 轻量原型 |
建议
- 原型 → Chroma / FAISS;生产 → Milvus/Qdrant(或 pgvector 若已在 PG 生态);超大规模 → 支持磁盘索引/分布式方案。
按「功能/规模/运维/成本/生态」五维选型,并说清「FAISS 是库、Milvus 是服务、pgvector 是 PG 扩展」的定位差异。
filtered search(带过滤的向量检索)性能如何优化?
问题
带元数据过滤时,纯向量索引(HNSW/IVF)会因过滤导致召回不足或性能骤降。
优化手段
- single-stage filtering:索引内嵌过滤(HNSW 遍历跳过不满足节点),比 post-filter 准、比 pre-filter 快。
- 过滤感知索引:为高基数字段建倒排 + 向量联合索引,先定位过滤桶再做局部向量搜索。
- 缓存过滤结果:固定过滤条件(如某租户/部门)的文档集合可缓存复用。
- 按过滤基数选择策略:过滤条件命中文档多 → 向量优先;命中极少 → 先过滤再精确算。
- PQ/量化 + 预过滤:缩小候选集后精算原始向量,减少计算量。
- 查询规划:评估过滤选择度(selectivity),动态决定「先过滤还是先向量」。
点出核心矛盾「过滤会破坏 ANN 索引的召回/速度」,并给「single-stage filtering + 按选择度动态规划」的优化思路。
query rewriting 是什么?multi-query 和 step-back 有什么区别?
query rewriting 是什么
用 LLM 把用户原始 query 改写/扩展成更适合检索的形式,缩小 query-doc 鸿沟。是提升召回的通用手段。
multi-query(多查询)
- 让 LLM 从多个角度生成同一问题的多个改写版本(如同义改写、不同粒度)。
- 每个版本各自检索,结果并集去重后 rerank,扩大召回覆盖面。
step-back(回退提问)
- 把具体问题抽象到更高层/更宽泛的问题,先检索背景性知识,再回答原问题。
- 例:「2026 年某产品参数」→ 回退为「该产品的发展历史/定位」,补充上下文。
区别
| 维度 | multi-query | step-back |
|---|---|---|
| 方向 | 横向(同层多角度) | 纵向(向上抽象) |
| 目的 | 扩大召回覆盖面 | 补充背景/全局知识 |
| 产出 | 多个平行改写 | 一个更抽象的问题 |
一句话区分:「multi-query 横向生成多个改写扩召回,step-back 纵向抽象补背景」,并点出二者都靠 LLM 改写 query。
HyDE 的原理是什么?有哪些局限?
原理(Hypothetical Document Embeddings)
- 用 LLM 根据 query 生成一段假设性文档/答案(即便可能是虚构的)。
- 把这段假设文档做 embedding,用它去检索,而非直接用 query 向量。
- 因为假设文档贴近真实文档的语言分布,能缩小 query-doc 鸿沟,召回更准。
query → LLM 生成假设答案 h → embedding(h) → 向量检索 → rerank → 生成局限
- 依赖 LLM 质量:假设文档编得离谱会误导检索(尤其冷门领域)。
- 额外延迟与成本:多一次 LLM 生成 + 一次 embedding。
- 不适合精确词/事实查询:需要精确命中型号、编号时,假设文档可能引入噪声。
- 语言/领域敏感:LLM 不了解的领域生成质量差。
讲清「先让 LLM 编一个假设答案再拿它检索」的核心,并主动说出「依赖 LLM、增延迟成本、冷门领域易跑偏」三个局限。
什么是 routing(路由)?query 路由如何实现?
什么是 routing
根据 query 的类型/意图,把请求分发到不同的处理分支(不同知识库、不同检索器、不同模型、是否走 RAG)。
query 路由实现
- 规则/关键词:关键词白名单、正则(如含「价格」→ 商品库)。
- 分类器:训练小模型/用 embedding 做语义分类。
- LLM 判断:few-shot 让 LLM 输出分类标签(
route: code/route: docs/route: chat),结构化输出。 - 语义路由(semantic router):把 query 与各知识库的描述/示例算相似度,选最接近的分支。
应用场景
- 多知识库(代码库 vs 文档库)、多领域(医疗 vs 通用)、是否需要检索(闲聊直接答)、不同 LLM(省钱用弱模型)。
报出「规则、分类器、LLM 判断、语义路由」四种实现,并点出「路由到不同知识库/不同模型」的典型场景。
单轮检索和多轮检索有什么区别?
单轮检索(single-turn)
- query 一次检索、一次生成即出答案。
- 简单、延迟低,适合独立问答。
多轮检索(multi-turn / iterative)
- 首轮检索→生成→根据中间结果再检索→再生成,循环多轮直到满足。
- 适合需要多步推理、信息补全、深入追问的复杂问题。
对比
| 维度 | 单轮 | 多轮 |
|---|---|---|
| 检索次数 | 1 次 | 多次 |
| 延迟/成本 | 低 | 高 |
| 适用 | 简单事实问答 | 多跳推理、复杂任务 |
| 实现 | 简单 | 需循环控制 + 停止条件 |
实现要点
- 循环终止条件(达到最大轮次 / 信息足够 / LLM 判断停止)。
- 每轮把前轮结果拼入上下文,驱动下一轮检索。
用「单轮一次检索一次生成、多轮检索-生成循环直到够」对比,并提「循环停止条件」这个实现细节。
iterative retrieval 和递归检索是什么?
iterative retrieval(迭代检索)
- 检索 → 生成 → 再检索的线性循环。每轮生成的中间答案/新发现驱动下一轮检索,逐步逼近答案。
- 例:第一轮找到「公司 X 收购了 Y」→ 第二轮查「Y 的 CEO」→ 拼出完整答案。
recursive retrieval(递归检索)
- 把复杂问题递归分解为子问题,对每个子问题独立检索,再逐层合并。
- 树形结构:父问题 → 子问题 → 子问题…,自底向上汇总。
区别
| 维度 | iterative | recursive |
|---|---|---|
| 结构 | 线性循环 | 树形递归分解 |
| 驱动 | 前轮结果驱动下轮 | 问题分解驱动 |
| 适用 | 信息逐步补全 | 可分解的复合问题 |
用「iterative=线性循环逐步补全,recursive=树形递归拆子问题」区分,两者都属多轮检索家族。
conversational RAG 如何实现?如何做多轮改写?
什么是 conversational RAG
把多轮对话上下文纳入 RAG:query 可能含指代、省略,需结合历史才能理解。
实现要点
- 多轮改写(query rewrite):把当前 query 与历史对话一起交给 LLM,改写为独立完整的检索 query。
- 「它是什么时候发布的?」+ 上文「iPhone 16」→ 「iPhone 16 是什么时候发布的?」
- 历史管理:保留近 N 轮对话摘要/原文,控制 token。
- 检索结果与历史对齐:避免重复检索、合并多轮证据。
- 记忆机制:短期(对话窗口)+ 长期(向量化历史,必要时召回)。
多轮改写的实现
改写成独立 query(指代消解、补全省略),再正常走检索-生成。- 用 LLM + few-shot,输出改写后的 query。
- 也可用专门的小改写模型降成本。
讲清「把含指代省略的 query 结合历史改写成独立 query 再检索」,并提「短期窗口 + 长期向量记忆」的记忆机制。
query 意图识别怎么做?
意图类型(RAG 场景常见)
- 知识问答(走 RAG)、闲聊(直接生成)、操作/执行(走工具/API)、多意图混合。
实现方法
- 规则/关键词:快、简单,覆盖有限。
- embedding 分类:把 query 向量与各意图的示例/描述向量算相似度(语义路由)。
- 微调小分类模型:领域定制、低延迟、低成本。
- LLM few-shot:直接输出结构化意图标签,灵活但延迟成本高。
应用
- 是否检索:闲聊类不检索,省成本降延迟。
- 路由:不同意图分发到不同知识库/工具/模型。
- 检索策略:事实查询走精确检索,开放问题走语义+多路召回。
报出「规则→embedding 分类→小模型→LLM few-shot」的递进方案,并点出意图识别用于「决定是否检索、路由到哪」。
GraphRAG 的社区摘要是什么?如何工作?
背景
GraphRAG 把文档抽取成知识图谱(实体+关系),再用图结构做检索,擅长多跳推理与全局性问题。
社区摘要(Community Summaries)
- 建图:LLM 抽取实体/关系,构建实体-关系图。
- 社区检测:用 Leiden 算法等社区发现,把图划分成若干紧密相连的社区(模块)。
- 社区摘要:对每个社区,用 LLM 生成社区摘要(该社区实体与关系的概括)。
- 分层(Hierarchical):社区可嵌套,形成层级摘要(细粒度到全局)。
如何使用
- 局部检索:定位相关实体,展开其邻居与社区,回答问题。
- 全局检索:直接对高层社区摘要做检索/聚合,回答「整体趋势/主题」这类全局问题。
讲清「实体关系建图 → Leiden 社区检测 → LLM 生成社区摘要(分层)」三步,并点出它专门解决「全局性、多跳问题」。
self-RAG 的反思 token 是什么?
背景
Self-RAG 让模型自己决定「要不要检索、检索好不好、生成对不对」,用反思 token(reflection tokens) 做软控制。
反思 token 类型
| Token | 含义 | 作用 |
|---|---|---|
| Retrieve | 要不要检索 | 判断是否需要外部知识 |
| IsREL | 检索片段是否相关 | 过滤无关片段 |
| IsSUP | 生成是否被片段支撑 | 判断忠实度 |
| IsUSE | 生成是否有用 | 判断回答质量 |
工作机制
- 生成
Retrieve=Yes时触发检索,否则直接生成。 - 对每个检索片段生成
IsREL判断,只保留相关片段。 - 生成后用
IsSUP/IsUSE自评,若差则改写/重新检索。
- 反思 token 由带标注数据微调得到,模型在生成过程中插入这些判断 token。
报出 Retrieve/IsREL/IsSUP/IsUSE 四个反思 token 及其各自作用,点出「模型自判检索与生成质量」的核心思想。
什么是 agentic RAG?
定义
把 RAG 的检索、生成、工具调用交给LLM Agent 自主规划与决策:Agent 决定「何时检索、检索什么、要不要用工具、多步编排」。
与传统 RAG 区别
| 维度 | 传统 RAG | Agentic RAG |
|---|---|---|
| 控制流 | 固定管线(检索→生成) | Agent 自主决策循环 |
| 检索次数 | 通常一次 | 多次、按需 |
| 工具 | 只检索 | 检索 + 计算器/API/代码执行等 |
| 能力 | 问答 | 多步推理、任务执行 |
| 复杂度/成本 | 低 | 高 |
核心能力
- 工具调用:不止检索器,还可调 API、搜索、代码执行。
- 规划与反思:多步 plan-act-observe 循环,检索失败自动重试/换策略。
- 实现:LangGraph、AutoGen、LlamaIndex Agent 等编排框架。
说清「从固定管线到 Agent 自主决策循环」的本质区别,并提「工具调用 + 多步反思 + 编排框架(LangGraph)」。
CRAG 的评分器(evaluator)是如何工作的?
背景
CRAG(Corrective RAG)在检索后加一个检索评分器,评估检索结果质量,据此决定后续动作。
评分器工作方式
- 对 query 与每个检索片段,用轻量模型(T5/微调分类器)打分,输出置信度。
- 把结果归类为三档:
- Correct(正确):多数片段相关 → 直接精炼生成。
- Incorrect(错误):片段质量差 → 触发纠正:改写 query 或改用网络搜索等外部知识源。
- Ambiguous(模糊):部分相关 → 保留相关片段 + 补充外部检索,组合后生成。
价值
- 检索差时自动兜底(换知识源),避免把垃圾上下文喂给 LLM 产生幻觉。
讲清「评分器把结果分 correct/incorrect/ambiguous 三档,incorrect 时换外部知识源纠正」这个 Corrective 核心。
RAPTOR 是什么?解决什么问题?
是什么(Recursive Abstractive Processing for Tree-Organized Retrieval)
把文档分块后,递归地对相邻块做 LLM 摘要/聚类,生成上层更粗粒度的节点,逐层构建一棵树。
工作流程
- 文档分块 → 每块 embedding。
- 对块做聚类,每个簇用 LLM 生成摘要节点(父节点)。
- 对摘要节点再次聚类+摘要,递归向上,直到根节点。
- 检索时在树的多层同时检索,融合不同粒度。
解决什么问题
- 单一粒度分块的局限:固定 chunk 无法同时服务「细节问题」与「全局问题」。
- 提供多粒度表示:叶子保细节、上层保概括,检索可在合适的层级命中。
说清「递归聚类+摘要建树,检索时多层命中多粒度」,点出它解决「单一分块粒度无法兼顾细节与全局」的问题。
semantic chunking 如何实现?
目标
按语义边界切块,而非固定长度,让每块语义完整。
实现方法
- embedding 相似度断点法:
- 逐句滑动,计算相邻句子的 embedding 相似度。
- 相似度骤降处视为语义边界,在此切块。
- 模型判断法:用 LLM/分类器判断某句是否是新话题的起点,是则切块。
- 句子聚合法:先分句,把语义相近的相邻句子聚成一块(贪心合并)。
关键点
- 需设相似度阈值(阈值越高切得越碎)。
- 可结合结构(标题/段落)作为辅助信号。
- 成本高于固定分块(多一次 embedding/LLM 调用)。
句子 → embedding → 相邻相似度 → 阈值判断断点 → 切块讲清「逐句算相邻 embedding 相似度,骤降处切块」的核心,并提「阈值调粒度、成本高于固定分块」。
什么是 lost in the middle?如何缓解?
现象
LLM 对上下文中间位置的信息关注度下降,首尾位置的信息更容易被正确利用(U 形注意力)。长上下文中,夹在中间的检索片段容易被忽略。
缓解方法
- 重排序:把最相关的片段放到开头或结尾,重要信息避开中间。
- 压缩上下文:片段先做摘要/去冗余,缩短总长度。
- 减少候选数:rerank 后只取必要 top-N,别塞太多。
- 分块递进:把多个片段拆成多轮/多段处理,而非一次性塞满。
- 结构化标注:给片段加清晰标题/编号,帮助模型定位。
点出「U 形注意力、中间信息被忽略」这一现象,并给「重排序避开中间 + 压缩 + 只取必要 top-N」的缓解组合。
stuffing 和 rerank 方式组织上下文有什么区别?
stuffing(全量填充)
- 把检索到的所有片段直接拼接进 prompt,一次性交给 LLM。
- 简单、无信息损失,但片段多时超长、噪声大、易 lost in the middle。
其它组织方式
- Map-Reduce:每片段单独总结,再汇总总结。
- Refine:逐段迭代精炼答案。
- Rerank 精选:用 reranker 对片段打分,只取最相关 top-N 组织上下文(生产主流)。
stuffing vs rerank 精选
| 维度 | stuffing | rerank 精选 |
|---|---|---|
| 处理 | 全量塞入 | 打分取 top-N |
| 上下文 | 可能超长 | 精简相关 |
| 噪声 | 高 | 低 |
| 成本 | 一次生成 | 多一次 rerank |
| 适用 | 片段少 | 片段多、追求质量 |
说清「stuffing=全量塞入易超长噪声,rerank 精选=打分取 top-N 更聚焦」,并提 map-reduce/refine 是中间折中方案。
引用溯源如何实现?如何保证引用忠实性?
引用溯源实现
- 片段编号:检索片段编号
[1][2]…,prompt 要求模型在句末标注引用[1][3]。 - 映射表:维护「编号 → 原文位置(文档/页码/段落)」映射,前端渲染可点击。
- 约束解码/结构化输出:强制模型只输出合法编号,防止编造不存在的引用。
- 生成后校验:用 NLI(自然语言推理)模型逐句校验「该句是否被引用片段支撑」。
保证引用忠实性
- 忠实度评估(RAGAS Faithfulness):答案每个断言是否被检索片段支撑。
- 引用校验器(citation validator):自动比对「句子的引用」与「句子内容」是否真的对应。
- 无支撑则丢弃/改写:不被支撑的句子删掉或标注「模型推测」。
- 惩罚机制:训练/RL 时对错误引用惩罚。
讲清「编号 + 映射 + 约束解码」的溯源链路,并强调「用 NLI/忠实度评估逐句校验」来保证引用不撒谎。
RAG 幻觉和无 RAG 幻觉有什么区别?
无 RAG 的幻觉
- 来源:模型知识缺失/过时,凭空编造事实。
- 特征:编造不存在的事件、数据、人物,无法追溯来源。
RAG 的幻觉(有检索仍幻觉)
- 上下文冲突:检索到矛盾信息,模型无法调和,输出错误或混淆。
- 过度依赖/被误导:检索到不相关或错误的片段,模型照单全收照抄错误。
- 错误引用:回答正确但引用错编号(张冠李戴)。
- 忽略上下文:检索到了对的,但模型仍用自己的旧知识回答。
区别与对策
| 维度 | 无 RAG 幻觉 | RAG 幻觉 |
|---|---|---|
| 根源 | 知识缺失 | 检索质量/忠实度控制 |
| 对策 | 加 RAG 补知识 | 提升检索质量 + 忠实度校验 + 引用约束 |
- RAG 能显著降低「知识缺失型」幻觉,但会引入「检索误导型」新幻觉,需配合 rerank、忠实度校验。
说清「RAG 消知识型幻觉,但引入检索误导型幻觉」,点出「上下文冲突、错误引用、忽略上下文」几种新形态及对策。
RAGAS 的四项指标分别是什么?
四项核心指标
| 指标 | 评估对象 | 含义 | 计算方式 |
|---|---|---|---|
| Faithfulness(忠实度) | 生成 | 答案是否忠于检索上下文(无幻觉) | LLM 逐句判断是否被上下文支撑 |
| Answer Relevancy(答案相关性) | 生成 | 答案是否切题、直接回答问题 | LLM 反向生成问题比对 |
| Context Relevancy(上下文相关度) | 检索 | 检索片段是否与问题相关、无冗余 | LLM 判断无关片段占比 |
| Context Recall(上下文召回率) | 检索 | 标准答案所需信息是否都被检索到 | 对照参考答案是否覆盖 |
- 另常补充 Answer Correctness(答案正确性) 作为第五项(结合语义 + 事实比对)。
记忆
- 生成侧:Faithfulness、Answer Relevancy。
- 检索侧:Context Relevancy、Context Recall。
报出四项英文指标并分「生成侧(忠实度/答案相关性)vs 检索侧(上下文相关度/上下文召回率)」,可补 Answer Correctness。
recall@k 和生成质量的关系是什么?
recall@k 定义
在 top-k 检索结果中,命中「相关文档」的比例。recall@k = |检索到的相关文档 ∩ 前k| / |全部相关文档|。
与生成质量的关系
- 必要条件而非充分条件:召回不到关键文档(recall 低),生成几乎必然答不出——检索是生成的上限。
- 非单调:recall@k 提升到一定值后,继续扩大 k 会引入噪声,生成质量反而可能下降。
- 存在最优 k:需在「召回全」与「噪声少」间取平衡,配合 rerank 可提高高质量片段占比。
- 相关性 ≠ 有用性:recall 只衡量「相关」,但「相关但重复/过时」的文档未必提升生成。
实践
- 用 recall@k 定位检索阶段问题;生成质量用忠实度/相关性定位。二者分层评估。
点出「检索是生成上限、recall 是必要不充分」,并强调「k 过大引入噪声、需配合 rerank、recall 与生成非单调」这个反直觉点。
RAG 系统如何做 A/B 测试?
步骤
- 定义指标:忠实度、答案相关性、用户满意度、延迟、成本。
- 分流:按用户/query 随机分流到 A(旧)与 B(新)版本,保证可比。
- 采样与统计:跑够样本量,用假设检验(t 检验/卡方)判断显著性。
- 分层分析:按 query 类型/用户群细分,避免总体均值掩盖局部退化。
陷阱
- 缓存污染:新旧版本共享缓存会互相影响,需按版本隔离。
- 指标选择:只看准确率不看延迟/成本会误判。
- 评估噪声:LLM 输出随机性,同一 query 多次结果不同,需足够样本。
- 离线 vs 在线:先用离线数据集(RAGAS)快速筛,再上在线 A/B 验证。
说清「随机分流 + 双指标(质量与成本延迟)+ 显著性检验」,并点出「缓存隔离、LLM 随机性需大样本」两个陷阱。
embedding 和 rerank 的成本如何权衡?
成本结构
- embedding:离线为全库文档编码(一次性+增量),在线只编码 query,单价低但文档规模大。
- rerank:在线对每个候选「query+doc」逐对计算,单价高,但只处理 top-k 小集合。
权衡策略
- 分层架构:便宜的双编码器 embedding 做海量粗召回,贵的 reranker 只做 top-50~100 精排。
- 控制候选规模:rerank 的 k 别太大,几十条即可覆盖大部分收益。
- 缓存:热门 query 的 embedding/rerank 结果缓存,避免重复计算。
- 量化/蒸馏:embedding 用小模型或量化版本;rerank 用蒸馏小交叉编码器。
- 按需 rerank:简单 query 可跳过 rerank,复杂 query 才精排。
说清「embedding 便宜管海量、rerank 贵管小集合」的成本定位,并给「控制 rerank 的 k + 缓存 + 按需精排」的降本组合。
什么是语义缓存?如何实现?
定义
对语义相近的 query 复用之前的检索/生成结果,避免重复的 embedding + LLM 调用,降本提速。相比精确缓存(仅完全相同 query 命中),语义缓存命中率更高。
实现
- 精确缓存:query 字符串哈希 → 命中直接返回(最简单)。
- 语义缓存:
- 把历史 query 存向量,新 query 算 embedding 相似度;
- 超过阈值(如 0.95)视为同义,复用缓存结果。
- 用向量库/ANN 索引快速找最近的历史 query。
新 query → embedding → 相似度匹配历史缓存 → 命中则返回,未命中则检索生成并写入缓存风险与对策
- 误命中:相似但语义不同(阈值过高)→ 返回错误答案;需低阈值 + 关键实体校验。
- 新鲜度:缓存结果过时 → 设 TTL,或对时效敏感 query 不走缓存。
- 个性化:不同用户/权限结果不同 → 缓存键加入用户/租户维度。
讲清「相似 query 复用结果」的核心,并主动说出「阈值误命中、TTL 过期、按租户隔离」三个落地风险。
权限多租户如何设计?
目标
不同租户/用户只能检索自己有权访问的文档,防止越权泄露。
设计要点
- 文档级 ACL:每个 chunk 关联访问控制标签(租户 ID、部门、角色、密级)。
- 检索时强制过滤:query 检索必须带上调用者的权限条件,服务端强制注入(不可信客户端传入)。
- 两种隔离模式:
- 物理隔离:每租户独立索引/集合,安全最强,成本高、难共享。
- 逻辑隔离 + 元数据过滤:统一索引,检索时按
tenant_id/权限过滤(主流,需 filtered search 支持)。
- 防越权:权限过滤与向量检索原子结合(single-stage filtering),避免 post-filter 漏掉过滤。
- 缓存与日志:缓存键含租户维度;审计日志记录谁查了什么。
说清「文档级 ACL + 检索时服务端强制过滤」,并对比「物理隔离 vs 逻辑隔离+元数据过滤」,点出 filtered search 必须原子防越权。
增量索引和 CDC(变更数据捕获)如何实现?
问题
知识库数据持续变更(新增/修改/删除),索引需同步更新,保持检索新鲜度。
增量索引
- 增量同步:只处理变更的文档(增/改/删),不全量重建。
- 更新动作:
- 新增:分块 → embedding → 写入向量库。
- 修改:删除旧向量 → 写入新向量(记录 chunk 的稳定 ID 便于定位)。
- 删除:按文档/chunk ID 删除对应向量。
CDC(Change Data Capture,变更数据捕获)
- 从数据源捕获变更事件,驱动索引更新:
- 数据库 binlog / WAL(MySQL binlog、Postgres WAL、Debezium)→ 解析变更事件。
- 消息队列(Kafka)解耦:变更 → MQ → 消费端执行索引更新。
- 定时全量 + 增量兜底:定期全量对账,修正漏更/脏数据。
一致性保证
- 幂等更新:重复消费同一变更不产生脏数据(按版本号/update 时间判断)。
- 最终一致性:容忍短暂延迟,用全量对账兜底。
说清「变更事件(binlog/WAL)→ MQ → 增量更新索引」的 CDC 链路,并提「幂等 + 定期全量对账」的一致性兜底。