跳转至

RAG 系统设计:从检索链路到生成可信度

本章导读

检索增强生成(Retrieval-Augmented Generation,RAG)是大模型应用中出现频率最高的架构之一,但“能跑通”和“可上线”之间隔着解析、切分、召回、重排、评估等一整条链路。
本章按数据流向拆解 RAG 的每个环节,重点讲清楚参数取舍、失败模式与评估方法,而不是罗列组件。
阅读时建议把“检索质量决定上限、生成策略决定下限”作为主线:大多数幻觉与答非所问,根因在检索而非模型。
文中的规模、延迟、成本数字均为量级估算,具体以实际压测和公开资料为准。

核心要点

  • RAG 解决的是“模型参数里没有的知识”和“需要可追溯来源”的问题,不解决推理能力不足。
  • 链路上游的解析与切分质量,往往比换一个更强的 embedding 模型收益更大。
  • 切分要区分“检索单元”和“生成单元”,父子块是兼顾两者的常用手段。
  • 混合检索(稀疏 + 稠密)加倒数排名融合(Reciprocal Rank Fusion,RRF)是性价比很高的默认方案。
  • 重排(rerank)用小模型换大收益,典型做法是召回百级、重排十级、生成取三到五条。
  • 评估必须拆成检索指标与生成指标,只看最终答案好坏无法定位问题。
  • 上线前要建立按问题类型分层的评测集,并把拒答与引用准确率纳入指标。

1. RAG 的动机与适用边界

1.1 为什么需要 RAG

大语言模型(Large Language Model,LLM)的知识来自训练语料,存在三个结构性限制:训练截止时间导致知识过期;私有数据从未进入参数;生成过程缺乏事实依据,容易产生幻觉(hallucination)。RAG 的思路是在生成前从外部知识库检索相关片段,把证据放进上下文,让模型“开卷答题”。

它带来的收益包括:知识可热更新,不必重新训练;答案可附引用,便于审计;敏感数据可以留在自有向量库;相比把全部文档塞进上下文,token 成本更可控。

1.2 适用边界

RAG 适合:企业知识库问答、客服、文档助手、法规与工单检索、需要引用来源的研究辅助。它不适合:需要复杂多步推理且证据分散的任务(要配合 Agent 或工具)、实时性要求毫秒级的场景、知识库本身质量极差且无法治理的场景、以及主要矛盾是“模型不会推理”而非“模型不知道”的场景。

一个常见误区是把 RAG 当成万能补丁。如果评测显示模型在给定正确上下文时仍答错,那么问题在推理或指令遵循,应该考虑换模型、微调或拆解任务,而不是继续调检索。

1.3 RAG、长上下文、微调、搜索的对比

维度 RAG 长上下文(Long Context) 微调(Fine-tuning) 传统搜索(Search)
知识新鲜度 高,改库即生效 高,但每次都要塞入 低,需重新训练 高
私有数据 适合 适合小规模 数据进入参数,需合规评估 适合
单次成本 中,检索加有限上下文 高,token 随长度线性增长 训练成本高,推理成本低 低
延迟 中,多一次检索与重排 较高,首 token 延迟明显 低 低
可追溯性 强,可给引用 中,取决于是否保留来源 弱 强
能力改变 只补知识 只补知识,受限于注意力稀释 可改变风格、格式、领域行为 不涉及生成
典型风险 召回失败、噪声 中间信息丢失、成本失控 灾难性遗忘、过拟合 无法直接回答自然语言问题

实践中的组合方式通常是:用搜索或 RAG 获取证据,用长上下文承载多篇材料,用微调固化输出格式与领域语气。四者不是互斥选项,而是不同层的工具。

2. 全链路总览

RAG 分为离线建库与在线服务两条链路。离线链路追求质量与可重建性,在线链路追求延迟与稳定性。

