跳到主要内容
极客日志极客日志
首页博客AI提示词GitHub精选代理工具
搜索
|注册
博客列表
PythonAI算法

从零开始构建简单 RAG 应用指南

综述由AI生成检索增强生成(RAG)技术的概念及其在解决大模型领域知识和时效性问题上的作用。文章提供了从零开始构建简单 RAG 应用的完整指南,涵盖环境配置、文档加载、文本分块、向量化、向量数据库存储、Prompt 编写及 Chain 构建等核心步骤。通过 Python 和 LangChain 框架的实际代码示例,展示了如何利用 Azure OpenAI 服务和 FAISS 向量库实现基本的问答系统,并给出了后续优化的最佳实践建议。

JavaCoder发布于 2025/2/6更新于 2026/4/254 浏览
从零开始构建简单 RAG 应用指南

从 0 开始构建简单 RAG 应用

前言

大型语言模型(LLM)已经从最初的研究性阶段转变为实际应用阶段。随着各大厂商都在探索 LLM 的商业化落地方案,RAG(检索增强生成)成为了最具使用价值且最能体现商业化场景的技术之一。

什么是 RAG

虽然 LLM 能处理多种任务,但在领域知识和最新信息方面存在局限。领域知识通常指企业私有化数据,这部分知识 LLM 无法直接获取。此外,LLM 的训练数据基于历史数据,无法知晓最新信息。RAG 技术正是为了解决这些问题而诞生的。

RAG,即检索增强生成(Retrieval-Augmented Generation),是一种结合了信息检索技术与语言生成模型的人工智能技术。它主要用于增强 LLM 处理知识密集型任务的能力,如问答、文本摘要、内容生成等。

RAG 的核心思想是让语言模型在生成回答时能够动态地从外部知识库中检索相关信息。这种方法提高了内容的准确性、可靠性和透明度,丰富了大模型的知识,同时有效减少了'幻觉'现象。

构建一个完整的 RAG 系统涉及多个流程和功能,是一个典型的工程化项目。本系列文章将逐步揭开 RAG 领域的神秘面纱。

构建简单 RAG

本系列文章假设读者具备 LangChain、Python 及向量数据库的基础知识。

构建一个简单的 RAG 流程通常包含以下步骤:

  • 文档加载
  • 文档拆分为 Chunk
  • 文档向量化(需要 Embedding 模型)
  • 向量化存储
  • Prompt 编写
  • LLM 配置与初始化
  • 提问(Query -> 检索 -> 构建 Prompt -> LLM -> Answer)

简单 RAG 架构如图所示:

RAG 架构图

安装环境以及安装包

首先,我们需要安装必要的依赖包。建议使用 Python 虚拟环境进行隔离。

pip install langchain_community tiktoken langchain-openai langchainhub chromadb langchain
配置环境变量

如果你使用 OpenAI 作为 LLM 服务,需要在环境变量中设置 OPENAI_API_KEY。

import os
os.environ['OPENAI_API_KEY'] = '<your-api-key>'

本文中使用 Azure 服务,在项目目录下新建 .env 文件,配置内容如下:

AZURE_OPENAI_API_KEY=""
AZURE_OPENAI_ENDPOINT=""
AZURE_DEPLOYMENT_NAME_GPT35="gpt-35-turbo"
AZURE_DEPLOYMENT_NAME_GPT4="gpt-4"
AZURE_EMBEDDING_TEXT_MODEL="text-embedding-ada-002"
OPENAI_API_VERSION="2024-03-01-preview"

我们只需要设置 model = os.environ.get("AZURE_EMBEDDING_TEXT_MODEL") 即可,LangChain 会自动读取这些环境变量。

然后加载配置信息:

import os, dotenv
# 加载.env 文件
dotenv.load_dotenv(".env")
代码实现过程

我们将结合官方文档中的 RAG 快速开始示例,根据实际场景实现一个简单的 RAG 应用。

1、加载依赖包
import bs4, os
from langchain import hub
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.document_loaders import WebBaseLoader
from langchain_community.vectorstores import FAISS
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from langchain_openai import AzureChatOpenAI, AzureOpenAIEmbeddings
from langchain.prompts import PromptTemplate
2、加载文档

这里我们抓取一篇公开文章作为示例数据。使用 bs4 来抓取文章,并配置抓取的内容为文章块(class 为 "article", "article-title" 中的内容)。关于 bs4 的使用可以查看官方文档。

