【手摸手学 RAG】从零开始,和我一起搭建一个RAG知识库问答机器人
大家好,我是胡琦。
上次我们聊了如何“升级”RAG的检索系统,很多小伙伴表示意犹未尽,想知道一个完整的RAG应用到底是如何从零搭建的。
安排!
本篇,我们就以Datawhale的开源项目all-in-rag
中的实战项目为例,完整地走一遍从环境配置到最终应用的全流程。您不需要任何高深的AI背景,只要跟着我的步骤,就能亲手“孕育”出一个属于你自己的知识库问答机器人。
准备好了吗?让我们开始吧!
第一步:谋定而后动 —— 架构设计与环境准备
任何一个项目,开工前都要先画好“蓝图”。我们的RAG问答机器人也不例外。它的工作流程非常清晰:
图片来源: all-in-rag
- 数据准备:把我们的私有知识(比如一堆PDF、Markdown文档)加载进来,并切割成小片段(Chunks)。
- 索引构建:用Embedding模型把每个文本片段“向量化”,然后存入向量数据库,建立索引。
- 检索:当用户提问时,同样将问题向量化,然后去向量数据库里找到最相似的几个文本片段。
- 生成:把原始问题和检索到的文本片段一起“喂”给大语言模型(LLM),让它生成最终的、人性化的答案。
蓝图有了,接下来就是准备“工具箱”。你需要一个安装了Python的环境,然后在项目目录下创建一个 requirements.txt
文件,写入以下内容:
langchain==0.3.26
langchain-huggingface==0.3.1
langchain-text-splitters==0.3.8
langchain-unstructured==0.1.6
langchain-community==0.3.27
faiss-cpu>=1.7.0
unstructured==0.18.11
Markdown==3.8.2
sentence-transformers>=3.0.0
lazy_loader==0.4
rank_bm25==0.2.2
openai>=1.86.0,<2.0.0
然后打开终端,一行命令把所有依赖都装好:
pip install -r requirements.txt
小贴士:langchain
和相关依赖为我们提供了文档读取、LLM等能力,faiss-cpu
则是我们要用到的向量数据库。
第二步:精雕细琢 —— 知识库“原料”处理
万丈高楼平地起,知识库就是我们RAG机器人的“地基”。这里的关键是加载和切分。
1. 加载文档:
我们的知识可能分散在各种格式的文档里。不用怕,LangChain
提供了强大的DirectoryLoader
,可以帮我们自动识别并加载一个文件夹下所有支持的文档。
from langchain_community.document_loaders import DirectoryLoader
# 设置你的知识库路径
DATA_PATH = "your_knowledge_base_path/"
# 创建一个加载器,它会自动处理路径下的 .md, .txt, .pdf 等文件
loader = DirectoryLoader(DATA_PATH, silent_errors=True)
raw_documents = loader.load()
print(f"成功加载了 {len(raw_documents)} 份文档。")
2. 文本切分(Chunking):
一篇长文档直接丢给模型,效果会很差。我们需要把它切分成大小适中、语义完整的“知识块”。这里我们选用RecursiveCharacterTextSplitter
,它会智能地尝试按段落、句子等方式切分,尽可能保持语义完整。
from langchain.text_splitter import RecursiveCharacterTextSplitter
# 初始化一个文本切分器
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500, # 每个chunk的大小
chunk_overlap=50, # 相邻chunk的重叠大小
separators=["\n\n", "\n", " ", ""] # 分隔符
)
# 开始切分
documents = text_splitter.split_documents(raw_documents)
print(f"文档被切分成了 {len(documents)} 个片段。")
好了,我们的“原料”已经处理完毕,变成了一块块高质量的“知识砖块”,随时可以用来构建我们的知识大厦了。
第三步:建立索引 —— 让知识“井井有条”
现在,我们需要把这些文本“砖块”转换成机器能理解的数学语言——向量,并存入一个可以被快速检索的数据库中。
1. 选择Embedding模型:
Embedding模型是连接自然语言和向量空间的“桥梁”。市面上有很多优秀的选择,这里我们使用社区广泛应用的 bge-large-zh-v1.5
,它在中英文上都有很好的表现。
from langchain_community.embeddings import HuggingFaceEmbeddings
# 指定我们要用的Embedding模型
embedding_model_name = 'BAAI/bge-large-zh-v1.5'
# 初始化Embedding模型
embeddings = HuggingFaceEmbeddings(
model_name=embedding_model_name,
model_kwargs={'device': 'cpu'}, # 如果你有GPU,可以改成 'cuda'
encode_kwargs={'normalize_embeddings': True}
)
2. 构建向量数据库:
FAISS
是一个非常高效的向量相似度搜索库。我们用它来存储并索引我们的文档向量。
from langchain_community.vectorstores import FAISS
# 使用我们准备好的文档片段和Embedding模型,构建FAISS索引
vectorstore = FAISS.from_documents(documents, embeddings)
# [可选] 我们可以把建好的索引存到本地,下次就不用重新构建了
vectorstore.save_local("faiss_index_directory")
# 加载方式:
# vectorstore = FAISS.load_local("faiss_index_directory", embeddings, allow_dangerous_deserialization=True)
# 把它变成一个检索器(Retriever)
retriever = vectorstore.as_retriever()
到这里,我们RAG系统的“检索”核心已经打造完毕!它已经具备了根据问题,快速找到相关知识的能力。
第四步:注入灵魂 —— 让机器人“开口说话”
最后一步,就是请出我们的大语言模型(LLM),让它扮演“大脑”的角色,整理检索到的信息,并用流畅的语言回答用户的问题。
1. 加载LLM:
你可以选择任何你喜欢的LLM,比如ChatGLM
、Qwen
等。这里我们以加载一个本地模型为例。
from langchain_community.llms import Ollama # 假设我们用Ollama来加载本地模型
# 初始化一个LLM
llm = Ollama(model="qwen:7b-chat") # 替换成你自己的模型
2. 创建问答链(QA Chain):
LangChain
已经为我们封装好了标准的RetrievalQA
链,它能完美地把“检索器”和“LLM”串联起来。
from langchain.chains import RetrievalQA
# 创建一个问答链
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff", # "stuff"模式会把所有检索到的内容一次性塞给LLM
retriever=retriever # 使用我们第三步创建的检索器
)
# 让我们来问个问题!
question = "请问,RAG系统中的混合检索是什么?"
answer = qa_chain.invoke(question)
print(answer)
效果拔群! 我们的机器人会根据我们提供的知识库,精准地回答出混合检索的定义和作用。
至此我们已经亲手完整地搭建了一个RAG应用。回顾一下我们的旅程:
- 规划架构,准备好开发环境。
- 处理数据,将原始文档制作成高质量的“知识砖块”。
- 建立索引,打造了一个高效的检索引擎。
- 串联生成,为机器人注入LLM的“灵魂”,让它能言善道。
是不是很有成就感?
当然,这只是一个起点。接下来,你还可以继续探索:
- 优化前端:用
Streamlit
或Gradio
为它穿上一件漂亮的外衣。 - 模型替换:尝试不同的Embedding模型和LLM,看看效果有何不同。
- 高级检索:集成我们上一篇讲到的混合检索、重排等高级技巧。
技术的魅力就在于不断探索和创造。希望这篇笔记能为你打开一扇通往更广阔AI世界的大门。动手试试吧,期待看到您的分享!
详细代码请参考: datawhalechina/all-in-rag/code/C8
本文基于[datawhalechina/all-in-rag]项目整理,仅代表个人学习心得,不代表任何官方观点。小伙伴们有疑问欢迎交流讨论,一起学习一起进步!
- 点赞
- 收藏
- 关注作者
评论(0)