Skip to content

RAG 基础链路

目录

1. 学习目标

  • 理解 Retrieval-Augmented Generation(检索增强生成,RAG)的离线摄取链路与在线查询链路;
  • 能够解释文档解析、切块、Embedding、向量索引、Top-k、上下文组装和生成各自解决的问题;
  • 能够推导余弦相似度、Recall@k,并说明精确检索与近似最近邻的复杂度边界;
  • 能够实现一个最小可运行的“切块 → 向量化 → 检索 → 带引用回答”教学系统;
  • 能够沿调用链定位“查不到、查错了、查对但答错、文档未更新”等生产问题。

2. 面试结论

2.1 30 秒回答

RAG 是在生成前从外部知识库检索证据,并把证据连同问题交给大模型回答。完整系统分两条链:离线把文档解析、切块、向量化并建立带版本和权限元数据的索引;在线由可信服务端先计算用户权限范围,把 ACL 条件推入 Top-k 召回,再二次授权、去重并按 Token 预算组装上下文,最后生成带引用的答案。它能改善知识新鲜度和可追溯性,但不会自动保证召回、事实正确或权限安全,所以必须分别评测检索、生成和系统链路。

2.2 一分钟复述版

我会先强调 RAG 不是“接一个向量库”。离线侧要保证内容解析正确,Chunk 既保留回答所需语义又不过度冗余,每个向量带 source_id、版本、权限和位置元数据;在线侧先由可信服务计算授权范围并规范化或改写查询,再让向量和关键词检索都携带 ACL 条件,对结果二次授权后按相关性、去重和 Token 预算构造上下文,最后要求模型只依据证据回答并返回引用。诊断时我会按“语料是否存在 → 索引是否新鲜 → 查询是否表达正确 → 召回是否命中 → 上下文是否丢失 → 模型是否忠实”逐层看证据。RAG 与微调也不是互斥:RAG 主要提供外部事实,微调主要改变行为和任务能力。

3. 面试官为什么问

  • 核心考察点:是否理解端到端数据流,而不是只会调用向量数据库;
  • 对应岗位与级别:AI 应用、AI 后端、搜索与平台工程;高级岗位会追问索引一致性、权限、评测和故障隔离;
  • 优秀回答的区分度
    • 能分离离线摄取和在线查询;
    • 能说明 Chunk、Embedding、索引和上下文预算之间的耦合;
    • 能区分检索错误与生成错误;
    • 能用元数据、版本和引用建立可追溯性;
    • 不声称 RAG 可以消除幻觉。

4. 概念与边界

4.0 小白先这样理解:新员工带着门禁卡查制度

小林入职第一天想知道“出差发票多久内可以报销”,没有凭印象作答,而是拿门禁卡进入公司资料室:目录员先按问题找到可能相关的制度,抽出其中几页交给小林,小林读完后组织答案,并标出制度名称和页码。这里,资料室是知识库,目录员是检索器,制度页是 Chunk,门禁卡是 ACL 权限,小林是 LLM,制度名称和页码是引用。如果没找到,小林应明确说证据不足,而不是编一个期限。

类比边界: 找到书页不代表书页最新、内容正确,也不代表小林一定读对;语料缺失、索引过期、权限过滤错误和模型误读仍要分别检查。门禁权限必须由可信服务端执行,不能让“像小林一样会说话的模型”自行决定能看哪些资料。

4.1 是什么

RAG 把参数化知识与非参数化知识结合:

  • 参数化知识:模型权重中学习到的模式;
  • 非参数化知识:查询时从文档库、数据库或搜索系统取回的外部证据。

工程上的基础 RAG 通常包含:

  1. 文档接入和版本识别;
  2. 解析、清洗与切块;
  3. Embedding 与索引;
  4. 可信身份解析、权限条件与 Top-k 检索;
  5. 候选二次授权、去重和上下文组装;
  6. 带证据生成、引用和拒答;
  7. 日志、评测和反馈。

