从零搭建本地 RAG 知识库:Ollama + LangChain 处理私有文档的完整实践
去年开始接触大模型应用开发时第一个遇到的实际问题就是怎么让模型回答我自己的文档内容直接把文档塞进提示词里肯定不行——上下文窗口就那么大几十页 PDF 根本放不下。后来才了解到 RAG检索增强生成是解决这个问题的标准做法。这里把从零搭建一个本地 RAG 系统的完整过程记录下来所有组件都是开源的数据不出本机。一、什么时候需要自己搭 RAG内部知识库问答公司有几十份技术文档、产品手册想让 AI 基于这些文档回答问题个人笔记检索自己写了半年的工作笔记想用自然语言找到相关内容敏感数据不外传文档涉及客户信息或商业机密不能上传到 ChatGPT 等云端服务定制化回答想让模型基于特定的技术规范或行业标准来回答问题RAG 的核心思路很简单先把文档拆成小块chunk并向量化存起来用户提问时把问题也向量化去库里找到最相关的几块内容连同问题一起丢给 LLM 去回答。模型不是记住了你的文档而是每次都在你的文档里查到答案再回答。二、方案一本地部署 RAGOllama LangChain ChromaDB这是今天要搭建的方案完全本地运行数据不出机器。环境准备# 安装 OllamamacOS / Linux curl -fsSL https://ollama.com/install.sh | sh # Windows 去官网下载安装包 # 下载一个本地模型7B 参数普通电脑够用 ollama pull qwen2.5:7b # 安装 Python 依赖 pip install langchain langchain-community chromadb pypdf sentence-transformers第一步文档加载与分割from langchain_community.document_loaders import PyPDFLoader from langchain.text_splitter import RecursiveCharacterTextSplitter from pathlib import Path def load_documents(doc_dir: str): 加载指定目录下的所有 PDF 文档 docs [] for pdf_file in Path(doc_dir).glob(*.pdf): print(f加载文档: {pdf_file.name}) loader PyPDFLoader(str(pdf_file)) docs.extend(loader.load()) print(f共加载 {len(docs)} 页) return docs def split_documents(docs, chunk_size500, chunk_overlap100): 将文档切分成小块块之间保留重叠 splitter RecursiveCharacterTextSplitter( chunk_sizechunk_size, chunk_overlapchunk_overlap, separators[\n\n, \n, 。, , , , , ] ) chunks splitter.split_documents(docs) print(f分割为 {len(chunks)} 个文本块) return chunks # 使用示例 documents load_documents(./my_docs) chunks split_documents(documents)chunk_size和chunk_overlap是两个需要调的核心参数。我试了不同组合chunk_sizechunk_overlap效果20050块数多但上下文容易断长段落被切碎500100平衡大部分场景适用1000200块数少但一次性返回的信息量大500/100 的组合对大多数技术文档表现比较平衡。第二步向量化存储from langchain_community.embeddings import HuggingFaceEmbeddings from langchain_community.vectorstores import Chroma # 使用本地 embedding 模型不需要联网 embeddings HuggingFaceEmbeddings( model_nameBAAI/bge-small-zh-v1.5, model_kwargs{device: cpu}, encode_kwargs{normalize_embeddings: True} ) def build_vector_store(chunks, persist_dir./chroma_db): 构建向量数据库并持久化到磁盘 vector_store Chroma.from_documents( documentschunks, embeddingembeddings, persist_directorypersist_dir ) vector_store.persist() print(f向量库已保存到 {persist_dir}) return vector_store vector_store build_vector_store(chunks)初次运行会下载 bge-small-zh-v1.5 模型到本地~/.cache/huggingface/目录之后离线也能用。向量库保存在./chroma_db目录下下次启动可以直接加载不需要重新处理文档。第三步检索与问答from langchain_ollama import OllamaLLM from langchain.chains import RetrievalQA from langchain.prompts import PromptTemplate # 连接 Ollama 本地模型 llm OllamaLLM( modelqwen2.5:7b, temperature0.3, num_predict2048, ) # 创建检索器每次返回最相关的 4 个文本块 retriever vector_store.as_retriever(search_kwargs{k: 4}) # 自定义提示模板 prompt_template 你是一个技术文档助手请基于以下文档内容回答问题。 文档内容 {context} 问题{question} 请用中文回答如果文档中没有相关信息请直接说文档中没有找到相关信息不要编造答案。 prompt PromptTemplate( templateprompt_template, input_variables[context, question] ) # 组装 QA 链 qa_chain RetrievalQA.from_chain_type( llmllm, chain_typestuff, retrieverretriever, return_source_documentsTrue, chain_type_kwargs{prompt: prompt} ) # 开始问答 def ask(question: str): result qa_chain.invoke({query: question}) print(f回答: {result[result]}) print(f\n参考来源: {len(result[source_documents])} 个文档片段) for i, doc in enumerate(result[source_documents], 1): print(f [{i}] {doc.metadata.get(source, 未知)} 第{doc.metadata.get(page, ?)}页) return result ask(我们的产品支持哪些导出格式)第四步用 Gradio 搭个简单的 Web 界面import gradio as gr def answer_question(question, history): result qa_chain.invoke({query: question}) sources \n.join([ f- {doc.metadata.get(source, ?)} 第{doc.metadata.get(page, ?)}页 for doc in result[source_documents] ]) return result[result] f\n\n**参考来源**\n{sources} with gr.ChatInterface( answer_question, title本地知识库助手, description基于私有文档的问答系统所有数据在本地运行, themesoft, ) as demo: demo.launch(server_name0.0.0.0, server_port7860)跑起来后浏览器打开 http://localhost:7860 就能用。我往里面塞了 5 份产品技术文档共 120 页问如何配置数据备份大概 3-4 秒出答案比翻 PDF 快多了。适合有 Python 基础、需要处理私密文档、希望完全掌控数据流向的场景。不太适合不想折腾环境配置、只需要在线问答一次性的场景。三、方案二Dify 社区版——Web 界面可视化搭建如果不想写代码Dify 是一个开源MIT 协议的 LLM 应用开发平台提供了可视化的 RAG 工作流编排界面。# 使用 Docker 部署 git clone https://github.com/langgenius/dify.git cd dify/docker cp .env.example .env docker compose up -d启动后访问 http://localhost:3000创建知识库 → 上传文档支持 PDF、TXT、Markdown、网页抓取系统自动切分文档并向量化内置 embedding 模型创建对话型应用 → 关联知识库 → 发布 API 或 Web 页面Dify 的切分策略比手动调参友好——提供了通用和父子切分两种模式。父子切分是比较实用的功能父块包含完整段落子块是小片段用于精确检索检索到子块后把父块内容送给 LLM既命中准了又保留完整上下文。Dify 还支持多用户权限管理如果部门里几个人都要用同一个知识库Dify 比脚本方案方便。适合不想写代码、需要 Web 管理界面、团队协作使用。不太适合需要深度定制检索逻辑、或者不想引入 Docker 依赖的场景。四、方案三使用 LangChain 自建 API 服务如果想把 RAG 能力封装成 API 供其他系统调用可以基于 FastAPI LangChain 搭建推理服务from fastapi import FastAPI, HTTPException from pydantic import BaseModel from typing import List, Optional import uvicorn app FastAPI(titleRAG API Service) class QueryRequest(BaseModel): question: str top_k: Optional[int] 4 class SourceInfo(BaseModel): source: str page: int content_preview: str class QueryResponse(BaseModel): answer: str sources: List[SourceInfo] app.on_event(startup) async def startup(): 启动时加载模型和向量库 global qa_chain qa_chain init_qa_chain() # 复用前文的初始化函数 app.post(/ask, response_modelQueryResponse) async def ask_question(request: QueryRequest): if not request.question.strip(): raise HTTPException(status_code400, detail问题不能为空) result qa_chain.invoke({query: request.question}) sources [] for doc in result[source_documents]: sources.append(SourceInfo( sourcedoc.metadata.get(source, 未知), pagedoc.metadata.get(page, 0), content_previewdoc.page_content[:100] )) return QueryResponse(answerresult[result], sourcessources) if __name__ __main__: uvicorn.run(app, host0.0.0.0, port8000)API 跑起来后其他系统可以这样调用curl -X POST http://localhost:8000/ask \ -H Content-Type: application/json \ -d {question: 如何安装和配置系统, top_k: 3}返回结果包含回答和引用来源可以在前端展示带引用的答案。适合需要将 RAG 能力嵌入到现有系统、需要多人多系统调用的场景。不太适合只需要一次性的问答需求方案一更直接。五、选型建议维度Python 脚本方案Dify 社区版FastAPI 自建服务代码量中等约 100 行零代码中等约 200 行部署复杂度Python 环境即可需要 DockerPython ASGI 服务器Web 界面Gradio 可选自带完整 UI需自建前端定制灵活度高可改任意环节中受限于平台功能高全栈可控团队协作单机支持多用户需自建用户体系文档更新需手动重建向量库支持增量更新需自实现更新逻辑embedding 模型本地 BGE本地或云端本地 BGE怎么选个人的技术文档需要做问答——Python 脚本方案100 行代码搞定想怎么调就怎么调团队内部要共享知识库且不想写前端——Dify 社区版开箱即用要把 RAG 能力嵌入已有的产品系统——FastAPI API 方案封装成微服务供其他模块调用六、几个实践中的坑chunk_size 不是越大越好我一开始设了 2000结果一个问题返回的内容填满了上下文模型反而抓不住重点。中文用 bge 系列 embedding试过用英文 embedding 模型处理中文文档检索准确率明显下降。source 信息要保留刚开始没保存文档来源信息模型回答的内容缺少可追溯性不敢直接用。加了 source_documents 后效果好很多。首次加载慢是正常的bge 模型下载 文档向量化初次运行要几分钟后续加载 Chroma 的持久化数据就快多了。七、总结RAG 是目前落地大模型应用最务实的方案——它不需要微调模型不需要昂贵的 GPU 训练只需要把文档处理好、向量库搭起来、检索策略调优就能让模型基于你的数据回答问题。从 Python 脚本到可视化平台再到 API 服务不同的复杂度对应不同的场景自己评估一下需求和资源选性价比最高的方式开始。搭完第一个 RAG 系统之后你会发现让 AI 理解我的文档这件事没有想象的那么复杂。本文涉及的组件Ollama、LangChain、ChromaDB、Dify、Gradio均为开源项目可在各自官方仓库查阅最新文档。

