
简介面向希望在自有环境中运行DeepSeek的技术爱好者、企业IT管理者与开发者这份PDF文档围绕数据安全、自主可控与垂直场景定制展开系统梳理模型背景、硬件与软件准备、部署流程、常见问题及进阶应用思路。内容对显存、内存、CPU选型给出分档建议并涉及Ollama运行框架、CUDA加速配置等关键环节适合具备一定深度学习基础、关注私有化AI落地的读者对照实践。包内共1个PDF文件约586KB篇幅精炼便于按章节查阅部署要点与排错线索。已有701人学习说明其在本地大模型部署话题上具有一定参考价值。读者可从中获得从环境评估到模型运行的完整知识框架理解医疗辅助诊断、金融风控、教育推荐等场景下的定制思路并掌握保障敏感数据不出本地、按业务需求调整模型表现的实践方向。1. 断网那天我才明白本地部署 DeepSeek 的价值给一个内部知识库做问答验证时对方提了一个硬要求整个过程不能出内网。那台机器上没有任何在线大模型接口可用最后是靠本地部署的 DeepSeek 把流程跑通的。从拉起模型到拿到第一段生成结果前后不到二十分钟——这件事让我对「本地部署」这四个字的看法变了它不是什么极客玩具而是数据不出门前提下唯一能把大语言模型塞进业务流程的办法。这篇笔记面向三类人手里有独立显卡、想把自然语言处理能力接到自己程序里的开发者需要对敏感文本做摘要、抽取、分类又不能上传的从业者以及刚接触大语言模型、想先在自己机器上跑通一次完整链路的新手。往下读你会看到一个真实的取舍过程显存怎么算、档位怎么选、装完之后怎么验证它真的在吃 GPU以及那几个几乎人人都会踩的坑。2. 先算显存再谈模型DeepSeek-R1 蒸馏版的档位与硬件配比选型这件事我见过太多人反过来做——先把几十 GB 的模型拉下来跑不动了再回头查显存。正确顺序是反的先量自己机器的显存和内存再倒推能跑哪个档位。这一章把账算清楚后面安装和拉取才有意义。2.1 参数量、量化精度与显存的三元账大语言模型落盘的文件大小和它加载进显存后占用的空间不是一回事但高度相关。业界常见做法是用 4bit 量化Q4_K_M 这一类来压缩权重压缩比大致是每个参数 0.55 到 0.65 字节。按这个系数一个 7B 模型落盘大约 4.7GB加载时权重部分占 4.5GB 上下。真正把显存吃掉的还有三块KV Cache、上下文缓冲、推理框架自身的开销。KV Cache 随上下文长度线性增长一个 7B 模型在 8K 上下文下KV Cache 可能吃掉 1 到 2GB上下文拉到 32K这一项会翻几倍。所以在显存这件事上最朴素也最够用的估算式是显存需求 ≈ 参数量(B) × 0.6 KV Cache 1.5GB 框架余量按这个式子推1.5B 模型落在 3GB 以内4GB 显存能松快地跑7B 模型约 6.5GB8GB 显存是舒适线6GB 会紧14B 模型约 11GB16GB 显存刚好12GB 就得靠部分层卸载到内存32B 模型超过 22GB24GB 显存是起点32GB 才谈得上从容。这里有个容易被忽略的点显存不够不等于跑不起来。推理框架会把放不下的层卸载到系统内存靠 CPU 补算代价是生成速度断崖式下跌——从每秒二三十个 token 掉到每秒两三个。这也是为什么很多人「跑起来了但慢得没法用」本质是没算清这笔账。提示把上面公式里的「参数量 × 0.6」当成下限不要当下限加一点余量就完事。实际部署时按估算值再上浮 20%留给上下文和并发。2.2 四档模型的取舍从 1.5B 到 32BDeepSeek-R1 蒸馏系列有几个常用档位落到具体硬件上取舍关系是这样的档位落盘体积约舒适显存内存建议典型用途1.5B1.1–1.3GB4GB8GB短文本分类、意图识别、格式化抽取7B / 8B4.7–5GB8GB16GB日常问答、文档摘要、代码片段补全14B9GB 左右16GB32GB长文分析、多轮对话、中等复杂度推理32B20GB 左右24–32GB64GB专业领域长文档、复杂逻辑链推理1.5B 这一档常被嫌弃「太笨」但它在结构化任务上的表现被严重低估了。我做过一组对比把一段工单文本抽成固定 JSON 字段1.5B 在给足 few-shot 示例后字段完整率能到九成以上而耗时只有 7B 的三分之一。如果你的场景是「批量处理十万条文本抽字段、打标签」1.5B 才是正解7B 反而浪费。7B 是真正的甜点位。它能在消费级显卡上跑出可用的速度同时具备一定的多步推理能力——比如让它读一段两百行的配置指出其中的逻辑矛盾7B 能给出方向大致正确的答案1.5B 基本会跑偏。14B 往上就要认真考虑投入产出比了。14B 相比 7B 的提升主要体现在长上下文里的信息保持能力和复杂指令的遵循度上。如果你的任务是「读完一份几十页的文档回答跨章节的问题」那 7B 会频繁丢信息14B 才够用。32B 则基本是工作站级别的选择普通台式机跑它要么慢要么爆显存。选型的实操建议别一步到位。先用 7B 把整条链路跑通——接口、前端、业务逻辑都接上确认流程没问题再考虑换大模型。链路没通就上大模型出了问题你分不清是模型不行还是集成不对。2.3 内存、CPU 与磁盘的隐性门槛绝大多数教程只讲显存实际上内存和磁盘更容易让人翻车。系统内存的下限是能装下整个模型文件。哪怕模型全部跑在 GPU 上加载过程中也会在内存里解包一次。7B 模型配 16GB 内存是够的但如果同时开着浏览器几十个标签页、IDE、几个容器16GB 会吃紧表现为加载到一半卡住或者被系统杀掉进程。我一般建议跑 7B 给 32GB跑 14B 给 32GB 起步并关掉不必要的大户程序。CPU 的作用在两种情况下会被放大。第一种是纯 CPU 推理——没有独显的笔记本或者服务器这时候核心数和内存带宽直接决定速度多核高频的处理器能明显改善体验。第二种是显存刚好不够、需要卸载部分层时CPU 会承担一部分计算此时它就成了瓶颈。所以买机器的时候别只看显卡处理器的主频和内存通道数也会影响最终手感。磁盘空间是第三个坑。模型目录会随拉取次数线性膨胀——你试了 1.5B、7B、14B 三个档位加起来就是十几个 GB。系统盘本来就紧张的话很容易在下到一半的时候报磁盘写入失败。我的习惯是装完框架第一件事就把模型目录改到数据盘具体做法在第 3 章讲。还有一个隐性指标是磁盘类型。机械硬盘加载 7B 模型要等一两分钟固态硬盘十几秒就绪。如果你打算频繁切换模型做对比这个差距会累积成很大的时间成本。3. 用 Ollama 把模型跑起来安装、拉取、验证的三段式Ollama 这类运行框架的价值在于把「下载权重、加载到显存、起一个 HTTP 服务、处理流式输出」这一整套脏活封装成几条命令。它的定位有点像容器运行时之于应用——你不需要关心底层的层分配和显存管理只要告诉它跑哪个模型。代价是可控参数变少了但对绝大多数场景够用。3.1 三平台安装与版本自检Windows 下直接跑安装包一路下一步即可。需要提前知道的是安装向导里没有修改安装路径的入口程序本身会装到系统盘。这不是死路模型权重可以单独搬走但程序主体占的空间不大真正吃盘的是模型。所以装之前先确认 C 盘有 5GB 以上可用空间这只是保证安装能完成模型的事后面单独处理。macOS 是拖拽安装把应用拖进应用程序目录就完事。Linux 用一行脚本# Linux 一键安装脚本会自动注册系统服务 curl -fsSL https://ollama.com/install.sh | sh # 确认服务已起来而不是只装了个二进制 systemctl status ollama三条路径装完之后验证方式统一开一个终端敲版本号。# 版本号能打出来说明二进制在 PATH 里且可执行 ollama -v # 再确认 HTTP 服务在监听默认端口 11434 curl -s http://localhost:11434/ # 期望返回Ollama is running这两步要分开看。ollama -v成功只证明客户端可用curl那一步返回Ollama is running才证明后台服务起来了。我在 Linux 上遇到过服务没启动、客户端却能敲出版本号的情况最后是靠systemctl status发现服务被禁用开机自启手动systemctl start ollama才通的。注意Windows 上装完之后Ollama 会以托盘程序的形式常驻关掉窗口不等于关掉服务。想彻底停掉得从托盘退出否则端口会一直被占着。3.2 拉取模型与模型目录搬迁拉取模型的命令是ollama pull后面跟模型名和标签。标签不写的话默认取latest这个行为要小心——不同时间点latest指向的版本可能不同做可复现的验证时一定把标签写死。# 显式指定标签避免 latest 漂移 ollama pull deepseek-r1:7b # 拉完看一眼本地都有什么SIZE 列是落盘体积 ollama list # 拉下来之后直接进交互模式 ollama run deepseek-r1:7bollama run的语义是「有就加载没有就先拉再加载」所以很多人图省事直接run。这在试探阶段没问题但在脚本里我建议拆成两步pullrun因为run会把下载进度和交互提示混在一起出问题不好定位。模型默认存放位置Windows 在用户目录下的.ollama\modelsmacOS 和 Linux 在~/.ollama/models。要搬家改环境变量OLLAMA_MODELS指向新目录然后重启服务。这里有个血泪经验直接剪切文件夹再改环境变量Ollama 会认不出来必须让它自己往新目录里重新拉一次或者把整个目录结构原样搬过去并保证权限一致。# Linux/macOS临时生效验证新目录可用 export OLLAMA_MODELS/data/ollama/models ollama pull deepseek-r1:1.5b # 确认模型确实落到了新位置 ollama listWindows 上则是在系统环境变量里新增OLLAMA_MODELS值填绝对路径然后从托盘退出 Ollama 再重新启动。改完一定要ollama list复核如果列表变空了说明路径没生效或者权限不对。顺带说一个离线场景的处理方式把已经拉好的整个 models 目录打包拷到目标机器的同位置ollama list能直接识别。这招在内网机器上特别管用——你不需要目标机器能访问外网只要目录结构一致就行。3.3 命令行交互与 HTTP 端点验证进到提示符之后直接提问就行。但命令行交互只适合验证真要接到业务里走 HTTP 接口。Ollama 默认在 11434 端口起服务提供两种调用方式自己的原生接口和 OpenAI 兼容接口。# 原生生成接口stream 设 false 便于一次性拿到完整结果 curl http://localhost:11434/api/generate -d { model: deepseek-r1:7b, prompt: 把下面这段话压缩成一句话……, stream: false, options: { temperature: 0.3 } }这段请求里model必须和ollama list里显示的完全一致包括标签stream设成false是为了调试方便生产环境的对话场景通常保持流式否则用户要盯着空白等好几秒options里的采样参数逐请求生效不写就吃模型默认值。返回体是一个 JSON正文在response字段里。另一个更通用的入口是兼容接口# 走 OpenAI 兼容路径方便直接复用现有 SDK curl http://localhost:11434/v1/chat/completions -d { model: deepseek-r1:7b, messages: [{role: user, content: 解释一下什么是 KV Cache}] }这条路径的意义在于任何为 OpenAI 接口写好的客户端、框架、工具链只要把 base_url 改成http://localhost:11434/v1api_key 随便填个非空字符串就能直接打到本地模型上代码几乎不用改。迁移成本极低这是本地部署方案里最划算的一点。验证「真的在用 GPU」这件事别靠感觉看ollama ps的 PROCESSOR 列# 模型加载后执行看算力分配 ollama ps # NAME ID SIZE PROCESSOR UNTIL # deepseek-r1:7b xxxx 5.2 GB 100% GPU 4 minutes from now如果显示100% GPU说明全部层在显存里显示100% CPU或者百分比混合说明有层被卸载了速度会打折。这一列是判断「我到底该不该换小模型」最直接的依据比任何跑分都实在。4. 避坑与排查五类必翻车的现场下面这五条是我自己和身边人在不同机器上重复踩过的。按「现象 → 原因 → 解决」写遇到对得上的直接照方抓药。4.1 安装与拉取阶段的三处暗礁坑一Windows 安装报「无法创建目录」装到一半回滚。现象是安装程序弹出错误框提示创建目录失败然后自动退出。原因基本只有一个系统盘可用空间不足。安装包解压、程序文件、以及默认的模型目录都会往系统盘写虽然程序本体不大但安装器会预留一块余量空间不够就直接拒绝。解决方式是先清出至少 5GB再重装如果系统盘实在腾不出空间装完之后立刻把OLLAMA_MODELS指向数据盘别等模型下到一半才发现盘满了。坑二执行ollama list | grep deepseek什么都没输出以为模型不存在。这是个认知偏差不是故障。ollama list的语义是「列出本地已下载的模型」它不会去远端搜索。新装的环境里这个列表本来就是空的管道给grep之后自然什么都没剩下。正确的做法是直接ollama pull你要的标签或者到模型库页面上确认标签名拼写。我第一次遇到时在这条命令上耗了十几分钟后来想想纯粹是把list当成了search。反过来说ollama list在排查时非常有用拉取报错之后先看列表里有没有半成品有的话它会占着几十 GB 空间得先ollama rm name清掉再重拉否则会一直失败。坑三拉取卡在「pulling manifest」或者下到 80% 断掉。现象是进度条长时间不动或者中途报连接中断。原因通常有两个一是网络质量差导致大文件传输中断二是磁盘剩余空间不足写到一半写不进去。排查顺序是先看磁盘df -h或资源管理器再考虑网络。解决上重新执行同一条ollama pull命令即可已下载的层会被复用不会从头再来——这一点很多人不知道以为断了就得重下几十 GB其实是增量续传。如果反复在同一个位置失败先ollama rm清掉这个标签再重新拉。残留的临时层有时候会让续传逻辑卡住清一次比反复重试有效。4.2 运行阶段的两类硬故障坑四CUDA out of memory或者跑起来但每秒只吐两三个字。这两种表现是同一个根因的两面显存不够。前者是加载阶段就放不下后者是部分层被卸载到内存靠 CPU 补算。判断方法很简单ollama ps看 PROCESSOR 列不是100% GPU就说明有卸载。解决路径按代价从低到高排先把上下文长度压下来默认上下文可能给到 4K 甚至更高改成 2048 能省下可观的 KV Cache再关掉其他吃显存的程序浏览器硬件加速、设计软件、其他推理进程都会抢还不行就降档14B 换 7B、7B 换 1.5B。最后才是考虑并发控制——如果同时有多个请求打进来每个请求都要一份 KV Cache两三个并发就能把 8GB 显存吃干净把并发数限制为 1 是应急手段。还有一种隐蔽情况显存明明够但一加载就报内存不足。这是系统内存在解包阶段被耗尽任务被系统杀掉。加内存或者关掉后台大户比调模型参数有效。坑五终端输出一堆乱码中文全变成方块和问号。现象是模型返回的内容在命令行里显示为÷ËÍ(cid:0)(cid:11)ºåzý这类字符串。原因不是模型坏了是终端编码和输出流编码对不上。Windows 的旧版命令提示符默认用 GBK 代码页而模型输出是 UTF-8中间没有做转换就成这样了。解决分两步先把当前终端切到 UTF-8 代码页再确认字体支持中文。# Windows 命令提示符里执行65001 代表 UTF-8 chcp 65001如果chcp之后仍然是乱码换终端——Windows Terminal 或者新版 PowerShell 默认就是 UTF-8直接用它们替代老 cmd 即可。这个问题纯粹影响观感不影响 API 返回的 JSON 内容所以如果你是通过程序调用而不是在终端里看可以完全忽略它。顺带一提端口被占用的情况也常出现curl http://localhost:11434/没响应但进程明明在跑。多半是上一次没有正常退出旧进程还占着端口。换个端口启动设置OLLAMA_HOST127.0.0.1:11435比找进程杀进程更快代价是后面所有调用地址都要跟着改。5. 从命令行到 Web 界面OpenWebUI 接入与接口封装命令行验证通过之后下一步通常是给非技术同事一个能点的界面或者把模型能力封成自己程序里的一个函数。这两条路可以并行界面交给 OpenWebUI程序集成走兼容接口。5.1 虚拟环境与依赖隔离这类 Web 前端依赖相当多直接往系统 Python 里装早晚会和别的项目打架。老老实实建虚拟环境这是我踩过几次依赖冲突之后养成的习惯。# 建一个独立环境避免污染全局 site-packages python -m venv openwebui_env # Windows 激活 openwebui_env\Scripts\activate # macOS / Linux 激活 source openwebui_env/bin/activate # 确认 pip 指向的是虚拟环境内部 python -m pip -V最后那条命令的输出路径里应该包含openwebui_env如果还是指向系统目录说明激活没生效先解决这个再往下走。Python 版本建议 3.11 及以上低版本在装某些依赖时会卡在编译阶段。激活之后安装本体# 首次安装耗时较长依赖体积不小 pip install open-webui # 验证安装 open-webui --version如果下载慢可以临时指定镜像源但注意镜像源的可信度别为了速度换来一堆来源不明的包。安装完成后不要急着启动先确认 Ollama 服务是活的——前端只是壳模型能力全在后面的 Ollama 上。5.2 启动服务并指向本地端点# 默认监听 8080数据落在一个本地的 sqlite 里 open-webui serve启动之后浏览器访问http://localhost:8080第一次进会要求注册一个本地账号这个账号只存在本机数据库里和任何在线服务无关。关键在于模型配置。进入设置里的模型服务配置把地址指向http://localhost:11434保存之后模型列表会自动刷新出来。如果列表是空的按这个顺序排查先在浏览器里直接开http://localhost:11434/看有没有Ollama is running再看地址写的是localhost还是127.0.0.1某些环境下这两者解析结果不同换成127.0.0.1反而能通最后确认容器化部署时有没有把宿主机地址写错——如果 OpenWebUI 跑在容器里localhost指的是容器自己必须换成宿主机的实际可达地址。这一步配通之后非技术同事就能在网页上选模型、开对话、传文档做检索问答体验和在线服务差不多但所有数据都在本机。5.3 用兼容接口接入自己的程序程序集成这条线更简单因为不用改代码结构只换 base_url。下面这段用官方 SDK 的写法几乎可以直接抄from openai import OpenAI # 指向本地 Ollama 的兼容端点api_key 只要非空即可 client OpenAI( base_urlhttp://localhost:11434/v1, api_keylocal, ) resp client.chat.completions.create( modeldeepseek-r1:7b, messages[ {role: system, content: 你是文本抽取助手只输出 JSON不要解释。}, {role: user, content: 从下面的工单里抽取设备型号、故障现象、处理结果……}, ], temperature0.1, # 抽取类任务压低随机性 max_tokens512, # 限制输出长度防止模型自我发挥 ) print(resp.choices[0].message.content)几个参数值得说清楚。base_url结尾的/v1不能省SDK 会在后面拼/chat/completions。api_key本地服务不校验但不能不传SDK 会在客户端侧做非空检查。temperature在抽取、分类这类任务上要压到 0.1 到 0.2模型才不会自作主张改写字段名。max_tokens是防止模型在 JSON 后面继续写解释文字的有效手段配合 system 里的强约束能让输出干净很多。如果要做批量处理别开多线程硬怼。本地模型的并发能力受显存限制两三个并发就能把 8GB 显存榨干反而更慢。串行处理加一个合理的超时比并发靠谱得多。真要提高吞吐正确的做法是换成更小的模型而不是加大并发。6. 调参与验证把 temperature、num_ctx 和并发拧到合适的位置模型跑通只是开始能不能用得舒服取决于参数有没有调对。这一章给几个我反复验证过的取值区间以及一套能重复跑的检查流程。6.1 采样参数的组合边界temperature是最常被滥调的参数。0.7 这个「默认值」在很多场景下是错的抽取、分类、格式转换这类任务要的是确定性取 0.1 到 0.2开放写作、头脑风暴要的是多样性0.8 到 1.0 才合适日常问答 0.5 左右最舒服。同一个模型换个 temperature主观感受能差出一整个档位。和它配合的是top_p控制候选词的累积概率阈值。我的习惯是只调其中一个另一个保持默认——两个一起改出问题你根本不知道是哪个起的作用。这些参数怎么落地命令行里那个--options的写法在很多版本上并不生效别在这上面浪费时间。可靠的两种方式是 Modelfile 和请求体# 方式一用 Modelfile 固化一套参数生成自己的模型变体 cat Modelfile EOF FROM deepseek-r1:7b PARAMETER temperature 0.2 PARAMETER num_ctx 4096 PARAMETER top_p 0.9 EOF # 从 Modelfile 构建之后用 my-extract 这个名字调用 ollama create my-extract -f Modelfile ollama run my-extractModelfile 的好处是参数跟着模型名走业务代码里只写模型名不用每次拼参数也便于版本管理——改参数就是改这个文件。适合「一类任务固定一套参数」的场景。# 方式二请求级覆盖适合同一个模型跑不同任务 curl http://localhost:11434/api/generate -d { model: deepseek-r1:7b, prompt: ……, stream: false, options: { temperature: 0.1, num_ctx: 4096, num_predict: 256 } }请求级覆盖更灵活代价是每次都要带。我的做法是稳定的业务用 Modelfile 固化调试和实验走请求级覆盖两者不混用。6.2 上下文长度的隐性代价num_ctx是第二个容易调错的参数。默认值往往比你实际需要的更大而它直接决定 KV Cache 的大小。从 8192 降到 4096显存占用能省下一大截在 8GB 卡上这就是「能跑」和「跑不动」的分界线。判断该给多少的方法很土但有效统计你实际输入的平均长度取它的两倍再向上取到 2048 的整数倍。一份三千字的文档做摘要输入大概两千 token输出留五百4096 完全够用硬套 32768 纯属浪费显存。代价是双向的。上下文设太小长文档会被截断模型只看了后半段就作答答案看起来头头是道实际上漏了关键信息——这种错误最危险因为不报错。所以处理长文档时我宁可把上下文设大一点同时接受速度变慢也不愿意让它悄悄截断。6.3 一份可重复的回归清单换模型、改参数之后光凭「感觉回答变好了」是不够的。我固定用一组任务做回归五分钟跑完能挡住大部分回退检查项输入特征通过标准指令遵循要求输出纯 JSON无多余解释文字可被json.loads解析长文保持跨章节提问答案引用的信息确实出现在对应章节拒答边界询问知识范围外的事明确说不知道不编造细节速度基线固定 200 字输入首 token 延迟与总耗时不劣于上一版 20%显存占用ollama ps观察PROCESSOR 列保持100% GPUimport json, time from openai import OpenAI client OpenAI(base_urlhttp://localhost:11434/v1, api_keylocal) def check(prompt: str, must_be_json: bool False) - dict: t0 time.time() r client.chat.completions.create( modelmy-extract, # 用 Modelfile 固化过参数的变体 messages[{role: user, content: prompt}], temperature0.1, max_tokens512, ) text r.choices[0].message.content cost time.time() - t0 ok True if must_be_json: try: json.loads(text) # 解析失败说明指令遵循不过关 except Exception: ok False return {ok: ok, cost: round(cost, 2), head: text[:60]} for p, j in [(输出设备型号的 JSON……, True), (跨章节问题……, False)]: print(check(p, j))这段脚本的价值不在代码本身而在于把「好不好用」变成了可比较的数字。每次换模型或者改参数跑一遍看ok有没有从 True 变 False、cost有没有明显上涨。我吃过一次亏换了档位更大的模型主观觉得回答质量上去了跑完回归才发现 JSON 解析通过率从九成掉到六成原因是新模型更爱在 JSON 前面加一句「好的以下是结果」。这种问题靠肉眼扫几眼根本发现不了。从那以后我每次动模型或参数都强制把这张表走一遍哪怕只改了一个temperature。希望这套流程能帮到你少在「感觉变好了」和「实际变差了」之间来回折腾。本文还有配套的精品资源点击获取