4.2 不是什么

  • RAG 不是微调:它不通过训练更新模型权重;
  • RAG 不是向量数据库:向量库只是索引与检索组件;
  • RAG 不是全文搜索的替代品:精确编号、专有名词和错误码常适合关键词检索;
  • RAG 不是长上下文的同义词:把全部文档塞入上下文会受成本、噪声和窗口限制;
  • RAG 不保证答案正确:检索命中后,模型仍可能忽略、误解或越过证据;
  • RAG 不自动实现权限:ACL 必须在可信服务端参与检索和上下文构造。

4.3 解决什么问题

RAG 主要解决:

  • 权重知识过时,业务文档持续变化;
  • 私有知识不适合或不足以训练;
  • 回答需要引用来源和审计;
  • 同一模型服务多个动态知识域;
  • 希望只更新语料和索引,而不是每次重新训练。

RAG 不适合单独解决:

  • 需要稳定格式或行为风格,可考虑 Prompt 或微调;
  • 需要严格计算、交易和权限判断,应使用确定性工具;
  • 知识库本身没有答案,检索无法凭空创造事实;
  • 极低延迟且答案集合固定的场景,缓存或规则可能更合适。

4.4 输入、输出与前置条件

  • 离线输入:源文档、版本、更新时间、访问控制和解析配置;
  • 离线输出:可检索 Chunk、向量、元数据、索引版本和失败记录;
  • 在线输入:用户问题、身份、会话上下文和过滤条件;
  • 在线输出:候选证据、最终上下文、答案、引用和链路诊断数据;
  • 前置条件:知识确实存在、解析可信、Embedding 空间一致、索引已就绪、权限可执行。

4.5 与相近方案的区别

方案主要改变优势局限
Prompt 上下文单次请求输入简单、透明需预先知道该放哪些内容
RAG查询时外部证据新鲜、可引用、易更新依赖检索和索引质量
微调模型参数或适配参数行为、格式和特定任务能力更新事实成本高,仍可能幻觉
工具/数据库查询确定性系统结果实时、结构化、可校验需要明确接口和参数
长上下文一次放入更多资料少一层索引成本、延迟、噪声和窗口仍有限

5. 原理剖析

5.1 直觉理解

可以把 RAG 看成“开卷考试”。模型负责理解问题和组织答案,检索系统负责在考试前迅速翻到相关页。书中有答案但没翻到,是召回问题;翻到正确页却答错,是生成忠实度问题;书本身没有答案,是语料覆盖问题。三者不能用一个“幻觉率”模糊处理。

5.2 端到端数据流

图 1:基础 RAG 的离线与在线双链路

替代文本: 上半部分将文档经过解析、切块和 Embedding 写入带版本与权限元数据的向量索引;下半部分将用户问题与身份条件转成查询,检索并组装上下文,再让 LLM 生成带引用答案,整个链路写入追踪和评测记录。

图表加载中…

读图结论: RAG 有两条独立但通过索引版本连接的链路;任何一层丢失内容、版本或权限,都可能让最终答案失败。

5.3 文档解析与切块

5.3.1 为什么要切块

文档通常大于单次检索单元。Chunk 太大:

  • 向量表达混合多个主题,匹配不精确;
  • 占用上下文,挤掉其他证据;
  • 引用定位粗。

Chunk 太小:

  • 丢失标题、定义条件和跨段关系;
  • 同义短片段难以区分;
  • 检索结果碎片化,重组困难。

常见策略:

  • 固定 Token 长度加 overlap;
  • 按标题、段落、列表和代码块递归切分;
  • 语义边界切分;
  • 子块检索、父块返回,即 small-to-big;
  • 表格、代码、PDF 页眉页脚采用专用解析。

Chunk 必须带 source_id、document_version、section_path、字符或页码位置、ACL、content_hash 和 parser_version,才能删除、更新、引用和排障。

5.3.2 overlap 的边界

重叠可以减少边界信息丢失,却会:

  • 增加索引体积和 Embedding 成本;
  • 让 Top-k 出现近重复结果;
  • 夸大某些文档在候选中的占比。

因此 overlap 不是越大越好,应与去重策略、文档结构和评测结果共同选择。

5.4 Embedding 与相似度

Embedding 模型把文本 t 映射为向量:

f(t)=vRd

查询向量 q 与文档向量 d 常用余弦相似度:

cos(q,d)=qdq2d2

若向量已做 L2 归一化,余弦排序等价于点积排序。必须确认向量库使用的距离方向:有的返回相似度(越大越好),有的返回距离(越小越好),阈值不能照搬。

Embedding 模型、预处理和维度属于索引契约。查询与文档必须位于兼容空间;模型升级时不能把新旧向量无标记混在同一索引中。

5.5 Top-k、上下文组装与生成

Top-k 不是“先从全库取 k 个块,再隐藏无权内容”,也不是“最终把 k 个块全部塞给模型”。基础流程是:

  1. 由可信身份服务计算 tenant、用户组、项目、文档 ACL 和策略版本等授权条件;
  2. 将授权条件推入关键词、向量等每一路检索算子,再执行 Top-k 候选召回;
  3. 对候选文档重新授权,作为索引或缓存错误的二次防线;
  4. 去掉重复或同源过密 Chunk;
  5. 取回原文并核对版本;
  6. 在 Token 预算内保留问题、指令、证据和输出空间;
  7. 用稳定引用 ID 标记证据;
  8. 明确要求证据不足时拒答;
  9. 返回答案与引用映射。

如果先取全局 Top-k 再过滤,无权文档会占满候选位,使有权文档进不了后续链路,候选分数或缓存也可能越过权限边界;如果把过滤放在生成之后,未授权内容已经进入模型上下文,属于直接数据泄露。召回后授权仍有必要,但它是二次防线,不能替代检索内 ACL。

5.6 检索指标

设查询 q 的相关 Chunk 集为 Gq,前 k 个检索结果为 Rqk

Recall@k(q)=|GqRqk||Gq|

若每个问题只标一个必要证据,也常报告 Hit@k:

Hit@k(q)=1(GqRqk)

边界:

  • Recall@k 依赖相关性标注;只有答案文本、没有证据标注时不能直接计算;
  • Chunk 粒度改变会改变 Gq,跨切块版本的数值不能直接比较;
  • k 增大通常不降低召回,但会增加噪声、上下文成本和生成干扰;
  • 检索命中不等于答案正确,还要单独评测忠实度与正确性。

5.7 复杂度与关键假设

假设有 N 个 Chunk、向量维度 d

  • 全量 Embedding 成本近似随总 Token 数增长;
  • 暴力精确向量检索需计算所有点积,时间约为 O(Nd)
  • 保存稠密向量的主体空间约为 O(Nd),还不含图索引、元数据和副本;
  • Approximate Nearest Neighbor(ANN,近似最近邻)用召回换延迟与内存,具体复杂度依赖 HNSW、IVF 等结构和参数,不能一概写成固定对数复杂度;
  • 上下文构造受模型输入预算 B 约束,所有 Chunk Token 总数必须与指令、问题、历史和输出预留共同满足预算。

关键假设是“语义相近能代表回答相关”。编号、稀有实体、否定条件和时间范围可能违反这个假设,因此基础向量检索往往需要在下一阶段加入关键词检索、过滤和重排。

6. 实现与代码

6.1 最小可运行示例

下面只依赖 Python 标准库,用字符二元组构造教学向量,演示切块、向量化、余弦检索、上下文与引用。它不是生产语义 Embedding,也不调用 LLM;生产环境应替换 embed 与 generate,但保留相同数据契约。

运行:保存为 rag_demo.py 后执行 python rag_demo.py。

python
import math
import re
from collections import Counter
from dataclasses import dataclass


@dataclass(frozen=True)
class Chunk:
    chunk_id: str
    source: str
    text: str


def normalize(text: str) -> str:
    return re.sub(r"\s+", "", text.lower())


def embed(text: str) -> Counter[str]:
    """教学用字符二元组向量;生产环境替换为同版本语义 Embedding。"""
    text = normalize(text)
    return Counter(text[i : i + 2] for i in range(max(0, len(text) - 1)))