# 加载文档
loader = WebBaseLoader(
    web_paths=("https://juejin.cn/post/7366149991159955466",),
    bs_kwargs=dict(
        parse_only=bs4.SoupStrainer(
            class_=("article", "article-title")
        )
    ),
)
3、文档拆分为小块

使用 LangChain 的文档加载器加载文档,并进行文本拆分。这是 RAG 效果的关键步骤。

  • chunk_size:文档块大小,决定了每个切片包含多少字符。
  • chunk_overlap:文档块重叠大小,用于保留上下文连贯性。

这两个属性会直接影响最终答案的准确性。如果切分过小,可能丢失上下文;如果过大,可能引入无关噪声。

# 文档加载器加载文档
docs = loader.load()
# 进行文档拆分
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
splits = text_splitter.split_documents(docs)
4、实例化向量模型

实例化 Embedding 模型 AzureOpenAIEmbeddings。关于向量化模型的选择,需要注意与选择的向量数据库兼容。不同的向量模型向量化文本后的维度可能与向量数据库不一致,导致查询或存储问题。

文档向量化过程:

文档向量化流程图

embeddings = AzureOpenAIEmbeddings(
    model=os.environ.get("AZURE_EMBEDDING_TEXT_MODEL")
)
5、向量数据库保存、检索

文档检索过程:

文档检索流程图

  • 向量数据库:这里我们使用本地向量数据库 FAISS。
  • 配置向量数据库:需要传入向量化的文档(splits)和向量模型(embeddings)。
vectorstore = FAISS.from_documents(
    documents=splits, 
    embedding=embeddings
)

# 设置检索器(用来向量查找文档相似度的)
retriever = vectorstore.as_retriever()

# 打印检索的 documents
def format_docs(docs):
    return "\n\n".join(doc.page_content for doc in docs)

检索功能已完成,我们可以尝试向量检索文本:

result = retriever.invoke("提高 LLM 的方法有哪些?")
print(format(result))

检索到的文档内容(原始内容):

