RAG 实战完全指南:用你自己的数据喂 AI,别再迷信微调

很多 AI 产品真正需要的不是把模型重新训练一遍,而是让它在回答前先读懂你的知识库。本文从检索链路、分块策略、向量索引、召回排序、上下文拼装到评测方法,系统讲清 RAG 怎么落地。

18 分钟阅读
小明

RAG 实战完全指南:用你自己的数据喂 AI,别再迷信微调

很多团队第一次做企业 AI,都会经历一个非常相似的阶段。

业务方说:

我们有很多内部知识,能不能让模型学会?

工程师脑子里马上浮现四个字:

微调模型。

这很正常。因为“训练一下让它学会”听起来很符合直觉。

但真实项目很快会告诉你,这条路没有想象中那么顺:

  • 数据不一定足够干净
  • 更新太频繁,根本不可能每次都重训
  • 你真正要解决的不是“模型不会说话”,而是“模型不知道你的资料放在哪”
  • 很多场景下,问题根本不是模型能力不够,而是上下文没给对

这也是为什么过去两年里,真正落地最多的方案,不是盲目 fine-tune,而是 RAG

RAG 这个词现在很热,但也很容易被讲得太玄。很多文章一上来就丢出一长串术语:

  • Embedding
  • Chunking
  • Vector DB
  • Recall
  • Rerank
  • Context Window

看完以后你大概率知道“这个东西挺复杂”,但还是不知道到底该怎么做。

所以这篇文章不打算讲一堆漂亮概念,而是从工程落地角度,把 RAG 拆成一条真正可操作的链路:

  1. 为什么很多知识型场景更适合 RAG 而不是微调
  2. 文档怎么切、索引怎么建、召回怎么做
  3. 为什么“检索到了”不等于“回答就会变好”
  4. 如何做重排、上下文拼装、引用溯源
  5. 怎样评估一个 RAG 系统到底是真的提升了准确率,还是只是在自我感动

如果你准备做企业知识库、客服助手、内部问答、文档搜索,这篇会很实用。


一、先统一认知:RAG 解决的不是“训练模型”,而是“给模型找对材料”

RAG 的全称是 Retrieval-Augmented Generation,也就是“检索增强生成”。

把它翻译成人话,核心其实就一句:

在模型回答之前,先从你的资料库里把最相关的内容找出来,再交给模型回答。

这件事的重要性在于,它绕开了很多“让模型自己记住一切”的幻想。

1.1 为什么很多场景更适合 RAG

比如你想做一个公司内部知识助手,它需要回答:

  • 报销政策是什么?
  • 某个 API 的鉴权方式怎么接?
  • 退款流程有哪些特殊规则?
  • 去年版本的 SLA 承诺是多少?

这些问题最大的特点不是“模型不会推理”,而是:

  • 答案散落在你的文档里
  • 文档会不断更新
  • 你希望回答能引用来源
  • 你不能接受模型编一个“很像真的”答案

这时候 RAG 的价值就非常明显:

  • 不需要频繁训练模型
  • 文档更新后,重新索引即可
  • 可以保留来源引用
  • 更容易控制回答依据

1.2 那微调什么时候有价值?

微调并不是没用,它更适合:

  • 固定输出风格
  • 某类任务的专门模式学习
  • 结构化任务精度提升
  • 特定领域表达习惯适配

但如果你当前的核心问题是:

模型不知道你的知识库里有什么

那第一优先级通常不是微调,而是把检索链路先建好。


二、一个 RAG 系统到底由哪些部分组成

很多团队说自己做了 RAG,实际只是:

  • 把文档丢进向量库
  • 用户一问,就 top-k 检索
  • 把结果拼进 prompt
  • 然后祈祷模型答得准一点

这当然能跑,但距离“可用系统”还差很远。

一个比较完整的 RAG 链路至少包括:

  1. 文档采集
  2. 清洗与切块
  3. 向量化
  4. 索引存储
  5. 召回
  6. 重排
  7. 上下文拼装
  8. 回答生成
  9. 引用与评测

你可以把它理解成两段能力:

  • 先找对材料
  • 再基于材料说对话

真正影响质量最大的,很多时候反而在第一段。


三、文档切块:RAG 第一个最容易被低估的问题

很多人做 RAG 时,第一反应是“把整篇文档直接向量化”。

这通常不太好。

因为一篇完整文档往往:

  • 太长
  • 主题太多
  • 局部信息密度不均
  • 用户问题通常只需要其中一小段

所以实际工程里,几乎都会做 chunking

3.1 切太大和切太小都不行

切太大

  • 召回不够精准
  • 上下文浪费窗口
  • 结果容易混入无关信息

切太小

  • 语义断裂
  • 上下文不完整
  • 模型拿到一段“半截话”很难稳定作答

3.2 一个更务实的切块原则