def cosine(a: Counter[str], b: Counter[str]) -> float:
    dot = sum(value * b.get(key, 0) for key, value in a.items())
    norm_a = math.sqrt(sum(value * value for value in a.values()))
    norm_b = math.sqrt(sum(value * value for value in b.values()))
    return dot / (norm_a * norm_b) if norm_a and norm_b else 0.0


def retrieve(query: str, chunks: list[Chunk], k: int = 2):
    query_vector = embed(query)
    scored = [
        (cosine(query_vector, embed(chunk.text)), chunk)
        for chunk in chunks
    ]
    return sorted(scored, key=lambda item: item[0], reverse=True)[:k]


def build_grounded_answer(query: str, ranked) -> str:
    # 为了可离线运行,这里只组装“交给 LLM 的证据”,不伪装成生成模型。
    evidence = "\n".join(
        f"[{chunk.chunk_id}] {chunk.text}" for score, chunk in ranked if score > 0
    )
    if not evidence:
        return "证据不足,无法回答。"
    return (
        f"问题:{query}\n"
        "请只依据以下证据回答;证据不足时明确拒答,并引用 chunk_id。\n"
        f"证据:\n{evidence}"
    )


if __name__ == "__main__":
    chunks = [
        Chunk("c1", "退款规则.md", "退款申请应在购买后七日内提交。"),
        Chunk("c2", "退款规则.md", "数字商品已完整下载后不支持无理由退款。"),
        Chunk("c3", "账号安全.md", "修改密码后应重新登录全部设备。"),
    ]
    query = "退款申请期限是多久?"
    ranked = retrieve(query, chunks, k=2)
    for score, chunk in ranked:
        print(f"{chunk.chunk_id}\t{score:.4f}\t{chunk.source}")
    print("--- prompt ---")
    print(build_grounded_answer(query, ranked))

6.2 关键实现说明

  • Chunk 是最小可检索和引用单元,chunk_id 必须稳定;
  • normalize 与 embed 的版本在生产中必须记录,避免查询和索引不一致;
  • 排序前没有设任意“通用阈值”,因为不同模型和距离实现分数不可直接迁移;
  • generate 阶段故意只输出 Prompt,避免把字符串拼接冒充 LLM;
  • 真实系统要批量 Embedding、持久化索引、按 ACL 过滤、限制 Token,并记录候选分数。

6.3 边界条件与验证

运行后应验证:

  1. 问退款期限时 c1 排在账号文档之前;
  2. 查询完全无关时不应因为“总有 Top-k”就强行回答;
  3. 删除 c1 后索引和原文同时不可见;
  4. 同一 source 的重叠 Chunk 不应占满所有候选;
  5. Chunk 文本与引用 source 能从当前版本原文核验;
  6. 切换 Embedding 版本时阻止新查询读取旧向量空间。

教学向量只利用字符重叠,无法处理真正同义表达。这个失败本身可作为对照实验,说明词法检索、语义 Embedding 和混合检索的差异。

6.4 技术栈与横向选型

RAG 是系统模式,不等于某个向量库或编排框架。下表使用三个主 TP 覆盖摄取、向量编码与候选存储;候选产品只是参考实现,真实结论需固定文档类型、权限、数据量和评测集。

