Langchain实现一个简单RAG!
Langchain实现一个简单RAG
一、RAG概述
RAG(Retrieval-Augmented Generation,检索增强生成) 是一种结合检索系统和生成式大语言模型的问答方法。它能有效缓解大模型“遗忘”和“幻觉”问题,提升回答的准确性与可靠性。
当用户提出问题时,RAG 会:1、先从外部知识库中检索与问题相关的信息; 2、然后将这些信息与用户的问题合并成一个提示(Prompt); 3、最后将提示输入到大模型中生成答案。

相比传统的生成方式,RAG 方法具备以下优势:1、利用了外部知识库,能回答超出模型训练范围的问题; 2、提升了答案的可解释性; 3、更便于实现个性化或特定领域的问答系统。
RAG 的典型流程
RAG 通常分为两个阶段:
1.数据准备阶段
- 数据收集:从网页、文档等来源获取原始文本;
- 文本分割:将长文本切分为适合检索的段落;
- 向量化:使用 embedding模型将文本转为向量;
- 数据入库:将向量存储在向量数据库中(如 Chroma等)。
2.应用阶段
- 用户提问;
- 系统从向量库中检索相关段落;
- 将上下文注入 Prompt 中;
- 交由大语言模型生成最终答案。

二、项目结构说明
在本项目中,我们将使用以下组件来构建一个本地运行的 RAG 系统:
- LangChain:用于编排数据流和调用组件;
- HuggingFace Embedding 模型:用于文本向量化;
- Chroma 向量数据库:用于存储和检索文本向量;
- Ollama 本地大模型:用于调用大模型生成答案;
- 本地知识库文件夹:作为信息源。
目录结构如下:
├── naiveRAG.py # 主程序代码
├── chroma_naive_db/ # 向量数据库(自动生成)
└── my_knowledge/ # 存放知识库文本
└── 1.txt # 示例文档(如从百度百科复制图灵相关内容粘贴进去)
三、代码解析
3.1 模型初始化
llm = OllamaLLM(model="qwen3:0.6b")
embedding_model = HuggingFaceEmbeddings(model_name="BAAI/bge-small-zh-v1.5")
OllamaLLM:调用的是本地部署的大语言模型,例如 qwen3:0.6b。需要先在本地部署并运行的大模型。
HuggingFaceEmbeddings:这是向量化模型,用于将文本转换为高维向量。这里我们选用了表现优异的中文嵌入模型 bge-small-zh-v1.5
3.2 构建知识库
file_dir = Path('my_knowledge') # 加载本地文档(如 .txt 文件)
text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=100) # 使用 RecursiveCharacterTextSplitter 分段
vector_store = Chroma(embedding_function=embedding_model, persist_directory="./chroma_naive_db") # 利用中文 embedding 模型向量化,并存入本地向量数据库(Chroma)
retriever = vector_store.as_retriever(search_kwargs={"k": 5}) # 检索5条相关信息
file_dir:设置知识库所在目录。
text_splitter:将文本切成每段最多 500 字,重叠 100 字,避免因分段切断语义。
Chroma:向量数据库,存储嵌入后的文本;persist_directory 指定本地持久化的数据库路径。
retriever:封装检索器,设置为返回 top-5 最相似文本段落。
3.3 加载器与 Prompt 模板定义
text_loader_utf8 = partial(TextLoader, encoding='utf-8')
prompt_template = PromptTemplate.from_template("""
你是一个严谨的RAG助手。请根据以下提供的上下文信息来回答问题。
要求:先回答用户的问题,如果回答中使用了上下文信息,在回答后输出使用了哪些上下文。
-----------------------------------
上下文信息如下:{context}
问题:{question}
""")
text_loader_utf8:为了支持中文,我们显式指定编码格式为 UTF-8。
prompt_template:定义输入给大模型的提示词模板。模板中会将上下文和用户问题注入。
3.4 构建 LangChain 编排链
chain = (
{"question": RunnablePassthrough()}
| RunnablePassthrough.assign(context=itemgetter("question") | retriever)
| prompt_template
| llm
| StrOutputParser()
)
编排步骤详解:
用户输入问题 → {“question”: RunnablePassthrough()}
保持原样传递给下一环节。
检索上下文信息 → assign(context=itemgetter(“question”) | retriever)
根据输入的问题,从向量库中检索相似的文本段,作为上下文 context。
注入模板生成 Prompt → prompt_template
将 context 和 question 注入上文定义的 prompt 模板中。
调用大语言模型生成回答 → llm
将 prompt 输入到本地模型中获取输出。
解析结果 → StrOutputParser()
抽取并返回字符串形式的结果。
3.5 主函数
if __name__ == '__main__':
if len(vector_store.get()["ids"]) == 0:
print("首次运行,正在初始化知识库...")
docs = DirectoryLoader(str(file_dir), loader_cls=text_loader_utf8).load()
docs = text_splitter.split_documents(docs)
vector_store.add_documents(docs)
print("知识库构建完成。")
else:
print("已加载知识库,跳过初始化。")
question = "图灵的论文标题是什么?"
answer = chain.invoke(question)
print(f"问题:{question}")
print(f"回答:{answer}")
主逻辑解析:
若向量库中如无文档,为首次运行:则从 my_knowledge 文件夹加载文本,进行分段、向量化后存入 Chroma。
若非首次运行:跳过初始化,直接加载向量库。
问答流程测试:使用 chain.invoke() 提交问题,并打印生成的回答。
四、完整代码
以下是一个完整的 RAG 实现示例
from _operator import itemgetter
from pathlib import Path
from langchain_core.prompts import PromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough, RunnableParallel
from langchain_community.document_loaders import DirectoryLoader, TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter, CharacterTextSplitter
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_openai import ChatOpenAI
from langchain_chroma import Chroma
from langchain_ollama import OllamaLLM
from functools import partial
# 1. 设置模型
llm = OllamaLLM(model="qwen3:0.6b")
embedding_model = HuggingFaceEmbeddings(model_name="BAAI/bge-small-zh-v1.5")
# 2. 设置数据处理(加载、分块、存储、检索)
file_dir = Path('my_knowledge')
text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=100)
# 创建向量存储(使用Chroma数据库)
vector_store = Chroma(embedding_function=embedding_model, persist_directory="./chroma_naive_db")
# 创建检索器(返回top5相似结果)
retriever = vector_store.as_retriever(search_kwargs={"k": 5})
text_loader_utf8 = partial(TextLoader, encoding='utf-8')
prompt_template = PromptTemplate.from_template("""
你是一个严谨的RAG助手。请根据以下提供的上下文信息来回答问题。
要求:先回答用户的问题,如果回答中使用了上下文信息,在回答后输出使用了哪些上下文。
-----------------------------------
上下文信息如下:{context}
问题:{question}
""")
# 3. 编排链: 问题输入 -> 检索 -> 注入prompt -> 模型 -> 解析
chain = {"question": RunnablePassthrough()} | RunnablePassthrough.assign(
context=itemgetter("question") | retriever) | prompt_template | llm | StrOutputParser()
if __name__ == '__main__':
# 检查向量数据库是否已经有文档
if len(vector_store.get()["ids"]) == 0:
print("首次运行,正在初始化知识库...")
docs = DirectoryLoader(str(file_dir), loader_cls=text_loader_utf8).load() # 加载文档
docs = text_splitter.split_documents(docs) # 切分文档
vector_store.add_documents(docs) # 存储文档
else:
print("已加载知识库,跳过初始化。")
print(chain.invoke("图灵的论文标题是什么"))
五、总结
本项目通过 LangChain 框架串联本地文档加载、文本切分、向量化存储与检索,再结合 Prompt 模板和本地大语言模型,实现了一个完整的 RAG 问答系统。RAG是增强LLM应用能力的关键技术,希望本文能为你探索更高级的AI应用打下坚实的基础。
更多推荐



所有评论(0)