【2026】 LLM 大模型系统学习指南 (7)
当大模型遇到 “知识滞后”(比如不知道 2025 年的新政策)或 “幻觉输出”(编造不存在的事实)时,我们该如何解决?答案是给它装一个 “外挂知识库”—— 这就是 RAG(Retrieval-Augmented Generation,检索增强生成)的核心价值。本次作业的目标,就是亲手搭建一个基础 RAG 系统,从数据处理到最终生成回答,完整走通 “检索→增强→生成” 的闭环。无论你是想解决大模型的
构建基础 RAG 系统 —— 给大模型装 “外挂知识库” 的全流程实践
当大模型遇到 “知识滞后”(比如不知道 2025 年的新政策)或 “幻觉输出”(编造不存在的事实)时,我们该如何解决?答案是给它装一个 “外挂知识库”—— 这就是 RAG(Retrieval-Augmented Generation,检索增强生成)的核心价值。本次作业的目标,就是亲手搭建一个基础 RAG 系统,从数据处理到最终生成回答,完整走通 “检索→增强→生成” 的闭环。无论你是想解决大模型的事实性错误,还是想让模型能 “查阅” 特定文档(如教材、报告),这份实操指南都能帮你把理论落地。
一、先搞懂:为什么要做 RAG 系统?——3 个核心痛点的解决方案
在动手前,我们先明确 RAG 的定位:它不是替代大模型,而是给大模型 “补短板”。传统大模型的 3 个核心痛点,正好是 RAG 的优势所在:
- 知识滞后:大模型的训练数据有 “截止日期”(比如 2023 年),无法获取之后的新信息。RAG 通过实时检索外部知识库(如最新新闻、政策文档),让模型能 “查阅最新资料”;
- 容易幻觉:大模型会基于概率生成文本,偶尔编造看似合理但错误的内容。RAG 让模型 “只基于检索到的权威信息回答”,像写论文时 “引用参考文献” 一样,大幅降低幻觉率;
- 领域适配难:通用大模型对医疗、法律等专业领域的知识深度不足。RAG 可接入专业知识库(如医疗指南、法律条文),让模型快速具备 “专业能力”,无需复杂的模型微调。
本次作业搭建的基础 RAG 系统,就是要解决这些问题,比如让模型能 “检索高中数学教材内容” 来解答题目,或 “查阅产品说明书” 来回答用户咨询 —— 本质是让模型从 “闭卷考试” 变成 “开卷考试”。
二、作业核心目标:掌握 RAG 的 4 个关键能力
本次作业不追求复杂的优化,重点是理解 RAG 的核心流程并实现基础功能,完成后你将掌握:
- 数据处理能力:把原始文档(如 TXT、PDF)拆成适合检索的 “语义块”(Chunk),避免因文档太长导致检索不精准;
- 索引构建能力:用嵌入模型(Embedding Model)将文本块转成 “数字向量”,并存储到向量数据库中,实现快速检索;
- 检索实现能力:将用户的问题转成向量后,在向量数据库中找到 “语义最相似” 的文本块,作为 “参考资料”;
- 生成整合能力:把 “用户问题 + 检索到的参考资料” 组织成提示词,让大模型基于这些资料生成准确回答。
三、实操步骤:5 步搭建基础 RAG 系统 —— 代码 + 逻辑双解析
本次作业将用Python+LangChain+FAISS实现(工具选择的原因:LangChain 简化流程,FAISS 是轻量级向量数据库,无需复杂部署,适合新手),全程不涉及高深算法,跟着步骤走就能完成。
1. 准备工作:安装必备工具库
首先安装 3 个核心库,打开终端输入以下命令(若用 Anaconda 环境,需先激活对应环境):
python
运行
# 安装LangChain(简化RAG流程的工具集)
pip install langchain
# 安装FAISS(轻量级向量数据库,用于存储向量)
pip install faiss-cpu # 若有GPU,可替换为faiss-gpu
# 安装Sentence-BERT(轻量级嵌入模型,用于文本转向量)
pip install sentence-transformers
# 安装文档加载工具(支持TXT、PDF等格式)
pip install pypdf python-dotenv
这些工具的分工很明确:LangChain 负责串联 “加载文档→分块→向量化→检索→生成” 全流程,FAISS 负责存向量,Sentence-BERT 负责把文本转成向量。
2. 第一步:数据处理 —— 把文档拆成 “可检索的语义块”
原始文档(如一本 500 页的教材)直接检索会 “抓不住重点”,必须拆成更小的 “语义块”—— 就像把一本书拆成 “章节→段落”,既能保留完整语义,又能精准定位。
具体操作:
- 步骤 1:加载文档:以 “高中数学必修 1 PDF 教材” 为例,用 LangChain 的
PyPDFLoader加载文档;python
运行
from langchain_community.document_loaders import PyPDFLoader # 加载PDF文档(替换为你的文档路径) loader = PyPDFLoader("高中数学必修1.pdf") # 把PDF按页拆分成文档对象 documents = loader.load() - 步骤 2:拆分语义块:用
RecursiveCharacterTextSplitter分块,核心参数是chunk_size(块大小,按字符数算)和chunk_overlap(块重叠度,避免拆分导致语义断裂)。👉 作业建议:chunk_size=300(每块约 300 字符,对应 1-2 个段落),chunk_overlap=50(每块重叠 50 字符),适合教材类文档;python
运行
from langchain_text_splitters import RecursiveCharacterTextSplitter text_splitter = RecursiveCharacterTextSplitter( chunk_size=300, # 每块最大字符数 chunk_overlap=50, # 块重叠字符数 length_function=len, # 按字符数计算长度 is_separator_regex=False # 不使用正则分割 ) # 拆分文档,得到语义块列表 chunks = text_splitter.split_documents(documents) - 关键提醒:分块不是 “越细越好”—— 太细会导致语义不完整(比如把一个公式拆到两个块里),太粗会导致检索精准度下降(比如一块包含 3 个知识点)。可根据文档类型调整:教材类选 300-500 字符,新闻类选 200-300 字符。
3. 第二步:构建索引 —— 把文本块转成 “可检索的向量”
计算机无法直接 “理解” 文本,必须把语义块转成 “高维向量”(比如 768 维的数字列表)—— 语义越相似的文本,向量距离越近。这一步就是构建 “向量索引”,为后续检索做准备。
具体操作:
- 步骤 1:选择嵌入模型:作业推荐用
all-MiniLM-L6-v2(Sentence-BERT 系列的轻量级模型,速度快、效果好,适合入门);python
运行
from langchain_community.embeddings import SentenceTransformerEmbeddings # 初始化嵌入模型 embedding_model = SentenceTransformerEmbeddings( model_name="all-MiniLM-L6-v2" # 轻量级模型,约40MB ) - 步骤 2:构建向量索引:用 FAISS 将语义块的向量存储起来,形成可快速检索的索引;
python
运行
from langchain_community.vectorstores import FAISS # 把语义块转成向量,并构建FAISS索引 db = FAISS.from_documents( documents=chunks, # 拆分后的语义块 embedding=embedding_model# 嵌入模型 ) # 保存索引(下次用不用重新构建,直接加载即可) db.save_local("math_textbook_faiss_index") - 后续加载索引:若下次想继续使用,无需重新处理文档,直接加载已保存的索引:
python
运行
# 加载已有的FAISS索引 db = FAISS.load_local( "math_textbook_faiss_index", # 索引保存路径 embedding_model, # 同之前的嵌入模型 allow_dangerous_deserialization=True # 允许加载本地索引(开发环境用) )
4. 第三步:实现检索 —— 让系统 “找到最相关的资料”
当用户提出问题(如 “什么是函数的定义域?”)时,系统需要先把问题转成向量,再在 FAISS 索引中找到 “向量距离最近” 的 Top-K 个语义块(比如 Top-3,即最相关的 3 个段落)。
具体操作:
python
运行
# 1. 定义用户问题
user_query = "什么是函数的定义域?请结合教材内容解释"
# 2. 检索最相关的3个语义块(k=3,可根据需求调整)
retriever = db.as_retriever(search_kwargs={"k": 3})
retrieved_chunks = retriever.get_relevant_documents(user_query)
# 3. 打印检索结果(查看找到的参考资料)
print("检索到的相关内容:")
for i, chunk in enumerate(retrieved_chunks, 1):
print(f"\n【第{i}条参考】")
print(f"内容:{chunk.page_content}")
print(f"来源:第{chunk.metadata['page']}页") # metadata包含文档页码等信息
- 关键逻辑:检索的核心是 “语义相似度匹配”,不是 “关键词匹配”—— 比如用户问 “函数的定义域怎么求”,即使语义块里写的是 “定义域的定义与求解步骤”,也能被精准检索到(因为语义相似)。
- 作业小挑战:尝试调整
k的值(如 k=2、k=5),观察检索结果的数量对后续生成回答的影响(k 太小可能信息不足,k 太大可能引入冗余)。
5. 第四步:生成回答 —— 让大模型 “基于参考资料说话”
这一步是 RAG 的 “增强” 核心:把 “用户问题 + 检索到的参考资料” 组织成提示词,再交给大模型生成回答,确保回答 “有依据、不胡说”。
具体操作(以开源模型 Llama 3 为例,也可改用 ChatGPT 等):
python
运行
from langchain.chains import RetrievalQA
from langchain_community.llms import HuggingFacePipeline
from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
# 1. 加载开源大模型(Llama 3-8B,轻量级,适合作业场景)
model_name = "meta-llama/Llama-3.2-8B-Instruct"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(model_name)
# 2. 构建模型管道
pipe = pipeline(
"text-generation",
model=model,
tokenizer=tokenizer,
max_new_tokens=512, # 最大生成字符数
temperature=0.3 # 低温度,保证回答稳定准确
)
llm = HuggingFacePipeline(pipeline=pipe)
# 3. 构建RAG问答链(串联检索和生成)
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff", # 简单直接的提示组织方式:把所有参考资料塞进提示
retriever=retriever,
return_source_documents=True # 让回答包含参考资料来源(方便溯源)
)
# 4. 生成回答
result = qa_chain({"query": user_query})
# 5. 打印结果
print("最终回答:")
print(result["result"])
print("\n回答依据(参考资料):")
for i, doc in enumerate(result["source_documents"], 1):
print(f"{i}. 第{doc.metadata['page']}页:{doc.page_content[:100]}...") # 显示前100字符
- 提示组织方式:作业用
chain_type="stuff"(简单直接,适合基础场景),进阶场景可改用map_reduce(先总结每个参考块,再整合)或refine(逐步优化回答)。 - 核心价值:生成的回答会明确基于检索到的教材内容,比如 “根据教材第 12 页的定义,函数的定义域是指……”,既解决了幻觉问题,又能追溯来源。
四、作业关键难点:3 个容易踩的坑及解决方案
在实操中,新手容易遇到 “检索不准”“生成杂乱” 等问题,这 3 个常见坑的解决方法要记牢:
1. 坑 1:分块大小不合适,导致语义断裂或检索不准
- 表现:检索到的内容不完整(比如公式只一半),或回答时漏关键信息;
- 解决方案:根据文档类型调整
chunk_size:- 教材 / 技术文档(多公式、长段落):300-500 字符,保留标题层级(比如用
MarkdownHeaderTextSplitter拆分,保留 “章节标题→小节标题”); - 新闻 / 短文本(段落短、信息散):200-300 字符,
chunk_overlap设为 30-50,避免拆分句子。
- 教材 / 技术文档(多公式、长段落):300-500 字符,保留标题层级(比如用
2. 坑 2:嵌入模型选得太复杂,导致速度慢
- 表现:向量化时卡住,或检索响应时间超过 10 秒;
- 解决方案:新手优先选轻量级模型:
- 入门级:
all-MiniLM-L6-v2(40MB,速度快,适合小文档); - 进阶级:
all-mpnet-base-v2(1.1GB,精度更高,适合专业文档); - 避免一上来就用大模型(如
text-embedding-3-large),除非有 GPU 支持。
- 入门级:
3. 坑 3:生成回答时,参考资料没被充分利用
- 表现:回答还是 “凭模型记忆”,没引用检索到的内容;
- 解决方案:优化提示词模板(用
chain_type="custom"自定义提示):python
运行
from langchain.prompts import PromptTemplate # 自定义提示模板:明确要求模型引用参考资料 prompt_template = """ 请根据以下参考资料,回答用户的问题。回答必须包含参考资料的来源(如“第X页”),不允许编造信息。 参考资料: {context} 用户问题:{question} 回答: """ prompt = PromptTemplate( template=prompt_template, input_variables=["context", "question"] ) # 用自定义提示构建问答链 qa_chain = RetrievalQA.from_chain_type( llm=llm, chain_type="stuff", retriever=retriever, chain_type_kwargs={"prompt": prompt}, # 传入自定义提示 return_source_documents=True )
通过明确指令,强制模型 “必须用参考资料”,避免 “忽略检索结果” 的问题。
五、如何评估你的 RAG 系统?——2 个简单有效的方法
作业完成后,不能只看 “能生成回答”,还要判断系统好不好用,这 2 个评估方法足够基础且实用:
- 定性评估:看回答是否 “有依据、无幻觉”—— 比如用户问 “函数定义域的求解步骤”,回答是否引用了检索到的教材内容,有没有编造步骤;
- 定量评估:用 JudgeBoi 评估 2 个核心指标:
- 检索准确率:检索到的 Top-K 个语义块,有多少是真正和问题相关的(比如 K=3 时,相关的块数≥2 才算合格);
- 生成准确性:回答与参考资料的匹配度(比如 “是否准确引用了教材定义”“步骤是否和参考资料一致”)。
六、知识联动:RAG 与之前内容的衔接
本次作业不是孤立的,它是之前学过的 “上下文工程”“提示工程” 的综合应用:
- 与上下文工程的衔接:RAG 的 “检索参考资料” 本质是 “精准筛选上下文”,把最有用的信息塞进大模型的 “上下文窗口”,避免信息过载;
- 与提示工程的衔接:生成回答时的 “提示模板设计”,是提示工程的具体落地 —— 通过明确指令,让模型高效利用参考资料,这和之前 “优化提示词控制推理长度” 的思路一致。
更多推荐


所有评论(0)