本节摘要:RAG 的全部思想可以压缩成一句话:先取证,再作答。本节把闭卷与开卷的差别讲透,走通"切块、嵌入、入库、检索、拼提示、生成、引用"的完整链路,并回答一个高频选型问题——知识该进检索库,还是该通过微调进模型权重。
模型训练完成的那一刻,它的知识就凝固了。之后世界上发生的一切——新政策、新产品、你公司上周刚改的报销制度——它一无所知,却依然会用流利的语气回答相关问题。RAG 的解法不是让模型"学"新知识,而是考试时允许它翻书:把相关资料找出来放在题目旁边,让它基于给出的材料作答。
闭卷(直接问模型)有三种必然的失败:过时知识自信作答、私有知识凭空编造、细节知识的模糊失真。开卷(RAG)把失败模式换成了三种可控的:检索不到就承认不知道、检索错了引用会暴露、材料与问题不匹配一目了然。从"错误不可见"到"错误可追溯",是 RAG 在工程上最重要的性质——它把幻觉从暗处拽到了明处,第 7 章的验真护栏才有处安放。
# 离线建库:文档 → 切块 → 嵌入 → 入库 def build_index(docs: list[str]): for doc in docs: for chunk in split_chunks(doc, size=400, overlap=60): vec = embed(chunk) vector_db.upsert(id=hash_id(doc, chunk), vec=vec, meta={"doc": doc.name, "chunk": chunk.seq, "text": chunk.text}) # 在线问答:检索 → 拼提示 → 生成 → 带引用输出 def answer(question: str) -> str: hits = vector_db.search(embed(question), top_k=5, where={"namespace": "company_kb"}) if not hits or hits[0].score < 0.7: # 没有像样的证据 return "资料库中没有找到依据,建议咨询相关负责人。" context = render(hits) # 每段材料带上 [1][2] 编号 reply = llm.complete( system="只依据给定材料回答;材料不足以回答时明确说明。" "每个关键结论后标注来源编号,如 [1]。", user=f"材料:\n{context}\n\n问题:{question}") return attach_citations(reply, hits) # 把编号替换为真实出处
链路里有两个容易被轻视的设计。"承认不知道"的出口:检索分数过低时直接告知无依据,好过硬凑一个回答——这句兜底话术是整套系统可信度的锚。引用机制:材料编号进提示、出答案时还原成真实出处,用户可以点开核对。引用不仅是用户体验,更是第 7 章自动验真的抓手——答案与证据的对应关系变成了可程序检查的结构。
团队常纠结的选型:知识到底是建库检索(RAG),还是微调进模型(第 3 章提过的 Fine-tuning)?判断依据是知识的三个属性:
| 知识属性 | 适合 RAG | 适合微调 |
|---|---|---|
| 变更频率 | 频繁更新(制度、价格、手册) | 几乎不变(行业术语、文风) |
| 答案形态 | 事实性内容,要求可追溯 | 技能与风格,不要求逐字溯源 |
| 数据规模 | 大量文档,随增随改 | 精心构造的千级别样本 |
| 错误代价 | 高(需要审计引用) | 低(风格偏差可容忍) |
一句话总结分工:RAG 管"知道什么",微调管"像什么"。公司的产品规格该进检索库(明天改了今天就要生效);客服的回复语气该进微调(没人需要追溯"为什么这么客气")。把高频变化的事实微调进权重,等于每次更新都要重训——成本与时效双输;反过来指望 RAG 教会模型一种文风,检索回来多少范文都收效有限。生产系统里两者并存且各司其职,冲突往往出在用错边。
背景:员工问"出差住宿标准是多少",公司制度今年刚调整过。
操作:问题进来先过路由判断——时效敏感且私有,走 RAG。检索召回两条高分材料:新版制度第三条(一线城市每晚四百元封顶)与旧版对应条款。提示词里附加了元数据"新版生效于今年三月",模型基于新版作答并标注来源。
结果:回答为"目前执行的标准是一线城市每晚四百元封顶(依据:差旅制度 2024 版第三条,三月起生效)",附制度文档链接。
解读:这个案例的隐含功臣是元数据——没有生效日期,新旧两版材料在语义上难分伯仲,模型可能引用旧版。6.2 节会把元数据与过滤展开成系统的参数管理。
变式:问题跨越多份文档("对比两个部门的报销口径")时,单轮检索可能漏材料,需要让智能体先拆解问题再分头检索——这正是第 4 章任务分解在 RAG 场景的直接应用。
⚠️ 常见坑:把 RAG 当万能补丁。检索只能补"库里有"的知识;库本身缺更新机制(文档改了索引没改),RAG 会一本正经地引用作废内容。RAG 的运维成本在库不在链路,这是新手最容易低估的一项。
链路搭通只是及格线,检索质量的上限藏在参数里——下一节把分块、嵌入、top_k、重排这些旋钮逐个讲清。
窗口越大,"全塞进去"的方案听起来越诱人,这个问题值得正面回答。长上下文与 RAG 解决的是不同的问题:前者解决"给得下",后者解决"找得准、管得住"。三笔账算下来,多数生产场景仍然落在 RAG 这边——成本账:每次问答都塞几十万 token,计费与延迟随库的规模线性恶化,而检索只取相关的一小片;注意力账:3.1 节讲过的中间盲区在超长上下文里更严重,塞进去不等于用得上;治理账:知识的更新、权限、审计都发生在库上,塞进上下文的方案意味着每次提问都要重新过一遍权限过滤,而库方案里过滤只发生在检索层。长上下文真正的用武之地,是单次任务内材料本就有限但很长的场景(一份长合同的通读分析)——它与 RAG 是分工而非替代。
6.1 的链路把引用做到了"条目级"——答案标注来自哪块材料。生产中还有更细的一级:句子级溯源。做法是把答案拆成关键句,逐句回到检索材料里定位支撑段落,找不到支撑的句子要么重写要么删除。这一步把验真从"整段答案大致有据"提升到"每句主张可点验",是合规要求高的场景(法务、财务、医疗问答)的标配。成本方面,逐句溯源多用一次判分模型调用,只在最终答案出口处执行,对整体延迟影响可控——7.3 节的输出校验闸正是它的安放位置。