尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

DeepSeek R1本地部署与知识库搭建:从Ollama到Dify实战指南

DeepSeek R1本地部署与知识库搭建:从Ollama到Dify实战指南 简介PDF教程围绕DeepSeek R1的本地部署展开面向想摆脱云端依赖、在个人电脑上运行大语言模型的开发者与普通用户。内容从安装Ollama入手涵盖模型版本选择、命令行验证再到Cherry-Studio界面化配置与密钥创建最后讲解本地知识库的新建、文档添加及对话中调用。教程还针对不同内存容量的电脑给出了相应的模型选型建议例如8GB内存可运行七十亿参数模型16GB内存可运行一百三十亿参数模型32GB内存可运行三百三十亿参数模型方便用户按实际设备灵活选择。整份资源为单个PDF文件约一点四六MB目前已有两千零三十四人学习。对初次尝试本地部署的用户而言这份教程最大价值在于把零散的官方文档整合为可直接跟做的完整流程省去大量搜索与排错时间。1. 先给 DeepSeek R1 本地部署泼盆冷水单卡跑不动原版知识库不是塞 PDFDeepSeek R1 本地部署这个标题十个人里八个是奔着“把 671B 原版塞进自己电脑”来的但真跑过一遍就会明白那个完整权重光下载就要几百 GB显存需求更是直接劝退单卡用户。现实里绝大多数“本地部署 DeepSeek”教程跑的是把 R1 蒸馏或量化过的版本用 Ollama 这类运行时把模型拉起来再配合一个简易本地 RAG 知识库才让它真正能回答“我们自己的文档内容”。这套组合解决两类问题一是数据不出内网二是把一堆格式杂乱的资料变成能检索、能追问、能给出处的问答系统。适合这篇文章的人也很具体手上只有一张 8GB 到 48GB 显卡的个人开发者、需要在内网交付问答应用的实施工程师、以及被“PDF 太多找不到答案”折腾过的人。我不会从零讲大模型原理而是按自己落地时的顺序来写先算硬件和模型档位跑通 Ollama再讲知识库的切块与向量化最后用 Dify 串成完整应用。新手能照着命令走熟手可以直接跳第 5 章的避坑清单和第 6 章的参数调优。2. 从硬件选型到模型拉取跑通 DeepSeek R1 的最小命令2.1 先算账原版、蒸馏版和量化版怎么选DeepSeek R1 的完整权重是 671B 参数的 MoE 模型虽然每次生成只激活约 37B 参数但要装下全部权重模型文件就要占用 350GB 以上推理时显存随手配到 80GB 起步个人电脑基本不用想。这决定了本地部署大语言模型的通行路径要么对原始权重做低比特量化要么直接用官方蒸馏版。Ollama 生态里deepseek-r1系列把这两种形态都打好了标签从 1.5B 到 70B 都有这才是大多数教程里真正能落地的对象。我把常见的档位整理成一张表方便你对着自己的显卡估算。注意体量以拉取时的实际输出为准下面是大致范围模型标识模型文件大小内存/显存建议适合场景deepseek-r1:1.5b约 1.1GB4GB 起步流程验证、嵌入式设备deepseek-r1:7b/8b约 4.9GB8GB 起步日常问答、知识库小规模deepseek-r1:14b约 9GB16GB 起步长文回答、复杂指令deepseek-r1:32b约 20GB32GB 起步更高推理质量能压榨单卡deepseek-r1:70b约 43GB64GB 起步接近完整版体验需多卡或大显存选型的核心原则是“先过内存线再谈质量”。8B 档位适合第一次跑通流程如果显卡在 16GB 以上14B 的综合性价比最高要拿去支撑团队知识库问答32B 和 70B 的效果差距会在长文档、多轮对话里明显拉开。不要一上来就拉 70B本地部署的翻车大部分发生在显存不够、服务被系统 OOM以及后续知识库的向量索引抢占内存上。还有一个很容易混淆的点蒸馏版和量化版不是一回事。蒸馏版是拿 R1 的输出去微调小型模型架构不同但继承了推理风格量化版是同一权重的低精度压缩硬件要求低但回答质量会有折损。Ollama 的deepseek-r1:8b属于蒸馏版真正写量化标签的版本通常要自己用 GGUF 转换工具处理。我建议普通知识库场景直接选 Ollama 的8b或14b省事坑少。2.2 安装 Ollama 并拉取模型最小可运行命令Ollama 是当前本地部署 DeepSeek R1 最省事的运行时。Windows 和 macOS 直接装桌面版安装包Linux 上常见做法是执行官方一键安装脚本之后服务会自动注册成后台进程。装完先确认服务状态终端里执行ollama serve会以前台方式启动正常会看到监听地址127.0.0.1:11434的日志如果服务已经在跑这个命令会提示端口占用那反而是好消息。拉取和启动模型的命令如下# 拉取 8B 蒸馏版模型文件会自动存到 OLLAMA_MODELS 目录 ollama pull deepseek-r1:8b # 启动交互式对话本地没有时会先自动拉取 ollama run deepseek-r1:8b第一次拉取会下载约 5GB 文件取决于网速和磁盘。参数说明8b是模型档位标签想换 14B 就把命令里的8b改成14bOLLAMA_MODELS环境变量可以改模型存储路径建议设到大容量分区避免默认盘被占满。启动后输入?可以看内置帮助输入/bye退出。如果你不想进交互界面Ollama 自带 HTTP API这也是后面 Dify 对接时真正会用到的方式。用一个简单的 curl 验证生成是否可用curl http://localhost:11434/api/generate -d { model: deepseek-r1:8b, prompt: 用一句话说明什么是本地知识库, stream: false }返回 JSON 里的response字段就是模型回答total_duration可以看总耗时。注意stream: false表示等完整回答返回方便快速判断模型有没有跑起来Dify 实际调用会改成流式让对话更跟手。2.3 验证模型真的在工作一次干净的手动调用拉完模型后不要急着搭知识库先用一组固定问题做冒烟测试。我会连续问三个不同类型的问题事实型、逻辑型、开放型。对 DeepSeek R1 系列来说回答里通常会出现一段reasoning_content也就是模型先“思考”再给最终答案这是 R1 家族的标志性行为如果这个能看到说明模型权重加载完整。同时打开第二个终端窗口跑ollama ps看模型是否真正常驻显存ollama ps输出里NAME是模型名SIZE是加载后的体积PROCESSOR列会写100% GPU或GPU/CPU。这一步非常关键如果你看到 CPU 占比很高、GPU 占比很低后面推理一定慢问题多半出在第 5 章要讲的num_gpu配置上。冒烟测试的另一层意义是先建立正确预期8B 模型生成速度平时能到三五十 token 每秒70B 在单卡上可能只有个位数 token 每秒别拿不同档位互相比较。2.4 临时对话界面Open WebUI 或直接用 APIOllama 的 CLI 够用但不适合给人点。常见做法是再起一个 Web 界面最省事的是 Open WebUI一条 docker 命令能带起来docker run -d --name open-webui \ --add-hosthost.docker.internal:host-gateway \ -p 3000:8080 \ -v open-webui-data:/app/backend/data \ ghcr.io/open-webui/open-webui:main镜像体积不小磁盘紧张可以跳过直接用第 2.2 节的 curl 验证就够。我现在一般先不装界面直接进入知识库环节因为后面 Dify 会统一接管对话入口。这里想说明的是模型一旦能以 API 形式被 curl 调用剩下所有工作都是在“召回文本”和“拼 Prompt”DeepSeek R1 本身不再需要改动这一步的长期收益是后面调试知识库时可以随时隔离模型问题。如果你需要局域网内其他设备访问启动 Ollama 时把OLLAMA_HOST设为0.0.0.0:11434即可但要注意这会带来无鉴权访问风险个人用别长期开着。3. 搭建本地知识库前先理解 RAG让召回从玄学变可控3.1 RAG 的完整链路不是把 PDF 喂给模型大模型不知道自己硬盘里那份 PDF 写了什么。要让 DeepSeek R1 基于本地材料回答标准做法是 RAG检索增强生成。这条链路由五个环节组成文档解析、文本切块、向量化、索引存储最后是检索后的生成。很多人一上来就下载 Ollama 和模型把 PDF 往 Dify 里一传发现回答牛头不对马嘴原因就是中间链路没有做可控的调校。在整个链路里召回环节决定了输出上限。模型只会看到你拼进 Prompt 的那几段文本它不会自己翻文件。如果切块把表格拆散、把段落切在半句话上或者嵌入模型把“报销流程”和“财务审批”算成不相似那么后面模型生成得再流畅也是无米之炊。所以这一章我会用一套最小 Python 实现把每个环节的参数空间讲清楚避免知识库变成黑匣子。3.2 文档解析与切块PDF 转文本再按 512/64 切块文档解析是常被省略的一步。直接拿 PyPDF2 抽出来的文本经常每行末尾带换行、表格字段乱序、代码块缩进丢失。我会先在本地把 PDF 转成 Markdown 再入库。工具链里 MinerU 是近期被验证过的方案能让公式和表格保持结构如果不想引入太重的东西下面的 PyMuPDF 脚本能处理纯文本型 PDFimport fitz # PyMuPDF def extract_pdf(path: str) - str: doc fitz.open(path) pages [page.get_text(text) for page in doc] return \n.join(pages) text extract_pdf(manual.pdf) print(len(text), text[:200])get_text(text)会把整页文字按阅读顺序取出对多栏 PDF 的还原还不够好但作为第一版够用。如果 PDF 是扫描图片必须先用 OCR 组件抽文字这一步不能省否则后面向量化等于在给空白文档做索引。拿到纯文本后就要切块。常用的最小参数是chunk_size512字符、overlap64字符我习惯写一个简单的循环函数def chunk_text(text: str, chunk_size: int 512, overlap: int 64) - list[str]: chunks [] start 0 while start len(text): end min(start chunk_size, len(text)) chunks.append(text[start:end]) if end len(text): break start end - overlap return chunks chunks chunk_text(text) print(len(chunks), [len(c) for c in chunks[:3]])参数说明chunk_size控制每块长度512 字符大约能容纳一个完整小节overlap让相邻块共享 64 字符避免关键句子被拦腰切断后两边都不完整。中文场景建议按字符而不是 token 算因为本地嵌入模型按字切更直观。实际工程里可以按 Markdown 标题先做结构切分再把过长小节按上面参数二次切分。表头和数据行如果被切到不同块检索时会漏掉上下文所以我处理含表格的文档时会先把表格单独拆出转成 Markdown 横向长句再入库。3.3 向量化模型与索引存储bge-m3 和 Chroma 的搭配切好的块要转成向量。DeepSeek R1 本身不做嵌入你必须单独准备一个 embedding 模型。选型上我推荐 bge-m3中英文都支持、输出 1024 维向量在本地部署大模型的知识库方案里出镜率最高。加载方式很多最简单的是通过 sentence-transformers 读本地已下载的模型路径from sentence_transformers import SentenceTransformer model SentenceTransformer(/models/bge-m3) # 替换为本地路径 vectors model.encode(chunks, normalize_embeddingsTrue) print(vectors.shape) # (块数, 1024)normalize_embeddingsTrue会把向量归一化这样后续用余弦相似度时分数范围更稳定。编码完了需要落库这里用 Chroma 的本地持久化模式import chromadb client chromadb.PersistentClient(path./kb_cache) collection client.get_or_create_collection( namelocal_kb, metadata{hnsw:space: cosine}, ) collection.add( ids[fchunk-{i} for i in range(len(chunks))], documentschunks, embeddingsvectors.tolist(), ) print(collection.count())参数说明PersistentClient(path)表示数据写到磁盘目录重启用不用重新导入hnsw:space: cosine告诉 Chroma 用余弦距离建索引。如果你的文档量不大这个方案足够等到了几十万片段的规模再考虑 Milvus 这类独立向量库。注意documents和embeddings必须同长度缺一个都会在插入时报错。3.4 检索与问答把召回结果拼进 Prompt 交给 R1向量库建好后问答流程就剩两步先按问题向量召回相关块再把召回文本拼进 Prompt 调 Ollama。查询端的代码很直接query 这个项目怎么配置环境变量 q_vec model.encode([query], normalize_embeddingsTrue)[0].tolist() results collection.query( query_embeddings[q_vec], n_results5, ) context \n\n.join(results[documents][0])n_results5是召回数量这个值值得反复试。文档短就取 3长文档取 5 到 8取太少漏信息取太多 Prompt 变长推理会变慢而且 R1 容易忽略夹在中间的低相关片段。接下来把 context 和问题拼成一个带约束的 Promptprompt f你是本地知识库助手。请只根据参考材料回答不要编造。 如果材料不足以回答就说“材料中没有相关说明”。 参考资料 {context} 问题{query} 回答然后把 Prompt 发给本地 Ollamaimport requests, json resp requests.post( http://localhost:11434/api/generate, json{ model: deepseek-r1:8b, prompt: prompt, stream: False, }, ) reply json.loads(resp.text)[response] print(reply)这一步的意义是把知识库和大模型彻底解耦先召回再生成。这样排查问题时也很容易定位——如果返回的context里根本没有答案问题出在解析或切块如果context有答案但回答乱编问题出在 Prompt 或模型档位太低。4. 用 Dify 把 RAG 串成完整应用Ollama 加 Dify 的本地知识库4.1 Dify 安装与首次启动docker compose 起服务Python 脚本能做验证但要给团队用还是得有个界面。Dify 是目前把知识库、模型、应用编排串起来最常用的脚手架。它的部署方式和开源项目一致先把官方仓库拉下来进入 docker 目录复制环境变量文件然后启动。下面命令里的仓库地址需要替换成你拿到的官方地址git clone Dify官方仓库地址 dify cd dify/docker cp .env.example .env docker compose up -ddocker compose up -d会在后台拉起 API、Worker、Web 前端以及依赖的 PostgreSQL 和向量库。首次启动要拉一堆镜像耗时和网络有关不要一看到日志滚动就 CtrlC。启动完成后浏览器访问http://localhost按页面提示设置管理员邮箱和密码这一步不涉及模型可以先建好账号。4.2 接入 Ollama 模型对话模型和嵌入模型各配一次Dify 的模型供应商体系里Ollama 作为供应商同时能提供 LLM 和 Embedding 两类模型但不能只配一次。你需要分别在“对话模型”和“Embedding 模型”两类角色下各添加一个 Ollama 来源。右上角头像进入设置找到模型供应商选 Ollama然后新增模型。关键参数如下API Base URL 在 Dify 跑在 Docker 容器内时不能填http://localhost:11434那是容器的回环地址会连到自己。Windows 和 macOS 的 Docker Desktop 一般写http://host.docker.internal:11434Linux 下用http://172.17.0.1:11434前提是把 Docker 的默认桥接网段保持原样。这个地址错了会表现为“添加成功但测试一直失败”这是 Dify 本地部署教程里最常见的配置失误。模型类型选LLM时模型名填deepseek-r1:8b上下文长度可以按模型能力填 8192 或更高模型类型选Embedding时模型名填bge-m3需要先在 Ollama 里执行ollama pull bge-m3。注意两类模型的模型名不能混Dify 不会替你判断某个模型到底是对话模型还是嵌入模型你选错角色它也会承认但知识库向量化或对话生成时会报错。4.3 创建知识库分块参数、索引模式和召回范围设置模型配好后进入“知识库”标签页新建知识库上传第 2 章处理过的 Markdown或直接传 PDF。Dify 自带文档解析和切块分段模式一般选“通用”最大分段长度按 token 计我建议设 400 到 800重叠设 50 到 100。这个范围比 Python 版的 512 字符略大因为 Dify 内部按 token 切中文一个 token 大约对应 0.6 到 1 个汉字别被数字一致迷惑。索引方式选“高质量”这样 Dify 会真正调用 embedding 模型生成向量索引而不是走内置的关键词倒排。创建完知识库上传文档后状态会经历“解析中”“索引中”直到显示可用。如果长时间停在“解析中”优先去检查 Embedding 模型是否配好以及 Ollama 是否还在跑这比怀疑文档本身来得快。召回设置在知识库详情或应用编排里都有检索召回模式建议“向量检索”文档少时足够如果文档里有大量精确名词、编号选“全文检索”或“混合检索”更好。Top K 设 3 到 5Score 阈值设 0.3 到 0.5 之间。阈值设太高会把相关片段全部过滤设太低则无关片段混进上下文两个值都需要用真实问题去试。4.4 编排应用让 R1 只依据知识库内容回答知识库建好后进入“应用”新建聊天助手。第一步选模型直接用刚配好的deepseek-r1:8b。第二步在编排页找到“上下文”组件把它拖到提示词部分并选择你刚建的知识库。第三步在系统提示词里写清楚约束“仅根据上下文材料回答上下文无关的信息一律回不知道”这能明显减少编造。完成这些后页面右上角会有预览按钮发一句你真实业务里会问的问题。注意看对话输入框下方是否出现了“召回片段来源”如果来源为空说明没有走到知识库检索去检查上下文组件有没有接到对话模型上。DeepSeek R1 的思维链在这时候可能会把“思考”过程显示出来Dify 里可以在模型参数区通过开关控制是否输出思考过程内网演示时建议关掉最终用户更关心答案不想看一大段自我分析。正式交付前我建议把 Dify 的应用 API 打开。应用设置里会生成一个 API 密钥这样外部系统可以把它当作一个 HTTP 接口来调用知识库细节全部藏在 Dify 后面。这样做的好处是不用把 Ollama 的地址暴露给业务方密钥在界面里可以随时重置复盘时也能通过 Dify 的日志看每次请求命中了哪些知识库片段。日志入口在应用侧边的“日志”页每条对话都带着检索到的上下文来源这是后续调参的重要依据。5. 避坑清单本地部署 DeepSeek R1 和知识库的五个翻车点本地部署这套东西最贵的不是模型文件而是排查问题的时间。下面五个翻车点来自我自己给团队做内网知识库时的真实血泪经验每条按现象、原因、解决的顺序写。如果你照着第 2 到第 4 章跑完还是不对劲先别急着换模型按这个清单逐条对一遍多半能找到根因。5.1 拉模型一直“等待”进度条纹丝不动现象ollama pull deepseek-r1:14b执行后长时间停在 Waiting 或 Received 0 B网络带宽没跑满。原因Ollama 拉模型默认做了分块校验每块都要向仓库确认如果网络不稳定或连接被限速就会反复重试另一个被忽略的原因是OLLAMA_MODELS所在分区空间不足下载任务会一直等磁盘写入。解决先确认磁盘容量df -h如果满了在启动服务前设环境变量OLLAMA_MODELS/data/models并重启 Ollama然后重新ollama pull。网络问题不要盲目等待建议CtrlC中断再重试Ollama 的下载任务支持断点续传已下载的块不会白费。如果你在同一台机器上同时拉多个模型把它们改成逐个拉取并发下载会明显拖慢单个任务的进度。观察是否在下数据最简单的办法是看模型目录体积有没有增长比如du -sh $OLLAMA_MODELS每两分钟看一次而不是只看屏幕上那个百分比。5.2 显存明明够推理却慢到以为死机现象运行 8B 模型时显存占用不到一半但生成速度只有每秒三四个 tokennvidia-smi 里 GPU 利用率也不高。原因Ollama 默认按保守策略计算可用的 GPU 层数当系统里其他程序占了一点显存它就可能把部分层留在 CPU 上CPU 推理单个 token 要几百毫秒到几秒整体速度直接被拖垮。解决在终端停下模型后设置环境变量OLLAMA_NUM_GPU1或者写一个 Modelfile 固化加载策略。这里把常见的 Modelfile 写法贴出来FROM deepseek-r1:8b PARAMETER num_gpu 999 PARAMETER num_ctx 4096然后执行ollama create my-r1 -f Modelfile之后ollama run my-r1。参数说明num_gpu设成 999 表示有多少层就放多少层到 GPU只要显存放得下num_ctx同时影响显存和上下文长度如果 8B 模型设 4096 后显存不够就降到 2048。注意这个参数必须在模型加载前决定运行时修改只能通过环境变量重启服务。5.3 知识库回答得像通灵完全没引用材料现象问“项目启动命令是什么”模型答出一段像模像样但文档里根本不存在的内容。原因多半是召回环节没把正确段落捞上来或捞上来的段落顺序颠倒模型拿到含噪声的上下文后倾向于把看起来顺的内容补全这不是模型“坏”是 Prompt 给了它发挥空间。解决先在 Python 或 Dify 日志里打印实际召回的 documents确认答案是否在里面。如果不在把chunk_size从 800 降到 400overlap从 50 提到 100同时把 Score 阈值从 0.3 提到 0.5如果在但回答不对把 Prompt 的约束写成“只允许引用参考资料中的原句参考资料没有的内容直接回答不知道”。还有一点经常踩知识库索引用 bge-m3后来为了测速度把 Embedding 模型换成别的索引和查询的向量空间不一致检索结果就完全失真。换嵌入模型一定要重建索引不能只改配置。5.4 Dify 里模型显示可用测试却报 401/404现象在 Dify 模型供应商里添加 Ollama 后点测试按钮立刻弹 401 或 404日志里没有任何有效的模型响应。原因最常见的是 API Base URL 写成了http://localhost:11434但 Dify 的后端跑在容器里这个 localhost 指向的是容器自己另一个原因是模型名带了空格或写错版本比如把deepseek-r1:8b写成deepseek-r1Ollama 会把没有 tag 的请求解析成默认标签如果没有默认标签就会 404。解决把 URL 换成http://host.docker.internal:11434Linux 是http://172.17.0.1:11434用ollama list拿到准确模型名后回填。如果仍报 401检查是否误开了 Ollama 的鉴权选项本地 Ollama 默认没有鉴权Dify 页面里的Enable Ollama Auth保持不勾即可。5.5 同时跑多个模型服务卡成死机现象知识库问答用着一个模型后台又有人ollama run deepseek-r1:70b试机几分钟后日常服务开始卡顿甚至容器被 OOM kill。原因Ollama 默认允许同时在显存里放多个模型显存不够就把旧模型移到内存然后重新加载这个过程会产生严重的抖动。解决设置OLLAMA_MAX_LOADED_MODELS1强制只加载一个模型并在不需要时执行ollama stop model释放显存。如果是通过 systemd 或 docker 运行的 Ollama环境变量要写到对应的配置文件里只在终端 export 只在当前终端有效。还要清理不再用的模型ollama rm deepseek-r1:70b会删除模型文件删除前先ollama list确认标签名避免误删正在用的版本。Dify 侧的知识库向量索引也可能占几个 GB 磁盘定期检查kb_cache目录体积重建索引前先清掉旧 collection。6. 把“能跑”调到“好用”先调上下文再调温度最后做回归当模型和知识库都跑通之后收益最大的一件事是调整服务端参数。我给 DeepSeek R1 做本地部署时第一优先是num_ctx。Ollama 默认上下文只有 2048 token知识库召回 5 段文本加一段 Prompt 很容易超限超出的内容会被截断表现就是回答到一半断掉或漏信息。我习惯在 Modelfile 里显式写FROM deepseek-r1:8b PARAMETER num_ctx 8192 PARAMETER temperature 0.6num_ctx不光影响生成长度还直接决定显存占用从 2048 提到 8192显存消耗会增加不少显存不足的机器不要硬提。temperature对 R1 这种已经内置思考链的模型尤其重要知识库问答场景里 0.6 附近最稳设太高会让它把思考过程写成小说设太低又会让回答反复重复同一句。改了之后要重新ollama create一个新标签生效直接ollama run改不了。第二件值得做的是固定测试集。挑 10 到 15 个你在真实工作里会被问的问题比如“报销上限是多少”“这个接口的鉴权方式是什么”每次调完参数跑一遍只记录“是否命中正确的知识库片段”和“回答是否依据片段”不看文采。我的习惯是拿这个测试集同时打 Python 脚本和 Dify两边结果不一致时优先怀疑 Dify 的重排或阈值配置。这样调参不是玄学而是有反馈的回归。第三个进阶动作是混合检索。单靠向量检索对精确编号不友好Chroma 的collection.query只支持向量我一般会额外用一个简单的关键词倒排扫描把命中的文档 ID 加权合并后再排序。不用引用太重的东西Python 里建一个collections.Counter统计词频就能在十秒内带来肉眼可见的改善。本地知识库和 DeepSeek R1 的价值就在这些细节里一点一点抠出来。我自己踩过最深的坑是“模型换大了问题就自然解决”的错觉。知识库效果不好时换 70B 只是让编造内容更流畅真正决定成败的永远是文档解析和召回片段的质量。所以我现在的固定流程是先跑通 8B再上测试集最后才去调模型和向量库参数。这篇方案讲到的做法就是我自己每次重装环境时都会照着走一遍的路径希望帮到你。本文还有配套的精品资源点击获取
返回列表