从零搭建本地AI知识库:基于RAG的智能问答系统实战指南
从零搭建本地AI知识库基于RAG的智能问答系统实战指南文章目录从零搭建本地AI知识库基于RAG的智能问答系统实战指南前言一、RAG 架构原理1.1 什么是 RAG1.2 为什么选择 RAG1.3 RAG vs 微调不是非此即彼二、技术选型2.1 整体架构图2.2 核心组件选型三、环境准备3.1 安装依赖3.2 项目结构四、完整代码实现4.1 配置文件4.2 文档处理与入库4.3 检索器4.4 生成器4.5 主程序五、运行效果5.1 第一步文档入库5.2 第二步启动问答六、进阶优化技巧6.1 检索质量优化6.2 分块策略优化6.3 更多优化方向七、总结下一步建议前言大语言模型LLM的能力有目共睹但直接使用通用模型时会面临两个核心痛点知识时效性差训练数据有截止日期和缺乏私有领域知识无法访问企业内部文档。RAGRetrieval-Augmented Generation检索增强生成通过先检索、再生成的方式优雅地解决了这两个问题。本文将带你从零开始用 Python 搭建一个完整的本地 RAG 智能问答系统覆盖从文档处理、向量存储到检索生成的全链路实现。一、RAG 架构原理1.1 什么是 RAGRAG 的核心思想很简单在让 LLM 回答问题之前先从知识库中检索出相关文档片段然后将这些片段作为上下文一并喂给模型。一个完整的 RAG 流程包含三个阶段用户提问 → [检索] → 召回相关文档片段 → [增强] → 拼接上下文 → [生成] → LLM 生成回答1.2 为什么选择 RAG对比维度直接使用 LLM微调Fine-tuningRAG知识更新成本高需重新训练高需重新微调低更新文档即可私有数据支持不支持支持支持可解释性差差好可追溯来源计算资源需求低高中幻觉控制差一般较好1.3 RAG vs 微调不是非此即彼一个常见的误区是认为 RAG 和微调是对立的。实际上微调改变模型怎么说风格、格式、领域理解RAG决定模型说什么事实、知识、数据在生产环境中两者经常配合使用。二、技术选型2.1 整体架构图┌─────────────┐ ┌──────────────┐ ┌─────────────┐ │ 文档输入 │ ──→ │ 文档处理 │ ──→ │ Embedding │ │ (PDF/TXT/ │ │ (分块/清洗) │ │ 向量化 │ │ MD/DOCX) │ │ │ │ │ └─────────────┘ └──────────────┘ └──────┬──────┘ │ ▼ ┌─────────────┐ ┌──────────────┐ ┌─────────────┐ │ LLM 生成 │ ←── │ Prompt 拼接 │ ←── │ 向量检索 │ │ 回答 │ │ (上下文问题) │ │ (Top-K 召回) │ └─────────────┘ └──────────────┘ └─────────────┘2.2 核心组件选型组件推荐方案备选方案Embedding 模型BAAI/bge-large-zh-v1.5text2vec-base-chinese向量数据库ChromaDB本地轻量FAISS / Milvus / QdrantLLM通义千问 / ChatGLM / GPT任意支持 OpenAI 接口的模型文档解析LangChain TextSplitterUnstructured / LlamaParse框架LangChainLlamaIndex选型建议如果是个人学习或小型项目ChromaDB bge-large-zh 是最佳起步组合零成本、易部署。三、环境准备3.1 安装依赖pipinstalllangchain langchain-community pipinstallchromadb pipinstallsentence-transformers pipinstallopenai pipinstallpypdf3.2 项目结构rag-demo/ ├── data/ # 知识库文档存放目录 │ ├── doc1.pdf │ ├── doc2.txt │ └── doc3.md ├── vectorstore/ # 向量数据库持久化目录 ├── config.py # 配置文件 ├── ingest.py # 文档处理与入库脚本 ├── retriever.py # 检索器 ├── generator.py # 生成器 └── main.py # 主程序入口四、完整代码实现4.1 配置文件# config.pyimportos# Embedding 配置 EMBEDDING_MODELBAAI/bge-large-zh-v1.5# 中文 embedding 模型EMBEDDING_DEVICEcpu# 有 GPU 可改为 cuda# 向量数据库配置 VECTORSTORE_PATH./vectorstoreCOLLECTION_NAMEmy_knowledge_base# LLM 配置 # 使用 OpenAI 兼容接口通义千问/DeepSeek/OpenAI 均可LLM_API_KEYos.getenv(LLM_API_KEY,your-api-key-here)LLM_API_BASEos.getenv(LLM_API_BASE,https://dashscope.aliyuncs.com/compatible-mode/v1)LLM_MODELqwen-plus# 检索配置 CHUNK_SIZE500# 文档分块大小字符数CHUNK_OVERLAP50# 分块重叠保持上下文连贯TOP_K3# 检索返回的文档片段数量4.2 文档处理与入库# ingest.py文档加载、分块、向量化并存入向量数据库importosimportglobfromlangchain_community.document_loadersimport(TextLoader,PyPDFLoader,UnstructuredMarkdownLoader,)fromlangchain_text_splittersimportRecursiveCharacterTextSplitterfromlangchain_community.embeddingsimportHuggingFaceEmbeddingsfromlangchain_community.vectorstoresimportChromafromconfigimport(EMBEDDING_MODEL,EMBEDDING_DEVICE,VECTORSTORE_PATH,COLLECTION_NAME,CHUNK_SIZE,CHUNK_OVERLAP,)defload_documents(data_dir:str./data):加载 data 目录下所有支持的文档loaders_map{.txt:TextLoader,.pdf:PyPDFLoader,.md:UnstructuredMarkdownLoader,}documents[]forfile_pathinglob.glob(os.path.join(data_dir,*)):extos.path.splitext(file_path)[1].lower()loader_clsloaders_map.get(ext)ifloader_clsisNone:print(f[跳过] 不支持的文件类型:{file_path})continueprint(f[加载]{file_path})docsloader_cls(file_path).load()# 为每个文档添加来源元数据fordocindocs:doc.metadata[source_file]os.path.basename(file_path)documents.extend(docs)print(f共加载{len(documents)}个文档页/段)returndocumentsdefsplit_documents(documents):将长文档切分为合适大小的块text_splitterRecursiveCharacterTextSplitter(chunk_sizeCHUNK_SIZE,chunk_overlapCHUNK_OVERLAP,separators[\n\n,\n,。,,,,, ,],)chunkstext_splitter.split_documents(documents)print(f切分为{len(chunks)}个文本块)returnchunksdefget_embeddings():初始化 Embedding 模型returnHuggingFaceEmbeddings(model_nameEMBEDDING_MODEL,model_kwargs{device:EMBEDDING_DEVICE},encode_kwargs{normalize_embeddings:True},)defbuild_vectorstore(chunks,embeddings):构建向量数据库并持久化vectorstoreChroma.from_documents(documentschunks,embeddingembeddings,collection_nameCOLLECTION_NAME,persist_directoryVECTORSTORE_PATH,)print(f向量数据库已保存到{VECTORSTORE_PATH})returnvectorstoredefingest():完整入库流程print(*50)print(开始文档入库流程)print(*50)# Step 1: 加载文档documentsload_documents(./data)ifnotdocuments:print(未找到任何文档请在 data/ 目录下放置文件)return# Step 2: 分块chunkssplit_documents(documents)# Step 3: 向量化并存储embeddingsget_embeddings()build_vectorstore(chunks,embeddings)print(*50)print(文档入库完成)print(*50)if__name____main__:ingest()4.3 检索器# retriever.py向量检索模块fromlangchain_community.vectorstoresimportChromafromconfigimport(VECTORSTORE_PATH,COLLECTION_NAME,EMBEDDING_MODEL,EMBEDDING_DEVICE,TOP_K,)fromingestimportget_embeddingsdefget_vectorstore():加载已有的向量数据库embeddingsget_embeddings()returnChroma(collection_nameCOLLECTION_NAME,embedding_functionembeddings,persist_directoryVECTORSTORE_PATH,)defretrieve(query:str,top_k:intTOP_K): 检索与 query 最相关的 top_k 个文档片段 返回: [(content, source, score), ...] vectorstoreget_vectorstore()resultsvectorstore.similarity_search_with_relevance_scores(query,ktop_k)retrieved[]fordoc,scoreinresults:retrieved.append({content:doc.page_content,source:doc.metadata.get(source_file,unknown),score:round(score,4),})returnretrieved4.4 生成器# generator.pyLLM 生成模块fromlangchain_openaiimportChatOpenAIfromconfigimportLLM_API_KEY,LLM_API_BASE,LLM_MODEL# 系统提示词引导模型基于检索内容回答SYSTEM_PROMPT你是一个专业的知识库问答助手。请严格根据以下检索到的上下文信息来回答用户的问题。 要求 1. 回答必须基于上下文内容不要编造信息 2. 如果上下文中没有相关信息请明确告知根据知识库内容未找到相关信息 3. 回答时请引用信息来源文件名 4. 保持回答简洁、准确、有条理 检索到的上下文信息 {context} defget_llm():初始化 LLMreturnChatOpenAI(modelLLM_MODEL,api_keyLLM_API_KEY,base_urlLLM_API_BASE,temperature0.1,# 低温度保证回答稳定max_tokens2000,)defgenerate_answer(query:str,retrieved_docs:list)-str: 基于检索结果生成回答 # 拼接上下文context_parts[]fori,docinenumerate(retrieved_docs,1):context_parts.append(f[片段{i}] 来源:{doc[source]}\n内容:{doc[content]})context\n\n.join(context_parts)# 构建提示system_promptSYSTEM_PROMPT.format(contextcontext)user_promptf用户问题:{query}# 调用 LLMllmget_llm()responsellm.invoke([{role:system,content:system_prompt},{role:user,content:user_prompt},])returnresponse.content4.5 主程序# main.pyRAG 智能问答系统主入口fromretrieverimportretrievefromgeneratorimportgenerate_answerdefrag_query(question:str)-str:完整的 RAG 问答流程print(f\n{*50})print(f问题:{question})print(f{*50})# Step 1: 检索print(\n[1/2] 正在检索知识库...)retrievedretrieve(question)print(f检索到{len(retrieved)}个相关片段:)fori,docinenumerate(retrieved,1):print(f 片段{i}(相似度:{doc[score]}):{doc[content][:80]}...)# Step 2: 生成print(\n[2/2] 正在生成回答...)answergenerate_answer(question,retrieved)print(f\n回答:{answer})print(f{*50}\n)returnanswerdefinteractive_mode():交互式问答循环print(*50)print(RAG 智能问答系统已启动)print(输入问题开始问答输入 quit 退出)print(*50)whileTrue:questioninput(\n你的问题: ).strip()ifquestion.lower()in(quit,exit,q):print(再见)breakifnotquestion:continuerag_query(question)if__name____main__:interactive_mode()五、运行效果5.1 第一步文档入库将你的文档PDF、TXT、Markdown放入data/目录然后执行python ingest.py输出示例 开始文档入库流程 [加载] ./data/产品手册.pdf [加载] ./data/FAQ.txt [加载] ./data/技术文档.md 共加载 15 个文档页/段 切分为 42 个文本块 向量数据库已保存到 ./vectorstore 文档入库完成 5.2 第二步启动问答python main.py交互示例你的问题: 产品的保修期是多久 [1/2] 正在检索知识库... 检索到 3 个相关片段: 片段1 (相似度: 0.8923): 本产品自购买之日起享受12个月免费保修服务... 片段2 (相似度: 0.7841): 保修范围不包括人为损坏和自然灾害造成的故障... 片段3 (相似度: 0.6512): 如需保修服务请联系就近售后服务中心... [2/2] 正在生成回答... 回答: 根据产品手册本产品自购买之日起享受12个月免费保修服务。 保修范围不包括人为损坏和自然灾害造成的故障。如需保修服务 请联系就近售后服务中心。 来源: 产品手册.pdf六、进阶优化技巧6.1 检索质量优化问题简单的向量相似度检索可能会召回语义相近但答非所问的内容。方案一混合检索Hybrid Search结合关键词检索BM25和语义检索向量取长补短fromlangchain_community.retrieversimportBM25Retrieverfromlangchain.retrieversimportEnsembleRetrieverdefhybrid_retrieve(query,top_k3):混合检索BM25 向量检索# BM25 关键词检索bm25_retrieverBM25Retriever.from_documents(all_chunks)bm25_retriever.ktop_k# 向量语义检索vector_retrieverget_vectorstore().as_retriever(search_kwargs{k:top_k})# 集成检索器各占 50% 权重ensembleEnsembleRetriever(retrievers[bm25_retriever,vector_retriever],weights[0.5,0.5],)returnensemble.invoke(query)方案二查询重写Query Rewriting用 LLM 将用户的口语化问题改写为更适合检索的形式defrewrite_query(original_query:str)-str:用 LLM 重写查询提升检索效果promptf请将以下用户问题改写为更适合检索的简洁关键词形式保留核心语义 原始问题:{original_query}改写后:llmget_llm()returnllm.invoke(prompt).content.strip()方案三重排序Reranking先粗检索召回更多候选如 Top-20再用更精准的模型重排序取 Top-3fromsentence_transformersimportCrossEncoderdefrerank(query:str,candidates:list,top_k:int3):使用 CrossEncoder 对候选结果重排序modelCrossEncoder(BAAI/bge-reranker-large)pairs[(query,doc[content])fordocincandidates]scoresmodel.predict(pairs)rankedsorted(zip(candidates,scores),keylambdax:x[1],reverseTrue)return[docfordoc,_inranked[:top_k]]6.2 分块策略优化不同的分块策略对检索效果影响巨大策略适用场景优点缺点固定长度分块通用场景实现简单可能切断语义按段落/标题分块结构化文档语义完整块大小不均匀递归字符分块混合文档灵活适配需调参语义分块长文/论文语义最优计算开销大6.3 更多优化方向多路召回同时检索多个粒度的分块如 256/512/1024 字符上下文压缩对检索结果做摘要后再喂给 LLM节省 token对话记忆支持多轮对话理解上下文中的指代关系流式输出使用 SSE 实现打字机效果提升用户体验引用溯源在回答中标注每个论断的来源文档和位置七、总结本文从 RAG 的核心原理出发完整实现了一个本地知识库问答系统。回顾关键要点RAG 检索 生成用检索解决知识更新问题用 LLM 解决理解表达问题文档分块是影响检索质量的第一道关卡需要根据文档类型选择策略Embedding 模型直接决定语义检索的精度中文场景推荐 bge 系列混合检索 重排序是生产级 RAG 的标配能显著提升召回质量Prompt 工程不可忽视好的系统提示词能有效抑制幻觉下一步建议尝试将系统部署为 Web 服务FastAPI Streamlit/Gradio接入更多文档类型Word、Excel、网页爬取添加文档管理界面上传、删除、重建索引引入评估体系RAGAS 等框架量化检索和生成质量本文完整代码已开源欢迎 Star 和交流。如果你在实践过程中遇到问题欢迎在评论区讨论参考资料LangChain 官方文档ChromaDB 文档BGE Embedding 模型RAG 论文Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks

