如何理解 RAG 项目?
RAG(Retrieval-Augmented Generation,检索增强生成)是当前大语言模型应用中最热门、最实用的技术架构之一。让我用一个通俗的方式来帮你理解。
一、RAG 是什么?用一个类比理解
传统 LLM 像一个闭卷考试的考生:
- 只能依靠训练时学到的知识(截止到某个时间点)
- 无法查阅新资料
- 遇到没学过的内容就会"胡编乱造"(幻觉)
RAG 像一个开卷考试的考生:
-
先到资料库中检索相关信息
-
再基于检索到的资料进行回答
-
回答有据可查,准确率大幅提升
┌─────────────────────────────────────────────────────────────┐
│ 用户提问 │
│ "2024年奥运会中国拿了多少金牌?" │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 第1步:检索(Retrieval) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 到知识库中搜索 → 找到相关文档: │ │
│ │ "2024巴黎奥运会,中国代表团获得40金27银24铜" │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 第2步:增强(Augmented) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 将【用户问题 + 检索到的资料】组合成新的提示词: │ │
│ │ "根据以下资料回答问题:... 2024年奥运会中国40金..." │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 第3步:生成(Generation) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ LLM 基于资料生成答案: │ │
│ │ "根据官方数据,2024年巴黎奥运会中国共获得40枚金牌" │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
二、RAG 的核心流程(技术视角)
RAG 系统通常包含两个阶段:索引阶段 和 查询阶段。
阶段一:索引(离线准备)
把文档库变成可供检索的格式:
python
文档 → 分割成块 → 向量化(Embedding)→ 存入向量数据库
例如:
"公司2024年财报.pdf"
→ 分割成100个文本块
→ 每个块转换为768维向量
→ 存入 Chroma/Pinecone 等向量数据库
阶段二:查询(在线服务)
用户提问时的实时处理:
python
用户提问 → 向量化 → 相似度检索 → 增强提示词 → LLM生成 → 输出答案
例如:
"去年公司赚了多少钱?"
→ 转换为向量
→ 在数据库中检索最相似的3个文本块
→ 把检索结果拼接到提示词中
→ LLM基于资料回答
→ "根据2024年财报,公司净利润为5.2亿元"
三、RAG 的核心组件
┌─────────────────────────────────────────────────────────────┐
│ RAG 系统架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 文档加载器 │ ──→ │ 文本分割器 │ ──→ │ 嵌入模型 │ │
│ │ (Loader) │ │ (Splitter) │ │ (Embedding) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ↓ │
│ ┌─────────────┐ │
│ │ 向量数据库 │ │
│ │ (Vector DB) │ │
│ └─────────────┘ │
│ ↓ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 用户查询 │ ──→ │ 检索器 │ ──→ │ 大语言模型 │ │
│ │ (Query) │ │ (Retriever) │ │ (LLM) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ↓ │
│ ┌─────────────┐ │
│ │ 最终答案 │ │
│ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘
| 组件 | 作用 | LangChain 实现 |
|---|---|---|
| Document Loader | 读取各种格式的文档(PDF、Word、网页等) | PyPDFLoader, WebBaseLoader |
| Text Splitter | 把长文档切成小块 | RecursiveCharacterTextSplitter |
| Embedding Model | 将文本转换为向量 | OpenAIEmbeddings, DashScopeEmbeddings |
| Vector Store | 存储和检索向量 | Chroma, FAISS, Pinecone |
| Retriever | 根据查询检索相关文档 | vector_store.as_retriever() |
| LLM | 基于检索结果生成答案 | ChatTongyi, ChatOpenAI |
四、一个完整的 RAG 代码示例
python
from langchain_community.document_loaders import TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.embeddings import DashScopeEmbeddings
from langchain_community.vectorstores import Chroma
from langchain_community.chat_models import ChatTongyi
from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_core.prompts import ChatPromptTemplate
# ========== 索引阶段 ==========
# 1. 加载文档
loader = TextLoader("my_document.txt")
documents = loader.load()
# 2. 分割文档
text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
docs = text_splitter.split_documents(documents)
# 3. 创建向量数据库
embeddings = DashScopeEmbeddings(model="text-embedding-v2")
vector_store = Chroma.from_documents(docs, embeddings)
# ========== 查询阶段 ==========
# 4. 创建检索器
retriever = vector_store.as_retriever(search_kwargs={"k": 3})
# 5. 创建提示词模板
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个助手,请基于以下上下文回答用户问题:\n\n{context}"),
("human", "{input}")
])
# 6. 创建 RAG 链
llm = ChatTongyi()
document_chain = create_stuff_documents_chain(llm, prompt)
rag_chain = create_retrieval_chain(retriever, document_chain)
# 7. 执行查询
response = rag_chain.invoke({"input": "文档中提到了什么重要内容?"})
print(response["answer"])
五、RAG vs 其他技术对比
| 技术 | 知识更新 | 幻觉风险 | 可解释性 | 成本 | 适用场景 |
|---|---|---|---|---|---|
| 纯 LLM | 延迟(需重新训练) | 高 | 低 | 训练成本高 | 通用知识问答 |
| RAG | 实时(只需更新文档) | 低 | 高(可追溯来源) | 较低 | 企业知识库、客服 |
| 微调(Fine-tuning) | 中(需重新训练) | 中 | 中 | 中 | 特定风格/格式任务 |
六、RAG 的核心优势
| 优势 | 说明 |
|---|---|
| 知识实时更新 | 文档库更新即可,无需重新训练模型 |
| 减少幻觉 | LLM 基于事实资料回答,而不是凭记忆编造 |
| 可溯源性 | 可以告诉用户答案来自哪份文档的哪一页 |
| 保护隐私 | 私有数据不用交给模型训练,只本地检索 |
| 成本可控 | 避免大量 API 调用浪费(检索比生成便宜) |
七、RAG 的常见应用场景
- 企业知识库问答:员工问公司制度、产品手册
- 客服机器人:基于产品文档自动回答用户问题
- 法律文书分析:从大量法律文件中找到相关条款
- 医疗文献检索:医生查询最新医学研究
- 代码库问答:基于项目文档回答代码相关问题
八、RAG 的挑战与优化方向
| 挑战 | 优化方法 |
|---|---|
| 检索质量不高 | 使用混合检索(向量+关键词)、重排序(Rerank) |
| 上下文窗口限制 | 智能压缩、文档摘要 |
| 多跳推理问题 | 使用 Agent + 多次检索 |
| 检索结果噪声 | 优化分割策略、增加相关性过滤 |
总结
RAG = 检索 + 生成 ,本质上是给大模型配了一个可实时更新的外部知识库。它解决了传统 LLM 的三大痛点:
- 知识过时 → 文档一更新,答案就更新
- 胡编乱造 → 基于资料回答,有据可查
- 数据隐私 → 私有数据不用交给模型厂商
对于企业级应用,RAG 是目前最成熟、最实用的 LLM 落地技术。