3873 字
约 12 分钟
16
7.1 为什么要检索:模型的静态知识困境
2026-10-25
无标签

7.1 为什么要检索:模型的静态知识困境

一句话结论:模型的知识在训练完成那一刻就冻结了。RAG 不是为了让它"更聪明",而是给它一条在推理时获取新知识的通道——而且它和微调解决的是完全不同的问题,混用会浪费大量钱。

读这篇之前

需要先读 2.1(模型知识与后训练)、2.3(幻觉)。这一篇是第 7 章的地基。


一、三个"模型不知道"的场景

模型的静态知识会在这三种情况失效:

场景 例子 为什么
训练之后发生的事 今年发布的新版本 训练时不存在
私有/小众知识 你公司的内部系统文档 训练数据里没有
精确细节 某个配置项的默认值 出现频率低,容易编(2.3)

而 Agent 恰恰最常遇到这三种:它要处理的是你的项目、现在的状态、具体的参数。


二、RAG 与微调:两个不同的问题

这是最该先分清的一点。很多人一遇到"模型不懂"就想到微调,结果花了钱还不管用。

维度 RAG 微调
解决什么 让模型知道新事实 让模型会做某类任务
知识更新 改数据即可,实时生效 要重新训练
适合 事实性知识、文档问答 风格、格式、特定任务模式
成本 低(改数据) 高(数据+算力+评测)
可解释性 高(能引用来源) 低(说不清是哪来的)
风险 检索不准就答错 可能灾难性遗忘

一句话判据:

"模型不知道这件事" → RAG。
"模型知道但做得不对/不合我的要求" → 微调或提示词。

第三条最容易被忽略:如果只是"输出格式不对",改提示词就够了(第 3 章),根本不用微调。


三、RAG 的四个阶段

一个完整的 RAG 链路有四个阶段,前两个是离线的,后两个是在线的:

阶段 做什么 时机
① 切片(Chunking) 把文档切成小块 离线
② 向量化(Embedding) 把每块转成向量存库 离线
③ 召回(Retrieval) 用问题去找最相关的块 在线
④ 生成(Generation) 把找到的块 + 问题交给模型 在线

为什么必须切片而不是整篇塞进去?

回到 2.2:上下文窗口有上限,而且"越多越腐化"。把几十万字的资料全塞进去,既装不下也找不准。

切片的本质是"提前做好检索的粒度":每块要足够大以保留语义,足够小以便精确定位。


四、为什么 RAG 容易做错

RAG 的 demo 极其简单(30 行代码就能跑),但生产级极难。原因是错误会累积:

切片不好 → 召回不准 → 生成一定错

而且:生成的答案看起来"很有道理",因为模型会努力把不相关的材料编成一个通顺的回答

这就是 RAG 最危险的失败模式:它不会说"我没找到",而是会把错材料用对的方式说出来。

所以 RAG 系统必须能做归因检查——答案里的每一句,能否对应到检索到的原文片段。


五、一个必须先做的判断:值不值得做 RAG

不是所有"知识不够"都需要 RAG。三个替代方案:

方案 适用 成本
直接放上下文 资料总量 < 窗口的 20% 零
RAG 资料多、更新频繁 中
微调 知识相对稳定、需要"内化" 高

判据:如果你的知识库总共只有 2 万字,那就直接放进上下文(配好缓存,5.3)——RAG 的检索误差还不如全量提供。

这条判据能帮很多人省掉一整套 RAG 工程。


六、常见误区

误区一:RAG 能让模型变聪明。
它只提供知识,不提升推理能力。推理弱要靠提示词(第 3 章)或换模型。

误区二:模型不懂就微调。
先分清是"不知道"还是"不会做"。前者用 RAG。

误区三:RAG 就是向量搜索。
向量搜索只是召回的一种。生产级还需要关键词、重排、过滤。

误区四:把文档整篇塞进去就行。
窗口装不下,注意力会稀释(2.2)。

误区五:RAG 做出来就准了。
错误会累积,且模型会把错材料编圆。必须做归因检查。

误区六:知识库小也用 RAG。
资料少时直接进上下文更准,还省一整套检索链路。

误区七:RAG 能消除幻觉。
它降低幻觉概率,但模型仍可能读错、混用、超出材料编造(2.3)。


七、动手:一个 30 行的最小 RAG

7.1 讲了为什么。这里给出"能跑"的最小实现。