相关新闻

终极iOS 15-16设备激活锁绕过指南:5分钟免费解锁iPhone 6s-X

终极iOS 15-16设备激活锁绕过指南:5分钟免费解锁iPhone 6s-X

终极iOS 15-16设备激活锁绕过指南:5分钟免费解锁iPhone 6s-X 【免费下载链接】applera1n icloud bypass for ios 15-16 项目地址: https://gitcode.com/gh_mirrors/ap/applera1n applera1n是一款基于checkm8硬件漏洞的iOS激活锁绕过工具,专门为运…

2026/9/23 7:48:37 阅读更多 →
终极指南:5分钟掌握KMS智能激活脚本的完整使用教程

终极指南:5分钟掌握KMS智能激活脚本的完整使用教程

终极指南:5分钟掌握KMS智能激活脚本的完整使用教程 【免费下载链接】KMS_VL_ALL_AIO Smart Activation Script 项目地址: https://gitcode.com/gh_mirrors/km/KMS_VL_ALL_AIO 还在为Windows系统激活问题而烦恼吗?每次开机看到烦人的激活提醒&…

2026/9/19 18:17:55 阅读更多 →
177、主观评价方法论:双盲测试、ITU-R BT.500标准与专家评审实战

177、主观评价方法论:双盲测试、ITU-R BT.500标准与专家评审实战

