第64篇:打造个人AI知识库与智能助理——基于私有数据的RAG系统实战(操作教程)
文章目录前言环境准备分步操作第一步文档加载与处理第二步构建向量数据库第三步加载本地大语言模型第四步组装RAG链并提问完整代码与运行踩坑提示总结前言在AI项目落地的过程中我踩过最大的一个坑就是模型“一本正经地胡说八道”。你问它公司最新的产品政策它能给你编出一套逻辑自洽但完全错误的答案。这背后的核心问题是大语言模型LLM的知识存在“截止日期”且无法记住你私有的、非公开的数据。为了解决这个问题让AI真正成为你业务上的得力助手检索增强生成RAG技术应运而生。今天我就带大家从零开始实战搭建一个基于私有数据的个人AI知识库与智能助理。这个系统能让你用自然语言查询自己的文档、笔记、聊天记录并得到精准、可靠的回答。环境准备我们选择轻量、高效且生态成熟的工具链确保大家能快速跑通并后续扩展。编程语言Python 3.9核心框架LangChain。它是目前构建LLM应用最流行的框架之一将RAG流程中的文档加载、切分、向量化、检索、生成等环节模块化极大降低了开发复杂度。向量数据库Chroma。轻量级、易上手、可持久化非常适合个人或小规模项目。生产环境可以考虑Qdrant、Milvus等。嵌入模型选用开源的text-embedding-ada-002的平替版如BAAI/bge-small-zh中文效果好或all-MiniLM-L6-v2。我们将通过Hugging Face使用它避免调用OpenAI API产生费用。大语言模型为了完全私有化部署我们使用开源模型。这里用ChatGLM3-6B的量化版它对中文支持好且对消费级显卡友好。你也可以换成Qwen、Llama等。硬件至少8GB内存。运行ChatGLM3-6B需要一张至少6GB显存的NVIDIA显卡如RTX 2060/3060。纯CPU推理也可行但速度会慢很多。首先安装必要的库pipinstalllangchain langchain-community langchain-chroma pypdf sentence-transformers# 安装ChatGLM3需要额外的依赖pipinstallprotobuftransformers4.36.2 cpm_kernels torch2.0gradio mdtex2html sentencepiece accelerate分步操作我们的目标是构建一个完整的RAG流水线流程如下加载文档 - 分割文本 - 文本向量化 - 存入向量库 - 问句向量化 - 检索相关片段 - 组合成提示 - LLM生成答案。第一步文档加载与处理假设你的知识库是若干PDF和TXT文件放在./data目录下。LangChain提供了大量的DocumentLoader。# document_loader.pyfromlangchain_community.document_loadersimportTextLoader,PyPDFLoaderfromlangchain.text_splitterimportRecursiveCharacterTextSplitterimportosdefload_and_split_documents(data_dir./data): 加载并分割文档 documents[]forfilenameinos.listdir(data_dir):filepathos.path.join(data_dir,filename)iffilename.endswith(.pdf):loaderPyPDFLoader(filepath)eliffilename.endswith(.txt):loaderTextLoader(filepath,encodingutf-8)else:continue# 跳过不支持的文件类型loaded_docsloader.load()# 每个文档被加载成一个Document对象列表documents.extend(loaded_docs)print(f已加载:{filename})# 分割文本。chunk_size控制每个片段的大小chunk_overlap控制重叠部分防止上下文断裂。text_splitterRecursiveCharacterTextSplitter(chunk_size500,# 每个片段约500字符chunk_overlap50,# 片段间重叠50字符length_functionlen,separators[\n\n,\n,。,,,, ,]# 中文友好分隔符)split_docstext_splitter.split_documents(documents)print(f文档加载分割完毕共得到{len(split_docs)}个文本片段。)returnsplit_docsif__name____main__:docsload_and_split_documents()第二步构建向量数据库我们需要一个嵌入模型将文本转换为向量 embeddings 然后存入Chroma。# build_vectorstore.pyfromlangchain_chromaimportChromafromlangchain_community.embeddingsimportHuggingFaceEmbeddingsimportosdefcreate_vector_store(split_docs,persist_directory./chroma_db): 创建并持久化向量数据库 # 1. 初始化嵌入模型# 使用中文效果较好的开源模型model_nameBAAI/bge-small-zhmodel_kwargs{device:cpu}# 如果显卡够用可改为 {device: cuda}encode_kwargs{normalize_embeddings:True}# 归一化提升检索效果embeddingsHuggingFaceEmbeddings(model_namemodel_name,model_kwargsmodel_kwargs,encode_kwargsencode_kwargs)# 2. 创建向量库。split_docs会被自动嵌入并存储。# persist_directory 指定持久化目录下次可直接加载无需重新计算。vectordbChroma.from_documents(documentssplit_docs,embeddingembeddings,persist_directorypersist_directory)# 显式持久化vectordb.persist()print(f向量数据库已创建并保存至{persist_directory})returnvectordbif__name____main__:fromdocument_loaderimportload_and_split_documents split_docsload_and_split_documents()vectordbcreate_vector_store(split_docs)第三步加载本地大语言模型我们使用Transformers库加载本地的ChatGLM3-6B模型。# local_llm.pyfromlangchain_community.llmsimportHuggingFacePipelinefromtransformersimportAutoTokenizer,AutoModelForCausalLM,pipelineimporttorchdefload_local_llm(model_pathTHUDM/chatglm3-6b): 加载本地LLM这里以ChatGLM3为例 tokenizerAutoTokenizer.from_pretrained(model_path,trust_remote_codeTrue)# 量化加载大幅降低显存需求。如果你的显卡显存12GB可以去掉 load_in_8bitTruemodelAutoModelForCausalLM.from_pretrained(model_path,trust_remote_codeTrue,torch_dtypetorch.float16,# 半精度device_mapauto,# 自动分配设备CPU/GPUload_in_8bitTrue# 8位量化RTX 3060 6G可跑)# 创建文本生成管道pipepipeline(text-generation,modelmodel,tokenizertokenizer,max_new_tokens512,# 生成的最大token数temperature0.1,# 较低的温度使输出更确定更适合知识问答do_sampleTrue)# 包装成LangChain的LLM对象llmHuggingFacePipeline(pipelinepipe)print(本地LLM加载完成。)returnllmif__name____main__:llmload_local_llm()# 简单测试test_responsellm.invoke(你好请介绍一下你自己。)print(test_response)第四步组装RAG链并提问这是最核心的一步我们将检索器Retriever和语言模型LLM串联起来形成一个“检索-增强-生成”的链条。# rag_chain.pyfromlangchain.chainsimportRetrievalQAfromlangchain.promptsimportPromptTemplatefrombuild_vectorstoreimportcreate_vector_storefromlocal_llmimportload_local_llmdefcreate_rag_chain(): 创建完整的RAG问答链 # 1. 加载已存在的向量数据库无需重新嵌入fromlangchain_community.embeddingsimportHuggingFaceEmbeddings embeddingsHuggingFaceEmbeddings(model_nameBAAI/bge-small-zh)fromlangchain_chromaimportChroma persist_directory./chroma_dbvectordbChroma(persist_directorypersist_directory,embedding_functionembeddings)# 2. 将向量数据库转换为检索器设置k4表示检索最相关的4个片段retrievervectordb.as_retriever(search_kwargs{k:4})# 3. 加载本地LLMllmload_local_llm()# 4. 构建提示模板。这是提升回答质量的关键# 模板告诉LLM根据给定的上下文context来回答问题question。prompt_template基于以下已知信息简洁和专业地回答用户的问题。 如果无法从已知信息中得到答案请直接说根据已知信息无法回答该问题不要编造答案。 已知信息 {context} 问题 {question} 请用中文回答PROMPTPromptTemplate(templateprompt_template,input_variables[context,question])# 5. 创建检索问答链# chain_typestuff 是最简单的方式将所有检索到的上下文塞进提示词。# return_source_documentsTrue 可以让我们看到检索到的源文档便于调试。qa_chainRetrievalQA.from_chain_type(llmllm,chain_typestuff,retrieverretriever,return_source_documentsTrue,chain_type_kwargs{prompt:PROMPT}# 使用我们自定义的提示模板)returnqa_chaindefask_question(qa_chain,question): 向RAG链提问 resultqa_chain.invoke({query:question})answerresult[result]source_docsresult[source_documents]print(f\n问题{question})print(f答案{answer})print(\n--- 参考来源 ---)fori,docinenumerate(source_docs[:2]):# 显示前2个来源print(f[来源{i1}]{doc.page_content[:200]}...)# 截取片段内容预览print(-*50)if__name____main__:qa_chaincreate_rag_chain()# 测试问题ask_question(qa_chain,我文档中提到的核心产品是什么)ask_question(qa_chain,总结一下第三章节的主要内容。)完整代码与运行将以上四个步骤的代码模块document_loader.py,build_vectorstore.py,local_llm.py,rag_chain.py放在同一目录下。按顺序执行准备数据将你的PDF/TXT文档放入./data文件夹。构建知识库运行python build_vectorstore.py。这会完成文档加载、分割、向量化并存储。只需运行一次除非文档有更新。启动并提问运行python rag_chain.py。它会加载已有的向量库和模型并等待你修改main函数中的问题进行测试。你也可以将rag_chain.py改造成一个简单的Gradio Web界面方便交互。# app.py (可选用于创建Web界面)importgradioasgrfromrag_chainimportcreate_rag_chain qa_chaincreate_rag_chain()defanswer_question(question,history):resultqa_chain.invoke({query:question})returnresult[result]gr.ChatInterface(answer_question).launch(shareFalse,server_name0.0.0.0)踩坑提示文本分割是门艺术chunk_size设置过大检索会不精准过小则上下文可能不完整。需要根据你的文档类型技术手册、会议记录、小说反复调整。我的经验是从500开始观察检索出的片段是否是一个完整的语义单元。嵌入模型的选择如果知识库全是中文务必选择中文优化的嵌入模型如BAAI/bge-*系列。用英文模型处理中文效果会大打折扣。提示词工程默认提示词可能不够强。务必在提示词中强调“根据上下文回答”和“不知道就说不知道”这是减少模型幻觉的关键。可以尝试在提示词中加入“请引用原文中的句子”来让答案更精确。本地LLM的显存瓶颈如果遇到CUDA out of memory可以尝试a) 使用load_in_8bitTrue或load_in_4bitTrueb) 换更小的模型如Qwen1.5-4Bc) 使用纯CPU模式device_mapcpu但推理会慢10倍以上。检索效果不佳如果总是检索不到相关文档检查a) 嵌入模型是否匹配语种b) 检索数量k是否太小c) 尝试使用vectordb.similarity_search_with_score(question, k4)查看相似度分数诊断问题。总结通过以上实战我们成功搭建了一个完全本地化、私有的AI知识库与智能助理。这个系统的核心价值在于它将LLM的通用推理能力与你独有的知识数据相结合产出的答案既智能又精准。这个基础框架有巨大的扩展空间你可以接入企业微信/钉钉机器人做成团队助手可以增加多轮对话记忆可以对接更多类型的文档Word, Excel, 网页爬虫甚至可以实现更复杂的“多路检索”或“重排序”来提升精度。RAG是当前让大模型落地、产生商业价值的最实用路径之一。希望这个教程能帮你迈出第一步亲手打造一个专属的AI大脑。如有问题欢迎评论区交流持续更新中…