1. RAG基础认知:什么是RAG、RAG与微调的区别、RAG的核心流程

大家好,我是这门课的主讲人。今天咱们来聊聊RAG——检索增强生成。说实话,我第一次接触这个概念时,也觉得它不过是给大模型配了个“搜索引擎”。但真正用起来才发现,这里面的门道比想象中深得多。

1.1 什么是RAG?

RAG,全称Retrieval-Augmented Generation。翻译过来就是“检索增强生成”。说白了,就是让大模型在回答问题之前,先去外部知识库“查资料”,然后再基于查到的资料来生成答案。

为什么要这么做?你想想看,大模型虽然知识渊博,但它有个硬伤——知识是静态的。训练完那一刻,它的知识就定格了。你问它“今天天气怎么样”,它只能瞎猜。但RAG不一样,它先去查今天的天气预报,再回答你。

核心思想:不依赖模型内部参数存储的知识,而是从外部知识源实时检索相关信息,作为生成答案的上下文。

我在项目中遇到过这样一个场景:客户想做一个企业内部知识库问答系统。如果只用微调,每次文档更新都得重新训练模型,成本太高。用RAG就简单了——文档更新后,重新索引一遍就行,模型本身不用动。

1.2 RAG与微调的区别

很多新手会问:“RAG和微调,到底选哪个?”嗯,这个问题我当年也纠结过。咱们直接看对比:

维度 RAG 微调(Fine-tuning)
知识更新 实时更新,改文档即可 需要重新训练,周期长
训练成本 几乎为零(只需索引) 高,需要GPU和大量数据
幻觉控制 强,答案有据可查 弱,模型可能胡编乱造
适用场景 知识问答、文档检索、实时信息 风格模仿、指令遵循、特定任务
模型能力 依赖基座模型本身 可以提升特定领域能力

我个人的习惯是:能用RAG解决的问题,绝不微调。为什么?因为微调就像给模型“动手术”,搞不好会破坏它原有的能力。我曾经见过一个团队,微调后模型在目标任务上表现不错,但写诗的能力却退化了——这就是“灾难性遗忘”。

我的建议:如果你需要模型学习新的知识(比如公司内部文档),用RAG。如果你需要模型改变回答风格或遵循特定指令(比如变成客服语气),用微调。两者也可以结合使用。

但注意,RAG不是万能的。它依赖检索质量,如果检索不到相关信息,模型还是会瞎编。我曾经踩过这个坑——索引没做好,用户问“公司年假政策”,结果检索到的是去年的版本,答案自然就错了。

1.3 RAG的核心流程:索引-检索-生成

RAG的流程,说白了就三步:先存好资料,再找到相关的内容,最后让模型回答。咱们一步步拆解。

1.3.1 索引(Indexing)

索引就是把你的文档“切碎”并“编码”,方便后续快速查找。具体来说:

  1. 文档切分:把PDF、Word、网页等原始文档,切成一个个小片段(chunk)。我一般切成256-512个token一段,太长了检索不准,太短了上下文不够。
  2. 向量化:用嵌入模型(比如text-embedding-ada-002)把每个片段转成向量。说白了,就是把文字变成一串数字。
  3. 存储:把向量和原始文本存到向量数据库里(比如FAISS、Pinecone、Milvus)。
# 伪代码示例:索引流程
documents = load_documents("company_handbook.pdf")
chunks = split_text(documents, chunk_size=512)
vectors = embedding_model.encode(chunks)
vector_store.add(vectors, chunks)

注意:切分策略很关键。我曾经试过按固定长度切分,结果把一句话从中间切断了,检索时语义不完整。后来改用按段落切分,效果好很多。

1.3.2 检索(Retrieval)

用户提问后,系统会做两件事:

  1. 问题向量化:用同样的嵌入模型,把用户的问题也转成向量。
  2. 相似度搜索:在向量数据库里找最相似的几个片段。通常用余弦相似度或欧氏距离。

我习惯检索top-3到top-5个片段。太少可能信息不全,太多又会把无关内容塞进上下文,干扰模型判断。

# 伪代码示例:检索流程
query_vector = embedding_model.encode("公司年假政策")
results = vector_store.similarity_search(query_vector, k=3)
# 返回最相似的3个文档片段

1.3.3 生成(Generation)

最后一步,把检索到的片段和用户问题一起,拼成一个完整的提示词(prompt),交给大模型生成答案。

# 伪代码示例:生成流程
context = "\n".join(results)
prompt = f"""
基于以下资料回答问题:

资料:
{context}

问题:{user_query}

请给出准确、简洁的回答。
"""
answer = llm.generate(prompt)

这里有个细节:提示词的设计。我刚开始做的时候,直接把资料和问题丢给模型,结果模型经常忽略资料,自己瞎编。后来我在提示词里加了“请严格基于资料回答,如果资料中没有相关信息,请说不知道”,效果立竿见影。

避坑指南:我曾经遇到过检索到的资料和问题不相关,模型还是强行回答的情况。后来我加了一个“相关性过滤”步骤——如果检索结果的相似度低于某个阈值(比如0.7),就直接告诉用户“没有找到相关信息”。

小结

好了,咱们总结一下:

  • RAG是什么:让模型先查资料再回答,解决知识静态和幻觉问题。
  • RAG vs 微调:RAG适合知识更新频繁的场景,微调适合改变模型行为。我建议优先用RAG。
  • 核心流程:索引(切分+向量化+存储)→ 检索(向量搜索)→ 生成(拼接提示词+模型回答)。

下一章,咱们会深入讲索引阶段的细节——文档切分到底怎么切才最合理?向量化模型怎么选?到时候我会分享一些我踩过的坑和总结的经验。

嗯,今天就到这儿。有问题欢迎在评论区交流。