阶段 输入 关键动作 输出 主要指标
文档解析 PDF、Word、HTML、扫描件 版面分析、OCR、表格还原 结构化文本 字符准确率、表格还原率
清洗 原始文本 去页眉页脚、去重、归一化 干净语料 噪声率、重复率
切分 长文档 按结构或语义切块 文本块(chunk)集合 平均长度、边界完整率
向量化 chunk 调用向量化(embedding)模型 向量 维度、归一化方式
索引 向量与元数据 建立近似最近邻索引 可检索库 建库耗时、召回率
查询理解 用户问题与对话 改写、指代消解、意图识别 检索查询(query) 改写命中率
召回 query 稀疏与稠密多路检索 候选集 Recall@k
重排 候选集 交叉编码器精排 Top-N nDCG@N
上下文组装 Top-N 文档 去重、排序、压缩 提示词(prompt)上下文 有效 token 占比
生成 上下文与问题 受控解码、引用标注 答案 忠实度、答案相关性
引用 答案与文档 对齐句子与来源 引用列表 引用准确率

在线链路的时间预算要做显式分配。以一次问答 3 秒为目标(估算),解析与 embedding 查询约 50 至 150 毫秒,向量检索约 10 至 50 毫秒,重排 20 条约 50 至 200 毫秒,生成占剩余大部分(以上均为量级估算)。任何一环没有超时与降级策略,都会拖垮整体可用性。

3. 文档解析与清洗

3.1 PDF 与版面分析

PDF 分两类:带文本层的电子版与扫描件。电子版优先直接抽取文本,但必须处理多栏、页眉页脚、脚注、图文混排的阅读顺序。常见做法是先做版面分析(layout analysis),识别标题、正文、表格、图片区域,再按阅读顺序拼接。直接按坐标从上到下抽取,在多栏文档中会把左右栏交错误读。

扫描件需要光学字符识别(Optical Character Recognition,OCR)。流程通常是:图像预处理(去噪、纠偏、二值化)→ 文字检测 → 文字识别 → 后处理(词典纠错、版面回填)。评估 OCR 质量可用字符错误率(Character Error Rate,CER):

\[\text{CER}=\frac{S+D+I}{N}\]

其中 \(S\)、\(D\)、\(I\) 分别为替换、删除、插入字符数,\(N\) 为参考字符总数。中文场景下 CER 低于 5% 通常可接受(经验阈值,估算),但专有名词和数字的错误更致命,需要单独抽样检查。

3.2 表格与图片

表格是 RAG 的高频失败点。可行策略有三类:把小表转为 Markdown 或 HTML 保留结构;按行切分并为每行重复表头,形成“字段名: 值”的自解释文本;对大表先做摘要,再保留原始表格的定位信息供回查。金额、日期、单位必须在清洗阶段统一格式,否则检索到了也无法正确比较。

图片中的信息应先做图注或 OCR,不应把图片二进制直接交给文本 embedding。若使用多模态模型,可为图片生成描述文本,并与原图建立引用关系。

3.3 清洗规则

清洗不是越干净越好,而是去掉会干扰检索、保留会改变语义的内容。常见规则包括:删除重复页眉页脚与页码;合并被硬换行打断的句子;统一全角半角、繁简与单位;去除导航栏、版权声明等模板文本;对近乎重复的文档做指纹去重(如 MinHash、SimHash);对个人身份信息(Personally Identifiable Information,PII)做脱敏或隔离。

清洗后要保留元数据:来源、标题、章节路径、发布时间、权限标签、页码或锚点。这些字段既用于过滤,也用于最终引用。缺少页码锚点,用户点开引用后无法定位原文,体验会明显下降。

4. 切分策略

4.1 五种常用策略

策略 做法 优点 缺点 适用
固定长度 按 token 数硬切,带 overlap 实现简单、块大小均匀 容易切断句子与表格 快速基线
递归切分 按段落、句子、字符逐级回退 尽量保留自然边界 结构复杂时仍会切碎 通用默认
语义切分 计算相邻句向量相似度,在低点断开 主题完整 成本高、阈值难调 长论述、报告
父子块 子块检索,返回父块生成 检索精准且上下文完整 存储与映射复杂 问答、法规
按结构切分 依据标题层级、代码块、表格切 可解释、保留层级 依赖解析质量 手册、文档站

递归切分是最常用的默认方案:先按标题或段落切,超长再按句子切,仍超长才按字符切。语义切分用相邻句的余弦相似度找“主题断崖”,但相似度阈值对领域敏感,通常需要标注少量数据校准。

4.2 chunk size 与 overlap 的取舍