技术点 ID技术点/环节类型采用方案链路职责版本/证据边界
TP-RB-01文档解析与结构化库/服务Markdown/HTML 优先原生解析器;复杂 Office/PDF 以 Unstructured 或 Apache Tika 作候选提取正文、标题、页码、表格与来源定位,为切块提供结构PDF/OCR 质量强依赖文档分布;解析率需用真实样本库评测
TP-RB-02Embedding 编码模型/服务通过 Adapter 封装本地 Sentence Transformers 或托管 Embedding API对文档切块与查询使用同一受控模型产生向量必须固定模型、维度、规范化、任务 Prompt 和 API 版本;不虚构召回收益
TP-RB-03向量与元数据存储存储/检索服务关系数据库已是主栈时优先评估 pgvector;独立向量服务以 Qdrant 作候选存储向量、原文引用、ACL、版本与过滤字段,返回可追溯候选产品不会自动保证 ACL 正确或召回质量;必须用权限与性能基准决策
技术点 ID候选方案优点缺点/代价适用场景不适用场景选择结论与依据
TP-RB-01Unstructured面向多格式文档提供元素化抽取与分区思路复杂依赖、版式差异和 OCR 错误需额外质检PDF、Office 等多格式摄取,需保留元素类型来源只是结构清晰的 Markdown,原生解析已足够仅在复杂格式样本库上证明标题、表格与定位收益后采用
TP-RB-01Apache Tika广泛文件类型检测与文本/元数据提取,服务边界清晰输出往往还需业务化结构恢复,不自带 RAG 切块质量保证多格式统一文本抽取、JVM 服务已成熟需高保真表格、版面与 OCR 领域化结构作为稳定通用抽取候选,用同一文档金标集与 Unstructured 对比
TP-RB-02本地 Sentence Transformers数据不出域、批处理与模型版本可控需 GPU/CPU 容量、模型加载、扩容和升级运维敏感数据、稳定高吞吐、需自主固定模型请求少且团队没有推理运维能力在隐私或稳定负载证明总成本收益时采用
TP-RB-02托管 Embedding API接入快、无需维护推理集群,容量由服务方提供存在数据出域、限流、成本和模型升级边界原型、弹性负载、合规允许的通用语义检索严格数据驻留、无外网或必须绑定自训模型以数据边界、限流、质量和总成本联合决策,并置于 Adapter 后
TP-RB-03PostgreSQL + pgvector向量、关系元数据和事务处在同一运维体系大规模 ANN 、独立扩容与索引调优会与业务数据库争资源已有 PostgreSQL、数据规模受控、元数据过滤重向量搜索需独立大规模扩展且会影响主库作中小规模首个可运维基线,容量与权限基准不达标再分离
TP-RB-03Qdrant向量检索、过滤与服务化运行边界清晰引入新存储、备份、容量和双写/迁移复杂度检索负载需独立扩展、复杂过滤与在线更新数据小或团队无多存储运维能力只在独立扩展、延迟或过滤证据超过额外成本时切换

6.5 架构与技术调用流程

图:架构|基础 RAG 离线摄取与在线问答边界

替代文本: 离线链路将权威文档经解析、切块、Embedding 与质量门禁写入版本化索引;在线链路将用户身份与查询一起进入权限过滤、向量检索、上下文构造和 LLM,索引清单连接两条链路的版本。

图表加载中…

读图结论: 离线索引发布与在线问答是两条独立链路,必须通过不可变索引清单对齐语料、Embedding 和 ACL 版本。

架构图表达静态数据与权限边界。向量索引不是权威事实源;回答必须能回到原文版本和用户可见的证据片段。

图:技术调用流程|RAG 查询的权限、召回与拒答时序

替代文本: 问答 API 先验证身份并生成可见过滤条件,再调用 Embedding 和索引;无可见候选或证据不足时拒答,LLM 超时时返回已受权的检索结果或明确失败,成功时校验引用后返回。

图表加载中…

读图结论: ACL 必须在召回前进入候选边界;证据不足和 LLM 不可用是两类失败,分别需要拒答语义与服务降级策略。

时序图将检索与生成故障分开。生产 Trace 应记录索引、Embedding、ACL、Prompt 和模型指纹,但不应将未脱敏原文无限制写入日志。

7. 实际项目案例

示例项目,非本仓库真实业务;不假设数据量、QPS 或效果提升。

7.1 背景、目标与约束

构建企业内部运维知识助手,回答部署、故障和权限流程问题。知识来自 Markdown、PDF 和工单总结,具有以下约束:

  • 文档更新频率不同,删除和撤权必须及时生效;
  • PDF 可能出现页眉、表格和扫描页解析错误;
  • 不同团队只能看到各自文档;
  • 回答必须给出文档与段落引用;
  • 无证据时应拒答,不能靠模型常识补全内部流程。

7.2 架构与调用链

图:业务双泳道|企业运维知识助手的索引发布与在线问答