177、主观评价方法论:双盲测试、ITU-R BT.500标准与专家评审实战 去年秋天,某旗舰机项目卡在影像调优的最后关口。算法团队把夜景降噪从3.0迭代到7.2版本,客观指标——PSNR涨了0.8dB,信噪比提升明显,但产品经理在评审会上直接拍了桌子:“你们自己看看,人脸纹理像塑料,天…

2026/9/22 15:25:49 阅读更多 →

最新新闻

DKG分布式密钥生成:从原理到工程落地的完整实践指南

DKG分布式密钥生成:从原理到工程落地的完整实践指南

1. 一次密钥单点事故引出的问题:为什么传统托管方案扛不住前阵子帮一个做联盟链基础设施的团队做技术咨询,场景很典型:他们的验证节点集群握着一把“超级私钥”,负责给链上交易做排序签名、给跨链消息做背书验证。这把这个私钥放在…

2026/9/23 16:33:29 阅读更多 →
vega-geo 地理数据变换实战指南:从投影、GeoJSON 到密度等值线完整解析

vega-geo 地理数据变换实战指南:从投影、GeoJSON 到密度等值线完整解析

vega-geo 地理数据变换实战指南:从投影、GeoJSON 到密度等值线完整解析 【免费下载链接】vega A visualization grammar. 项目地址: https://gitcode.com/gh_mirrors/ve/vega 导读 vega-geo 是 Vega 可视化语法(vega 项目)中负责地理…

