第一章 RAG 基础与前置知识
1.1 大模型与 RAG 核心背景
大语言模型(LLM)虽然强大,但在实际落地中并非无所不能。理解它的局限性,是理解 RAG 价值的前提。
- 1.1.1 LLM 的固有缺陷
- **知识截止(Knowledge Cutoff)**:LLM 的知识来自于训练数据,而训练数据有截止时间。例如,GPT-4 的知识可能截止于 2023 年,它无法回答"2026 年最新的科技趋势"或"贵公司昨天发布的财报数据"。
- **幻觉(Hallucination)**:LLM 本质上是基于概率生成文本,当它不知道答案时,可能会"一本正经地胡说八道",编造事实、引用不存在的文献。这在严谨的商业或医疗场景中是不可接受的。
- **上下文窗口限制(Context Window Limit)**:尽管模型的上下文窗口越来越大(如 128k, 1M tokens),但它仍然无法一次性处理海量的企业文档(如数万页的技术手册或长达数年的会议记录)。
- 1.1.2 RAG 的定义与核心价值
RAG(检索增强生成,Retrieval-Augmented Generation) 正是为了解决上述痛点而生。- 定义 :RAG 是一种将信息检索系统 与文本生成模型相结合的技术架构。它的核心思想是:**"先检索,后生成"**。在用户提问时,系统首先从外部知识库(如公司文档、数据库)中检索与问题最相关的信息,然后将这些信息作为"参考依据"连同问题一起交给大模型,让大模型基于这些事实来生成答案。
- 核心价值 :
- 解决知识时效性:无需重新训练模型,只需更新外部知识库,模型就能掌握最新信息。
- 抑制幻觉:强制模型基于检索到的事实回答,大大减少了胡编乱造的可能。
- 突破上下文限制:通过检索,只将与问题最相关的"一小部分"知识送入模型,实现了"用有限的窗口,处理无限的知识"。
- 1.1.3 RAG 的三大范式演进
RAG 技术本身也在不断进化,经历了三个阶段:- **Naive RAG(朴素 RAG)**:最基础的形态。流程是"索引 -> 检索 -> 生成"。它将文档切块、向量化存储,用户提问时进行向量相似度检索。缺点是检索精度不高,容易受噪声干扰。
- **Advanced RAG(高级 RAG):在朴素 RAG 基础上引入了优化。例如, 查询重写(Query Rewriting),将用户模糊的问题改写得更适合检索;重排序(Re-ranking)**,对初步检索出的结果进行二次精排,确保最相关的信息排在前面。
- **Agentic RAG(智能体 RAG):这是当前最前沿的方向。它引入了智能体(Agent)**,让 AI 不仅能检索,还能"思考"和"行动"。例如,当一个问题需要多步推理时("对比 A 产品和 B 产品的最新价格"),智能体可以自主决定先查 A 的价格,再查 B 的价格,最后进行对比,甚至调用外部 API 来获取实时数据。
- 1.1.4 行业应用场景分析
- 企业知识库:员工可以快速查询公司内部的政策、流程、技术文档,无需在海量文件中翻找。
- 智能客服:基于最新的产品手册和 FAQ 回答用户问题,保证答案的准确性和一致性。
- 教育辅导:为学生构建个性化的学习资料库,AI 导师可以根据学生的提问,从资料库中检索相关内容进行解答。
- 医疗辅助:医生在诊断时,系统可以从海量的医学文献和病例库中检索相似案例,为医生提供决策支持。
用户提问
RAG 范式
Naive RAG
Advanced RAG
Agentic RAG
简单向量检索
查询重写 + 重排序
智能体规划 + 工具调用
生成答案
1.2 技术栈与环境准备
工欲善其事,必先利其器。搭建一个稳定、高效的开发环境是 RAG 工程的第一步。
-
1.2.1 Python 基础与环境配置
Python 是 AI 领域的首选语言。推荐使用 Anaconda 来管理 Python 环境和包,它可以避免不同项目之间的依赖冲突。- 创建虚拟环境 :
conda create -n rag_env python=3.10 - 激活环境 :
conda activate rag_env
- 创建虚拟环境 :
-
1.2.2 核心依赖库安装
RAG 系统的构建依赖于几个核心库:-
LangChain / LlamaIndex:这是两个主流的 RAG 应用开发框架。它们提供了丰富的组件,可以像搭积木一样快速构建 RAG 流程。
-
Sentence-Transformers:用于将文本转换为向量(Embedding)的库,是语义检索的核心。
-
FAISS / ChromaDB:向量数据库。FAISS 由 Meta 开发,速度快,适合本地部署;ChromaDB 轻量级,易于上手。
-
安装命令 :
bashpip install langchain llemaindex sentence-transformers faiss-cpu chromadb
-
-
1.2.3 开发工具链
- Jupyter Notebook:非常适合进行 RAG 原型的快速开发和调试,可以分步执行代码,直观地看到每一步(如索引、检索)的效果。
- VSCode:功能强大的代码编辑器,适合编写大型、结构化的 RAG 项目。
- Postman:当你将 RAG 系统封装成 API 后,可以用 Postman 来测试接口的稳定性和返回结果。
-
1.2.4 硬件与云服务选型
- 本地部署:对于开发和小型应用,一台配备 NVIDIA GPU(如 RTX 3090/4090)的电脑即可。CPU 也可以运行,但向量化和模型推理速度会慢很多。
- 云端部署 :对于生产环境,推荐使用云服务。
- GPU 加速:AWS、Google Cloud、阿里云等都提供 GPU 实例,可以显著加速 Embedding 和 LLM 的推理。
- Serverless 方案:使用 Vercel、Replicate 等平台,可以无需管理服务器,直接部署 AI 应用,按调用次数付费。
Naive RAG系统
下面的代码将演示如何从零开始,用 LangChain 构建一个最简单的 Naive RAG 系统。
python
# 1. 环境准备
# 在命令行中执行以下命令:
# conda create -n rag_env python=3.10
# conda activate rag_env
# pip install langchain langchain-community langchain-huggingface faiss-cpu
import os
from langchain_community.document_loaders import TextLoader
from langchain_text_splitters import CharacterTextSplitter
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_community.vectorstores import FAISS
from langchain_core.prompts import ChatPromptTemplate
from langchain_huggingface import HuggingFacePipeline
from transformers import pipeline, AutoModelForSeq2SeqLM, AutoTokenizer
# === 2. 模拟数据准备 ===
# 创建一个简单的文本文件作为我们的"知识库"
sample_text = """
RAG (Retrieval-Augmented Generation) 是一种结合检索和生成的 AI 技术。
它首先从外部知识库中检索与用户问题相关的信息。
然后将检索到的信息作为上下文,交给大语言模型生成答案。
RAG 的核心优势在于可以解决大模型的知识截止和幻觉问题。
LangChain 是一个流行的 RAG 应用开发框架。
"""
with open("knowledge_base.txt", "w", encoding="utf-8") as f:
f.write(sample_text)
# === 3. Naive RAG 核心流程 ===
# 3.1 加载文档
loader = TextLoader("knowledge_base.txt", encoding="utf-8")
documents = loader.load()
# 3.2 文档切块 (Text Splitting)
# 将长文档切分成小的片段,便于向量化和检索
text_splitter = CharacterTextSplitter(chunk_size=50, chunk_overlap=10)
docs = text_splitter.split_documents(documents)
# 3.3 向量化 (Embedding)
# 使用 Sentence-Transformers 模型将文本转换为向量
embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
# 3.4 构建向量索引 (Vector Store)
# 使用 FAISS 将向量存储在内存中
vectorstore = FAISS.from_documents(docs, embeddings)
# 3.5 检索 (Retrieval)
query = "RAG 技术如何解决幻觉问题?"
# 从向量库中找出与问题最相关的 2 个片段
relevant_docs = vectorstore.similarity_search(query, k=2)
# 3.6 生成 (Generation)
# 为了演示,我们使用一个轻量级的本地模型 (如 google/flan-t5-small)
# 实际应用中,这里会替换为 GPT-4, Claude 等更强大的模型
model_name = "google/flan-t5-small"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForSeq2SeqLM.from_pretrained(model_name)
pipe = pipeline("text2text-generation", model=model, tokenizer=tokenizer, max_new_tokens=100)
llm = HuggingFacePipeline(pipeline=pipe)
# 构建 Prompt
prompt_template = """
根据以下已知信息回答问题。如果已知信息中不包含答案,请说"我不知道"。
已知信息:
{context}
问题:
{question}
回答:
"""
prompt = ChatPromptTemplate.from_template(prompt_template)
# 将检索到的文档内容拼接成字符串
context_text = "\n\n".join([doc.page_content for doc in relevant_docs])
# 格式化 Prompt 并调用模型
input_text = prompt.format(context=context_text, question=query)
response = llm.invoke(input_text)
print(f"问题: {query}")
print(f"检索到的上下文: \n{context_text}")
print(f"回答: {response}")
代码说明:
- 数据加载与切块 :我们创建了一个简单的文本文件,并使用
CharacterTextSplitter将其切分成小块。 - 向量化与索引 :使用
sentence-transformers模型将文本块转换为向量,并用FAISS构建内存中的向量索引。 - 检索:当用户提问时,系统将问题也转换为向量,并在 FAISS 中查找最相似的文本块。
- 生成 :将检索到的文本块和用户问题一起填入 Prompt 模板,然后交给本地的小型 LLM (
flan-t5-small) 生成最终答案。
这个简单的例子完整展示了 Naive RAG 的核心流程,是理解更复杂 RAG 系统的基础。