不要按固定字数机械切,而要优先按“语义完整单元”切,比如:

  • 标题 + 段落
  • FAQ 问答对
  • API 文档中的单个接口说明
  • 表格和其对应解释段落

3.3 示例:基于标题段落切块

type Chunk = {
  id: string
  title: string
  content: string
  source: string
}

export function splitBySection(doc: string, source: string): Chunk[] {
  const sections = doc.split(/\n##\s+/)

  return sections
    .map((section, index) => {
      const [firstLine, ...rest] = section.split('\n')
      return {
        id: `${source}:${index}`,
        title: firstLine.trim(),
        content: rest.join('\n').trim(),
        source,
      }
    })
    .filter(item => item.content.length > 80)
}

这不是最高级的切法,但已经比“每 1000 字砍一刀”靠谱很多。


四、Embedding 和向量库:别把它想成黑盒魔法

4.1 Embedding 在干什么

简单说,Embedding 会把一段文本映射成一个向量,让“语义相近”的内容在向量空间里也更靠近。

这意味着:

  • 用户问“退款多久到账”
  • 文档里写的是“退款预计在 3-5 个工作日原路返回”

即使词面不完全一样,系统也有机会把它们匹配出来。

4.2 向量库到底在解决什么

当你有几百、几千甚至几十万段切块时,不可能每次全量比对。

向量数据库的价值在于:

  • 高效存储向量
  • 快速做相似度检索
  • 支持 metadata 过滤
  • 支持混合检索和扩展查询

常见选项有:

  • Pinecone
  • Weaviate
  • Milvus
  • pgvector

4.3 选型时不要只看性能榜单

你更应该关心:

  • 你的数据量多大
  • 是否需要 metadata 过滤
  • 是否已有 PostgreSQL 技术栈
  • 是否需要托管服务
  • 查询延迟和成本能否接受

很多团队早期用 pgvector 就够了,不一定一上来就要专门的向量平台。


五、召回不是 top-k 一把梭:很多 RAG 差,就差在这里

最常见的入门写法是:

  1. 把用户问题 embedding
  2. 查 top 5
  3. 拼进 prompt

这当然能跑,但质量经常不稳定。原因在于:

  • 纯向量召回不一定抓住关键词约束
  • 问题表达和文档表达方式可能差很多
  • top-k 里常混进“有点像但不够准”的片段

5.1 真实工程里更常见的是混合检索

也就是把:

  • 关键词检索
  • 向量召回
  • metadata 过滤

结合起来。

例如:

  • 先按知识域过滤:只查“财务制度”文档
  • 再做向量召回
  • 再做 BM25 关键词补充

5.2 一个简化的检索流程

export async function retrieveDocs(query: string, domain?: string) {
  const denseResults = await vectorStore.search(query, {
    topK: 12,
    filter: domain ? { domain } : undefined,
  })

  const sparseResults = await keywordSearch.search(query, { topK: 8, domain })

  return mergeAndDeduplicate(denseResults, sparseResults)
}

这类“混合召回”通常比纯向量检索更稳,尤其在:

  • 专有名词很多
  • 编号和术语重要
  • 文档格式结构化明显

的场景里。


六、重排(Rerank):RAG 提升质量最值钱的一步之一

很多人做完召回后直接把 top-k 塞给模型。

问题是,召回的目标通常是“别漏掉”,而不是“顺序一定最准”。

这时候就需要 rerank。

6.1 为什么 rerank 很关键

因为生成模型上下文窗口有限。你不可能把 30 段都塞进去。

所以你真正需要的是:

从“可能相关”的候选里,再挑出“最值得进入上下文”的几段。

6.2 一个简单的重排思路

type RetrievedDoc = {
  id: string
  content: string
  score: number
}

export async function rerank(query: string, docs: RetrievedDoc[]) {
  return docs
    .map(doc => ({
      ...doc,
      rerankScore: lexicalBoost(query, doc.content) + doc.score,
    }))
    .sort((a, b) => b.rerankScore - a.rerankScore)
    .slice(0, 5)
}

实际生产里可以用专门 reranker,也可以先用轻量规则做第一版。

6.3 哪些场景特别需要 rerank

  • 候选文档很多
  • 不同文档语义都“有点像”
  • 用户问题很短,歧义大
  • 需要更高引用准确率

七、上下文拼装:不是把检索结果贴进去就完事

这是 RAG 工程中第二个高频误区。

很多系统即使召回不错,回答还是不稳定,原因常常在上下文构造太粗糙。

7.1 拼装时要解决三个问题

  1. 片段顺序怎么排
  2. 每段保留多少原文
  3. 怎样明确告诉模型“只基于这些内容回答”

7.2 一个更稳的 prompt 结构

export function buildRagPrompt(question: string, docs: string[]) {
  return `
你是企业知识助手,请仅根据给定资料回答问题。
如果资料不足,请明确说“当前资料不足以回答”。
回答时尽量引用资料编号。

资料:
${docs.map((doc, i) => `[资料${i + 1}] ${doc}`).join('\n\n')}

问题:${question}
`
}

这类 prompt 的关键不在文案华丽,而在边界清晰:

  • 明确只能基于资料回答
  • 资料不足时允许说不知道
  • 提示引用来源

这比“请你回答以下问题”稳定得多。


八、引用与可追溯性:企业 RAG 不能只要答案,还要能回头查

在企业场景里,一个能说得像模像样但没有来源的回答,风险其实很大。

用户会继续追问:

  • 这个结论来自哪份文档?
  • 是最新版本吗?
  • 这是谁写的规则?

所以一个成熟 RAG 系统最好能提供:

  • 引用片段
  • 来源文档
  • 文档版本 / 更新时间
  • 命中的章节信息

8.1 为什么引用这么重要

因为它直接决定两个东西:

  1. 用户信任感
  2. 团队排错效率

没有引用时,你很难判断:

  • 是检索错了
  • 是文档本身过时
  • 还是模型生成时理解偏了

九、评测:别只问“感觉好像更准了”

RAG 最大的问题之一,就是太容易做成“主观上看起来不错”。

但真正上线前,你需要更可量化的评测方法。

9.1 至少分两层评估

第一层:检索评估

  • 正确资料是否被召回
  • top-k 命中率如何
  • 是否召回了太多噪音

第二层:回答评估

  • 是否基于资料回答
  • 是否引用正确
  • 是否出现幻觉
  • 是否漏掉关键限制条件

9.2 一个最小评测集做法

先整理 30~100 个真实问题,每个问题配:

  • 标准答案要点
  • 正确参考文档
  • 不应引用的错误文档

然后评测:

  • top-3 / top-5 召回命中率
  • 生成答案准确率
  • 引用正确率

9.3 为什么评测必须用真实问题

因为很多系统在“理想问题”上表现很好,一到真实用户输入就明显下降:

  • 用户问法不标准
  • 会有错别字
  • 会混合多个意图
  • 会引用内部黑话和简称

没有真实样本,RAG 质量很容易被高估。


十、三个高频落地坑,提前讲清楚

10.1 坑一:把所有文档都塞进一个索引,不做域隔离

结果是:

  • 财务问题召回到技术文档
  • 客服话术召回到运营策略
  • 用户越问越混乱

解决办法通常是:

  • 先按知识域拆索引或加 metadata
  • 检索前先做 query classification

10.2 坑二:文档更新了,但索引没跟上

这是企业系统非常常见的问题。

如果文档更新频繁,索引同步机制必须设计好,否则模型会拿旧知识回答新问题。

10.3 坑三:只优化生成,不优化检索

很多团队发现答案不准,就一直改 prompt。

其实很多时候真正问题是:

  • 没召回到正确片段
  • 上下文片段不完整
  • 排序不对

生成层优化有用,但在 RAG 里,检索层往往更值得先下功夫。


十一、什么时候 RAG 不够,要考虑更进一步的方案

RAG 很强,但不是万能。

以下几种情况,可能需要进一步组合:

  • 长链路业务流程:需要工具调用和 agent orchestration
  • 高结构化规则系统:需要知识图谱或规则引擎辅助
  • 特定格式抽取:需要微调或专门 extractor
  • 强实时数据:需要和数据库 / API 实时联动,而不是只靠静态文档

所以更成熟的看法是:

RAG 是很多知识增强场景的基础设施,但不是全部答案。


十二、给团队的 RAG 落地检查清单

数据准备层

  • 是否明确了知识域边界
  • 是否清洗了噪音文档和过期文档
  • 是否设计了合理切块方式

检索层

  • 是否支持 metadata 过滤
  • 是否评估过混合检索
  • 是否有 rerank 策略
  • 是否测过 top-k 召回命中率

生成层

  • 是否明确要求“只基于资料回答”
  • 是否支持资料不足时明确拒答
  • 是否返回引用和来源

运营层

  • 是否有文档更新后的索引同步机制
  • 是否有真实问题评测集
  • 是否能区分检索错误和生成错误

总结

RAG 讲透,可以收敛成 5 句话:

  1. 很多企业知识场景需要的不是微调,而是先把正确资料找出来。
  2. RAG 的核心不是向量库本身,而是整条检索增强链路。
  3. 切块、召回、重排、上下文拼装,任何一环粗糙都会直接拉低回答质量。
  4. 可引用、可追溯、可评测,比“看起来聪明”更重要。
  5. 真正好的 RAG,不是让模型更会编,而是让模型更少乱编。

如果你只记住一句话,我希望是这一句:

RAG 的价值,不是让 AI 知道更多,而是让它在回答前先学会查资料。

否则最后你得到的,很可能不是企业知识助手,而是——

一个读过你文档封面、但没认真看正文的同事。