简介:这份PDF文档面向希望零基础完成AI知识库本地部署的技术爱好者与开发者,围绕DeepSeek大模型与Dify开源平台,提供一套可落地的本地化部署方案。内容涵盖系统环境变量配置、Ollama软件安装、DeepSeek-R1与bge-m3模型的拉取、Docker镜像加速配置,以及Dify平台的下载、环境变量调整与运行验证,最终实现聊天助手与知识库的完整搭建。资源包共1个PDF文件,大小约1.47MB,以图文步骤形式呈现,便于对照操作。目前已有2337人学习下载,适合想摆脱云端依赖、在本地运行大模型与知识库的读者参考,可帮助快速理解各组件间的协作关系与配置要点,降低本地部署的入门门槛。
1. DeepSeek+Dify本地部署知识库:为什么这套组合值得你花一个周末
公司内网不让调外部 API,但团队又想用大模型查内部文档,这个矛盾我遇到过不止一次。最后的解法是 DeepSeek 出推理能力,Dify 出编排和知识库流水线,全部跑在本地。DeepSeek 负责把检索回来的片段读懂、组织成答案,Dify 负责文档上传、切分、向量化、召回这一整条 RAG 链路。两者拼起来,就是一套不依赖外部服务、数据不出内网的知识库问答系统。
这套方案适合谁?手里有一台带独显的机器或者一台内网服务器,想给团队搭一个能查产品文档、运维手册、合同模板的问答入口,又不想把文件传到别人服务器上的人。新手跟着步骤能跑通最小闭环,熟手可以在这套骨架上换模型、调切分参数、接自己的业务系统。接下来我按实际搭建顺序,把选型理由、部署命令、参数设置和踩过的坑一条条讲清楚。
2. 部署前的选型账:DeepSeek 怎么跑、Dify 怎么装
2.1 本地推理用 Ollama 拉 DeepSeek,还是直接上 vLLM
本地跑 DeepSeek 有两条常见路线。一条是用 Ollama 拉量化版模型,一条是用 vLLM 加载完整权重。我一般先看硬件:显存 16GB 以下,走 Ollama 的deepseek-r1:7b或deepseek-r1:14b量化版,部署快、依赖少,一条命令就能起服务。显存 24GB 以上、并且有多人并发需求,才考虑 vLLM,因为它的吞吐和并发明显更好,但配置复杂度也上一个台阶。
这里有个容易翻车的点:很多人以为本地部署 DeepSeek 就是下载一个 exe 双击运行。实际上 DeepSeek 是模型权重,需要一个推理引擎来加载它。Ollama 就是最省事的那个引擎,它把模型下载、量化加载、HTTP 服务全包了。你只需要装好 Ollama,然后拉模型。
# 安装 Ollama(Linux 一行命令,Windows 去官网下安装包) curl -fsSL https://ollama.com/install.sh | sh # 拉取 DeepSeek 推理模型,7b 适合 8GB 显存起步 ollama pull deepseek-r1:7b # 启动服务,默认监听 11434 端口 ollama serve # 验证模型是否可用 curl http://localhost:11434/api/generate -d '{ "model": "deepseek-r1:7b", "prompt": "用一句话解释什么是 RAG", "stream": false }'这段命令的逻辑是:先装引擎,再拉模型,然后起 HTTP 服务,最后用 curl 发一个生成请求验证。参数上,deepseek-r1:7b里的 7b 是参数量,显存不够就换更小的,显存充裕可以换 14b 或 32b。stream: false表示一次性返回完整结果,调试时方便看全貌;生产环境一般用流式,体验更好。
提示:Ollama 默认只监听 127.0.0.1,如果 Dify 跑在 Docker 里,需要设置
OLLAMA_HOST=0.0.0.0让它监听所有网卡,否则容器内访问不到宿主机服务。
2.2 Dify 用 Docker Compose 起,别手动装 Python 依赖
Dify 的部署方式里,Docker Compose 是最稳的。手动装 Python 依赖那条路我走过一次,光是 PostgreSQL、Redis、Weaviate 这几个组件的版本匹配就耗掉半天,最后还因为某个包的 C 扩展编译失败卡住。Docker Compose 把 API 服务、Worker、Web 前端、数据库、向量库全部编排好,一条docker compose up -d就能起。
# 克隆 Dify 仓库(用官方 release 分支,别用 main) git clone https://github.com/langgenius/dify.git cd dify/docker # 复制环境变量模板 cp .env.example .env # 启动所有服务,-d 表示后台运行 docker compose up -d # 查看容器状态,确认没有反复重启的 docker compose ps启动后默认 Web 端口是 80,API 端口是 5001。第一次访问会让你设置管理员账号。这里的关键参数在.env文件里:EXPOSE_NGINX_PORT控制 Web 端口,DB_PASSWORD是数据库密码,VECTOR_STORE决定用哪个向量库,默认是 Weaviate。如果你机器上 80 端口被占了,改EXPOSE_NGINX_PORT=8080再重启。
注意:CentOS 7 上装 Dify 容易遇到 Docker 版本过低的问题,
docker compose子命令可能不存在,需要先升级 Docker 到 20.10 以上,或者用docker-compose(带横杠)的老写法。
2.3 把 Ollama 接进 Dify 的模型供应商配置
Dify 起好之后,默认没有本地模型。需要进「设置 → 模型供应商 → Ollama」,填两个东西:基础 URL 和模型名称。基础 URL 填http://host.docker.internal:11434,这是 Docker 容器访问宿主机的地址。模型名称填你刚才拉的deepseek-r1:7b。
填完点保存,如果报An error occurred during credentials validation,九成是网络不通。先在 Dify 的 API 容器里执行curl http://host.docker.internal:11434/api/tags,看能不能列出模型。不通就检查 Ollama 是否监听了 0.0.0.0,以及宿主机防火墙有没有放行 11434。
这一步做完,Dify 里就有了一个可用的对话模型。但知识库还需要一个嵌入模型,用来把文档转成向量。Ollama 也支持嵌入模型,拉一个nomic-embed-text就行:
ollama pull nomic-embed-text然后在 Dify 的 Ollama 供应商里把嵌入模型也配上。至此,模型侧的准备就完成了。
3. 知识库流水线:从上传文档到能问答的完整链路
3.1 文档切分:分段标识符和最大长度的配合
Dify 的知识库不是把整个 PDF 塞进去就完事,它要先切分。切分质量直接决定召回质量。Dify 提供两种切分模式:自动切分和自定义切分。自动切分按固定长度硬切,适合格式规整的文本;自定义切分可以指定分段标识符,比如按\n\n切段落,按#切标题。
我一般这样设:分段标识符用\n\n,最大分段长度设 500 tokens,分段重叠设 50 tokens。重叠的作用是防止一个完整句子被切断后语义丢失。比如「本合同的违约责任条款适用于……」这句话如果正好卡在边界,重叠 50 tokens 能让下一段也包含这句话的开头,召回时就不会漏。
| 参数 | 建议值 | 说明 |
|---|---|---|
| 分段标识符 | \n\n | 按空行切段落,保留语义完整性 |
| 最大分段长度 | 500 tokens | 太长召回不准,太短上下文不足 |
| 分段重叠 | 50 tokens | 防止边界句子被切断 |
| 索引方式 | 高质量 | 用嵌入模型,召回更准 |
| 检索方式 | 混合检索 | 向量加关键词,兼顾语义和精确匹配 |
这些参数不是拍脑袋定的。500 tokens 大约对应中文 350 到 400 字,一个段落通常在这个范围内。如果你的文档是法律合同这种长条款,可以调到 800;如果是 FAQ 这种短问答,调到 200 更合适。
3.2 用 API 批量灌文档,比手动上传靠谱
Dify 的 Web 界面支持拖拽上传,但文档一多就痛苦。更稳的方式是走 API。Dify 提供了知识库创建和文档上传的接口,可以用脚本批量处理。
import requests API_BASE = "http://localhost:5001/v1" API_KEY = "dataset-xxxxxxxx" # 在知识库设置里生成 DATASET_ID = "your-dataset-id" # 上传文档 def upload_document(file_path): url = f"{API_BASE}/datasets/{DATASET_ID}/document/create-by-file" headers = {"Authorization": f"Bearer {API_KEY}"} with open(file_path, "rb") as f: files = {"file": (file_path.split("/")[-1], f)} data = { "indexing_technique": "high_quality", "process_rule": { "mode": "custom", "rules": { "pre_processing_rules": [ {"id": "remove_extra_spaces", "enabled": True}, {"id": "remove_urls_emails", "enabled": False} ], "segmentation": { "separator": "\n\n", "max_tokens": 500, "chunk_overlap": 50 } } } } resp = requests.post(url, headers=headers, files=files, data=data) return resp.json() result = upload_document("./docs/product_manual.pdf") print(result)这段代码的逻辑是:构造一个 multipart 请求,把文件和切分规则一起发给 Dify 的文档创建接口。indexing_technique设为high_quality表示用嵌入模型做高质量索引。process_rule里的segmentation就是前面说的切分参数,和界面上设的是一回事。pre_processing_rules里的remove_extra_spaces建议开启,能去掉文档里多余的空格和换行,减少噪声。
参数上,API_KEY在知识库的「API 访问」页面生成,DATASET_ID在知识库 URL 里能看到。上传成功后返回的 JSON 里会有document和batch字段,batch是这批文档的处理批次号,可以用它查进度。
3.3 检索召回:混合检索和重排序怎么配
文档索引完之后,问答质量取决于召回。Dify 支持三种检索方式:向量检索、全文检索、混合检索。向量检索靠语义相似度,适合「意思相近但用词不同」的场景;全文检索靠关键词匹配,适合「必须精确命中某个术语」的场景。混合检索把两者结合,再通过重排序模型统一打分。
我一般开混合检索,并且开启 Rerank 模型。Rerank 的作用是对召回结果做二次排序,把最相关的排到前面。Dify 支持本地部署的 Rerank 模型,比如bge-reranker-base,也可以用 Ollama 跑。配置路径在知识库的「召回测试」旁边,设置 Top K 为 5,Score 阈值设 0.5。Top K 是召回条数,太大容易引入噪声,太小可能漏掉关键信息。Score 阈值是过滤低分结果的,低于 0.5 的直接丢掉。
提示:如果召回结果总是不相关,先别急着换模型,去「召回测试」里输入问题,看实际召回了哪些片段。很多时候是切分粒度不对,而不是模型不行。
4. 避坑与排查:那些让我加班到凌晨的报错
4.1 Dify 报 credentials validation 失败
现象:在 Dify 里配置 Ollama 模型供应商,点保存时提示An error occurred during credentials validation。
原因:Dify 的 API 容器访问不到 Ollama 服务。常见情况有三种:Ollama 只监听了 127.0.0.1;Docker 容器没有配置host.docker.internal的解析;宿主机防火墙拦截了 11434 端口。
解决:先确认 Ollama 监听地址,OLLAMA_HOST=0.0.0.0 ollama serve。然后在 Dify 的 API 容器里执行curl http://host.docker.internal:11434/api/tags,如果提示无法解析主机名,在docker-compose.yml里给 api 服务加extra_hosts: - "host.docker.internal:host-gateway"。最后检查防火墙,firewall-cmd --add-port=11434/tcp放行。
4.2 文档上传后一直显示「等待中」
现象:通过 API 上传了 PDF,返回成功,但知识库里文档状态一直是「等待中」,不进入索引。
原因:Dify 的 Worker 容器负责异步处理文档索引,如果 Worker 挂了或者队列堵了,文档就会卡住。
解决:docker compose ps看 worker 容器是否在运行。如果没运行,docker compose logs worker看报错。常见的是 Redis 连接失败,检查.env里的REDIS_HOST和REDIS_PORT是否和 compose 文件里的服务名一致。如果 Worker 在跑但队列堵了,重启 Worker 容器:docker compose restart worker。
4.3 嵌入模型报维度不匹配
现象:知识库索引时报错,提示向量维度不匹配,比如expected dim 768, got 1024。
原因:Dify 的向量库在创建时确定了维度,后续换嵌入模型如果维度不同,就会冲突。比如nomic-embed-text是 768 维,bge-large是 1024 维。
解决:要么换回同维度的嵌入模型,要么新建一个知识库。已经建好的知识库没法直接改维度,这是向量库的硬限制。所以选嵌入模型时要想清楚,别中途换。
4.4 Docker 磁盘占用暴涨
现象:跑了一段时间后,宿主机磁盘满了,Docker 相关目录占了上百 GB。
原因:Dify 的日志、向量库数据、模型缓存都在 Docker volume 里,加上 Ollama 下载的模型文件,磁盘消耗很快。另外 Docker 的日志驱动默认不限制大小,容器日志能涨到几个 GB。
解决:在/etc/docker/daemon.json里加日志限制:{"log-driver": "json-file", "log-opts": {"max-size": "100m", "max-file": "3"}},然后重启 Docker。定期清理无用镜像:docker image prune -a。Ollama 的模型文件在~/.ollama/models,不用的模型及时删。
4.5 中文文档召回率低
现象:问一个中文问题,召回的都是不相关的英文片段,或者干脆召回为空。
原因:嵌入模型对中文的支持不好。很多默认的嵌入模型是在英文语料上训练的,中文语义空间没学好。
解决:换一个中文优化的嵌入模型,比如bge-large-zh或m3e-base。如果显存不够跑大模型,至少用nomic-embed-text这种多语言支持的。另外,切分时把最大分段长度调小一点,中文信息密度高,500 tokens 可能包含太多内容,调到 300 试试。
5. 让知识库答得更准:三个我反复验证过的调优技巧
第一个技巧是给知识库加「元数据」。Dify 支持给文档打标签,比如「产品手册」「运维文档」「合同模板」。检索时可以按标签过滤,避免问产品问题时召回合同条款。配置方式是在知识库设置里开启元数据过滤,然后在 API 调用时传metadata_filtering_conditions。这个功能在文档类型混杂时特别有用,能把召回准确率拉高一个档次。
第二个技巧是调整提示词里的上下文拼接方式。Dify 的问答节点默认把召回片段直接拼在提示词里,但拼接顺序会影响模型注意力。我一般把最相关的片段放在最前面和最后面,中间放次相关的。因为大模型对开头和结尾的信息更敏感,这是注意力机制的特性。具体做法是在「提示词编排」里用变量控制片段顺序,而不是简单按召回分数排列。
第三个技巧是定期做召回测试并记录。Dify 的「召回测试」功能可以输入问题看实际召回结果,我每周会抽十个典型问题跑一遍,把召回不准的记下来,回头调整切分参数或补充文档。这个习惯帮我发现了很多问题,比如某份 PDF 是扫描件,OCR 出来的文字有大量错别字,导致嵌入向量偏移。后来我把扫描件单独走 OCR 清洗再上传,召回质量明显改善。
| 调优动作 | 频率 | 预期收益 |
|---|---|---|
| 补充元数据标签 | 文档入库时 | 召回准确率提升 15% 到 30% |
| 调整上下文拼接顺序 | 提示词迭代时 | 答案相关性提升 |
| 每周召回测试 | 每周一次 | 及时发现切分和文档质量问题 |
| 清洗扫描件 OCR 文本 | 入库前 | 避免噪声向量污染 |
最后说一个我自己的习惯:每次改完切分参数或换嵌入模型,一定新建一个知识库做对比测试,别在原知识库上直接改。因为向量库的索引一旦建立,改参数不会自动重建,你以为改了,实际用的还是旧索引。这个坑我踩过两次,后来就养成了「改参数必新建」的习惯。希望帮到你。
本文还有配套的精品资源,点击获取