块太小,单块信息不足,召回碎片化,生成时缺少上下文;块太大,向量被多个主题平均,检索精度下降,且浪费上下文预算。经验区间是 256 至 1024 token(估算),问答类偏小,摘要与法规类偏大。overlap 常取块长的 10% 至 20%(估算),用于避免边界信息丢失,但会带来重复召回与存储膨胀。

更合理的做法是“检索用小块、生成用大块”:子块 200 至 400 token 负责被召回,命中后返回其所属父块 800 至 1500 token 用于生成(均为估算)。这样既保持向量语义集中,又不让模型看到断裂的上下文。

4.3 切分伪代码

def recursive_split(text, max_tokens=512, overlap=64,
                    seps=("\n\n", "\n", "。", ";", " ")):
    """按段落 -> 句子 -> 字符逐级回退,超长片段继续递归。"""
    if count_tokens(text) <= max_tokens:
        return [text]
    for i, sep in enumerate(seps):
        parts = [p for p in text.split(sep) if p.strip()]
        if len(parts) <= 1:
            continue                                 # 该层级切不开,换下一级
        chunks, buf = [], ""
        for part in parts:
            if count_tokens(part) > max_tokens:      # 单个片段仍超长
                if buf:
                    chunks.append(buf)
                    buf = ""
                chunks.extend(recursive_split(part, max_tokens, 0, seps[i + 1:]))
                continue
            candidate = f"{buf}{sep}{part}" if buf else part
            if count_tokens(candidate) <= max_tokens:
                buf = candidate
            else:
                chunks.append(buf)
                buf = part                           # 新块从当前片段开始
        if buf:
            chunks.append(buf)
        return add_overlap(chunks, overlap)          # 相邻块重叠若干 token
    return hard_split(text, max_tokens)              # 所有分隔符都无效

真实系统还要处理表格不跨块、标题跟随、代码块完整等约束。切分完成后应做抽检:随机抽 30 个块,判断“只看这一块能否回答一个合理问题”,这是比任何自动指标都直接的质检方式。

5. Embedding 与向量索引

5.1 Embedding 模型选型

选型看五点:语言覆盖、最大输入长度、向量维度、检索任务表现、部署成本。中文场景要确认模型在中文语义匹配上的表现,不能只看英文榜单。多数模型要求查询与文档使用相同的前缀或指令格式,混用会显著掉点。向量通常做 L2 归一化后用余弦相似度或内积检索。

\[ \text{sim}(q,d)=\frac{\mathbf{q}\cdot\mathbf{d}}{\|\mathbf{q}\|\,\|\mathbf{d}\|} \]

领域术语多、缩写多时,通用 embedding 可能把“同义不同词”判得很远。可以用难负样本做对比学习微调,损失函数为 InfoNCE:

\[ \mathcal{L}=-\log\frac{\exp(\text{sim}(q,d^{+})/\tau)}{\sum_{j=1}^{K}\exp(\text{sim}(q,d_j)/\tau)} \]

其中 \(d^{+}\) 是正例,其余为负例,\(\tau\) 为温度系数。难负样本应从当前系统真实召回的头部错误中挖,而不是随机采样。

5.2 向量数据库选型

方案 形态 优势 局限 适用规模(估算)
FAISS 嵌入式库 性能强、算法全、无服务依赖 无服务化与权限管理,持久化需自行封装 十万到千万级
Milvus 分布式服务 水平扩展、多索引、生态完整 运维重、资源占用高 千万到十亿级
pgvector PostgreSQL 扩展 与业务库同事务、SQL 过滤方便 超大规模性能有限 十万到千万级
Qdrant 独立服务 过滤能力强、部署轻、API 友好 超大规模需集群调优 百万到亿级

选型不要只看 benchmark。若业务数据已在 PostgreSQL,且规模在百万级,pgvector 能省掉一套系统;若需要强过滤与多租户,Qdrant 的 payload 索引更顺手;若追求极致召回与离线实验,FAISS 更灵活。

5.3 HNSW 原理与参数

分层可导航小世界图(Hierarchical Navigable Small World,HNSW)通过多层图实现近似最近邻搜索:上层稀疏用于长跳,下层稠密用于精搜。查询从顶层入口点出发,每层贪心走到局部最近,再下沉一层,最终在底层做候选扩展。