2026/9/23 16:33:29 阅读更多 →
你与AI之间,隔着一整套认知操作系统

你与AI之间,隔着一整套认知操作系统

大多数人把AI用成了高级搜索。少数人把它用成了实习生。而真正的高手,把它用成了自己思维的延伸器官。这三者之间的差距,不是几个提示词技巧能填平的。它是一整套认知操作系统的代差。网上流传的那些“角色扮演”“给参考”“说人话”之类的技巧&#xf…

2026/9/23 16:33:29 阅读更多 →
使用 Prisma 引导构建基于 Node.js 的 GraphQL 服务端:从 graphql-yoga 到 prisma-binding 的完整实战

使用 Prisma 引导构建基于 Node.js 的 GraphQL 服务端:从 graphql-yoga 到 prisma-binding 的完整实战

后端数据库GraphQL 【免费下载链接】prisma1 💾 Database Tools incl. ORM, Migrations and Admin UI (Postgres, MySQL & MongoDB) [deprecated] 项目地址: https://gitcode.com/gh_mirrors/pr/prisma1 点击查看 免费下载 本篇技术指南基于本仓库&…

2026/9/23 16:33:29 阅读更多 →
零基础学UE5:从蓝图到动画蓝图,新手入门指南

零基础学UE5:从蓝图到动画蓝图,新手入门指南