替代文本: 离线泳道从文档版本判断开始,解析、切块和批量向量化后写入候选索引;质量或权限检查失败时保留旧索引,通过后才原子切换。在线泳道从可信身份和租户上下文开始,检索、原文复核和上下文预算后生成带引用答案;无证据、越权或生成失败进入拒答或降级分支。

图表加载中…

读图结论: RAG 的可信边界跨越发布和查询两条链:候选索引未过门禁不能被读,在线候选未过权限、版本和证据检查不能进入模型或伪装成正常答案。

数据模型至少包含 Document、DocumentVersion、Chunk、EmbeddingVersion、IndexBuild、RetrievalTrace。删除不是只删原文,还要产生可审计的索引删除事件。

7.3 方案选择与实现难点

  • Markdown 按标题和代码块切分,PDF 使用保留页码/版面的解析结果,不统一粗暴定长;
  • 检索子块但返回包含标题的父级上下文,兼顾定位与完整性;
  • 写入新索引后先做完整性与抽样查询,再切换可读别名,避免半更新;
  • ACL 在检索前或检索算子内执行,不能只在答案显示层隐藏;
  • 文档正文和工具输出都标记为非可信数据,防止其中指令覆盖系统规则。

未选择“把全部文档放进长上下文”,因为它无法解决权限、更新一致性、成本和可追溯检索问题。

7.4 异常处理、监控与测试

现象根因假设解决方案验证证据
明明有文档却零命中文档未解析;索引任务失败;版本过滤错误查 source_id 全链路;重放失败任务;校验别名当前版本 Chunk 可数;金标准查询 Hit@k 恢复
命中旧制度增量更新未删旧 Chunk;缓存键无版本tombstone 删除;索引版本入缓存键旧 chunk_id 不可检索;引用指向新版本
Top-k 都是重复段落overlap 过大;没有同源去重降低重叠;按 source/section 做 MMR 或配额候选唯一来源数与 Recall@k 同时检查
检索正确但答错上下文被截断;Prompt 允许常识补全记录最终上下文;调整预算;要求引用/拒答相同证据下忠实度回归测试通过
用户看到他组文档ACL 晚于检索;只按 tenant/role 缓存;撤权后未失效每路召回推入完整 entitlement 条件;命中后二次授权;权限指纹和策略版本入缓存键;撤权主动失效覆盖同租户同角色但不同文档权限的越权测试;Trace 显示授权条件与策略版本
PDF 答案乱码OCR/表格解析失败解析质量门禁;类型化解析;失败隔离原文抽样、页码引用和解析错误率检查

7.4.1 故障演练:撤权后缓存仍返回其他团队文档

  • 现象与影响:用户权限已撤销,但相同查询仍命中旧缓存并引用受限文档,造成持续的数据泄露窗口。
  • 定位证据:检查身份、完整 entitlement、policy_version、缓存键、候选文档 ACL、撤权事件时间、命中记录与最终上下文。
  • 根因:检索缓存只按 query 或 tenant/role 隔离,撤权事件没有主动失效缓存;命中后也没有二次授权。
  • 临时止损:禁用或清理受影响缓存命名空间,阻断相关检索流量,撤销已生成链接并启动安全审计。
  • 长期修复:每路召回携带可信权限过滤,缓存键绑定完整权限指纹与策略版本;命中后二次授权,撤权和删除事件主动失效。
  • 回归验证:覆盖同租户同角色不同 ACL、撤权传播、共享变更、缓存命中和索引回滚,确认未授权候选始终不可见。
  • 防复发:权限测试加入发布门禁,监控异常跨主体命中、撤权传播延迟和缓存失效失败;审计日志绑定 request_id 与策略版本。

监控至少分层记录 ingest_lag、parse_failure、chunk_count、index_build_status、retrieval_candidate_count、filtered_count、Recall@k(离线)、无证据率、引用缺失率和端到端延迟。高基数的 query_id 放日志/Trace,不直接当无界指标标签。

7.5 结果与复盘

项目验收不能写“能回答几个问题”:

  • 为每个问题标注答案是否存在、必要证据和允许引用;
  • 分别测试文档新增、修改、删除、撤权和回滚;
  • 将失败归到覆盖、解析、索引、查询、召回、上下文或生成;
  • 记录每次变更的 parser、chunker、embedding、index、prompt 与 model 版本;
  • 只有在固定评测集与线上安全门禁均通过后才发布。

