去年给客户做内部制度问答,第一版上线当天就被打脸。用户问「试用期能不能休年假」,系统回答:"试用期员工年假按 80% 折算,需提前 3 个工作日申请。"——语气笃定、格式工整,而公司制度里根本没有这一条。
复盘时我们才想明白:模型不是"记错了",它是在没有任何证据的情况下,用最像答案的语气补全了一个最合理的句子。这就是要上 RAG 的真正原因——不是为了让答案更聪明,是为了让答案有据可查。
关键词:RAG、检索增强生成、向量检索、Embedding、Rerank、大模型、知识库问答
一、RAG 原理:一句话,以及它为什么真的管用
1.1 原理本身一句话就能说完
RAG(Retrieval-Augmented Generation,检索增强生成)=答题前先翻资料,照着翻到的内容答,并注明出处。
形式化一点:
普通生成:$\hat{y} = \arg\max P(y \mid x)$
RAG 生成:$\hat{y} = \arg\max P(y \mid x, z)$,其中 $z$ 是检索器找回来的证据片段
差别只在多了一个 $z$,但这个 $z$ 把"模型觉得自己知道什么"换成了"资料里写着什么"。
1.2 它为什么管用:把两类知识拆开
这是 RAG 原始论文[1]最核心的贡献,也是很多人忽略的一层理解:
| 知识类型 | 存在哪里 | 怎么更新 | 适合装什么 |
|---|---|---|---|
| 参数化知识 | 模型权重里(训练烧进去的) | 重训 / 微调,成本极高 | 通用的语言能力、推理方式、世界常识 |
| 非参数化知识 | 外部索引里(向量库 / 搜索引擎) | 改文档即可,秒级生效 | 公司制度、产品手册、实时数据、私有文档 |
RAG 的本质不是"给模型外挂一个硬盘",而是把"会说话"和"知道什么"这两件事解耦——让模型只负责它擅长的(理解、组织、表达),把事实性知识交给可随时修改的外部系统。
想通这一点,很多设计问题就自动有答案了:
为什么要做溯源?因为 $z$ 是可查的外部事实,答案的信任来自 $z$ 而不是模型;
为什么改文档就能改答案?因为知识压根不在权重里;
为什么 RAG 不等于"消灭幻觉"?因为它只管住了 $z$,管不住模型在 $z$ 之外自由发挥。
1.3 三个先天毛病,决定了什么时候必须上 RAG
知识截止:训练数据有时间终点,问它之后的、以及高频变动的事,它只能猜;
私有数据看不见:公司内部制度、工单、客户资料,从来不在训练集里;
无证据时仍会补全:这是最危险的——模型被训练成"总要给出一个通顺的回答",于是没有答案时它会编一个最像的答案,而且语气和真答案毫无区别。
第三条是开头那个事故的根因,也是 RAG 最不可替代的价值:它给了模型一条"我不知道"的合法出路。
1.4 RAG vs 微调 vs 塞长上下文
这三个方案经常被拿来一起比较,但它们在解决不同的问题:
| 维度 | RAG | 微调 | 长上下文 |
|---|---|---|---|
| 改变的是 | 模型看到什么 | 模型怎么说话 | 模型一次能看多少 |
| 知识更新 | 改文档,秒级 | 重新训练,天级 | 改文档,秒级 |
| 适合灌知识 | ✅ 事实、制度、数据 | ❌ 不适合 | ✅ 但受长度和成本限制 |
| 适合改风格/格式 | ❌ 很难 | ✅ 强项 | ❌ |
| 可溯源 | ✅ 天然支持 | ❌ 无法溯源 | ✅ 但token 成本高 |
| 成本 | 中(检索 + 长 prompt) | 高(训练 + 维护) | 高(每次全量付费) |
| 典型误用 | 拿它教模型"语气要客气" | 拿它灌产品手册 | 把整个知识库每次都塞进去 |
一句话选型口诀:教它怎么做 → 微调;告诉它是什么 → RAG;一次性读完整份材料 → 长上下文。三者也经常组合使用(RAG 召回 + 微调过的生成风格)。
二、完整链路总览:两条链,而不是一条
新手最容易犯的认知错误,是把 RAG 想成"一次问答调用"。实际上它是两条独立运行的链路:
═════════════ 离线链(写):文档进来,索引建好,跑一次或定时跑 ═════════════ 原始文档 解析 切片 向量化 写入 PDF/Word → Loader → Chunking → Embedding → VectorDB HTML/DB ① ② ③ ④ │ │ │ │ │ └── 元数据 ─────┘ │ │ (标题/页码/时间/权限) │ └──────────────────────────────────────────┘ ↑ 90% 的线上问题出在这里 ═════════════ 在线链(读):用户提问,实时执行 ═════════════ 用户问题 │ ├─→ ⑤ Query 改写(指代消解 / 多查询扩展 / HyDE) │ ├─→ ⑥ 检索(关键词 BM25 + 向量语义 → 融合 → Top-N 粗排) │ ├─→ ⑦ 重排 Rerank(交叉编码器精排 → Top-K) │ ├─→ ⑧ 上下文组装(去重 / 排序 / 截断 / 加引用编号) │ └─→ ⑨ 生成 + 溯源(带拒答约束的 Prompt → LLM → 带 [1][2] 出处的答案)
这张图里最值钱的一句话:绝大多数"RAG 答不准"的问题,根因在离线链,但团队的时间都花在调在线链的 prompt 上。
我们项目踩过这个坑:线上答案质量不达标,两周内改了十几版生成 prompt,收效甚微。后来把召回的 chunk 打印出来肉眼一看——该找的内容压根没被召回来。分片把一条完整规则切成了两半,两半的相关性分数都不够高,双双落榜。改了切片策略之后,prompt 一字未动,准确率直接涨了 20 多个点。
这个教训后来变成了我们团队的第一条排查纪律:先打印召回结果,再谈生成质量。
顺带一提,RAG 的演进通常被划分为 Naive / Advanced / Modular 三个阶段[6],上面这条链路属于 Advanced 级别——它的每个环节都可独立替换与优化。
三、九个模块逐个拆解:干什么、不做会怎样
① 文档解析(Loader)
作用:把 PDF / Word / HTML / Markdown / 数据库里的非结构化内容,变成带元数据的纯文本。
不做会怎样:PDF 双栏排版被读成左右两栏文字交错;页眉页脚混进正文;扫描件全是图片一个字都提取不出来。这是最容易被低估的"脏活"——它不产生任何可见的技术含量,但它决定了后面所有环节的输入质量上限。
关键决策:
优先选结构化源(数据库 > Markdown > Word > PDF > 扫描件 PDF);
表格是最大的坑。表格直接转文本会变成一堆对不上号的散字,行级展开(把每行拼成一句自包含的自然语言,如"产品A,单价199元,库存30件")是性价比最高的处理法;
扫描件必须上 OCR,并且要接受 OCR 有误这一事实,在下游设计容错。
② 切片(Chunking)—— RAG 的第一杀手
作用:把长文档切成适合检索和塞进 prompt 的小段。
为什么它是第一杀手:这个环节同时卡着两个互相矛盾的目标——
| 切得太小 | 切得太大 |
|---|---|
| 语义完整,但噪声多 | 信息集中,但语义被切断 |
| 单块信息量不足,答不全 | 无关内容稀释相关性,检索分数被拉低 |
| 召回多但质量低,prompt 塞不下 | 超出 embedding 模型的最佳输入长度 |
关键决策:
按结构切优先于按字数切:先按标题层级、段落、句号切,实在切不动再按字数硬切;
重叠(overlap)不是可选项:每块开头回带上一块末尾的 1~2 个完整句子,能显著缓解"答案恰好落在切分边界"的问题。注意要按整句回带,不要按字数回带——按字数回带会切出"天。""如前所述,"这类语义碎片,它们本身无法独立读懂,反而污染检索(第四节的代码里特意避开了这个坑);
每块要能独立读懂:块里不能只有"见上表""如前所述"——必要时把标题、表头回填进每个块。这一条的收益经常被低估;
块大小没有银弹,我们的起点是中文 300~500 字,然后按召回结果的实际情况调。
③ 元数据(Metadata)
作用:给每个 chunk 挂上标题、章节、页码、生效时间、来源 URL、权限标签等结构化信息。
为什么值得单独当一节:它是成本最低、收益最高的优化手段——不需要换模型、不需要改算法,只在入库时多存几个字段。
它的两个核心用途:
检索前过滤:只查"2024 年之后的""研发部可见的"文档,把检索空间砍掉一大半,准确率和性能同时提升;
检索后展示:答案末尾给出"来源:《员工手册》第 3 章,2025 版",用户能一键点进去核对。
这里有个安全红线:权限过滤必须发生在检索层(查询条件里带权限标签),不能靠在 prompt 里写"不要泄露你没有权限的内容"——那是许愿,不是访问控制。
④ 向量化(Embedding)
作用:把文本映射成高维向量,让"语义相近"变成"空间里距离近"。
关键决策:
中文场景优先选中文榜单靠前的模型(BGE 系列等),不要直接用只训过英文的通用模型。选型的经验标准是看 MTEB / C-MTEB 这类公开榜单的中文子集,而不是看模型名气;
检索任务和语义相似度任务是两回事,要选标注为 retrieval 的模型;
query 和 doc 的处理要区分:BGE 这类模型官方建议给 query 加指令前缀(如"为这个句子生成表示以用于检索相关文章:"),文档侧不加。忽略这个细节会白白损失几个点的召回率;
模型和索引绑定:换 embedding 模型 = 全库重算重灌。所以这个选型要在项目早期定死,中途换的代价是全量重建。
⑤ Query 改写
作用:把用户的"大白话"变成更适合检索的查询。
为什么需要:用户问的和文档写的是两套语言。用户问"能不能提前走?",文档写的是"离职申请流程与审批权限"。直接拿原句去检索,语义匹配不上就召不回。
三种主流手段(按成本递增):
指代消解:多轮对话里"那病假呢?"必须还原成"病假如何申请"才能检索;
多查询扩展:把一个问题改写成 3~5 个不同角度的查询,分别检索后合并,用召回率的提升换一点成本;
HyDE[2]:让模型先"编"一个假答案,再用这个假答案去检索——假答案虽然内容可能不准,但它的用词和表述方式与真实文档更接近,检索效果往往比原问题更好。这个思路很反直觉,但确实有效。
⑥ 检索(Retrieval)
作用:从海量 chunk 里粗筛出几十条候选。
三条路线及其分工:
| 路线 | 原理 | 强项 | 弱项 |
|---|---|---|---|
| 关键词(BM25) | 词频 + 逆文档频率 | 精确词、专有名词、型号、报错码 | 同义词、口语化表达 |
| 向量(稠密检索) | 语义相似度 | 同义表达、模糊描述 | 精确词、罕见专有名词 |
| 混合检索 | 两路都查再融合 | 覆盖率最高 | 实现复杂一点 |
实践结论:直接用混合检索。纯向量检索在真实业务里几乎总会漏掉一些"看着就应该命中"的精确词,而这类失败用户最容易感知到。
融合算法用RRF(Reciprocal Rank Fusion)就够了,它只依赖排名不依赖分数,不需要归一化两路的可比性:
$$score(d) = \sum_{i} \frac{1}{k + rank_i(d)} \quad (k \approx 60)$$
⑦ 重排(Rerank)
作用:对粗排结果做精排,把 Top-50 收敛成 Top-3~5。
为什么必须有这一步:粗排用的是双塔模型(query 和 doc 各自独立编码成向量再比距离),速度快但精度有限;重排用的是交叉编码器(把 query 和 doc 拼在一起过一遍模型),能真正"读"到两者的交互,精度高得多,代价是慢——所以只适合作用在小候选集上。(交叉编码器之外,ColBERT 的"延迟交互"是另一条折中路线:精度接近交叉编码,速度却快得多[8]。)
这也是目前投入产出比最高的一个模块:加一个开源 rerank 模型(如 bge-reranker),通常能带来肉眼可见的准确率提升,而改造成本只是多一次模型调用。
什么时候可以不上:召回量本身很小(知识库只有几十条),或者对延迟极度敏感的场景。
⑧ 上下文组装
作用:把选中的 chunk 编排成喂给模型的 prompt。
容易被忽略的三个细节:
去重:多路检索和 overlap 都会带来重复内容,重复的 chunk 会挤占宝贵的上下文窗口;
位置:研究发现长上下文中模型对开头和结尾的内容利用得最好,中间部分容易"丢失"[3]。所以不要把最相关的 chunk 放在中间——最相关的放首尾,次相关的放中间;
加引用编号:给每个 chunk 编号
[1][2][3],并在 prompt 里要求模型在每个结论后标注出处。这既让答案可核,也是一个隐性约束——模型知道每句话都要"挂到某个编号上"时,会更少地自由发挥。
⑨ 生成与溯源
作用:产出最终答案,并让它可追溯。
Prompt 里必须写死的三件事(缺一件就会回到"编得很好听"的老路):
只允许依据给定资料回答;
每句结论标注引用编号;
资料不足时明确拒答——给出"根据现有资料无法回答"这个合法选项,模型才不会硬凑。
第三条最关键。我们上线前后对比过:加了显式拒答约束后,用户投诉"答案看着对但查无此项"的比例下降了一个数量级。给模型一条体面的退路,比反复强调"不要编造"有效得多。
四、跑一遍:一份能直接运行的最小 RAG
下面这份代码不依赖任何向量数据库,用 numpy 手算余弦相似度,装两个包就能跑通完整链路。真实项目里把第 4 步换成向量库、第 6 步换成你的大模型客户端即可。
# pip install sentence-transformers numpy import re import numpy as np from sentence_transformers import SentenceTransformer # ══════════════ 离线链 ══════════════ RAW_DOC = """ 第五条 年假:员工累计工作已满1年不满10年的,年休假5天; 已满10年不满20年的,年休假10天;已满20年的,年休假15天。 第六条 试用期:试用期为3个月,试用期员工不享受年休假。 第七条 病假:员工请病假需提供二级及以上医院出具的诊断证明, 病假期间按当地最低工资标准的80%发放病假工资。 第八条 加班调休:工作日加班按1.5倍时薪计算,休息日加班优先安排调休, 调休须在加班发生后三个月内使用完毕,逾期作废。 第九条 离职:正式员工离职需提前30日书面通知,试用期员工提前3日通知即可; 离职前应完成工作交接与资产归还,未完成的暂缓办理离职手续。 """ def chunk(text: str, size: int = 120, overlap_sents: int = 1) -> list[str]: """先按标点断句,再合并成块——比粗暴按字数切更保语义完整""" sents = [s.strip() for s in re.split(r"(?<=[。;\n])", text) if s.strip()] # 兜底:单句本身就超过 size 时按字数硬切,否则这个块会无限长 units: list[str] = [] for s in sents: while len(s) > size: units.append(s[:size]) s = s[size:] if s: units.append(s) chunks: list[str] = [] cur: list[str] = [] # 当前块由若干"整句"组成 for u in units: if sum(len(x) for x in cur) + len(u) <= size: cur.append(u) else: if cur: chunks.append("".join(cur)) # 回带上一块末尾的整句:按字数回带会切出"天。""如前所述,"这类碎片 cur = cur[-overlap_sents:] if overlap_sents else [] cur.append(u) if cur: chunks.append("".join(cur)) return chunks chunks = chunk(RAW_DOC) print(f"[离线] 切成 {len(chunks)} 块:") for i, c in enumerate(chunks, 1): print(f" [{i}] len={len(c):>3} {c[:40]}...") # Embedding:中文检索场景用 BGE 系列 model = SentenceTransformer("BAAI/bge-small-zh-v1.5") # BGE 官方建议:检索场景下 query 侧加指令前缀,doc 侧不加 QUERY_PREFIX = "为这个句子生成表示以用于检索相关文章:" docs_vec = model.encode(chunks, normalize_embeddings=True) # shape: (N, d) # 归一化之后,向量内积 == 余弦相似度 # ══════════════ 在线链 ══════════════ REJECT_THRESHOLD = 0.45 # 拒答阈值:必须用自己的数据实测标定,别抄这个值 def retrieve(query: str, top_k: int = 3): qv = model.encode([QUERY_PREFIX + query], normalize_embeddings=True) scores = docs_vec @ qv.T # (N, 1) idx = np.argsort(-scores.ravel())[:top_k] return [(chunks[i], float(scores[i, 0])) for i in idx] def build_prompt(query: str, hits) -> str: ctx = "\n".join(f"[{i+1}] {c}" for i, (c, _) in enumerate(hits)) return f"""请只依据下面的资料回答问题,并在每句结论后用 [编号] 标注出处。 如果资料中没有足够信息,请直接回答"根据现有资料无法回答",不要推测、不要编造。 资料: {ctx} 问题:{query} """ def answer(query: str) -> str: hits = retrieve(query) # —— 排查纪律第一条:先看召回,再看生成 —— print("\n[在线] 召回结果:") for i, (c, s) in enumerate(hits, 1): print(f" [{i}] score={s:.3f} {c[:40]}...") # 最高分都够不着阈值,说明库里大概率没有,直接拒答 if not hits or hits[0][1] < REJECT_THRESHOLD: return "根据现有资料无法回答。" prompt = build_prompt(query, hits) # 换成你自己的大模型客户端即可: # resp = client.chat.completions.create( # model="qwen-max", # messages=[{"role": "user", "content": prompt}], # ) # return resp.choices[0].message.content return prompt # 没有 API Key 时打印 prompt,方便调试 print(answer("试用期能不能休年假?"))这份代码里有两个刻意保留的"实战痕迹":
REJECT_THRESHOLD带着一句警告:相似度的绝对值没有跨数据集的通用阈值,必须在你自己的文档上采样标定。这个值抄来的结果不是"更准",是"该拒的没拒、该答的拒了";召回结果强制打印:这是我们团队那条排查纪律的代码化——出问题时第一件事是看这里打印了什么。
五、RAG 的优势:不只是"减少幻觉"
大部分文章讲 RAG 优势只讲"减少幻觉",这只说了最小的那一层。真正让它在企业场景不可替代的,是下面这五条:
1. 知识可以热更新,且更新成本近乎为零改一份文档,答案立刻跟着变,不需要重新训练、不需要发版。对于制度、价格、库存这类高频变动的知识,这个特性的价值远超"准确率高几个点"。
2. 答案可溯源——这是企业场景的准入门槛每个答案能给出"出自哪份文件第几节",用户可以一键核对。在金融、医疗、法务这类领域,不能溯源的答案等于不可用的答案,无论它多准确。这是微调方案永远给不了的能力。
3. 私有数据不必离开自己的域知识索引可以完全部署在内网,只有问题和召回的片段会经过模型。相比把文档塞进外部大模型的做法,RAG 让"用上大模型"和"数据不出域"不再互斥。
4. 成本可控且有明确的优化杠杆不需要训练算力,主要的成本是检索和 prompt。而且优化方向非常清晰——检索不准就改切片和检索,生成不好就改 prompt 和模型,两者解耦,可以分别优化、分别衡量。
5. 权限控制有真实的落点访问控制可以做在检索层(查询条件带权限标签),这是在执行层面真正生效的隔离,而不是寄希望于模型"懂事"。
需要泼的一盆冷水是:上面每一条都有前提条件。知识热更新的前提是索引流水线可靠;可溯源的前提是生成端真的老老实实标注且不作弊;权限控制的前提是你真的把它写进了查询条件。RAG 给的是可能性,不是保证。
六、RAG 的不足:这些坑,踩过才知道
这是全文最该认真读的一节。RAG 不是银弹,它有明确的能力边界,而且边界比大多数人以为的要窄。
① 检索是硬天花板,且它是"乘法"不是"加法"
$$最终质量 \approx 检索质量 \times 生成质量$$
检索召不回,生成再强也是零——模型不会因为你 prompt 写得好就凭空知道库里的内容。更麻烦的是错误不会自己消失,只会被包装得更好看:召回了错误片段时,模型会非常自信地基于错误证据给出一个逻辑严密的错答案,比直接说"不知道"危险得多。
一句话总结:RAG 的质量上限由检索决定,下限由生成决定。
这也解释了为什么近年的改进大多集中在检索侧——比如 CRAG 引入一个轻量级检索评估器,一旦发现召回质量不合格就触发纠正动作(重写查询、补充网页检索等)[7]。
② 切片天然会割裂语义
只要切了片,就一定存在"答案恰好横跨两个块"的问题。overlap 能缓解但无法根除。表现是:问一个需要跨段归纳的问题,系统只答出了一半,而且答得很笃定。
③ 多跳和全局性问题天生不擅长
「去年四个季度里,哪个季度的客诉最多?」——这个问题需要扫一遍全部相关数据再比较,而检索只给你 Top-K 个片段。Top-K 检索假设"答案藏在少数几个片段里",这个假设对全局统计类问题根本不成立。
这正是 GraphRAG[4]、RAPTOR 这类"预先构建层级摘要"方案出现的动机——用离线建索引时的额外成本,换取全局问题的回答能力。
④ 表格、图片、公式先天弱势
向量化是为自然语言设计的。表格被展平成文本后,行列关系大量丢失;图片里的流程图、架构图基本无解;数学公式的语义相似度几乎无意义。多模态 RAG 目前仍是个未解决的开放问题,不要在方案里假装它已经成熟。
⑤ 长上下文的"中间丢失"效应
模型对长上下文的利用并不均匀——开头和结尾记得最牢,中间部分容易忽略[3]。这意味着:你辛辛苦苦召回并重排好的 10 个片段,如果最相关的那个排在第 5 位,它的实际影响力可能还不如排在第 10 位的。这也是为什么第 ⑧ 个模块里强调"最相关的放首尾"。
⑥ "拒答"是最难训的能力
让模型承认"我不知道"极其困难——它被训练的目标就是"给出下一个最可能的 token",而"根据现有资料无法回答"在多数语境下并不是那个最可能的输出。即便 prompt 里写了,模型仍经常绕着弯子给出推测性内容。这需要专门的约束设计、专门的测试用例,以及接受一定的误拒率。
⑦ 延迟和成本是叠加的
一次问答的模型调用可能是:改写 1 次 + 向量化 1 次 + 重排 1 次 + 生成 1 次,再加检索本身。四个环节各自达标,串起来仍然可能超时。每一个优化项都在和延迟做交易:多查询扩展提升召回但 ×3 成本,重排提升精度但增加一次模型调用。
⑧ "实时"是假的
索引更新是有延迟的——文档改了,要重新解析、切片、向量化、入库才能生效。RAG 的"实时"取决于你的索引流水线有多快,不是天然实时的。对秒级一致性有要求的场景(比如实时库存),RAG 不是正确答案,应该走接口查询。
⑨ 评估困难,且错因会互相掩盖
答错了,是检索没召回?召回了但重排把它排下去了?还是召回了正确的,模型没照着说?三种故障的表现完全一样,但修法完全不同。这就是为什么必须把检索和生成分开评估(RAGAS[5] 这类框架的 context_recall / faithfulness 分指标设计就是为此):context_recall低说明检索有问题,faithfulness低说明生成有问题。笼统地看"准确率",你连该改哪里都不知道。
七、什么时候不该上 RAG
基于上面的不足,这份决策表比"RAG 有什么优势"更实用:
| 场景 | 该不该上 RAG | 理由 |
|---|---|---|
| 企业制度 / 产品手册问答 | ✅ 非常适合 | 知识稳定、需要溯源、更新频繁 |
| 客服知识库 | ✅ 适合 | 同上,且答案需要可核对 |
| 实时库存 / 订单状态查询 | ❌ 不该 | 需要强一致,走接口而不是检索 |
| 数学计算 / 精确统计 | ❌ 不该 | 应走代码执行或 SQL,检索解决不了精确性 |
| 教模型改语气、改输出格式 | ❌ 不该 | 这是微调的活 |
| 全局性统计汇总("全年趋势") | ⚠️ 谨慎 | Top-K 检索假设不成立,需额外设计 |
| 重度依赖表格 / 图片的文档 | ⚠️ 谨慎 | 需先解决多模态解析,否则效果很有限 |
| 知识库只有几十条 | ⚠️ 未必 | 可能直接全量塞进上下文更简单 |
八、八条工程经验(踩坑换来的)
先打印召回结果,再调生成 prompt——离线链的问题占大多数,调 prompt 是最低效的排查路径;
切片策略是第一个该调的旋钮,不是最后一个。块大小、overlap、标题回填这三件事的收益通常大于换模型;
元数据过滤 > 检索算法优化。能用"只查 2024 年后的研发部文档"缩小检索空间,就别指望语义模型从全库里捞对;
直接上混合检索(BM25 + 向量 + RRF),纯向量在真实业务里几乎总会漏掉精确词;
重排是性价比最高的单点优化,一个开源 rerank 模型的收益往往超过换更大的生成模型;
最相关的 chunk 放首尾,别放中间;
prompt 里必须给"我不知道"这个选项,否则模型一定会编;
检索和生成分开评估——准确率是一个平均数,它会掩盖你真正该修的那个环节。
九、参考文献
只列真正查阅过、对本文观点有直接影响的资料:
Lewis P. et al.Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks. NeurIPS 2020. arXiv:2005.11401 —— RAG 范式奠基之作,参数化/非参数化知识的切分即出自此文
Gao L. et al.Precise Zero-Shot Dense Retrieval without Relevance Labels(HyDE). 2022. arXiv:2212.10496 —— 用"生成假答案再检索"提升召回的反直觉方法
Liu N.F. et al.Lost in the Middle: How Language Models Use Long Contexts. 2023. arXiv:2307.03172 —— 上下文位置效应的实证依据(本文第 ⑧ 模块与不足 ⑤)
Edge D. et al.From Local to Global: A Graph RAG Approach to Query-Focused Summarization. 2024. arXiv:2404.16130 —— 面向全局性/多跳问题的代表性方案(本文不足 ③)
Es S. et al.RAGAS: Automated Evaluation of Retrieval Augmented Generation. 2023. Ragas —— 检索与生成分开评估的指标体系(本文不足 ⑨)
Gao Y. et al.Retrieval-Augmented Generation for Large Language Models: A Survey. 2023. arXiv:2312.10997 —— Naive / Advanced / Modular 三阶段划分,理解 RAG 演进路径的权威综述
Yan S.-Q. et al.Corrective Retrieval Augmented Generation(CRAG). 2024. arXiv:2401.15884 —— 对检索结果做质量评估并触发纠正,应对"检索是硬天花板"的思路
Khattab O. & Zaharia M.ColBERT: Efficient and Effective Passage Search via Contextualized Late Interaction over BERT. SIGIR 2020 —— 重排环节"延迟交互"路线的代表工作
十、写在最后
回到开头那个"试用期年假 80% 折算"的事故。修好它之后,客户反馈里最让我们意外的一条不是"答案变准了",而是:
"现在它说'根据现有资料无法回答'的时候,我反而更相信它的其他答案。"
这句话说出了 RAG 真正的价值——它给模型装上的不是更强的记忆力,而是一个可核对、可追溯、也敢于承认无知的机制。
所以如果你只带走一句话,我希望是这句:
RAG 的上限由检索决定,下限由生成决定,而它的可信度由"敢不敢说不知道"决定。
如果觉得本文有帮助,欢迎点赞、收藏、评论三连。你的 RAG 系统踩过什么坑,评论区见。
本文首发于 CSDN,作者原创。转载请注明出处。