ollama+dify搭建本地知识库

模型与算力

讲清用 Ollama 跑本地模型、由 Dify 编排检索问答的搭建顺序、参数取舍与常见报错排查,做到私有文档不出内网。

你手上有一堆内部文档,想让它们能问答,又不想把内容传到别人服务器。思路是 Ollama 在本机把模型跑起来,Dify 负责切分、检索和编排。这篇按动作顺序讲:先确认模型接口通不通,再配模型、选嵌入与重排、调切分参数、最后做一轮可用性验证和排查。踩到的坑大多是接口地址、模型名和上下文长度对不上。

你手上有一堆内部文档,想让它们能问答,又不想把内容传到别人服务器上。一个常见做法是:用 Ollama 在本机把模型跑成一个可调用的服务,用 Dify 负责文档切分、向量检索、提示编排和对话界面。数据不出内网,模型也不用按调用量付费。

这篇按动作顺序讲:先确认模型接口通不通,再配模型、选嵌入与重排、调切分参数,最后做一轮可用性验证和排查。踩到的坑大多是三件事对不上:接口地址、模型名、上下文长度。先把这三样对齐,后面就顺了。

先想清楚:为什么是 Ollama 加 Dify 这套组合

这两个组件各管一段。Ollama 把模型跑成本地可调用的服务,你不用关心推理细节;Dify 管的是文档切分、向量检索、提示词编排和前端对话。你只需要把两者用一条 HTTP 接口连起来,剩下的都是配置。

判断维度适合这套组合不适合,换思路
文档量中等规模,单机能装下向量库上百万文档、要分布式检索
问答形态以检索原文为主、有出处可查要复杂多轮推理、多工具联动
数据要求文档必须留在内网无此要求,可接受公有云
并发几人到几十人内部用高并发、多租户隔离
扩容单机或少量机器需要弹性伸缩、跨机调度

需要极高并发或者要跨机器弹性扩容的场景,更适合看 vLLM 一类专门的推理框架,Dify 在这里主要是编排层。选型前先到 /models/deploy 按模型和量化档位估算一遍显存占用,别等装完才发现跑不动。

装之前先把三件事定下来

很多人失败不是技术不行,是装之前没想清楚要跑什么。先把模型、嵌入模型、部署方式这三件事定下来,后面每一步都有依据。

  • 跑哪个生成模型、量化到什么档位:模型越大对显存越敏感,量化越低省显存但效果会打折,先定一个能跑起来的档位
  • 嵌入模型用哪个:中文检索效果很大程度取决于它,可到 /embeddings 对比不同嵌入模型的适用面
  • 部署方式:Docker 和宿主机混装最容易出网络问题,先把端口规划写下来,谁连谁心里有数
  • 把机器配置、显存占用、预期文档量记成一页纸,后面排查时拿来对照

部署方式这一项特别容易被忽略。如果 Dify 跑在容器里、Ollama 跑在宿主机上,两边的网络视角完全不同,地址怎么写、端口通不通,是后面最常见的卡点,提前规划能省很多时间。

Ollama 这一侧:把服务跑成能对外调用的接口

装好之后,先确认服务真的在监听、能列出已下载的模型,再谈对接。这一步没验证就去配 Dify,等于闭着眼睛调接口。具体命令和路径可以到 /guides/ollama-getting-started 对照着做。

  1. 确认服务在跑看进程和服务端口,能列出本地已有模型列表,说明服务本身没问题
  2. 拉模型优先选带中文能力的模型;下载慢或中断就换镜像源重试,别在一个源上硬等
  3. 放开监听地址默认只监听本机,Dify 跑在容器里会连不上,需要改成能被外部访问的地址,做法见 /guides/ollama-local-api-address
  4. 量一个速度基线有条件就让 Ollama 用 GPU;用一条短请求量出首字延迟和生成速度,到 /tools/speed-test 记下基线,后面改动前后有对比

速度基线这一步看着多余,其实很值。等你换模型、改量化档位、调召回条数之后,能立刻看出是变快了还是变慢了,而不是凭感觉。

Dify 这一侧:模型接不上的排查顺序

Dify 里的流程是:在模型供应商里选 Ollama 类型,填服务地址和模型名,保存后点一下测试。报连接失败的时候,别乱改配置,按固定顺序排查最快。

报错表现先查什么再查什么
连接被拒容器能不能访问到宿主机服务有没有真的在监听该端口
超时地址写的是不是可达地址防火墙或端口有没有拦
模型不存在模型名是否和服务里列出的一致有没有多写或漏写标签后缀
能连但很慢是不是退回 CPU 跑显存是否被其他进程占满

最容易犯的错是地址写 localhost。容器里的 localhost 指的是容器自己,不是宿主机,所以要用宿主机的可达地址或者容器网络别名。模型名也要和服务里列出的完全一致,多一个标签后缀就找不到。