8. 方案权衡与常见误区

8.1 适用与不适用场景

适用:

  • 私有或频繁变化的文档问答;
  • 需要引用和审计;
  • 多租户、多知识域且可建立检索语料;
  • 允许“证据不足时拒答”。

不适用或需组合其他方案:

  • 权威实时数值应直接查数据库/API;
  • 需要模型稳定遵守风格可组合微调;
  • 没有可治理知识源时,RAG 无法修复知识空洞;
  • 确定性流程应由状态机或规则主导。

8.2 关键权衡

决策一侧收益另一侧成本验证方式
Chunk 变小定位精确上下文破碎按问题类型比较 Recall@k 与答案忠实度
overlap 增大减少边界丢失重复、成本、候选挤占唯一来源数、索引体积、Recall@k
k 增大可能提高召回噪声与 Token 增加检索-生成联合曲线
精确检索结果确定大规模延迟高以精确结果作 ANN 召回基线
ANN延迟可控近似误差、参数复杂ANN Recall 与延迟压测
强拒答降低无证据回答可能误拒answerable/unanswerable 分开评测

8.3 常见错误回答

  • “Top-1 分数高就一定相关”:分数依赖模型、查询和索引实现,需标注集校准;
  • “Chunk 越大信息越全”:可能混合主题并挤占上下文;
  • “用了 RAG 就不会幻觉”:生成仍可能不忠实;
  • “Embedding 升级只改模型名”:必须重建兼容索引并管理版本;
  • “权限在返回前过滤即可”:未授权文本进入上下文已构成泄露;
  • “向量库召回差就是换更大模型”:先确认语料、解析、版本、查询和标注。

8.4 生产问题的诊断顺序

对一条失败请求保留并依次检查:

  1. 用户身份、租户和过滤条件;
  2. 答案所需事实是否存在于当前权威文档;
  3. 文档版本是否完成解析和索引;
  4. Chunk 是否包含完整答案及标题条件;
  5. 查询向量与索引 Embedding 版本是否一致;
  6. 原始候选、分数、过滤前后列表和最终上下文;
  7. 模型输入是否截断,输出是否引用证据;
  8. 缓存是否跨版本、跨租户或保存旧答案。

这个顺序先查确定性数据链,再判断模型质量,能避免把摄取失败误报为“LLM 幻觉”。

9. 面试题与参考答案

问题 1:完整 RAG 链路有哪些关键步骤?

  • 难度:基础;
  • 考察点:端到端理解;
  • 合格答案要点:离线解析、切块、Embedding、索引;在线查询处理、检索、过滤、上下文、生成和引用;
  • 优秀答案加分项:版本、ACL、删除、观测和评测;
  • 常见错误:只回答“Embedding 加向量库”;
  • 可继续追问:哪个步骤最容易造成“文档存在但查不到”?

问题 2:Chunk 大小如何选择?

  • 难度:中级;
  • 考察点:检索单元与上下文完整性的权衡;
  • 合格答案要点:根据文档结构、答案跨度、Embedding 与 Token 预算,通过固定集实验;
  • 优秀答案加分项:子块检索父块返回、overlap 去重、表格/代码专用解析;
  • 常见错误:给出一个适用于所有系统的固定数字;
  • 可继续追问:切块版本变化后为什么不能直接比较旧 Recall@k?

问题 3:为什么检索到正确 Chunk,模型仍可能答错?

  • 难度:中级;
  • 考察点:检索与生成解耦;
  • 合格答案要点:上下文截断、冲突证据、指令不清、模型忽略或误解证据;
  • 优秀答案加分项:查看最终实际上下文、引用和忠实度,不只看原始候选;
  • 常见错误:直接增大 Top-k;
  • 可继续追问:如何设计证据不足拒答?