1. 为什么零基础反而更适合从UE5开始学很多人一听“虚幻引擎5”就觉得门槛高得离谱,觉得自己连代码都没写过几行,怎么可能玩得转这种做3A大作的东西。我刚开始接触的时候也是这个心态,后来真正上手才发现,恰恰是因为零基础&#x…

2026/9/23 16:33:29 阅读更多 →
中小网络组网实战指南:从IP规划到无线漫游与排错

中小网络组网实战指南:从IP规划到无线漫游与排错

简介:这是一份面向中小企业与网络运维人员的网络组网解决方案PDF文档。文档聚焦中小网络建设中“部署简单、管理智能、成本可控”的核心诉求,从企业网络建设背景、需求痛点切入,详细给出信锐中小企业网络的极简交付架构设计:只需网…

2026/9/23 16:32:28 阅读更多 →

日新闻

3招搞定手机怎么下载微信面试难题实战项目解析

3招搞定手机怎么下载微信面试难题实战项目解析

3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A…

2026/9/23 0:00:23 阅读更多 →
2k显示屏性能优化踩坑:版本升级后API全变了,这份源码解析救了我

2k显示屏性能优化踩坑:版本升级后API全变了,这份源码解析救了我

2k显示屏性能优化踩坑:版本升级后API全变了,这份源码解析救了我 刚把开发环境的显示器从1080P换到2K,跑老项目直接报错,版本升级后 API…

2026/9/23 0:01:25 阅读更多 →
3步搞定美眉图实战项目,告别官方文档抓不住重点

3步搞定美眉图实战项目,告别官方文档抓不住重点

3步搞定美眉图实战项目,告别官方文档抓不住重点 官方文档翻了三遍还是云里雾里?别急,美眉图在实战项目中常被用来做数据可视化,但它的原理比你想的简单。今天咱们直接上手,用一个完整的小项目把美眉图跑通,不再死磕那些冗长的理论说明。…

2026/9/23 0:01:25 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/23 4:55:02 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/23 4:49:06 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/23 9:53:41 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/23 9:53:40 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/23 9:53:40 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/23 9:53:40 阅读更多 →