
1. 为什么我要从“API 打工人”变成“本地优先玩家”1.1 一个让我彻底醒悟的账单瞬间去年年底我负责的一个内部知识助手项目跑得正顺日活不高但稳定。直到某天早上打开后台发现当月 API 消耗已经超了预算的三倍。排查下来原因很朴素一个批量文档摘要任务被误触发几千份 PDF 在半小时内把上下文窗口塞满token 像流水一样往外淌。那一刻我意识到把核心能力完全押在按量计费的云端 API 上本质上是在给 API 打工——你写的每一行代码、跑的每一次推理都在为别人的计费器添砖加瓦。这不是说云端 API 不好。它的模型能力强、维护成本低、上手快对于验证阶段的项目几乎是唯一理性选择。但一旦进入稳定运行期尤其是涉及内部文档、客户资料、代码仓库这类敏感数据时“本地优先、云端兜底”就从一个技术选项变成了架构刚需。本地跑得动的任务本地跑本地搞不定的难题再交给云端既控成本又保隐私还能在断网时保持基本可用。这套思路落地下来我最终选定的组合是Dify Ollama DeepSeek。Dify 负责编排和工作流Ollama 负责本地模型托管DeepSeek 作为云端兜底和高质量推理的补充。整套平台跑在 Docker 里迁移和备份都方便。下面我把这套东西从选型到落地、从踩坑到调优的完整过程拆开讲适合已经用过一两次大模型 API、想进一步掌控自己技术栈的开发者也适合团队里负责基础设施的同学参考。1.2 这套组合到底解决了什么问题先把价值说清楚免得读者跟着搭完发现不是自己想要的。第一成本可控。本地 Ollama 跑推理不产生按量费用只有电费和硬件折旧。日常的问答、摘要、分类、信息抽取这类任务7B 到 14B 级别的模型完全够用没必要每次都调用云端大模型。第二数据不出内网。Dify 的知识库、工作流、对话记录全部落在自己的服务器上Ollama 的推理也在本地完成。只有明确需要云端兜底的那部分请求才会把脱敏后的内容发出去。第三断网可用。本地模型一旦拉取完成整个问答链路不依赖外网。对于内网环境或者网络不稳定的场景这一点比什么都重要。第四可替换性强。Dify 支持多种模型供应商接入Ollama 支持任意 GGUF 格式模型DeepSeek 的 API 也是标准 OpenAI 兼容格式。任何一环想换改动量都不大不会被某一家锁死。注意这套方案不是要完全取代云端 API而是把“什么时候用本地、什么时候用云端”这个决策权拿回自己手里。全本地化在效果上一定有妥协全云端化在成本和隐私上一定有风险混合才是稳态。2. 选型背后的逻辑为什么是 Dify、Ollama 和 DeepSeek2.1 Dify 的角色不只是聊天界面很多人第一次接触 Dify 以为它就是个开源的聊天前端其实它的核心价值在工作流编排和知识库流水线。你可以把 Dify 理解成一个可视化的 LLM 应用开发平台拖拽节点就能搭出一条“接收问题 → 检索知识库 → 组装上下文 → 调用模型 → 格式化输出”的完整链路不需要自己写胶水代码。我选 Dify 而不是自己用 FastAPI 手搓主要看中三点。一是知识库流水线开箱即用文档上传、分段、向量化、检索这一套它都封装好了省掉大量调试时间。二是变量聚合器和条件分支这类节点让复杂逻辑不用写代码就能表达团队里非技术同学也能看懂流程。三是模型供应商抽象层做得好同一个工作流里可以同时挂本地 Ollama 模型和云端 DeepSeek 模型按节点切换这正是“本地优先、云端兜底”需要的底层能力。Dify 的部署方式有几种社区版用 Docker Compose 拉起是最省事的。它自带 PostgreSQL、Redis、Weaviate 这些依赖一条docker compose up -d就能跑起来。这里有个细节Dify 的镜像体积不小第一次拉取会比较慢建议提前配好镜像加速或者在有网络的环境下拉好镜像再导出到目标机器。2.2 Ollama 的角色本地模型的“应用商店”Ollama 最大的贡献是把本地大模型的部署门槛降到了几乎为零。以前跑一个开源模型要处理 CUDA 版本、量化格式、推理框架、显存分配一堆事现在ollama run deepseek-r1:7b一条命令就完事。它内置了模型下载、量化、推理服务、API 暴露这一整套对开发者极其友好。我选 Ollama 而不是 vLLM 或者 llama.cpp 直接上手理由是维护成本。vLLM 吞吐高但配置复杂对显存要求也高llama.cpp 灵活但需要自己编译和调参。Ollama 在易用性和性能之间取了个很好的平衡点对于个人和小团队场景它是性价比最高的选择。而且 Ollama 默认就在11434端口暴露 OpenAI 兼容接口Dify 接入时几乎不用改配置。Ollama 的模型存储路径默认在用户目录下Linux 是/usr/share/ollama/.ollama或~/.ollamaWindows 是C:\Users\用户名\.ollama。模型文件动辄几个 GC 盘很容易被撑爆。修改模型存储路径是部署后第一件要做的事具体方法后面实操部分会讲。2.3 DeepSeek 的角色云端兜底与质量天花板本地模型再强遇到复杂推理、长上下文、多步规划这类任务和云端旗舰模型还是有差距。DeepSeek 在这里扮演两个角色一是质量兜底当本地模型置信度低或者任务复杂度高时把请求转给云端二是能力补充比如需要处理超长文档、需要更强的代码生成能力时直接走云端。DeepSeek 的 API 是 OpenAI 兼容格式接入 Dify 时选“OpenAI 兼容”供应商填上 base URL 和 API Key 就行。它的定价在同类模型里算很有竞争力的配合本地兜底策略整体成本能压到纯云端方案的零头。这里要提醒一点不要把敏感数据直接发给云端。我的做法是在 Dify 工作流里加一个脱敏节点把姓名、手机号、身份证号、内部项目代号这类信息替换成占位符再决定是否走云端。这个节点用 Dify 的代码节点几行 Python 就能实现后面会给出示例。2.4 三者组合的架构全景把这三个东西串起来整体架构是这样的接入层Dify 提供 Web 界面和 API用户通过浏览器或外部系统调用。编排层Dify 工作流决定每个请求走本地还是云端负责知识库检索、上下文组装、结果格式化。推理层Ollama 跑本地模型DeepSeek 提供云端推理。存储层PostgreSQL 存业务数据向量库存知识库索引Ollama 存模型文件。运行层全部跑在 Docker 里用 Docker Compose 编排。这个架构的好处是每一层都可以独立替换和扩展。想换向量库改 Dify 配置想加本地模型Ollama 拉一个就行想换云端供应商Dify 里加一个供应商配置即可。3. 从零搭建Docker 环境与依赖准备3.1 Docker 安装的坑与正确姿势整套平台跑在 Docker 上所以第一步是把 Docker 装好。这一步看似简单但我在不同系统上踩过的坑足够写一篇长文。Windows 用户装Docker Desktop是最省事的但要注意几个点。一是需要开启 WSL2 后端否则性能会差很多。二是在安装过程中如果遇到 “Docker Desktop installation failed” 或者启动后一直转圈大概率是 WSL2 内核没更新去微软官网下载最新的 WSL2 内核更新包装上就好。三是 Docker Desktop 默认把镜像和容器数据存在 C 盘如果 C 盘空间紧张要在设置里把磁盘镜像位置改到其他盘。Linux 用户直接用包管理器装 Docker Engine 就行Ubuntu 下大概是sudo apt update sudo apt install -y docker.io docker-compose-plugin sudo systemctl enable --now docker sudo usermod -aG docker $USER最后一行是把当前用户加入 docker 组避免每次敲命令都要 sudo。执行完要重新登录一次才生效。注意国内网络环境下拉取 Docker 镜像可能会很慢甚至超时。建议在 Docker 配置里加上镜像加速地址具体地址各云厂商都有提供配置在/etc/docker/daemon.json的registry-mirrors字段里改完重启 Docker 服务。3.2 Dify 的 Docker Compose 部署Dify 官方提供了 docker-compose.yaml直接拉下来改改就能用。我的做法是先建一个目录把 compose 文件和.env文件放进去git clone https://github.com/langgenius/dify.git cd dify/docker cp .env.example .env然后编辑.env重点改这几个地方。EXPOSE_NGINX_PORT是 Web 访问端口默认 80如果 80 被占用就改成别的。数据库密码、Redis 密码这些默认值建议改掉尤其是部署在公网可访问的机器上时。SECRET_KEY一定要换成随机字符串这个用于加密敏感信息。改完执行docker compose up -d第一次启动会拉取一堆镜像包括 PostgreSQL、Redis、Weaviate、Nginx、API、Worker、Web 等耐心等几分钟。启动完成后访问http://你的IP:端口应该能看到 Dify 的初始化页面设置管理员账号密码就能进去了。这里有个常见问题Dify SSL 错误。如果你在 Dify 里配置了 HTTPS 访问或者通过反向代理转发可能会遇到证书验证失败。排查思路是先确认证书链完整再确认 Nginx 配置里的proxy_set_header有没有把 Host 和协议头正确传递。如果是自签证书Dify 内部调用时可能不信任需要在容器里把证书加到信任列表或者干脆在内网环境用 HTTP。3.3 Ollama 的安装与模型存储路径迁移Ollama 的安装更简单。Linux 下一条命令curl -fsSL https://ollama.com/install.sh | shWindows 和 macOS 直接下载安装包。安装完ollama serve会作为服务自动启动监听11434端口。模型存储路径迁移是我强烈建议做的第一件事。默认路径在系统盘模型一多就爆。Linux 下修改 systemd 服务配置sudo systemctl edit ollama.service在打开的编辑器里加上[Service] EnvironmentOLLAMA_MODELS/data/ollama/models然后sudo systemctl daemon-reload sudo systemctl restart ollama。Windows 下则是设置系统环境变量OLLAMA_MODELS指向新的目录重启 Ollama 服务。迁移完把旧目录里的模型文件挪过去或者干脆重新拉。这里提醒一句ollama 下载太慢是高频问题尤其是拉大模型的时候。可以在拉取前先确认网络或者用ollama pull的断点续传特性中断了重新执行会接着下。如果实在慢找一台网络好的机器拉好模型把整个 models 目录打包拷过来放到对应路径下 Ollama 就能识别。3.4 拉取适合本地跑的 DeepSeek 模型Ollama 上的 DeepSeek 系列有多个尺寸选哪个取决于你的硬件。我的经验是模型规格显存需求适用场景推荐硬件deepseek-r1:1.5b2GB 左右简单分类、抽取笔记本核显deepseek-r1:7b6GB 左右日常问答、摘要入门独显deepseek-r1:14b12GB 左右复杂推理、代码中端独显deepseek-r1:32b24GB 左右高质量推理高端独显deepseek-r1:70b48GB 以上接近云端质量多卡或大内存拉取命令就是ollama pull deepseek-r1:7b把 7b 换成你要的规格。拉完用ollama run deepseek-r1:7b测试一下能正常对话就说明本地推理链路通了。提示如果显存不够Ollama 会自动把部分层放到内存里跑速度会慢但能跑起来。不过内存占用会飙升8GB 内存的机器跑 7b 模型会比较吃力建议至少 16GB。4. Dify 接入 Ollama 与 DeepSeek 的完整配置4.1 在 Dify 里配置 Ollama 供应商Dify 默认的模型供应商列表里就有 Ollama。进入“设置 → 模型供应商”找到 Ollama点配置。关键是Base URL这一项。如果 Dify 和 Ollama 跑在同一台机器上但 Dify 在 Docker 里Ollama 在宿主机上那么 Dify 容器里访问宿主机要用host.docker.internalWindows/macOS或者宿主机的内网 IPLinux。填http://host.docker.internal:11434或者http://192.168.x.x:11434。填完点保存如果配置正确Dify 会自动拉取 Ollama 里已有的模型列表。如果报错 “an error occurred during credentials validation”八成是网络不通。排查步骤先在 Dify 的 API 容器里curl一下 Ollama 的地址确认能通再确认 Ollama 的OLLAMA_HOST环境变量是不是绑定了0.0.0.0默认只绑127.0.0.1的话容器访问不到。配置成功后在 Dify 的模型列表里就能看到deepseek-r1:7b这类模型可以设为默认对话模型或者在工作流里按节点选用。4.2 配置 DeepSeek 云端供应商DeepSeek 的接入走“OpenAI 兼容”这条路。在模型供应商里选 OpenAI但把 Base URL 改成 DeepSeek 的 API 地址API Key 填你在 DeepSeek 平台申请的密钥。模型名称填deepseek-chat或deepseek-reasoner具体看你要用哪个。这里有个容易踩的坑模型名称必须和供应商那边完全一致多一个空格都会报 “no api key for provider route” 这类错误。另外如果你在 Dify 里同时配了多个 OpenAI 兼容供应商要注意区分别把请求发错地方。配置完建议在 Dify 的“模型测试”里发一条消息验证确认能正常返回再往下走。4.3 工作流里实现“本地优先、云端兜底”这是整套方案的核心逻辑。在 Dify 的工作流里我一般这样设计第一步问题分类节点。用一个轻量本地模型判断用户问题的类型和复杂度输出一个标签比如“简单”“中等”“复杂”。第二步条件分支。根据标签决定走哪条路。“简单”和“中等”走本地 Ollama 模型“复杂”走 DeepSeek 云端。第三步本地推理节点。调用 Ollama 的 deepseek-r1:7b设置合理的上下文长度和温度参数。第四步质量校验节点。用一个代码节点检查本地模型的输出比如长度是否过短、是否包含“我不知道”这类兜底话术、是否触发了敏感词。如果校验不通过走云端重试。第五步云端兜底节点。调用 DeepSeek把原始问题和本地模型的输出一起发过去让云端模型做修正或补充。第六步结果聚合。把最终答案返回给用户同时记录这次请求走了哪条路方便后续统计本地命中率。这个设计的关键在于分类节点的准确性。分类错了要么该本地的走了云端浪费钱要么该云端的走了本地效果差。我的经验是分类节点用规则加小模型结合的方式规则处理明显简单的比如短问题、常见 FAQ小模型处理模糊地带。4.4 知识库流水线的搭建要点Dify 的知识库是它的一大卖点。上传文档后它会自动分段、向量化、建索引。但默认配置不一定适合所有场景有几个参数值得调。分段长度默认是 500 字符左右对于技术文档可能偏短导致上下文碎片化。我一般调到 800 到 1000重叠 100 到 200。分段方式有自动和自定义两种自动模式对格式规整的文档效果好格式乱的建议自定义按标题或段落分。检索方式有向量检索、全文检索、混合检索。混合检索效果最稳但配置稍复杂。我的做法是先用混合检索如果召回质量不理想再调权重。注意知识库的向量化也要消耗模型调用。如果用的是云端 embedding 模型大批量文档上传时会产生费用。建议用本地 embedding 模型Ollama 上拉一个nomic-embed-text或者bge-m3就能用Dify 里配置成 embedding 供应商即可。5. 实操中踩过的坑与排查技巧5.1 容器网络不通的排查套路Dify 和 Ollama 分处不同容器或宿主机时网络问题是最常见的。我的排查顺序是先在 Dify 的 API 容器里docker exec -it dify-api bash然后curl http://目标地址:端口。如果 curl 不通问题在网络层如果 curl 通但 Dify 里配置报错问题在配置层。网络层的问题通常是三种一是目标服务只绑了127.0.0.1容器访问不到要改成0.0.0.0二是防火墙没放行端口三是 Docker 网络模式不对容器之间要用同一个自定义网络才能通过服务名互访。配置层的问题多半是 URL 写错比如该用host.docker.internal的地方写了localhost。记住一个原则容器里的 localhost 是容器自己不是宿主机。5.2 上下文超长的处理策略“dify 工作流 上下文超长”是高频报错。本地模型上下文窗口通常比云端小7b 模型一般 8k 到 32k云端动辄 128k。当知识库检索回来的内容加上对话历史超过窗口限制时就会报错。处理策略有几个层次。最直接的是限制检索条数把 top-k 从默认的 5 调到 3 甚至 2。其次是压缩上下文用一个本地小模型把检索回来的内容做摘要只保留关键信息。再就是分段处理把长文档拆成多轮对话逐步处理。如果报错信息里出现 “maximum context length is 1048576 tokens” 这类说明你调用的模型上下文窗口很大但实际传入的内容还是超了这时候要检查是不是有节点把整个知识库都塞进去了。5.3 模型输出质量不稳定的调优本地小模型输出质量波动大是常态。我的调优经验是温度调低日常问答设 0.3 到 0.5需要创意的场景再调高。系统提示词写清楚明确告诉模型它的角色、输出格式、禁止事项。加 few-shot 示例在提示词里给一两个输入输出样例效果提升明显。还有一个技巧是后处理。本地模型输出经常带一堆废话或者格式不对用一个代码节点做正则清洗和格式校验能显著提升最终呈现质量。5.4 常见问题速查表问题现象可能原因排查方向Dify 配置 Ollama 报凭证错误网络不通或地址写错容器内 curl 测试Ollama 拉模型极慢网络或镜像源问题换网络或离线拷贝工作流报上下文超长检索内容过多调小 top-k 或加摘要节点本地模型输出乱码编码或量化问题换模型版本或调温度Docker 启动失败端口占用或权限不足查日志和端口知识库检索不准分段或检索方式不当调分段长度和检索模式云端 API 报 400模型名或参数错误核对模型名和请求格式容器间无法互访网络模式不一致统一到同一自定义网络5.5 离线安装与迁移的实操有些环境不能联网这时候离线安装就派上用场。Docker 镜像可以在一台联网机器上docker pull后docker save成 tar 包拷到目标机器docker load。Ollama 的模型文件直接拷贝 models 目录即可。Dify 的插件如果也要离线装在联网环境装好后把插件目录打包迁移。迁移 Dify 整体环境时要迁移的东西包括PostgreSQL 数据、Redis 数据可选、向量库数据、上传的文件、.env配置。最稳的方式是用docker compose down停掉服务把整个数据卷目录打包在新机器上恢复后docker compose up -d。6. 性能与成本的平衡我的实际运行数据6.1 本地命中率与成本对比跑了一个月后我统计了一下数据。在约 12000 次请求里本地模型处理了大约 78%云端处理了 22%。本地处理的平均响应时间 2 到 4 秒云端 1 到 2 秒但受网络影响波动大。成本方面相比纯云端方案整体 API 费用下降了约 70%。这个命中率不是固定的取决于你的任务分布。如果业务里复杂推理占比高本地命中率会下降成本优势缩小。但即便如此把简单任务分流到本地仍然划算。6.2 硬件投入的回收周期我用的是一台带 12GB 显存的机器跑 14b 模型。硬件成本按市场价算如果纯用云端 API这笔钱大概能在 8 到 12 个月的 API 费用里省回来。之后就是净赚。当然这是按我的用量算的用量小的团队回收周期会更长但隐私和可控性的价值没法用钱衡量。6.3 后续可以扩展的方向这套平台搭好后扩展空间很大。可以接入更多本地模型做 A/B 测试可以加缓存层减少重复推理可以把工作流暴露成标准 API 供其他系统调用还可以加监控和告警统计本地命中率和响应质量。我最近在试的是把 Dify 的工作流和内部工单系统打通让工单自动分类和摘要进一步减少人工。这个方向跑通后再来分享。最后分享一个我踩过好几次坑才记住的小技巧改任何配置前先备份.env和数据卷。Dify 的配置项多改错一个可能导致服务起不来有备份能省下大量重装时间。另外Ollama 的模型文件很大迁移前先确认目标盘空间够别拷到一半发现满了。