相关新闻

2026-07-30 AI 新闻汇总

2026-07-30 AI 新闻汇总

1. 1122名前沿AI公司员工联署"Pacing the Frontier"请愿书,呼吁美国政府建立机制以在必要时放缓AI研发节奏 7月28日,来自OpenAI、Anthropic、谷歌、Meta等近12家前沿AI公司的 112211221122 名员工联合签署名为"Pacing the Frontier"…

2026/10/17 5:11:50 阅读更多 →
Linux内核学习路线图2026:从入门到内核贡献者的知识体系与资源索引

Linux内核学习路线图2026:从入门到内核贡献者的知识体系与资源索引

Linux内核学习路线图2026:从入门到内核贡献者的知识体系与资源索引 作者:钟伊人(钟哩哩)日期:2026年7月31日标签:Linux内核、操作系统、内核开发、学习路线 模块一:为什么2026年仍要深入学习Lin…

2026/10/17 18:24:25 阅读更多 →
钟哩哩的8月预告:AI产品化Deep Dive系列、Linux内核专栏与创业工具链评测

钟哩哩的8月预告:AI产品化Deep Dive系列、Linux内核专栏与创业工具链评测

钟哩哩的8月预告:AI产品化Deep Dive系列、Linux内核专栏与创业工具链评测 作者:钟伊人(钟哩哩)日期:2026年7月31日标签:8月预告、AI产品化、Linux内核、创业工具链、内容规划 模块一:7月亮相总结…