嵌入与重排:决定检索效果的两块

知识库的检索质量主要由嵌入模型决定。中文语料要挑在中文上训练过的嵌入模型,选型可以到 /embeddings 对比。嵌入模型换一次,就要把全部文档重新向量化一遍,所以别中途随便换。

文档多、提问比较绕的时候,可以加重排模型:先用向量粗召回一批,再用重排精挑出真正相关的几条,能明显减少答非所问。重排模型的选型思路见 /guides/ollama-rerank-model-pick。

  • 生成模型和嵌入模型可以不是同一个,分开配是常规做法,别强行用同一个
  • 嵌入模型偏重语义匹配,重排模型偏重相关性排序,两者职责不同
  • 文档量小、提问直接时,不加重排也能用,先跑通再优化
  • 重排会增加一次计算,机器吃力时先只上嵌入,看效果够不够

切分与检索参数:调这几个就够了

切分块大小按文档类型走:条款式文档语句独立、适合切小一点;叙述式文档上下文连在一起、适合切大一些。先定一个值,再回看检索结果调整,不要一次改好几个参数。

参数作用怎么定
块大小每段被切多长条款式切小,叙述式切大
重叠长度相邻块保留多少重合给一点,避免一句话被切断两边都搜不到
召回条数每次取回几段原文先给小值,不够再加,多了容易被无关内容带偏
上下文长度拼给模型的文本总长卡在模型窗口内,超出会被截断

召回条数不是越大越好。条数多了,模型容易被无关内容带偏,答案反而更差。上下文长度也要卡在模型窗口之内,超出的部分会被直接截断。相关概念可以到 /ai-dict/category/basics 补一下。

怎么判断这套东西真的能用

跑通不等于能用。准备一组带标准答案的问题集,故意包含两类:文档里能查到答案的,和文档里根本没有的。看它答不出来的时候会不会硬编。

  • 答案能不能落到原文:回答里的关键信息要能在引用片段里找到
  • 引用片段对不对:检索出来的段落是不是真的和问题相关
  • 响应要等多久:单次问答的等待时间是否在可接受范围
  • 并发会不会卡:同时进来几个人,响应是否明显变慢
  • 边界问题表现:文档里没有的内容,是老实说不知道还是编一个

如果发现编造答案,先查检索层,别急着怪模型。大部分情况下是检索压根没拿到原文,模型只能靠训练记忆硬答。把检索修好,编造问题往往自己就消失了。验证结果记成一份对照表,换模型或改切分参数后重跑一遍。

常见卡点:按这个顺序排除

遇到问题按层次排除,比东改一处西改一处高效得多。从接口层往下,一层一层确认,哪层不通就停在哪层解决。

  1. 先看接口层模型调不通和答案不好是两回事,先确认能正常调用再谈效果
  2. 再看检索层到 /tools/verify 一类在线检测工具确认服务状态,检索结果为空多半是嵌入或切分的问题
  3. 然后看上下文层报错里出现长度超限,就下调召回条数或块大小,把拼给模型的文本压回窗口内
  4. 最后看资源层显存满了会退回 CPU 跑,速度断崖式下跌,排查思路见 /guides/vram-optimization-guide
下一步想知道本地跑不同模型大概要多少显存、自己的机器能不能扛住,可以到站内模型部署估算页按模型和量化档位核对当时的数字,再决定用哪个档位开跑。

常见问题

本地知识库问答答不准,是模型不行还是检索不行?

多数情况先怀疑检索。去 Dify 里看命中的文档片段,如果片段本身跟问题无关,换生成模型也没用,该调块大小、召回条数或换嵌入模型;如果片段是对的、模型还是答偏,再考虑换更强的生成模型。

Ollama 和 Dify 都装在本机,为什么还是连不上?

常见原因是 Dify 跑在容器里,而 Ollama 只监听本机地址,容器里的本机不是你的本机。要放开 Ollama 的监听地址,并在 Dify 里填容器能访问到的地址,同时确认端口没有被防火墙挡。

文档要更新,是不是每次都得重新做一遍?

只更新改动部分,Dify 侧重新解析对应文档即可。但要注意:如果换了嵌入模型,必须全量重新向量化,否则新旧向量的语义空间不一致,检索结果会乱。

这套方案适合多大文档量、多少人用?

中小团队、文档以内部资料和手册为主、同时在线人数不多的场景比较合适。文档量很大或并发要求高的时候,瓶颈通常在检索和推理资源上,得先算资源再定方案。

不想让文档出内网,这套做法能满足吗?

模型推理和文档处理都在自己的机器上,链路本身不外发。但要注意别在流程里接入外部模型接口做兜底,也别把日志和备份传到外部存储,否则等于绕开了隔离。

本文依据各平台公开文档与官方公告整理,只做中文归纳;具体做法、参数与限制以官方文档为准。