news 2026/4/24 11:24:47

第64篇:打造个人AI知识库与智能助理——基于私有数据的RAG系统实战(操作教程)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
第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需要额外的依赖pipinstallprotobuftransformers==4.36.2 cpm_kernels torch>=2.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):filepath=os.path.join(data_dir,filename)iffilename.endswith('.pdf'):loader=PyPDFLoader(filepath)eliffilename.endswith('.txt'):loader=TextLoader(filepath,encoding='utf-8')else:continue# 跳过不支持的文件类型loaded_docs=loader.load()# 每个文档被加载成一个Document对象列表documents.extend(loaded_docs)print(f"已加载:{filename}")# 分割文本。chunk_size控制每个片段的大小,chunk_overlap控制重叠部分,防止上下文断裂。text_splitter=RecursiveCharacterTextSplitter(chunk_size=500,# 每个片段约500字符chunk_overlap=50,# 片段间重叠50字符length_function=len,separators=["\n\n","\n","。","!","?",","," ",""]# 中文友好分隔符)split_docs=text_splitter.split_documents(documents)print(f"文档加载分割完毕,共得到{len(split_docs)}个文本片段。")returnsplit_docsif__name__=="__main__":docs=load_and_split_documents()

第二步:构建向量数据库

我们需要一个嵌入模型将文本转换为向量( embeddings ),然后存入Chroma。

# build_vectorstore.pyfromlangchain_chromaimportChromafromlangchain_community.embeddingsimportHuggingFaceEmbeddingsimportosdefcreate_vector_store(split_docs,persist_directory="./chroma_db"):""" 创建并持久化向量数据库 """# 1. 初始化嵌入模型# 使用中文效果较好的开源模型model_name="BAAI/bge-small-zh"model_kwargs={'device':'cpu'}# 如果显卡够用,可改为 `{'device': 'cuda'}`encode_kwargs={'normalize_embeddings':True}# 归一化,提升检索效果embeddings=HuggingFaceEmbeddings(model_name=model_name,model_kwargs=model_kwargs,encode_kwargs=encode_kwargs)# 2. 创建向量库。split_docs会被自动嵌入并存储。# `persist_directory` 指定持久化目录,下次可直接加载,无需重新计算。vectordb=Chroma.from_documents(documents=split_docs,embedding=embeddings,persist_directory=persist_directory)# 显式持久化vectordb.persist()print(f"向量数据库已创建并保存至{persist_directory}")returnvectordbif__name__=="__main__":fromdocument_loaderimportload_and_split_documents split_docs=load_and_split_documents()vectordb=create_vector_store(split_docs)

第三步:加载本地大语言模型

我们使用Transformers库加载本地的ChatGLM3-6B模型。

# local_llm.pyfromlangchain_community.llmsimportHuggingFacePipelinefromtransformersimportAutoTokenizer,AutoModelForCausalLM,pipelineimporttorchdefload_local_llm(model_path="THUDM/chatglm3-6b"):""" 加载本地LLM,这里以ChatGLM3为例 """tokenizer=AutoTokenizer.from_pretrained(model_path,trust_remote_code=True)# 量化加载,大幅降低显存需求。如果你的显卡显存>=12GB,可以去掉 `load_in_8bit=True`model=AutoModelForCausalLM.from_pretrained(model_path,trust_remote_code=True,torch_dtype=torch.float16,# 半精度device_map="auto",# 自动分配设备(CPU/GPU)load_in_8bit=True# 8位量化,RTX 3060 6G可跑)# 创建文本生成管道pipe=pipeline("text-generation",model=model,tokenizer=tokenizer,max_new_tokens=512,# 生成的最大token数temperature=0.1,# 较低的温度使输出更确定,更适合知识问答do_sample=True)# 包装成LangChain的LLM对象llm=HuggingFacePipeline(pipeline=pipe)print("本地LLM加载完成。")returnllmif__name__=="__main__":llm=load_local_llm()# 简单测试test_response=llm.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 embeddings=HuggingFaceEmbeddings(model_name="BAAI/bge-small-zh")fromlangchain_chromaimportChroma persist_directory="./chroma_db"vectordb=Chroma(persist_directory=persist_directory,embedding_function=embeddings)# 2. 将向量数据库转换为检索器,设置`k=4`表示检索最相关的4个片段retriever=vectordb.as_retriever(search_kwargs={"k":4})# 3. 加载本地LLMllm=load_local_llm()# 4. 构建提示模板。这是提升回答质量的关键!# 模板告诉LLM:根据给定的上下文(context)来回答问题(question)。prompt_template="""基于以下已知信息,简洁和专业地回答用户的问题。 如果无法从已知信息中得到答案,请直接说"根据已知信息无法回答该问题",不要编造答案。 已知信息: {context} 问题: {question} 请用中文回答:"""PROMPT=PromptTemplate(template=prompt_template,input_variables=["context","question"])# 5. 创建检索问答链# `chain_type="stuff"` 是最简单的方式,将所有检索到的上下文塞进提示词。# `return_source_documents=True` 可以让我们看到检索到的源文档,便于调试。qa_chain=RetrievalQA.from_chain_type(llm=llm,chain_type="stuff",retriever=retriever,return_source_documents=True,chain_type_kwargs={"prompt":PROMPT}# 使用我们自定义的提示模板)returnqa_chaindefask_question(qa_chain,question):""" 向RAG链提问 """result=qa_chain.invoke({"query":question})answer=result["result"]source_docs=result["source_documents"]print(f"\n问题:{question}")print(f="答案:{answer}")print("\n--- 参考来源 ---")fori,docinenumerate(source_docs[:2]):# 显示前2个来源print(f"[来源{i+1}]{doc.page_content[:200]}...")# 截取片段内容预览print("-"*50)if__name__=="__main__":qa_chain=create_rag_chain()# 测试问题ask_question(qa_chain,"我文档中提到的核心产品是什么?")ask_question(qa_chain,"总结一下第三章节的主要内容。")