2026/10/16 4:02:56 阅读更多 →

最新新闻

GitHub 开源趋势日报 | 2026年10月8日:AI Agent 与 TypeScript 项目实战配置指南

GitHub 开源趋势日报 | 2026年10月8日:AI Agent 与 TypeScript 项目实战配置指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 19:43:30 阅读更多 →
插入排序为何在工程中比冒泡更受欢迎?

插入排序为何在工程中比冒泡更受欢迎?

1. 项目概述:从一道经典面试题切入真实工程选择逻辑“为什么插入排序比冒泡排序更受欢迎?”——这道题常出现在算法入门课的期末卷、校招笔试的选择题第3题,甚至某次技术面中面试官随口一问。但如果你真以为这只是在考“谁交换次数少”或者“…

2026/10/18 19:43:30 阅读更多 →
Claude Code 权限模式完全指南:Auto、Bypass、Ask 三模式深度解析与 TaoToken 接入实践

Claude Code 权限模式完全指南:Auto、Bypass、Ask 三模式深度解析与 TaoToken 接入实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 19:43:30 阅读更多 →
Unity3D快抢红包互动小游戏开发全流程:从玩法设计到真机适配踩坑记录

Unity3D快抢红包互动小游戏开发全流程:从玩法设计到真机适配踩坑记录

做活动互动开发的人应该都有感觉,需求方现在越来越不满足于“摇一摇”“扫码抽奖”这种老套路,点名要的往往是更有画面感、更刺激的玩法。Unity3D 快抢红包互动小游戏这类项目,就是在这种需求里反复出现的类型:大屏上倒计时跳动&a…

2026/10/18 19:43:30 阅读更多 →
本地化AI代码评审系统:Java静态分析与GLM-4双通道实践

本地化AI代码评审系统:Java静态分析与GLM-4双通道实践

简介:这是一套面向Java中高级开发者与AI工程实践者的代码质量提升工具,聚焦于利用人工智能技术实现Java代码的自动化评审与漏洞识别,适用于CI/CD集成、团队代码规范统一及个人代码健壮性自查等场景。资源共34个文件,含24个Java核心…

2026/10/18 19:43:30 阅读更多 →
Cursor Agent 文件写入频繁要求确认 — 排查记录与 TaoToken 配置实践

Cursor Agent 文件写入频繁要求确认 — 排查记录与 TaoToken 配置实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 19:42:30 阅读更多 →

日新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 0:55:02 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →