ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

本地部署DeepSeek指南:Ollama+RAG知识库完整搭建与踩坑记录

本地部署DeepSeek指南:Ollama+RAG知识库完整搭建与踩坑记录 最近 DeepSeek-R1 把大模型的话题带火之后我身边不少朋友都在折腾同一件事用 Ollama 在本地把 DeepSeek 跑起来再搭一个知识库把自己积累的文档变成能聊天的私库。这套组合其实不复杂但细节特别多尤其是环境配置、模型拉取、知识库索引这几个环节稍有疏忽就报错。这篇文章我把自己的实操过程完整梳理一遍包括部署思路、Ollama 的配置、知识库的完整链路以及我踩过的三个典型报错和对应的解决办法希望能帮正在本地部署 DeepSeek 或者纠结知识库怎么搭的人少走弯路。这套方案适合谁两类人最合适一类是手上有私有文档技术手册、论文、行业报告、笔记整理但又不想把内容传到云端的人另一类是刚接触本地大模型想低成本验证 RAG 效果的技术爱好者。全文我会说清楚每一步“为什么这么做”也会给出可以直接抄作业的命令和配置。1. 先想清楚本地跑 DeepSeek 到底图什么1.1 本地部署解决的核心问题本地部署 DeepSeek本质上解决的是三件事数据隐私、成本控制、离线可用。数据隐私这一点最直接。公司内部文档、个人笔记、客户资料只要发到云端 API就等于把内容交给了别人的服务器。虽然很多大厂都承诺数据不用于训练但站在企业和个人隐私角度把文档留在内网让模型在本地读心理上和合规上都要踏实得多。尤其是医疗、金融、法律这些行业数据出境和第三方接口往往是红线本地部署几乎是唯一选择。成本控制也很现实。云端 API 是按 token 计费的普通聊天还好一旦接上知识库每次提问都要把检索到的上下文塞给模型长文档、高频查询场景下费用涨得很快。本地部署是一次性硬件投入加上电费跑个 7B 或 14B 的蒸馏模型用 3060 级别的显卡就能带得动长期用下来比 API 便宜很多。离线可用是另一个容易被忽略的点。内网环境、出差断网、机房隔离这些场景下云端大模型直接失效而本地部署的模型只要机器不关机随时可以回答。这套链路跑通之后我基本把它当成一个永远在线、不偷看数据的“文档助理”。1.2 为什么运行时选 Ollama而不是直接跑 Python很多人会问模型直接用 Transformers 加载不就行了吗为什么要多套一层 Ollama我的答案是Ollama 把大模型运行时的脏活累活全包了包括量化、显存管理、上下文缓存、OpenAI 兼容接口这些自己用 Python 去折腾非常费劲。举个例子如果你用 Transformers 加载一个 7B 模型先得装 PyTorch配置 CUDA处理量化库然后自己写推理循环、管理显存释放稍微没写好就 OOM。而 Ollama 把这些封装成开箱即用的服务一条命令拉模型一条命令跑推理还自带 OpenAI 兼容的/v1/chat/completions接口。这意味着什么意味着你知识库里的代码可以只面向 OpenAI 接口写本地模型和云端 API 可以无缝切换哪天想换模型只需要换一个 base_url。另外Ollama 对显存的管理确实做得不错。它会在执行完一轮推理之后自动释放显存默认 keep_alive 5 分钟不用你去手动清。多模型共存的场景下你甚至可以同时加载 embedding 模型和聊天模型系统会自动调度显存。这一点对后面搭知识库非常关键因为知识库需要 embedding 模型做向量化对话时又需要聊天模型做生成两个模型要同时跑在一台机器上。1.3 知识库的完整链路长什么样知识库的技术路径业内喜欢叫 RAGRetrieval-Augmented Generation检索增强生成。我一直给朋友打一个比方大模型是一个博学但记性差的实习生你的知识库是一堆整理好的参考资料RAG 就是那个“先翻资料再回答”的过程。这条链路分五步文档解析、文本切分、向量化、存储检索、组装回答。文档解析是把 PDF、Word、Markdown、HTML 这些格式转换成纯文本文本切分是把长文档切成一个个固定长度的小块方便检索向量化是让 embedding 模型把每块文本转成一个高维向量存储检索是把所有向量放进向量库提问时把问题也转成向量然后用相似度算法找出最相关的几块文本组装回答是把这些文本和用户问题一起塞给大模型让它基于给定资料作答。这里面每一步都有坑。解析会丢格式切分会把语义切断向量化会选错模型检索会搜出无关内容组装时 Prompt 写不好模型就会瞎编。这篇文章后面会逐个展开实操细节先记住一个结论知识库效果好不好80% 取决于前面检索环节而不是最后那个生成模型。2. 环境准备与 Ollama 部署含模型手动导入2.1 硬件底线和选型建议在动手之前先确认你的机器能跑什么规模的模型。DeepSeek-R1 官方原版是 671B 参数那不是普通机器能跑的大部分人用的都是它的蒸馏小模型1.5B、7B、8B、14B、32B、70B。Ollama 仓库里的 deepseek-r1 系列就是这些蒸馏版本。选多大模型看两样东西显存大小和可容忍的生成速度。我实测的结论是模型规格量化格式模型文件大小建议显存实测感受deepseek-r1:1.5bq4_k_m约 1.1GB4GB 也可跑速度快智力有限适合玩具和 API 测试deepseek-r1:7bq4_k_m约 4.7GB8GB 起步日常问答够用长上下文稍卡deepseek-r1:14bq4_k_m约 9.0GB16GB 推荐推理质量明显更好知识库场景比较舒服deepseek-r1:32bq4_k_m约 20GB24GB 起步接近云端体验但响应速度明显下降deepseek-r1:70bq4_k_m约 42GB48GB 才稳非发烧友不建议本地跑CPU 也不是不能跑纯 CPU 推理 7B 模型大概每秒只能输出几个 token耐心够的话用 Intel 12 代以上加 32GB 内存也能凑合。但老实说体验很差我还是建议至少有一块 NVIDIA 显卡哪怕是 10 系的旧卡也能明显加速。Apple Silicon 用户反过来Mac 的 M 系列统一内存架构跑起来意外地顺M1 16GB 跑 7B 和 14B 都是很舒服的区间。选型的一个重要原则是“显存宁多勿少”。量化格式里我优先推荐 q4_k_m因为它把质量和体积平衡得最好。q2 和 q3 体积更小但明显降智q8 质量高但体积翻倍对消费级显卡不划算。在你最大可用显存范围内选能装下的最大模型加 q4_k_m永远是性价比最高的组合。2.2 Ollama 安装与常用命令Ollama 的安装很简单官方支持 Windows、macOS、Linux。Windows 直接下载安装包就行macOS 也是双击 dmgLinux 官方推荐一行命令但国内下载这个脚本偶尔会慢更稳的办法是去 GitHub Releases 手动下载对应架构的二进制包。装完之后先做两件事确认服务启动确认模型存储位置。确认服务最简单的方法是浏览器打开http://localhost:11434如果能看到Ollama is running就说明正常。命令行里也能验证执行ollama list如果显示NAME ID SIZE MODIFIED的表头说明服务没问题。模型存储位置经常被忽略默认会放在 C 盘的用户目录下一个 14B 模型就是 9GB几个模型下来 C 盘直接飘红。我一直建议把模型目录挪走。在 Windows 上通过系统环境变量加一个OLLAMA_MODELS值指向你希望存放的路径比如D:\ollama\models重启 Ollama 服务后生效。Linux 和 macOS 则在当前用户的 shell 配置里export OLLAMA_MODELS/data/ollama/models。常用命令并不需要记很多列一张速查表命令作用ollama pull 模型名从仓库拉取模型ollama run 模型名启动命令行对话同时自动拉取未下载模型ollama list查看本地已有模型ollama ps查看当前加载了哪些模型以及显存占用ollama stop 模型名停止一个已加载的模型释放显存ollama rm 模型名删除本地模型ollama create 模型名 -f Modelfile从自定义 Modelfile 或本地 GGUF 文件创建模型这里有个小技巧ollama run进对话界面后输入/bye退出如果想看模型的系统提示词和参数输入/?能看到全部斜杠命令。2.3 把 DeepSeek 跑起来命令、参数与量化模型跑起来其实就三步拉模型、跑对话、调参数。拉模型我一般直接指定标签而不是拉默认版本ollama pull deepseek-r1:7b如果你不写后面的:7bOllama 会拉取一个比较大的默认版本尺寸不可控一开始就老老实实写明标签。跑对话更简单ollama run deepseek-r1:7b进去之后可以直接提问。DeepSeek-R1 是推理模型回答之前会生成一段思考过程屏幕上能看到它一边推理一边输出这是正常现象。如果希望生成的回答更稳建议把温度调低。命令行里输入/set parameter temperature 0.6然后重新提问。R1 系列对温度比较敏感0.6 到 0.7 之间效果平衡再高就容易胡说八道。如果你完全不想看到那段思考过程有两个办法一个是换用非推理模型比如 deepseek-v2.5 这类对话模型另一个是在提示词里明确要求“不要展示思考过程直接给出结论”虽然 R1 内部还是会推理但输出层会收敛到答案本身。关于量化前面已经说过建议用 q4_k_m。这里再解释一句Ollama 拉取未指定 quant 标签的模型时一般会给一个有 max 的标签文件体积偏大。如果你显存吃紧可以在拉取时明确指定带q4_k_m的标签或者拉完默认后自己确认实际体积再决定是否换版本。2.4 模型下载慢的替代方案GGUF 手动导入拉取模型时会遇到一个老大难问题官方仓库在国内下载很慢经常几 KB 每秒一个 4.7GB 的文件能下到天荒地老。我踩过这个坑之后现在基本都用“国内模型社区下载 GGUF 文件 手动导入 Ollama”的方式。先到可用性比较好的国内开源模型平台找对应模型的 GGUF 文件比如 ModelScope魔搭社区上有人上传 DeepSeek-R1 蒸馏版的 GGUF 量化文件。注意选和 Ollama 标签匹配的量化版本比如deepseek-r1-7b-q4_k_m-00001-of-00002.gguf这种分卷文件需要把全部分卷下完。下载完成后写一个 Modelfile 让 Ollama 从本地文件创建模型FROM /data/models/deepseek-r1-7b-q4_k_m.gguf PARAMETER temperature 0.6 SYSTEM 你是DeepSeek一个由深度求索创造的智能助手。请基于用户提供的资料和常识尽可能准确、简洁地回答问题。然后在 Modelfile 所在目录执行ollama create deepseek-r1:7b -f Modelfile创建成功后用ollama list确认再ollama run deepseek-r1:7b验证效果。手动导入有几个注意点。第一Modelfile 里的FROM路径必须写绝对路径否则 Ollama 找不到文件第二分卷 GGUF 文件要把所有分卷放在同一个目录下文件名顺序别改第三做完手动导入后最好用ollama show deepseek-r1:7b看一下模型的量化参数是否正确。这个方法还有一个额外的好处你可以把模型文件放到 NAS 或移动硬盘上换机器时把 GGUF 文件和 Modelfile 一起拷过去几分钟就能在新机器上重建模型环境完全不用二次下载。这也是我强烈推荐的方式。3. 知识库搭建从文档到可问答的系统3.1 方案选择Dify 流水线还是 Python 自建知识库的搭建路线我分两种推荐一个是用 Dify 社区版可视化编排一个是 Python 自建完整 RAG 流水线。这两个我都跑过各有适用场景。如果你没有太多代码经验或者想快速出一套带知识库的问答系统Dify 是最优解。它的界面是拖拽式的模型管理、知识库、工作流、应用发布都做成了可视化模块。本地部署 Dify 一般用 Docker Compose官方仓库克隆下来后在项目根目录执行docker compose up -d拉起之后访问本机端口就能进入控制台。在后台把 Ollama 接入模型供应商填上服务地址和模型名再创建知识库上传文档一套系统就算跑通了。整个过程不写一行代码。但如果你对知识库有定制需求比如特定的切分逻辑、专属的检索策略、把结果写入自己的业务系统Dify 反而有点不透亮。这时候 Python 自建更合适。我用的组合是 LangChain 加 Chroma外加在 Ollama 上跑的一个 embedding 模型。代码量不大但每一步都看得见摸得着调参也方便。我个人建议第一次玩知识库先用 Dify 把链路跑通获得直观感受跑通之后再自己写一个几十行的 Python 脚本把核心流程替换成可控代码这样理解最深。3.2 Embedding 模型选型与本地部署知识库里最容易被人忽略的组件是 embedding 模型。很多新手把注意力全放在 DeepSeek 上结果检索效果一塌糊涂其实问题多半出在向量化环节。embedding 模型负责把文本变成向量中文场景我优先推荐bge-m3。它是智源开源的多语言向量模型支持中文效果很好长度上限 8192 token同时支持稠密检索、稀疏检索和多向量检索。Ollama 仓库里有现成的标签ollama pull bge-m3这个模型体积不算大约 1.2GB普通电脑都能跑。另外一个选择是m3e-base体积更小老机器上也能用但综合效果比 bge-m3 略逊一筹。embedding 模型和问答模型是两个独立模型注意别搞混。在一个完整的本地知识库系统里Ollama 上至少挂着两个模型一个bge-m3管向量化一个deepseek-r1管生成回答。Dify 里配置模型供应商时要分别指定聊天模型和 embedding 模型少配一个知识库就起不来。选型上再补一句如果你处理的文档以英文为主可以考虑nomic-embed-text如果以中文为主bge-m3 是最稳妥的选择。向量模型之间的差距在中文场景下经常比聊天模型之间的差距还大这块投资千万别省。3.3 文档切分与向量化实操切分策略决定了检索的下限。切得太碎单块文本信息量不足模型读了也答不好切得太长检索时容易混入大量无关内容反而稀释了关键信息。我实测下来的经验是通用文档用 500 到 800 字符的块大小重叠 50 到 100 字符代码示例、表格、列表这类结构化内容最好单独处理。LangChain 里最常用的是按语义边界切分的 RecursiveCharacterTextSplitterfrom langchain_text_splitters import RecursiveCharacterTextSplitter splitter RecursiveCharacterTextSplitter( chunk_size600, chunk_overlap80, separators[\n\n, \n, 。, , , , ], length_functionlen, ) chunks splitter.split_text(document_text)这里的 chunk_overlap 很关键。文本切分就像把一根长绳剪断重叠的部分相当于绳子头尾各留出一小段避免关键语义正好被剪刀切掉。80 字符是我用的中间值既不会太多导致重复检索也足够保住跨块语义。向量化这一步如果用 LangChain可以这样调用 Ollama 上的 bge-m3from langchain_community.embeddings import OllamaEmbeddings embeddings OllamaEmbeddings( base_urlhttp://localhost:11434, modelbge-m3, )向量化之后就要存进向量库。Chroma 上手最简单不需要单独部署、不需要配置文件数据落在本地目录from langchain_chroma import Chroma vectorstore Chroma.from_documents( documentschunks, embeddingembeddings, persist_directory./chroma_db, )这里多说一句关于“RAG 知识库能存图片吗”的常见疑问。向量库存的是文本的向量不是图片文件本身。图片如果要入库常见做法是先用 OCR 把图片里的文字提取出来把文字交给 embedding 模型向量化图片文件本身可以放在本地目录或对象存储里向量记录里保存一个路径字段。如果你的业务里真的需要图文混合检索那就要引入多模态 embedding 模型本地小模型很难做好建议优先走 OCR 路线。3.4 检索、排序与 Prompt 组装入库只是开始检索才是知识库的命门。提问时先把用户问题向量化然后在库里做相似度搜索得到最相关的若干块文本再把这些文本和问题拼在一起送给 DeepSeek。Chroma 检索的代码非常简单retriever vectorstore.as_retriever( search_typesimilarity, search_kwargs{k: 5} ) docs retriever.invoke(你的问题)k表示返回几个块我建议从 5 开始调。块太大或k太大上下文里塞满太多原文模型容易被无关内容干扰k太小又可能漏掉关键信息。知识库内容越杂k越要谨慎宁可小一点。检索质量的经验是先看相似度阈值。Chroma 默认返回最相似的 5 条未必都相关要加一层过滤比如相似度低于 0.7 的结果直接丢弃。具体阈值要在测试集上调你会发现不同 embedding 模型的距离范围差异很大bge-m3 的结果一般在 0.4 到 0.8 之间需要先跑一条测试看看基值再定。Prompt 组装这块我总结了一个可用性很高的模板核心思想是明确告诉模型只依据资料回答、不能编造、引用来源、超出范围就明说。你是基于知识库回答问题的助手。请严格根据下面提供的资料回答用户问题 1. 如果资料中有答案请直接回答并用 [1][2] 标注来源序号 2. 如果资料中没有答案请明确回答“知识库中未找到相关信息”不要编造 3. 如果资料内容相互矛盾请指出矛盾点。 资料内容 [1] {{chunk_1}} [2] {{chunk_2}} ... 用户问题{{question}}你可以用 LangChain 的 PromptTemplate 来做变量替换再用 LangChain 的 ChatOllama 接口调 DeepSeek 生成最终答案。因为 Ollama 暴露的是 OpenAI 兼容接口代码也可以直接按 OpenAI 客户端的方式写好 base_url这样从本地模型切换到云端 API 只改一个地址非常灵活。3.5 小模型能不能做 RAG我的结论这是一个高频问题尤其是很多人看了卡帕西吐槽小模型做 RAG 之后更纠结。我的结论是小模型完全能做 RAG但你得调整预期。RAG 的本质是“先检索后生成”它把模型不知道的知识显式地塞进上下文。DeepSeek-R1 7B 这类模型参数量虽然小但在“读资料回答”这个任务上是过关的。实测下来一个 7B 模型接上优质检索结果回答质量可以和 70B 模型裸答不相上下只要资料找得准、Prompt 写得稳、模型不瞎编。小模型的短板主要体现在三个地方长上下文理解能力弱、逻辑链稍长就崩、推理速度慢。所以用 7B 模型做知识库时检索一定要精准不要给它塞太长的资料单次注入控制在 1200 字左右效果最好问题也别设计得太复杂拆成多个子问检索会更稳。如果显存允许我还是建议直接上 14B。它在长上下文和多轮追问上的表现比 7B 好一个档次而知识库问答恰恰是长上下文场景14B 是本地部署甜点位。4. 三个真实报错与排查过程4.1 报错一Ollama 拉模型超时context deadline exceeded这是我从官方仓库直接拉模型时遇到的第一个报错报错信息长这样Error: pull model manifest: Get https://registry.ollama.ai/v2/...: context deadline exceeded出现这种情况本质是 Ollama 默认从官方源拉取网络质量差的时候 manifest 或 blobs 下载直接超时。你重试多少次都差不多因为它不是服务器问题是链路问题。我最终解决的方式是放弃官方拉取改用 GGUF 手动导入就是前面 2.4 节写的流程。这里补充两个容易忽略的细节。第一Modelfile 创建出来的模型名字最好不要带官方标签里那种多层前缀直接用deepseek-r1-local这种自定义名免得和官方源模型混淆。第二手动导入后ollama list能看到模型但ollama run的时候如果报model not found八成是你ollama create打错了名字或者没有在正确的目录下运行命令。检查方法很简单ollama list看输出里实际模型名再ollama run 实际模型名。另外给一个提速技巧ollama pull虽然慢但如果你能保持网络稳定也未必完全不能用。我试过凌晨时段拉取7B 模型勉强能跑完但这只能算是玄学不推荐作为主要方案。4.2 报错二知识库连不上 Ollama连接被拒启动 Dify 之后在模型设置里填 Ollama 地址时很多人会报连接失败错误提示类似Failed to connect to Ollama at http://127.0.0.1:11434这个问题我排查了很久原因是端口绑定和容器网络的组合问题分三种情况。第一种Ollama 服务确实没启动。Windows 下安装 Ollama 之后它会在后台运行但偶尔服务挂掉不提示。先到命令行执行ollama serve看能不能正常启动再试试ollama list。第二种Dify 在 Docker 容器里跑容器内访问宿主机的127.0.0.1指向容器自己不是你的宿主机。Docker for Mac 和 Docker for Windows 的解决方案是改用host.docker.internalhttp://host.docker.internal:11434Linux 下 Docker 需要额外加参数才能支持host.docker.internal否则直接用宿主机内网 IP 也行。第三种Ollama 默认只监听127.0.0.1容器访问宿主机 IP 依然连不上。需要把 Ollama 的监听地址改成0.0.0.0。Windows 在环境变量里加OLLAMA_HOST0.0.0.0:11434然后重启 Ollama 服务。这里提醒一句把监听地址暴露到内网之后同一个局域网里的其他机器也能访问你的模型接口了如果不希望这样记得在防火墙里限制来源 IP。4.3 报错三MySQL 1064 语法错误第三个报错比较有意思不是发生在模型上而是发生在知识库的元数据存储环节。我的自建知识库脚本里文档向量存在 Chroma元数据文档名、来源、标签、入库时间存在 MySQL。往 MySQL 插入元数据的时候报错信息ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near key, value) VALUES ... at line 1一眼看过去是 SQL 语法错误但真正原因有两个我都遇到过。第一个原因是表字段命名踩了保留字。我建表时有一个字段叫key还有一个字段叫value这俩都是 MySQL 保留字。解决方法是给字段名加反引号CREATE TABLE document_chunks ( id INT PRIMARY KEY AUTO_INCREMENT, key VARCHAR(255), value TEXT, doc_name VARCHAR(255), ... );更建议直接改字段名不要用key这种保留字。改成chunk_key和chunk_value后面所有查询和插入都会清爽很多。第二个原因是客户端把多行 SQL 按分号截断了。我第一次测试时用 Python 脚本执行一段多行建表 SQL结果只执行了第一行后面的语句被当成新语句报错信息看起来像语法错误实际是执行逻辑问题。解决方法是检查 Python 驱动执行多语句 SQL 时是否真的把整段指令发过去了或者干脆把建表语句拆成单条执行。排查 1064 这类报错我的固定套路是三步。第一步SELECT sql_mode;看看当前 SQL 模式部分模式组合会放大语法兼容性差异第二步把最终执行的 SQL 原样打印出来人眼检查一遍很多时候问题就出在字段名和引号上第三步把 SQL 拿到 Navicat 或命令行客户端里手动执行一次如果客户端能执行、代码里报错那就是驱动或拼接的问题。4.4 报错速查表把三个报错整理成速查表方便你直接对照报错现象根本原因解决动作pull model manifest 超时官方源下载慢、链路超时国内平台下 GGUF写 Modelfile 手动导入Failed to connect to Ollama服务未启动 / 容器网络隔离 / 监听地址不对启动服务Docker 用 host.docker.internalOLLAMA_HOST0.0.0.0ERROR 1064 语法错误字段名是保留字 / 多语句执行截断加反引号或改字段名拆分 SQL打印完整语句人工检查排查时还有一个通用思路把所有组件拆开单独测。先测 Ollama 服务本身通不通再测 embedding 模型能不能向量化再测向量库能不能检索最后测大模型能不能生成。链路里每一环单独验证一遍问题基本就能定位到具体位置不用盯着一个报错瞎猜。写在最后这套环境我跑了大概两周最大的体会是本地知识库真正值钱的不是模型有多大而是检索质量有多好。当你把文档切分、embedding 选型、检索阈值这些细节调到位之后一个 14B 的 DeepSeek-R1 配合 bge-m3已经能非常靠谱地回答私有文档问题而这个过程里没有一条数据离开你的机器。最后再分享一个我觉得特别实用的小技巧如果你经常用 Obsidian 管理笔记、用 Trae 写代码、或者想把微信公众号文章沉淀进知识库不用搞什么复杂爬虫。公众号文章用浏览器打印成 PDFObsidian 笔记直接导出 Markdown全部丢进知识库的文档目录写一个定时脚本统一解析入库就行。这样一份“第二大脑”就能持续生长而不是布置完就吃灰。等哪天你的文档量突破了千篇量级再去研究重排、混合检索、多路召回那些高级玩法也不迟先把基础链路用起来。
返回列表