问题 4:RAG 与微调如何选择?

  • 难度:中高级;
  • 考察点:方案边界;
  • 合格答案要点:动态事实与引用优先 RAG,行为与任务能力可考虑微调,两者可组合;
  • 优秀答案加分项:比较更新频率、数据质量、延迟、成本、审计和评测;
  • 常见错误:把两者说成互斥;
  • 可继续追问:如果答案来自实时订单状态,应使用哪种方案?

问题 5:如何安全地做多租户 RAG?

  • 难度:高级;
  • 考察点:数据权限和缓存隔离;
  • 合格答案要点:可信身份下发、每路检索前/检索内 ACL、候选二次授权、租户隔离索引或强过滤、缓存绑定完整权限指纹和策略版本;
  • 优秀答案加分项:撤权同步、越权红队、Trace 审计和最小化日志;
  • 常见错误:生成后隐藏敏感句子;
  • 可继续追问:索引库不支持高效 ACL 过滤时如何设计?

10. 递进追问

  1. 基础概念:为什么 RAG 被称为“非参数化知识”增强?
  2. 原理细节:L2 归一化后,为什么点积排序与余弦排序一致?
  3. 实现边界:文档更新时怎样避免一半新索引、一半旧索引?
  4. 工程权衡:增大 Top-k 为什么可能提高召回却降低最终答案质量?
  5. 系统设计:设计一个支持删除、撤权、回滚和引用的文档索引版本系统。
  6. 项目复盘:线上“无答案率”上升,你如何证明是语料变化、检索退化还是拒答策略变化?

参考回答线索:

  1. 知识保存在外部可检索存储而非只在模型参数;
  2. 单位向量的范数为 1,余弦分母恒定;
  3. 新索引暂存、校验后原子切换别名,保留可回滚版本;
  4. 更多弱相关证据会挤占 Token、制造冲突并分散注意;
  5. 不可变版本、事件驱动删除、ACL 元数据、引用定位和切换审计;
  6. 按版本切分并重放固定查询,分别观察语料覆盖、Recall@k 和忠实度/拒答指标。

11. 实践任务

  • [ ] 最小实现:运行第 6 节代码,为 Chunk 增加 section 与 document_version;
  • [ ] 对比实验:构造同义表达与精确编号查询,观察字符二元组向量的失败,作为语义/关键词检索基线;
  • [ ] 切块实验:对同一篇自有文档使用段落切块、定长切块和父子切块,人工标注必要证据后比较;
  • [ ] 故障注入:模拟文档删除但向量未删、Embedding 版本混用、ACL 缺失和上下文截断;
  • [ ] 面试口述:不看文档完整讲出离线与在线两条调用链,并解释每层失败证据。

12. 相关知识与参考资料

12.1 相关知识

12.2 参考资料

以下均为原始论文、官方文档或官方源码,访问日期均为 2026-07-10

  1. Lewis et al., Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks, NeurIPS 2020:RAG 的原始问题定义与参数化/非参数化记忆组合;
  2. Karpukhin et al., Dense Passage Retrieval for Open-Domain Question Answering, EMNLP 2020:双编码器稠密检索;
  3. Johnson, Douze, Jégou, Billion-scale similarity search with GPUs, IEEE BigData 2017:FAISS 相似度检索设计;
  4. Malkov and Yashunin, Efficient and robust approximate nearest neighbor search using Hierarchical Navigable Small World graphs, IEEE TPAMI:HNSW 原始论文;
  5. Facebook Research, FAISS source repository:精确与近似向量索引的官方源码;
  6. OpenAI, Embeddings guide:Embedding 输入、相似度用途与官方 API 说明。

13. 简明总结

一句话记忆: RAG 是“离线把知识做成可追溯索引,在线把正确证据送进上下文”,不是简单连接一个向量库。

  • 基础链路必须拆成文档摄取与查询生成两条路径;
  • Chunk、Embedding、Top-k 和 Token 预算互相制约,要靠标注集选择;
  • 文档存在、检索命中、上下文保留和生成忠实是四个不同检查点;
  • 权限、版本、删除和引用必须从数据模型开始设计;
  • 面试中要能沿“语料 → 解析 → 索引 → 检索 → 上下文 → 生成”逐层定位失败。