'[Document(metadata={'source': 'https://juejin.cn/post/7366149991159955466'}, page_content='回答不完整
有时候 LLM 的回答并不完全错误,但会遗漏了一些细节。这些细节虽然在上下文中有所体现,但并未被充分呈现出来。例如,如果有人询问'文档 A、B 和 C 主要讨论了哪些方面?'对于每个文档分别提问可能会更加适合.....'
]`
6、构建 Prompt

在 LLM 应用场景中,Prompt 是一个重要的环节。Prompt 是我们告诉 LLM 要做什么、怎么做的指令。

下面的 Prompt 是构建 RAG 的简单模板:

# 首先我们需要一个 prompt 模板
# prompt = hub.pull("rlm/rag-prompt")
prompt_template = """
You are an assistant for question-answering tasks. Use the following pieces of retrieved context to answer the question. If you don't know the answer, just say that you don't know. Use three sentences maximum and keep the answer concise.

Question: {question} 

Context: {context} 

Answer:
"""
prompt = PromptTemplate.from_template(prompt_template)  # 这一步是为了把 prompt 模板格式化

初始化 LLM,LLM 的配置会自动获取环境变量中的值。读者可以根据自己的实际情况配置,并不一定要使用 OpenAI 服务,其他支持 OpenAI 协议的模型也是可以的。

# 初始化 LLM,LLM 的配置会自动获取环境变量中的值。
llm = AzureChatOpenAI(
    azure_deployment=os.getenv("AZURE_DEPLOYMENT_NAME_GPT35"),
    temperature=0
)
7、构建 Chain

最后一步是向 LLM 提问,使用 LangChain 构建 Chain。关于 LangChain 的 Chain 能力,不熟悉的可以去官网了解。

# 构建 chain
rag_chain = (
    {"context": retriever | format_docs, "question": RunnablePassthrough()}
    | prompt
    | llm
    | StrOutputParser()
)

所有的步骤已经完成,我们可以使用 LLM 来回答问题:

# 开始提问
response = rag_chain.invoke("提高 LLM 的方法有哪些?")
print(response)
# '提高 LLM 的方法包括使用查询转换来确保全面理解问题并作出回应,以及添加一层查询理解层,进行一系列的 Query Rewriting。另外,可以采用路由、查询重写、子问题和 ReAct 代理选择器等转换方法来优化 RAG 系统的效能。最后,通过对 RAG 系统挑战的深入分析和优化,可以提升 LLM 的准确性和可靠性,大幅提高用户对技术的信任度和满意度。'

response = rag_chain.invoke("文章中提到了哪些优化方案?")
print(response)
# '抱歉,我不知道。'

最佳实践与优化建议

在实际生产环境中,简单的 RAG 可能无法满足所有需求。以下是一些优化建议:

  1. 混合检索:结合关键词检索(BM25)和向量检索,提高召回率。
  2. 重排序(Rerank):在检索后增加重排序步骤,筛选出最相关的片段。
  3. 查询改写:对用户的问题进行改写,使其更适合检索。
  4. 元数据过滤:利用文档的元数据进行过滤,缩小检索范围。

总结

本文是 RAG 系列文章的第一篇,初步介绍了 RAG 是什么、有什么作用,以及构建一个 RAG 应用的几个关键步骤:

  • 文档加载:将文档(网页、常用文档)解析为 LangChain Documents 对象的过程。
  • 文档拆分:将大的文档进行拆分为 Chunk,并配置 chunk_size 和 overlap 属性,这两个属性会影响 RAG 的最终效果。
  • 文档向量化:将高维度的文本转换为向量表示的过程。
  • 向量化存储:将向量数组、原文档一起存储到向量数据库。
  • Prompt 编写:构建 LLM 的指令,引导其正确生成回答。
  • LLM 配置、初始化:选择合适的模型并进行参数配置。
  • 提问流程:Query -> 检索 -> 构建 Prompt -> LLM -> Answer。

RAG 总结图

通过本文的学习,读者应该能够搭建一个基础的 RAG 系统,并根据实际需求进行进一步的优化和扩展。

目录

  1. 从 0 开始构建简单 RAG 应用
  2. 前言
  3. 什么是 RAG
  4. 构建简单 RAG
  5. 安装环境以及安装包
  6. 配置环境变量
  7. 加载.env 文件
  8. 代码实现过程
  9. 1、加载依赖包
  10. 2、加载文档
  11. 加载文档
  12. 3、文档拆分为小块
  13. 文档加载器加载文档
  14. 进行文档拆分
  15. 4、实例化向量模型
  16. 5、向量数据库保存、检索
  17. 设置检索器(用来向量查找文档相似度的)
  18. 打印检索的 documents
  19. 6、构建 Prompt
  20. 首先我们需要一个 prompt 模板
  21. prompt = hub.pull("rlm/rag-prompt")
  22. 初始化 LLM,LLM 的配置会自动获取环境变量中的值。
  23. 7、构建 Chain
  24. 构建 chain
  25. 开始提问
  26. '提高 LLM 的方法包括使用查询转换来确保全面理解问题并作出回应,以及添加一层查询理解层,进行一系列的 Query Rewriting。另外,可以采用路由、查询重写、子问题和 ReAct 代理选择器等转换方法来优化 RAG 系统的效能。最后,通过对 RAG 系统挑战的深入分析和优化,可以提升 LLM 的准确性和可靠性,大幅提高用户对技术的信任度和满意度。'
  27. '抱歉,我不知道。'
  28. 最佳实践与优化建议
  29. 总结
  • 💰 8折买阿里云服务器限时8折了解详情
  • 💰 8折买阿里云服务器限时8折购买
  • 🦞 5分钟部署阿里云小龙虾了解详情
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • Django REST Framework 企业级 API 架构实战
  • AI 大模型入门指南:从零部署与开发实战
  • Agent 系统架构设计:持久化、模块化与风控实践
  • OpenClaw 自动化控制平台:本地与远程智能代理
  • Telegram 关键词搜索机器人搭建指南(含 Python 脚本)
  • LazyLLM 多 Agent 应用全流程实践:源码部署与可视化 Web 调试
  • 人工智能对上位机系统的全面重塑与影响分析
  • 基于 WebGIS 的体感温度实证分析:中国火炉城市评估
  • LazyLLM 低代码框架实战:代码专家智能体开发
  • 前端文本测量瓶颈突破:Pretext 用户态纯 TypeScript 引擎
  • Qwen3-Embedding-4B 本地部署实战:llama.cpp 与 vLLM 方案
  • 双指针算法详解:移动零、复写零、快乐数及盛水容器问题
  • 带随机指针的链表复制算法:三步法原地实现
  • Rust 与 WebAssembly 深度实战:浏览器与 Node.js 的高性能融合
  • C++ 红黑树详解与实现
  • 无人机航拍图像标注:从采集到训练全流程
  • WebGIS 开发:WKT 转 GeoJSON 技巧与 Leaflet 加载应用
  • 微服务架构下 Spring Session 与 Redis 分布式会话实战
  • OpenClaw 开源 AI 助手中文发行版部署指南:Docker 与 NPM 安装配置
  • JavaScript 基础核心知识点梳理

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如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