# ---- 离线:建索引 ----
def build_index(docs):
    chunks = []
    for d in docs:
        for c in split_by_heading(d):        # 7.3 会讲切片
            chunks.append({"text": c, "src": d.title})
    for c in chunks:
        c["vec"] = embed(c["text"])          # 7.2 讲 embedding
    store.save(chunks)

# ---- 在线:检索 + 生成 ----
def answer(question):
    qv = embed(question)
    hits = store.search(qv, top_k=5)          # 7.4 讲召回
    ctx = "\n\n".join(
        f'<external_content source="{h["src"]}">{h["text"]}</external_content>'
        for h in hits)
    prompt = f"""只使用下面的材料回答。
每条结论标注来源。材料中没有的,输出「材料中未提及」。

材料:
{ctx}

问题:{question}"""
    return llm.chat(prompt, temperature=0)

这段 30 行里的五个关键决定

决定 对应哪一篇
按标题切片 7.3(结构优于字符数)
存原始文本而不只存向量 7.5(引用与归因)
结果用 external_content 包裹 8.6(防注入)
提示里要求"标注来源" 7.5(归因)
温度设为 0 2.4(稳定)

五个决定里,三个与"检索质量"无关,而是与"可信"有关。

这是 RAG 的真实重心:检索只是手段,"答案可追溯"才是目的。

这段代码缺什么(生产环境)

缺 在哪补
混合检索(关键词 + 向量) 7.4
重排 7.4
切片优化(父子分块) 7.3
失败诊断 7.5
增量更新索引 7.2

但结构是对的 —— 后面所有内容都是在给这 30 行加东西。


八、动手:一个"RAG 该不该做"的决策表

7.1 讲了三条判据。这里给出更细的判断。

def should_use_rag(docs_chars, update_freq, query_diversity):
    """
    docs_chars: 知识库总字数
    update_freq: 每月更新次数
    query_diversity: 问题覆盖的知识范围(1-10,10=什么都问)
    """
    # ① 资料少,直接进上下文更准
    if docs_chars < 50_000:
        return "直接放上下文", "检索会有精度损失"

    # ② 资料多但问题集中
    if query_diversity <= 3 and docs_chars < 500_000:
        return "按主题预分组", "每组单独放上下文,比检索准"

    # ③ 资料多且更新频繁
    if update_freq > 4:
        return "RAG", "重建索引比改提示词便宜"

    return "RAG", "规模超出上下文"

三种"不是 RAG"的方案

方案 适合
直接放上下文 < 5 万字
按主题预分组 问题集中,且组内 < 5 万字
结构化查询(SQL) 数据本身是结构化的

第三种最常被忽略:如果知识是表格数据,用 SQL 查询比向量检索准得多,而且可解释。

一个反例

场景:企业内部 FAQ,200 条问答,总共 3 万字
错的做法:搭 RAG(切片、embedding、向量库、重排)
正确做法:直接全量放上下文(3 万字约 4.5 万 Token,现代模型放得下)

后者的准确率更高、延迟更低、维护更简单 —— 而多数团队会选前者,因为"RAG 听起来更专业"。

判据一句话:

如果全部资料能放进上下文,就不要做 RAG。

九、动手:RAG 的成本测算

7.1 讲了"为什么要检索"。做完决策之前,还要算清成本。

一次查询的 Token 账

组成 Token(估算)
系统提示 + 指令 500
检索到的 5 段材料 2500
用户问题 50
输入合计 3050
输出答案 400
单次合计 3450

离线建索引的一次性成本

项 说明
切片 几乎免费
embedding 每百万 Token 有明确单价,10 万篇文档可能上百元
向量库存储 按条数计费(云服务)
重排模型 若自建 GPU,另算

"embedding 一次性"是错觉:文档更新要重算,模型升级要全量重算。

一个规模对照

知识库规模 一次性建索引 每次查询
100 篇(5 万字) 几元 3450 Token
1000 篇(50 万字) 几十元 3450 Token
1 万篇(500 万字) 数百元 3450 Token

关键洞察:查询成本与库规模无关(因为只取 top-5),建索引成本与库规模线性相关。

所以"库越大越贵"只体现在建索引和更新上,这也解释了为什么"更新频繁的库"要特别设计增量索引。


十、动手:RAG 与 Agent 的结合