关键参数:M 是每个节点的邻居数,越大召回越高、内存越大;efConstruction 是建图时的候选队列长度,影响图质量与建库时间;efSearch 是查询时的候选队列长度,直接 trade-off 召回与延迟。经验上 M 取 16 至 64,efSearch 从 64 起调,按 Recall@10 达到 0.95 左右确定(估算)。

内存量级可粗略估算为 \(N \times (4d + 8M)\) 字节,其中 \(d\) 为维度,\(N\) 为向量数;再乘约 1.1 至 1.3 的图层开销。一百万条 768 维、M=32 的索引大约在 3 至 5 GB 量级(估算),实际以压测为准。

5.4 IVF-PQ 原理与参数

倒排文件加乘积量化(Inverted File with Product Quantization,IVF-PQ)先用 k-means 把向量聚成 nlist 个簇,查询时只扫 nprobe 个最近簇;再用乘积量化把高维向量切成 m 段,每段用 256 个码字编码,把存储压到每向量 m 字节。

nlist 越大,单簇越小、每簇样本越少,但训练与查表开销上升;nprobe 越大召回越高、延迟越高;m 越大精度越高、压缩率越低。IVF-PQ 适合内存受限的超大规模场景,但召回通常低于 HNSW,且对分布漂移敏感,需要定期重训练。

带元数据过滤时要注意“先过滤再搜索”还是“先搜索再过滤”。前者召回完整但可能退化为暴力扫描,后者快但过滤条件苛刻时结果不足。生产系统常用分区、租户隔离或可过滤的图索引来规避。

6. 查询理解与改写

用户问题往往不适合直接检索:有指代(“它的价格是多少”)、有口语省略、有多跳意图、有时间约束。查询理解的目标是把问题变成“可检索的查询集合”。

技术 机制 收益 风险 适用
指代消解 用对话历史补全代词与省略 多轮场景必备 历史过长时误补 客服、助手
Multi-Query 让模型生成 3 至 5 个同义查询并行召回 提升召回率 延迟与成本上升 召回不足
HyDE 先生成假设答案,再用答案向量检索 缓解问题与文档表述差异 假设错误会放大偏差 专业问答
Step-back 先抽象出上位问题再检索 补充背景知识 可能偏离具体诉求 原理、政策类
查询分解 把多跳问题拆成子问题依次检索 支持多跳 依赖分解质量 对比、因果

改写要设护栏:保留原始 query 作为一路召回,避免改写漂移导致原本能命中的文档丢失;对时间、数字、专有名词做实体锁定;改写结果过长时截断,防止向量被稀释。

7. 检索与融合

7.1 BM25 与稠密检索

BM25 是稀疏检索的代表,基于词频、逆文档频率与文档长度归一化:

\[ \text{BM25}(q,d)=\sum_{t\in q}\text{IDF}(t)\cdot\frac{f(t,d)(k_1+1)}{f(t,d)+k_1(1-b+b\cdot|d|/\text{avgdl})} \]

它擅长精确匹配:型号、错误码、人名、法规条款号。缺点是不懂同义改写,中文还需分词。

稠密检索把 query 与文档映射到同一向量空间,用近似最近邻找语义相近的块。它擅长同义表达与跨语言,但对罕见实体、数字、否定词不敏感,且需要训练数据与向量库支撑。

两者互补,混合检索是默认方案。融合可用加权分数归一化,也可用排名融合。RRF 不需要分数可比,稳健且对参数不敏感:

\[ \text{RRF}(d)=\sum_{r\in R}\frac{1}{k+\text{rank}_r(d)} \]

其中 \(R\) 为各召回列表,\(\text{rank}_r(d)\) 是文档在第 \(r\) 路中的名次,\(k\) 常取 60(经验值)。RRF 只使用名次,避免不同检索器分数量纲不一致的问题。

7.2 多路召回与元数据过滤

多路召回可以包括:原始 query 的稠密检索、改写 query 的稠密检索、BM25、标题或摘要字段检索、按实体精确匹配、以及图关系扩展。每路取 Top 50 至 100(估算),融合后截断到 20 至 50 条进入重排(估算)。

