跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
PythonAI算法

基于 LangChain 的 RAG 技术实践与实现

RAG 技术通过整合预训练模型参数记忆与向量数据库非参数记忆,有效缓解大模型的幻觉、知识封闭及更新滞后问题。 RAG 离线索引与在线检索生成架构,利用 LangChain 框架结合 LlamaCpp 本地模型与 Chroma 向量库构建 RAG 原型。通过对比实验验证外部知识库对提升回答准确性的价值,深入分析文档加载、分块策略、嵌入生成及检索优化等关键环节,并提供提示词工程与系统评估的实践建议。

PentesterX发布于 2025/2/7更新于 2026/9/967 浏览
基于 LangChain 的 RAG 技术实践与实现

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 个主要的步骤:

  1. 加载内容:非结构化数据通常需要提取内容,比如从 Word 文档、PDF 文档中提取文本内容。
  2. 内容分块:将提取的内容进一步切分为小块(chunk)。这样在匹配问题时可以将上下文缩减到很小,避免超出模型上下文窗口限制。
  3. 获取向量:对于每个分块的内容获取其向量(embedding)。这个获取向量的过程可以借助大模型本身的能力来实现,例如,GPT 就提供了 embedding 的接口,或者使用专门的 Embedding 模型。
  4. 存储向量:将获取的向量通过向量数据库存储起来,方便后续查询。

这里最终存储的结果就是论文中提出的基于向量的非参数化的记忆。接下来我们再来看在线(检索和生成)的部分。

在 Question 到大模型这条链路中,增加了 Retrieve 这个步骤。用户的问题被 embedding 后,会在向量库中匹配出最佳的内容,并和用户的问题一起,构成 Prompt 交给大模型。大模型根据这个 Prompt 再生成对应的答案返回给用户。除了第二节中提到的 RAG 带来的好处,这里还有一个工程层面的优势,通过 Retrieve 找到与问题最相关的知识,从而减少了上下文,压缩了 Prompt 的 token 数量,降低了成本并提高了响应速度。

上面两部分构成了 RAG 的基本架构,下面我们将使用 LangChain 来完整地实现一个 RAG 原型。

3.2 基于 LangChain 的 RAG 实现

为了方便我们对比效果,我们首先先实现一个直接将问题抛给大模型的流程,代码如下:

from langchain_community.llms import LlamaCpp
# 加载本地模型文件地址,使用 mixtral-8x7B 的大模型
model_home = "~/models/mixtral-8x7b-instruct-v0.1.Q8_0.gguf"
# 使用 llm_model 作为加载框架
llm_model = LlamaCpp(model_path=model_home)
prompt = "孙悟空几打白骨精?"
print(llm_model.invoke(prompt))

这里,我使用的是本地的大模型 mixtral-8x7b-instruct 8 位量化的版本,通过 LlamaCpp 框架进行加载。模型输出的答案为:

孙悟空与白骨精的第一次较量是在《西游记》第六回中发生的...

可以看到,模型给出的答案并不尽如人意。首先,'三打白骨精'这个故事并不是在原文第六回发生的,其次,给的答案并没有准确地回复'几打'这个问题。即便是 ChatGPT 3.5 也无法回答这样的问题,因为它依赖于训练数据中的概率分布,而非精确的事实检索。

我们尝试用 RAG 来解决这个问题。基于 RAG 的流程和架构,我们除了依赖大模型,还需要依赖一个用于向量存储和查询的引擎。为了方便,直接 follow 官方的样例,使用 Chroma 作为向量数据库。

对于非参数化记忆,我先后选择了目录、《三打白骨精》这章内容和《三打白骨精》概要。

下面的代码实现了 RAG 的离线过程:

from langchain_community.document_loaders import DirectoryLoader
from langchain_community.embeddings import LlamaCppEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import Chroma

# 使用 DirectoryLoader 加载文件,作为外部知识
loader = DirectoryLoader('/Users/trent/dev/data/rag', glob="**/*.txt")
docs = loader.load()

# 设置分块策略,chunk_size 控制块大小,chunk_overlap 控制重叠部分以保留上下文
text_splitter = RecursiveCharacterTextSplitter(chunk_size=256, chunk_overlap=200)
splits = text_splitter.split_documents(docs)

# 初始化嵌入模型
embeddings = LlamaCppEmbeddings(model_path=model_home)

# 创建向量存储
vectorstore = Chroma.from_documents(documents=splits, embedding=embeddings)

下面的代码实现了 RAG 的在线过程:

import os
from langchain import hub
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough

# 可以在 LangSmith 生成一个 API key 用于整个 RAG 链路的追踪
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_API_KEY"] = "langSmith_api_key"

# 将向量存储作为 retriever
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})

# 从 LangSmith Hub 拉取 prompt 的模版
prompt = hub.pull("rlm/rag-prompt")

def format_docs(docs):
    return "\n\n".join(doc.page_content for doc in docs)

