在 AI 应用爆发的今天,大模型虽然拥有强大的语言理解能力,但往往面临“知识过时”、“一本正经地胡说八道(幻觉)”以及“无法读取企业私有数据”三大痛点。检索增强生成(RAG)技术正是解决这些问题的最佳方案。本文将带你使用 Python 和 LangChain 框架,从零搭建一套完全离线、免费、数据安全的本地 RAG 知识库问答系统。
一、 RAG 核心原理与架构设计
RAG(Retrieval-Augmented Generation)的核心思想是“先检索,再生成”。其标准工作流包含以下几个关键步骤:
数据准备:将本地的文档(如 TXT、Markdown、PDF 等)加载到系统中。
文本切块(Chunking):大模型有上下文窗口限制,且长文本检索精度低。因此需要将长文档按一定字符数(如 500 字)切分为小段,并设置一定的重叠区(Overlap)以保持语义连贯。
向量化(Embedding):使用嵌入模型将文本块转换为多维向量(一串数字)。这一步相当于将人类语言翻译成了机器能理解的“语义坐标”。
存入向量数据库:将生成的向量及其对应的原文存入向量数据库中。
检索与生成:当用户提问时,系统将问题转化为向量,在数据库中找出最相似的几个文本块,然后将“原文 + 问题”拼接成 Prompt 发送给大模型,大模型据此生成精准回答。
二、 技术栈选型与环境准备
为了降低入门门槛并保证数据绝对安全,本方案采用纯本地运行的技术栈:
流程编排:LangChain(大模型应用开发事实标准,组件丰富)
向量数据库:Chroma(嵌入式轻量级本地向量库,无需部署服务,开箱即用)
嵌入模型:all-MiniLM-L6-v2(开源轻量模型,本地离线运行,无需 API)
大语言模型:兼容 OpenAI 接口规范的任意模型(如本地部署的 Qwen-7B、Llama 3 等)
首先,确保你的电脑安装了 Python 3.9+,然后一键安装核心依赖:pip install langchain langchain-text-splitters langchain-chroma sentence-transformers openai python-dotenv
三、 核心代码实战:从文档入库到智能问答
以下是一个经过优化的、可直接复制运行的完整 RAG 系统代码。代码包含了文档加载、中文语义分割、向量库构建以及抗幻觉问答链。
importosfromdotenvimportload_dotenvfromlangchain_text_splittersimportRecursiveCharacterTextSplitterfromlangchain_chromaimportChromafromlangchain_community.embeddingsimportHuggingFaceEmbeddingsfromlangchain_openaiimportChatOpenAIfromlangchain.chainsimportRetrievalQAfromlangchain_community.document_loadersimportDirectoryLoader,TextLoader# ====================== 1. 核心配置项 ======================KNOWLEDGE_DIR="./knowledge_base"# 你的本地文档文件夹VECTOR_DB_PATH="./chroma_vector_db"# 向量库持久化路径CHUNK_SIZE=500# 文本块大小CHUNK_OVERLAP=50# 文本块重叠大小RETRIEVE_TOP_K=3# 检索最相关的片段数量# 大模型配置(以本地 Ollama 或兼容 OpenAI 接口的服务为例)LLM_BASE_URL="http://localhost:11434/v1"LLM_API_KEY="ollama"LLM_MODEL_NAME="qwen2:7b"load_dotenv()# ====================== 2. 文档加载与切分 ======================defload_and_split_documents():loader=DirectoryLoader(KNOWLEDGE_DIR,glob="**/*.txt",loader_cls=TextLoader,loader_kwargs={"encoding":"utf-8"})documents=loader.load()# 针对中文优化的递归字符分割器text_splitter=RecursiveCharacterTextSplitter(chunk_size=CHUNK_SIZE,chunk_overlap=CHUNK_OVERLAP,separators=["\n\n","\n","。","!","?",";",","," ",""])chunks=text_splitter.split_documents(documents)print(f"文档处理完成,共生成{len(chunks)}个文本块")returnchunks# ====================== 3. 构建向量数据库 ======================defbuild_vector_db(chunks):embeddings=HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2",model_kwargs={"device":"cpu"})ifos.path.exists(VECTOR_DB_PATH)andlen(os.listdir(VECTOR_DB_PATH))>0:vector_db=Chroma(persist_directory=VECTOR_DB_PATH,embedding_function=embeddings)print("已加载本地已有向量库")else:vector_db=Chroma.from_documents(documents=chunks,embedding=embeddings,persist_directory=VECTOR_DB_PATH)print("向量库构建完成并已持久化")returnvector_db# ====================== 4. 初始化模型与问答链 ======================defcreate_rag_chain():llm=ChatOpenAI(base_url=LLM_BASE_URL,api_key=LLM_API_KEY,model=LLM_MODEL_NAME,temperature=0)vector_db=build_vector_db(load_and_split_documents())retriever=vector_db.as_retriever(search_type="similarity",search_kwargs={"k":RETRIEVE_TOP_K})qa_chain=RetrievalQA.from_chain_type(llm=llm,retriever=retriever,return_source_documents=True)returnqa_chain# ====================== 5. 交互式问答测试 ======================if__name__=="__main__":qa_chain=create_rag_chain()whileTrue:question=input("\n请输入问题(输入 exit 退出):")ifquestion.lower()=="exit":breakresult=qa_chain.invoke({"query":question})print(f"\n答案:{result['result']}")print("参考来源:",[doc.metadata['source']fordocinresult['source_documents']])四、 避坑指南与进阶优化
在搭建本地 RAG 时,新手常遇到以下问题,需特别注意:
中文切分失效:默认的英文空格切分器会破坏中文语义,务必使用 RecursiveCharacterTextSplitter 并传入中文标点作为分隔符。
检索结果不准:如果切块太大(如超过 1000 字),向量语义会被稀释,导致检索不准;建议将 CHUNK_SIZE 控制在 300-500 之间。
大模型幻觉:在 Prompt 中必须加入约束,例如:“请仅根据以下参考内容回答问题,如果参考内容中没有相关信息,请直接回答‘我不知道’,不要编造。”
性能优化:如果文档量达到数万篇,建议将本地嵌入模型替换为针对中文优化的 m3e-base 或 bge-large-zh,并将向量库升级为 Milvus 或 Elasticsearch 以支持高并发检索。
通过上述步骤,你就能在本地快速搭建起一个专属的 AI 知识库。无论是用于个人学习笔记问答,还是企业内部规章制度检索,RAG 都是目前落地成本最低、效果最显著的技术方案。