元数据过滤要先于向量检索生效:租户、权限、时间范围、文档类型、语言。权限过滤尤其不能用“检索后再删”,否则既浪费算力,也可能把无权限内容送进模型上下文,形成越权风险。

7.3 检索指标

\[ \text{Recall@}k=\frac{|R_k\cap R_{gold}|}{|R_{gold}|} \]
\[ \text{MRR}=\frac{1}{|Q|}\sum_{i=1}^{|Q|}\frac{1}{\text{rank}_i} \]
\[ \text{nDCG@}k=\frac{\text{DCG@}k}{\text{IDCG@}k},\quad \text{DCG@}k=\sum_{i=1}^{k}\frac{2^{rel_i}-1}{\log_2(i+1)} \]

Recall@k 衡量“该找到的有没有找到”,MRR 关注第一个正确结果的位置,nDCG 兼顾相关度等级与排序位置。问答系统通常先看 Recall@20 是否足够高,再看 nDCG@10 判断排序质量。

8. 重排

召回追求高召回,重排(rerank)追求高精度。常见三方案:

  • 交叉编码器(cross-encoder):把 query 与文档拼接后过一次模型,输出相关性分数。精度高,但每条候选都要前向一次,延迟随候选数线性增长。
  • ColBERT 类延迟交互(late interaction):query 与文档各自编码为 token 向量,用 MaxSim 计算细粒度匹配,可离线建索引,兼顾精度与速度。 $$ S(q,d)=\sum_{i\in q}\max_{j\in d}\mathbf{E}{q_i}\cdot\mathbf{E} $$}^{\top
  • LLM 重排:让模型对候选逐条打分或分组排序。灵活、可解释,但成本高、延迟大,适合低 QPS 或高价值场景。

生产常用级联:混合召回 100 条,cross-encoder 重排到 20 条,再用轻量规则或 LLM 选出 3 至 5 条进入上下文(均为量级估算)。重排模型要在业务标注集上评估,公开榜单的排序能力不一定迁移到你的领域。

9. 上下文组装与生成

9.1 组装策略

组装不是简单拼接。要先去重(同一文档的多个块只保留最相关的一段)、按相关性排序、控制总 token 预算、保留来源标识。研究发现模型对上下文中间位置的信息利用较弱,重要证据应放在开头或结尾,这就是常说的“中间遗忘”(lost in the middle)。

上下文压缩可以用小模型抽取与问题相关的句子,或直接让生成模型忽略无关段落。压缩能降低噪声与成本,但过度压缩会删掉回答所需的限定条件,必须用忠实度评估兜底。

9.2 引用与拒答

引用要满足三点:答案中的关键结论能对应到具体文档与位置;引用片段真的支持该结论;没有依据时明确拒答。实现上可要求模型输出结构化引用标记,再在服务端校验标记是否落在给定上下文内,防止编造来源。

拒答策略要分级:检索为空或最高分低于阈值时直接拒答;检索有结果但证据冲突时,说明冲突并给出各自来源;证据不足但可部分回答时,明确标注不确定性。阈值应在评测集上按“误拒率”和“漏拒率”调,而不是拍脑袋。

9.3 冲突处理

知识库冲突很常见:旧版制度与新规并存、不同部门口径不一致。处理顺序建议为:按发布时间与生效状态过滤过期文档;按来源权威性排序;在 prompt 中要求模型优先采用最新且权威的来源;若冲突无法消解,在答案中并列呈现并提示用户核实。不要让模型“自行裁决”而不说明。

10. 评估

10.1 检索与生成分开评

检索评估用带标注的 query-文档对,指标是 Recall@k、MRR、nDCG。生成评估看忠实度、答案相关性、引用准确率。只评最终答案,无法判断是召回没找到,还是找到了但模型没用。

RAGAS 是常用的自动化评估框架,核心指标包括:

\[ \text{Faithfulness}=\frac{\#\text{claims supported by context}}{\#\text{claims in answer}} \]
\[ \text{AnswerRelevancy}=\text{sim}\big(q,\ \text{questions generated from answer}\big) \]
\[ \text{ContextPrecision@}k=\frac{\sum_{i=1}^{k}\text{precision@}i\cdot v_i}{\sum_{i=1}^{k}v_i} \]
\[ \text{ContextRecall}=\frac{\#\text{gold claims covered by context}}{\#\text{gold claims}} \]

其中 \(v_i\) 表示第 \(i\) 个片段是否相关。Faithfulness 低说明模型超出证据自由发挥;Context Recall 低说明召回不全;Context Precision 低说明噪声多;Answer Relevancy 低说明答非所问。

10.2 评测集构造

评测集应覆盖:单跳事实、多跳推理、表格数值、时间与版本、否定与排除、无法回答、权限隔离、口语与错别字。每类 30 至 50 题(估算),总量 200 至 500 题可支撑一次迭代。题目来源包括真实日志抽样、业务专家编写、以及从文档反向生成问题。

反向生成要人工校验,否则会得到“文档里有一句话、问题就照抄这句话”的伪题。难负样本要刻意加入:同主题不同条款、旧版本、相似实体。标注内容包括 gold 文档块、参考答案要点、是否可回答、允许的引用范围。

10.3 在线指标

离线看质量,在线看效果与成本:答案采纳率、追问率、转人工率、点赞点踩、引用点击率、P95 延迟、单次成本。A/B 实验要控制流量分配与 novelty 效应,指标至少观察一个完整业务周期。

11. 常见失败模式与排查

现象 可能原因 诊断方法 处理方向
召回不到 切分过碎、同义词缺失、过滤过严、embedding 不匹配 看 gold 文档是否在候选集、逐层放宽过滤 改切分、加 BM25、补改写、换模型
召回噪声多 块过大、相似主题干扰、无重排 检查 Top20 相关比例、看 nDCG 缩小块、加重排、加元数据过滤
忽略上下文 prompt 过长、证据在中间、指令冲突 缩短上下文复测、调换证据位置 压缩、重排、把证据前置、强化指令
幻觉 证据不足、模型过度自信、缺少拒答示例 对照答案与引用逐句核查 拒答阈值、引用校验、few-shot 拒答
多跳失败 单轮检索、子问题未拆解 看中间实体是否被召回 查询分解、迭代检索、Agent 化
引用错误 引用标记后处理缺失、块定位不准 抽查引用片段与结论对应关系 结构化引用、服务端校验、保留页码

排查顺序建议从数据到模型:先确认 gold 文档在不在库里,再看能否被召回,再看重排后是否还在,最后才怀疑生成模型。这个顺序能避免大量无效的 prompt 调参。

12. 最小检索与重排实现

"""
最小 RAG:混合召回 + RRF 融合 + 交叉编码器重排(伪代码,22 行)
"""
def rrf_fuse(rankings, k=60):
    scores = {}
    for ranking in rankings:                 # 每一路召回单独计算名次
        for rank, doc_id in enumerate(ranking, start=1):
            scores[doc_id] = scores.get(doc_id, 0.0) + 1.0 / (k + rank)
    return sorted(scores, key=scores.get, reverse=True)

def rag_answer(query, top_k=5):
    q = rewrite_query(query)                 # 指代消解与查询改写
    dense = vector_store.search(embed(q), k=50)
    sparse = bm25.search(q, k=50)
    candidates = rrf_fuse([dense, sparse])[:20]
    pairs = [(q, doc_text[d]) for d in candidates]
    scores = cross_encoder.predict(pairs)    # 逐对打相关性分
    ranked = [d for _, d in sorted(zip(scores, candidates), reverse=True)][:top_k]
    context = assemble_context(ranked, token_budget=3000)  # 去重、排序、压缩
    answer = llm.generate(PROMPT.format(context=context, question=query))
    return answer, [doc_meta[d] for d in ranked]           # 返回引用来源

面试高频问题

1. RAG 和长上下文怎么选?

参考回答要点:

  • 先看知识规模与更新频率:知识库远大于窗口、需要频繁更新时选 RAG;材料少且一次性分析时用长上下文更简单。
  • 看可追溯性:需要逐条引用与审计时,RAG 的文档边界更清晰。
  • 看成本结构:长上下文的 token 成本随长度线性增长,RAG 多一次检索但上下文更短。
  • 实践中常组合:RAG 选材,长上下文承载多篇材料,微调固化输出格式。

2. 为什么切分策略比 embedding 模型更值得先优化?

参考回答要点:

  • 切分决定了检索单元的信息完整性,块被切断时再强的模型也无法召回完整语义。
  • 块过大导致向量主题平均,过小导致上下文缺失,二者都会让召回指标失真。
  • 换 embedding 需要重建索引、评估迁移成本,而调整切分可以快速 A/B。
  • 经验顺序是先把解析与切分做对,再考虑混合检索与重排,最后才换模型。

3. chunk size 和 overlap 如何确定?

参考回答要点:

  • 从业务问题出发:事实型问答偏小(256 至 512 token),综述与法规偏大(512 至 1024 token),均为估算。
  • overlap 取 10% 至 20%,用于保护边界,但会增加重复召回。
  • 用评测集扫参:固定其他环节,比较 Recall@20 与 nDCG@10,而不是只看答案观感。
  • 更推荐父子块:小块检索、大块生成,减少“检索精度与上下文完整性”的矛盾。

4. 混合检索为什么有效?RRF 的优缺点是什么?

参考回答要点:

  • 稀疏检索擅长精确词、型号、条款号;稠密检索擅长同义改写与跨语言,错误相关性低。
  • RRF 只用名次不用分数,避免不同检索器分数量纲不一致,几乎不需要调参。
  • 缺点是丢失分数强弱信息,且对只有一路召回的文档不够敏感。
  • 可先用 RRF 做稳健基线,再在标注集上尝试加权分数融合。

5. HNSW 的参数如何调?

参考回答要点:

  • M 控制图连通度,越大召回越高、内存越大,常用 16 至 64(估算)。
  • efConstruction 影响建图质量与时间,数据量大时可适当提高。
  • efSearch 是查询时召回与延迟的旋钮,从 64 起按目标 Recall 调。
  • 调参要在真实数据分布上做,并监控内存与 P99 延迟,不能只看离线召回。

6. 召回结果很多但答案仍然错,怎么排查?

参考回答要点:

  • 先看 gold 文档是否被召回、重排后是否还在,区分召回问题与生成问题。
  • 检查上下文是否超长、证据是否落在中间、是否被无关段落稀释。
  • 检查 prompt 是否存在指令冲突,模型是否被要求“必须回答”而不敢拒答。
  • 做对照实验:只给 gold 片段,若仍答错,问题在生成或推理,不在检索。

7. 如何评估 RAG 系统?

参考回答要点:

  • 检索与生成分开:Recall@k、MRR、nDCG 评检索;Faithfulness、Answer Relevancy、引用准确率评生成。
  • 评测集按问题类型分层,包含不可回答与权限隔离样本。
  • 自动指标用大模型作为评审(LLM-as-judge)时要与人工标注校准,注意位置与长度偏差。
  • 线上线下都要看采纳率、追问率、转人工率、延迟与成本,避免只优化离线分数。

8. 多跳问题为什么容易失败?如何改进?

参考回答要点:

  • 单轮检索只能拿到与原始问题表面相似的片段,中间实体往往没有被召回。
  • 查询分解把问题拆成子问题,逐步检索并累积证据。
  • 迭代检索根据已获证据生成下一轮查询,必要时用 Agent 控制流程。
  • 评估时要看中间步骤的召回,而不仅是最终答案。

9. 如何降低 RAG 的幻觉?

参考回答要点:

  • 提高证据覆盖率:混合召回、重排、父子块,确保正确证据进入上下文。
  • 强化 grounding:要求逐句引用,服务端校验引用片段是否真的支持结论。
  • 设计拒答:证据不足、分数过低、来源冲突时明确说明,而不是强行作答。
  • 降低解码随机性,并在评测集中加入“无法回答”样本做回归。

10. 向量数据库怎么选型?

参考回答要点:

  • 先看规模与增长预期:百万级可用 pgvector 或 Qdrant,千万级以上考虑 Milvus 或分片方案。
  • 看过滤需求:多租户、权限、时间范围要求强过滤时,优先支持 payload 索引的方案。
  • 看运维能力:FAISS 灵活但需要自建持久化与服务化,托管服务省事但有成本与锁定。
  • 最终以真实数据压测召回、延迟、成本与故障恢复,而不是只看公开 benchmark。

本文档为面试复习资料,指标与产品信息建议结合官方文档复核。