完整代码与运行

将以上四个步骤的代码模块(document_loader.py,build_vectorstore.py,local_llm.py,rag_chain.py)放在同一目录下。按顺序执行:

  1. 准备数据:将你的PDF/TXT文档放入./data文件夹。
  2. 构建知识库:运行python build_vectorstore.py。这会完成文档加载、分割、向量化并存储。只需运行一次,除非文档有更新。
  3. 启动并提问:运行python rag_chain.py。它会加载已有的向量库和模型,并等待你修改main函数中的问题进行测试。

你也可以将rag_chain.py改造成一个简单的Gradio Web界面,方便交互。

# app.py (可选,用于创建Web界面)importgradioasgrfromrag_chainimportcreate_rag_chain qa_chain=create_rag_chain()defanswer_question(question,history):result=qa_chain.invoke({"query":question})returnresult["result"]gr.ChatInterface(answer_question).launch(share=False,server_name="0.0.0.0")

踩坑提示

  1. 文本分割是门艺术chunk_size设置过大,检索会不精准;过小,则上下文可能不完整。需要根据你的文档类型(技术手册、会议记录、小说)反复调整。我的经验是从500开始,观察检索出的片段是否是一个完整的语义单元。
  2. 嵌入模型的选择:如果知识库全是中文,务必选择中文优化的嵌入模型(如BAAI/bge-*系列)。用英文模型处理中文,效果会大打折扣。
  3. 提示词工程:默认提示词可能不够强。务必在提示词中强调“根据上下文回答”和“不知道就说不知道”,这是减少模型幻觉的关键。可以尝试在提示词中加入“请引用原文中的句子”来让答案更精确。
  4. 本地LLM的显存瓶颈:如果遇到CUDA out of memory,可以尝试:a) 使用load_in_8bit=Trueload_in_4bit=True;b) 换更小的模型(如Qwen1.5-4B);c) 使用纯CPU模式(device_map="cpu"),但推理会慢10倍以上。
  5. 检索效果不佳:如果总是检索不到相关文档,检查:a) 嵌入模型是否匹配语种;b) 检索数量k是否太小;c) 尝试使用vectordb.similarity_search_with_score(question, k=4)查看相似度分数,诊断问题。

总结

通过以上实战,我们成功搭建了一个完全本地化、私有的AI知识库与智能助理。这个系统的核心价值在于,它将LLM的通用推理能力与你独有的知识数据相结合,产出的答案既智能又精准。

这个基础框架有巨大的扩展空间:你可以接入企业微信/钉钉机器人,做成团队助手;可以增加多轮对话记忆;可以对接更多类型的文档(Word, Excel, 网页爬虫);甚至可以实现更复杂的“多路检索”或“重排序”来提升精度。

RAG是当前让大模型落地、产生商业价值的最实用路径之一。希望这个教程能帮你迈出第一步,亲手打造一个专属的AI大脑。

如有问题欢迎评论区交流,持续更新中…

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/24 11:22:28

Heightmapper终极指南:3步生成专业地形高度图的免费工具

Heightmapper终极指南:3步生成专业地形高度图的免费工具 【免费下载链接】heightmapper interactive heightmaps from terrain data 项目地址: https://gitcode.com/gh_mirrors/he/heightmapper Heightmapper是一款强大的开源地形高度图生成工具,…

作者头像 李华
网站建设 2026/4/24 11:20:18

抖音批量下载器:从手动保存到智能收集的完整解决方案

抖音批量下载器:从手动保存到智能收集的完整解决方案 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback suppor…

作者头像 李华
网站建设 2026/4/24 11:17:18

Ubuntu下SpaceMouse驱动配置与Python/Robosuite集成实战

1. SpaceMouse与Ubuntu环境准备 SpaceMouse作为专业3D交互设备,在工业设计和机器人仿真领域有着广泛应用。但很多开发者不知道的是,官方早在2014年就停止了对Linux驱动的维护。这导致在Ubuntu系统上使用SpaceMouse需要依赖开源社区方案。我最近在机器人仿…

作者头像 李华
网站建设 2026/4/24 11:16:12

别再死记硬背!用‘扔鸡蛋问题’的DP解法,轻松拿下CSP-J阅读程序题

从扔鸡蛋问题到动态规划:轻松攻克CSP-J阅读程序题 想象一下,你站在一座100层高的大楼前,手里拿着两个鸡蛋。你的任务是找出鸡蛋从哪层楼扔下会摔碎。最笨的方法是从第一层开始一层层试,但这样最坏情况下要扔100次。有没有更聪明的…

作者头像 李华