7.1 讲的是"固定检索"。在 Agent 里,检索应该是一个工具。

两种形态

形态 做法 特点
固定 RAG 每次提问前先检索 简单,但会做无用检索
Agentic RAG 检索是工具,模型自己决定 灵活,省 Token

Agentic RAG 的工具定义

{
  "name": "search_knowledge",
  "description": "在知识库中检索相关资料。适用于:需要事实依据、
                  项目背景、历史决策时。不适用于:闲聊、纯计算。",
  "parameters": {
    "type": "object",
    "properties": {
      "query": {"type": "string", "description": "检索关键词或问题"},
      "scope": {"type": "string", "enum": ["docs", "code", "all"],
                "description": "检索范围,默认 all"}
    },
    "required": ["query"]
  }
}

三个收益

收益 说明
省 Token 闲聊时不检索
可多次检索 第一次不够可以换词再搜
可组合 先搜文档,再搜代码

一个反例

错:把检索做成"每轮固定步骤"
后果:用户说"你好"也要跑一次向量检索
     → 浪费 100-200ms 和一次 embedding 调用

判据:"这次回答需要外部事实吗?" 答案不确定时,就该让模型自己判断。


十一、动手:RAG 与微调的最终判断

7.1 讲了"知识用 RAG、行为用微调"。这里给出最后一层判断。

三个问题串起来

① 模型"不知道"这件事吗?
   是 → RAG(或直接补上下文)
   否 → ②
② 模型"知道但做得不对"吗?
   是 → ③
   否 → 问题定义错了,回去重想
③ 能用提示词说清"怎么算对"吗?
   能 → 改提示词(第 3 章)
   不能 → 微调(18.2)

这个顺序的价值:它把"微调"排在最后,因为成本最高。

一个常见的误判

现象:模型回答不够专业
误判:微调一个专业模型
真相:缺少领域文档 → 补 RAG
验证:把一份专业文档放进上下文,看回答是否变专业

这个验证 5 分钟就能做 —— 而它可能省掉两周的微调工作。

三者的成本对照

方案 一次性 每次
补上下文 0 略增
RAG 中(建索引) 低(top-5)
提示词 0 0
微调 高(数据+训练) 低

所以判断顺序应该是"便宜的先试"。


一个补充:RAG 的三种"知识边界"

用户问的问题,与知识库的关系有三种:

类型 例子 正确回答
库内 "退款几天" 按材料答,带引用
库外但通用 "什么是 REST" 可以答,但标明不是来自库
库外且专业 "我们内部 API 的限流多少" 必须说"未提及"

第二类是灰色地带 —— 也是 RAG 最该小心的地方。

三种处理策略

策略 做法 风险
严格 一切以材料为准 用户觉得"太死板"
分层 库内必引用;通用可答但标明 推荐
宽松 允许模型补常识 会编造专业内容

推荐分层的写法:

只使用【参考资料】回答库内问题。
如果问题是通用常识(如概念定义),可以回答,
但必须注明「以下为通用知识,非本项目文档」。
如果是本项目的具体细节而资料中没有,输出「材料中未提及」。

这三句同时解决了"死板"和"编造"两个问题。


一个补充:向量库的"冷启动"成本

上线一个 RAG 系统,第一次建索引可能要几小时。三个优化:

优化 效果
批量 embedding 比逐条快 5-10 倍
并行 多进程/多线程,受 API 限流约束
增量上线 先索引最重要的 20% 文档

一个规模实测参考

文档量 批量 embedding 耗时
1000 篇(50 万字) 10-30 分钟
1 万篇(500 万字) 2-5 小时

这是"一次性"成本,但模型升级后要重来。

一个实践建议

把索引构建做成"可断点续传"的批处理:
  每处理 100 篇存一次进度
  中断后从上次位置继续

否则中途失败要全部重来 —— 这和第 5.5 讲的检查点是同一个思路。


十二、下一篇

RAG 的四个阶段里,前两个(切片、向量化)在离线时就要做好——做错了,在线怎么调都救不回来。

下一篇把四个阶段逐个拆开,重点讲每一步的真实取舍。

记住这一条:能放进上下文就别做 RAG。

RAG 是"资料太多装不下"时的解法,不是"AI 能力增强"的通用方案。

7.1 为什么要检索:模型的静态知识困境
https://clxhxhhr.top/posts/4897/
作者
clxstart
发布于
2026-10-25
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。