rag_chain = (
    {"context": retriever | format_docs, "question": RunnablePassthrough()}
    | prompt
    | llm_model
    | StrOutputParser()
)

我们以 RAG 的形式再次进行提问:

rag_chain.invoke("孙悟空几打白骨精?")

非参数化记忆的不同,得到的答案也不尽相同。对于这个问题,概要作为非参数化记忆,得到的答案最为准确。LangSmith 中对利用三个外部文件进行试验的结果显示,引入外部知识库后,回答的准确性显著提升。

这里要推荐一下 LangSmith 这个可观测性组件,可以清晰地追踪到 RAG 的流程。以下图为例,既可以看到一次 Q&A 的全过程,又可以观测到 Retriever 的输入输出,这对于调试和优化 RAG 系统至关重要。

以上就是用 LangChain 实现的一个简单 RAG 流程。

Retriever 这个组件的引入可以有效地增强 LLM 的能力,但也会带来新的挑战:

  1. 外部的知识如何选择:不同的外部知识会带来不一样的效果表现,这就要具体问题具体分析了。需要确保知识库的权威性和相关性。
  2. 外部的知识如何进行处理:chunk 如何切分,chunk size 如何设置等等。过小的 chunk 可能丢失上下文,过大的 chunk 可能引入噪声。
  3. 提问的模板如何设置:好的提问模板可以充分利用 LLM 的能力,从工程上来讲,Context 的长度也需要尽可能的精简,以减少 Token 消耗。

此外,为了进一步提升 RAG 系统的性能,还可以考虑以下优化策略:

  • 混合检索:结合关键词检索(BM25)和向量检索,提高召回率。
  • 重排序(Re-ranking):对检索回来的结果进行二次排序,选择最相关的片段。
  • 元数据过滤:利用文档的元数据(如时间、作者、来源)进行过滤,缩小检索范围。
  • 评估指标:建立 Faithfulness(忠实度)、Answer Relevance(答案相关性)等评估体系,量化系统效果。

这些问题,需要在具体的场景中进行具体的分析,同时也需要有合适的机制通过不断的反馈来积累最佳实践。通过持续迭代,RAG 系统能够成为企业级 AI 应用的核心基础设施。

目录

  1. 1. 什么是 RAG
  2. 2. LLM 面临的挑战和 RAG 带来的好处
  3. 3. LangChain 的 RAG 实践
  4. 3.1 RAG 架构
  5. 3.2 基于 LangChain 的 RAG 实现
  6. 加载本地模型文件地址,使用 mixtral-8x7B 的大模型
  7. 使用 llm_model 作为加载框架
  8. 使用 DirectoryLoader 加载文件,作为外部知识
  9. 设置分块策略,chunksize 控制块大小,chunkoverlap 控制重叠部分以保留上下文
  10. 初始化嵌入模型
  11. 创建向量存储
  12. 可以在 LangSmith 生成一个 API key 用于整个 RAG 链路的追踪
  13. 将向量存储作为 retriever
  14. 从 LangSmith Hub 拉取 prompt 的模版

更多推荐文章

查看全部
  • 基于 SSM 的高校后勤管理系统设计与实现
  • 一个博客系统的 Python + Selenium 自动化测试记录
  • Midjourney 中文版入门指南:指令优化与使用技巧
  • 大模型零基础入门到精通:转行全攻略与学习路径
  • Windows 11 本地安装 WSL 2 支持 Ubuntu 24.04 指南
  • Midjourney 绘画实战:梵高风格提示词与参数详解
  • Visual C++ 运行库诊断与部署完整方案
  • Flutter inappwebview_cookie_manager 鸿蒙适配:Web 容器 Cookie 隔离方案
  • 双指针算法实战:移动零与复写零详解
  • 前端通用 AI Rules 规范:适配 Cursor、Trae 等主流 AI 工具
  • OpenClaw 及 16 款 AI Agent 工具选型指南
  • 逻辑漏洞挖掘原因与实战案例解析
  • whisper.cpp 离线语音识别快速上手指南
  • 昇腾 NPU 部署 Llama 2 模型:性能测试与优化实战
  • AI 绘画工具背后的视觉技术:Stable Diffusion 解析
  • Python 布尔类型详解:真值规则与逻辑运算实战
  • 基于统一接口的大模型成本优化与选型实践
  • Python 七大主流职业方向与技术栈详解
  • Google DeepMind 发布 SynthID-Text 文本水印技术,登 Nature 封面
  • 数据结构:堆与链式二叉树详解

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • RSA密钥对生成器

    生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online

  • Mermaid 预览与可视化编辑

    基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online

  • 随机西班牙地址生成器

    随机生成西班牙地址(支持马德里、加泰罗尼亚、安达卢西亚、瓦伦西亚筛选),支持数量快捷选择、显示全部与下载。 在线工具,随机西班牙地址生成器在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • curl 转代码

    解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online