1. 什么是 RAG
RAG(Retrieval-Augmented Generation,检索增强生成)的概念最早在 2020 年由 Facebook 的研究人员在论文中提出。在这篇开创性的工作中,他们提出了两种记忆类型:
- 参数型记忆:基于预训练模型的权重参数。当时 LLM(大语言模型)的概念尚未像现在这样普及,但 LLM 本质上可归类为预训练模型的一种演进形式。
- 非参数型记忆:基于向量数据库的外部知识存储。这种记忆不占用模型参数量,而是通过外部索引进行访问。
RAG 技术的核心在于将这两种记忆类型进行了有效整合。在知识密集型的 NLP 任务上,例如问答系统(QA),RAG 比单独使用上述两种类型的记忆获得了更好的效果。它允许模型在不更新参数的情况下访问最新的外部信息,从而弥补了传统大模型的短板。接下来将具体介绍 RAG 如何补充 LLM 的不足,以及在两种记忆中的具体体现,并使用 LangChain 框架来实现基本的 RAG 流程。
2. LLM 面临的挑战和 RAG 带来的好处
目前来看,LLM 几乎是解决各个自然语言处理任务的最佳解决方案。在通用聊天这一领域,很多大模型都能够实现接近人类的水平表现。但它的表现也不是完美的,也存在着诸多显著的不足:
- 幻觉问题:在没有答案的情况下提供虚假的信息。模型倾向于生成看似合理但事实错误的回答。
- 专业领域表现不足:无法给出准确回答,这和大模型使用的训练数据息息相关。许多垂直领域的数据是相对封闭的,未包含在公开训练集中。
- 回答稳定性差:对于同样的问题可能会产生不同的回答,这在对问题答案稳定性要求高的领域是不能接受的。
- 无法感知不断变化的知识:大模型的训练数据截止于特定时间点,无法实时获取最新的新闻、政策或企业内部变动。
可以把大模型比做一个刚毕业找到工作的大学生,他具备了很多通识性的知识,但对组织内部的专业知识知之甚少。因此需要尽快掌握组织内部的领域知识,可以让资深员工手把手地传输知识,也可以通过阅读组织内的文档吸收知识。与此类似,RAG 通过问题匹配知识,并将知识带给大模型,再利用大模型出色的生成能力来回答问题。这样大模型这个'新人'就能变得专业,也能感知到不断变化的外部信息。
3. LangChain 的 RAG 实践
在本节,我们将重点利用 LangChain 框架来进行 RAG 实践。
3.1 RAG 架构
典型的 RAG 架构与搜索引擎的架构类似,分为离线和在线部分。其中离线部分是对数据进行索引,这里的索引和传统的搜索引擎的倒排索引不同,这里的索引是对数据的向量化。
从图中我们可以清晰地看到,在离线索引阶段,总共有 4 个主要的步骤:
- 加载内容:非结构化数据通常需要提取内容,比如从 Word 文档、PDF 文档中提取文本内容。
- 内容分块:将提取的内容进一步切分为小块(chunk)。这样在匹配问题时可以将上下文缩减到很小,避免超出模型上下文窗口限制。
- 获取向量:对于每个分块的内容获取其向量(embedding)。这个获取向量的过程可以借助大模型本身的能力来实现,例如,GPT 就提供了 embedding 的接口,或者使用专门的 Embedding 模型。
- 存储向量:将获取的向量通过向量数据库存储起来,方便后续查询。
这里最终存储的结果就是论文中提出的基于向量的非参数化的记忆。接下来我们再来看在线(检索和生成)的部分。
在 Question 到大模型这条链路中,增加了 Retrieve 这个步骤。用户的问题被 embedding 后,会在向量库中匹配出最佳的内容,并和用户的问题一起,构成 Prompt 交给大模型。大模型根据这个 Prompt 再生成对应的答案返回给用户。除了第二节中提到的 RAG 带来的好处,这里还有一个工程层面的优势,通过 Retrieve 找到与问题最相关的知识,从而减少了上下文,压缩了 Prompt 的 token 数量,降低了成本并提高了响应速度。
上面两部分构成了 RAG 的基本架构,下面我们将使用 LangChain 来完整地实现一个 RAG 原型。
3.2 基于 LangChain 的 RAG 实现
为了方便我们对比效果,我们首先先实现一个直接将问题抛给大模型的流程,代码如下:
from langchain_community.llms import LlamaCpp
model_home =
llm_model = LlamaCpp(model_path=model_home)
prompt =
(llm_model.invoke(prompt))


