做 Dify 本地部署的人,十有八九会在知识库这一步被同一个问题卡住:模型供应商里 Rerank 模型那一栏是空的。如果不想每个月给云厂商交 rerank 费用,最快也最可控的方案,就是用 Docker 把 Xinference 拉起来,在本地跑一个开源 rerank 模型。这篇就把我实际操作的完整链路写出来——从为什么 Dify 离不开 rerank,到 Docker 部署 Xinference、启动 bge-reranker 模型,再到 Dify 里的配置和验证,最后附上我踩过的那些坑。
1. 先搞清楚:Rerank 在 Dify 知识库里到底是干嘛的
1.1 向量检索的“召回有余、精准不足”
Dify 知识库的底层逻辑是 RAG(检索增强生成),说白了就是:用户提问后,系统先从你上传的文档切片里找回一批最相关的段落,再把段落拼进上下文,交给大模型生成回答。
关键在这一步“找回”。Dify 默认用的是向量检索,也就是把问题转成 embedding 向量,然后去知识库里做相似度匹配。向量检索本质是“粗筛”:它能在海量切片里快速捞回候选内容,但捞回来的东西常常鱼龙混杂。
举个我实际遇到的例子。知识库里有“苹果公司的财报分析”和“水果苹果的种植技术”两类文档。用户问“苹果今年营收怎么样”,向量检索按语义相似度召回,是分不清“公司苹果”和“水果苹果”的,因为两段文字里都有“苹果”“今年”“产量”这些词。top 50 的候选里可能混着大半篇水果种植内容,非常辣眼睛。
这就是召回有余、精准不足。向量检索解决的是“别漏掉”,但它没办法精确判断“哪个候选才是用户真正想要的”。
1.2 Rerank 是在做第二道精排
Rerank 模型就是用来解决这个问题的第二道精排环节。它的工作方式是:拿到向量检索召回的一组候选文档片段,再结合用户原始 query,逐条计算“这个片段和用户问题到底有多大关系”,然后重新排序,把真正相关的排到前面,把不相关的压下去,最后只取前几个高分片段进入大模型上下文。
简单理解就是:第一轮海选(向量检索)捞回 50 条,第二轮精品筛选(rerank 模型)从 50 条里挑出最相关的 5 条。
Dify 的设计里,Rerank 模型是独立于 embedding 模型和 LLM 的第三类模型。它的位置有两个:一个是全局的“模型供应商”配置里的 Rerank 类型;另一个是每个知识库的“检索设置”里,可以选择是否启用 Rerank 以及用哪个 Rerank 模型。
1.3 不配 rerank 的常见症状
如果你跳过 Rerank,只用向量检索,也不是完全不能用,但会遇到两类典型问题:
一种是 top_k 取得太少,比如只召回 3 个片段,结果文档里真正相关的段落没进候选,大模型只能硬答或者答非所问;另一种是 top_k 取得多,比如取 10 个,结果上下文里塞了 6 个不相干片段,大模型的注意力被噪声分散,回答反而变差。
所以我在给客户或朋友做 Dify 项目时,Rerank 基本默认要配,尤其是文档量超过几十份、内容主题比较杂的场景。否则你用再好的 gpt-4 或 qwen,喂进去的素材是脏的,出来也很难干净。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 为什么我选了 Xinference 来扛 rerank 服务
2.1 需求倒推:Dify 需要一个 OpenAI 兼容的本地 rerank API
Dify 本身不内置任何推理引擎,它只负责调度模型服务。要接入 rerank,方案大致分三类:
第一类是云厂商 API,比如 Cohere Rerank、Jina Rerank,效果不错,但需要注册账号、填 key、按量付费,而且文档内容会出内网。对于本地部署用户,这是很多人不愿意接受的。
第二类是用 Dify 自带的一些开源模型镜像,比如某些集成方案里直接内置了本地推理。但 Dify 官方镜像并不包含模型推理能力,模型这块始终要外部接进来。
第三类就是自己起一个本地推理服务。而 Dify 接入本地推理服务时,最好是 OpenAI 兼容接口,因为 Dify 对 OpenAI 兼容协议的支持最成熟。Xinference 恰好就是这种服务。
Xinference 是 Xorbits 社区出的一个本地化推理框架,全称叫 Xorbits Inference,支持 LLM、embedding、rerank、语音识别等多类模型,暴露的接口风格是 OpenAI 兼容的,而且 Dify 的模型供应商列表里直接就有 Xinference 这一项,不用写一堆自定义代码去适配。
2.2 为什么不是 TEI 或者 Infinity
我知道有不少人用 huggingface 的 text-embeddings-inference(TEI)或者 Infinity 来做 embedding 和 rerank。这两个也是好东西,尤其 TEI 在性能上很强。但我最终选了 Xinference,有几个很现实的原因:
一是 Dify 集成友好度。Dify 的模型供应商界面里直接有 Xinference 选项,填入地址就能用,不需要额外折腾自定义 API 网关。TEI 虽然也能起 rerank 服务,但 Dify 没有专门入口,你要做的适配工作会更多。
二是模型管理方便。Xinference 自带一个 Web UI,能直接浏览模型列表、启动模型、查看运行状态,对新手特别友好。TEI 要用命令行逐个模型起服务,进程管理要自己写。
三是 Xinference 一个服务能搞定多种模型。我不仅用它的 rerank,还顺便在里面跑了 embedding 模型。后期如果想让 LLM 也本地化,直接在同一个 Xinference 里启动就行,一个端口解决所有模型诉求,省得部署一堆不同的框架。
2.3 rerank 模型怎么选:bge-reranker-base 还是 v2-m3
Xinference 支持很多 rerank 模型,实际用得最多的是这三个:
| 模型 | 体积 | 特点 | 适合场景 |
|---|---|---|---|
| BAAI/bge-reranker-base | 约 1.1GB | 轻量、CPU 可跑、启动快 | 新手入门、纯 CPU 机器、文档量不大 |
| BAAI/bge-reranker-v2-m3 | 约 2.2GB | 多语言效果好、精度更高 | 中文为主、文档类型复杂 |
| jina-reranker-v2-base-multilingual | 约 1.2GB | 多语言、长文本支持好 | 多语言混排项目 |
我的建议是:第一台机器先用 bge-reranker-base 把链路跑通。原因很简单,它下载快、占内存小,后续全部配置没问题了,再升级成 bge-reranker-v2-m3,只是改一下模型名的事,不用动任何架构。
如果你只有 CPU 没有 GPU,bge-reranker-base 完全能跑。它每次推理就是算一个分数,耗时在毫秒到几十毫秒级别,对于知识库检索这种低频场景,完全够用。
2.4 用 Docker 而不是 pip 装的考量
Xinference 官方支持 pip 安装,一条 pip install "xinference" 就能装。但我在真实项目中几乎都是建议用 Docker,原因有三个:
- 隔离干净。pip 装会带进来一堆 Python 依赖,比如 torch、transformers、sentencepiece 这些,很可能把系统里的其他 Python 环境搅乱。
- 升级回滚方便。Docker 镜像换个 tag 就是新版本,出问题随时退回旧镜像。
- 和 Dify 部署形态匹配。Dify 本身推荐 Docker Compose 部署,你把 Xinference 也容器化,整条链路都在容器里,管理方式统一,网络沟通也方便。
当然,pip 方式有个优势是宿主机可以直接访问模型缓存目录,调模型文件比较直观。但这个问题用 Docker 数据卷挂载也能解决,后面会细说。
3. 用 Docker 把 Xinference 跑起来:完整操作
3.1 前置条件:Docker 环境与镜像准备
先确认你的机器上有 Docker。Windows 上一般装 Docker Desktop,Linux 上装 Docker Engine + docker compose。这里有一个注意点:Docker Desktop 对 Windows 版本有要求,Windows 10 64 位专业版/企业版/教育版或者 Windows 11 比较稳。如果你打开 Docker Desktop 一直报错,先不用急着重装,后面第六节专门讲排查。
拉取镜像命令很简单:
bash复制docker pull xprobe/xinference:latest
镜像体积有点大,几百 MB,取决于网络情况。国内网络如果拉不动,参考 6.2 节配置 registry mirror,不要死磕默认源。
拉完确认一下:
bash复制docker images | grep xinference
3.2 运行容器命令逐行拆解
我实际用的启动命令是这样:
bash复制docker run -d --name xinference \
--restart unless-stopped \
-p 9997:9997 \
-e XINFERENCE_HOME=/root/.xinference \
-e XINFERENCE_MODEL_SRC=modelscope \
-v /data/xinference:/root/.xinference \
xprobe/xinference:latest \
xinference-local --host 0.0.0.0 --port 9997
逐行解释:
-d --name xinference:后台运行,容器名字叫 xinference,方便后面用 docker exec 进入。--restart unless-stopped:容器挂了或者机器重启后自动拉起服务。这点在本地部署场景很重要,我不想每次开机都手动启动一次。-p 9997:9997:把容器内的 9997 端口映射到宿主机。Xinference 的服务端口默认就是 9997,Web UI 也走这个端口。-e XINFERENCE_HOME=/root/.xinference:指定 Xinference 的工作目录。模型文件、日志、缓存都放在这个目录下。-e XINFERENCE_MODEL_SRC=modelscope:指定模型默认从 ModelScope 下载。这个环境变量是给后面 launch 模型用的,能绕开 Hugging Face 下载不稳定的问题。注意这个环境变量要么在 docker run 时加,要么在容器里 export,二选一即可。-v /data/xinference:/root/.xinference:把宿主机 /data/xinference 目录挂载到容器里的模型目录。这是一个非常关键的操作,后面单独讲。xprobe/xinference:latest:镜像名称。xinference-local --host 0.0.0.0 --port 9997:启动 Xinference 的本地模式。这里必须指定--host 0.0.0.0,因为默认可能只绑定容器内部地址,外部访问不到。
如果你的机器有 NVIDIA GPU,并且要在 Xinference 里跑比较大的模型,可以加一个 --gpus all:
bash复制docker run -d --name xinference \
--restart unless-stopped \
--gpus all \
-p 9997:9997 \
-e XINFERENCE_HOME=/root/.xinference \
-e XINFERENCE_MODEL_SRC=modelscope \
-v /data/xinference:/root/.xinference \
xprobe/xinference:latest \
xinference-local --host 0.0.0.0 --port 9997
但只跑 bge-reranker-base 这种小模型的话,CPU 就够了,没必要上 GPU。
3.3 把模型默认目录持久化,避免容器一删全没
-v /data/xinference:/root/.xinference 这一步我建议所有人不要省。
原因很简单:如果不挂载这个目录,模型文件会下载到容器内部的可写层里。容器一旦删除(不是停止,是 docker rm),整个文件系统就没了,模型需要重新下载一遍。对于 bge-reranker-base 这种 1GB 多的模型,重新下载的时间成本很肉疼,更别说 v2-m3 这种 2GB 以上的。
挂载之后,模型文件落在宿主机 /data/xinference 下。以后要升级镜像,旧容器删掉,新容器重新挂载同一个目录,模型直接复用,完全不用重新下载。
不过要注意一个点:挂载目录的权限。Docker 容器内的用户是 root,挂载出来的文件在宿主机上经常是 root 权限。如果你在宿主机上也想直接操作这些文件,可能会遇到权限不够的情况。我一般直接 sudo chmod -R 755 /data/xinference 解决,或者干脆就用 root 用户管理这台部署机器。
3.4 第一次启动验证
启动完成后,先看日志:b 如果命令能正常跑起来,日志里会出现类似 Xinference is running on 0.0.0.0:9997 的信息。
然后浏览器访问 http://localhost:9997,正常情况下会看到 Xinference 的 Web UI 页面。这个页面就是模型管理后台,后面启动模型的另一种方式就在这上面点。
如果你在服务器上部署,记得在安全组或防火墙里放行 9997 端口。这里有个安全提醒:Xinference 默认没有很强的鉴权,如果服务器有公网 IP,最好限制只允许内网访问,或者用防火墙只放行指定来源,否则别人也能看到你的模型服务。
4. 在 Xinference 里部署 bge-reranker 模型
4.1 通过命令行 launch 模型
Xinference 部署模型的命令是 xinference launch。要启动一个 rerank 模型,用 --model-type rerank 指定模型类型,--model-name 指定模型名称。
进入容器执行:
bash复制docker exec -it xinference bash
然后在容器里:
bash复制xinference launch --model-type rerank --model-name bge-reranker-base
如果一切顺利,命令会输出一行 JSON,里面包含模型 UID、端口等状态信息,然后模型就进入运行状态了。
需要注意一点:这个命令是阻塞式的。launch 之后命令行会一直卡着,代表模型服务在前台运行。如果你想让它回到 shell,可以加 -d 参数,让模型在后台运行:
bash复制xinference launch -d --model-type rerank --model-name bge-reranker-base
实际使用中我更推荐加 -d,否则容器 attach 进去一次就被一直占着。
4.2 从 ModelScope 拉模型,绕开 Hugging Face 下载困境
这是我这篇文章最想说的一点。
Xinference 默认从 Hugging Face 下载模型。对于国内用户,HF 下载经常存在速度慢、断连的问题。最典型的表现就是:launch 之后进度条卡住不动,或者下载到一半报 connect error。
解决方案是在启动容器时已经加了 -e XINFERENCE_MODEL_SRC=modelscope,这样 Xinference 会优先从 ModelScope 拉模型。ModelScope 是国内阿里的模型社区,下载速度快很多,尤其是在国内服务器上。
如果你容器已经启动了,没加这个环境变量,也不用重建容器。在容器里临时指定环境变量再 launch 即可:
bash复制docker exec -it xinference bash
export XINFERENCE_MODEL_SRC=modelscope
xinference launch -d --model-type rerank --model-name bge-reranker-base
我实测下来,bge-reranker-base 从 ModelScope 下载,1GB 多点的文件基本几分钟就完事;同样大小从 HF 下,运气不好可能要半小时以上,还经常断。
4.3 “进度跑到 80% 就不动了”的真正原因
这个标题是我从实际搜索热词里看到的,说明遇到这个问题的人非常多。模型下载到 80% 左右卡住,主要有三类原因。
第一类是网络断流。下载大文件时网络不稳定,连接被重置,进度就停住不动了。Xinference 有时会自动重试,有时不会,表现为进度条一直卡在某个百分比。
第二类是默认走 Hugging Face 源。HF 的下载链路在国内不稳定,大文件下载经常中断在中间阶段。
第三类是分片缓存损坏。Xinference 下载模型时会把文件缓存到 XINFERENCE_HOME 下,如果上次下载中断,残留的临时文件或 shard 有可能损坏,导致重试时反复卡在同一个地方。
解决思路依次是:
- 切换 ModelScope 源,这个是治本。
- 清理缓存,把卡住的那个模型目录删掉,重新 launch。
- 手动下载模型文件,然后用挂载目录塞进去。具体做法:在宿主机用 modelscope 的 CLI 或者浏览器把模型文件下载到
/data/xinference/models对应目录,再回到容器里 launch。注意目录结构要符合 Xinference 的规范,这个方法适合有一定经验的用户。
我的建议顺序是:先删缓存重试,不行就手动下载模型文件挂进去。不要反复看进度条空等,浪费时间。
4.4 确认模型状态
launch 完成后,验证模型是否正常运行:
bash复制docker exec -it xinference xinference list
输出里会列出所有已启动的模型,包括类型、名称、UID、状态。看到 rerank 类型、名称为 bge-reranker-base、状态为 running 就说明成功了。
如果你想测试 rerank 接口本身是否正常,可以用 curl 调一下 Xinference 的 OpenAI 兼容接口:
bash复制curl -X POST http://localhost:9997/v1/rerank \
-H "Content-Type: application/json" \
-d '{
"model": "bge-reranker-base",
"query": "苹果公司今年营收",
"documents": ["苹果公司的财报分析", "水果苹果的种植技术", "手机市场趋势"]
}'
正常会返回每个文档的相关性分数,分数越高越相关。这个接口通了,Dify 那边就好配了。
5. 把 Xinference 接进 Dify:配置与验证
5.1 在 Dify 模型供应商里添加 Xinference
Dify 后台左侧菜单找到“设置”,进入“模型供应商”,往下翻能找到 Xinference 或 Xorbits Inference(不同版本显示名称可能不一样)。
点进去之后,需要填写几个关键字段:
- 模型类型:切换到 Rerank。
- 模型名称:填你 launch 时的模型名,比如
bge-reranker-base。 - Server URL:填 Xinference 服务地址。
- 其他鉴权字段:如果 Xinference 没配置鉴权,留空即可。
填完点“测试连接”,Dify 会调用一次 rerank 接口验证连通性。测试通过后保存。
5.2 Server URL 的地址写法,这里太容易踩坑
Server URL 写什么,取决于 Dify 和 Xinference 各自部署在哪,这里我整理了一个对照表:
| Dify 部署位置 | Xinference 部署位置 | Server URL 写法 |
|---|---|---|
| Docker 容器(Windows/Mac Docker Desktop) | 宿主机 Docker | http://host.docker.internal:9997 |
| Docker 容器(Linux) | 宿主机 Docker | http://host.docker.internal:9997(需在 docker-compose 加 extra_hosts) |
| 宿主机直接运行 | 宿主机 Docker | http://127.0.0.1:9997 |
| 局域网另一台机器 | 局域网另一台机器 | http://<对方IP>:9997 |
最常见的场景是 Dify 用官方 docker compose 跑在容器里,Xinference 也跑在同一台机器的 Docker 里。这时候 Dify 容器访问宿主机,关键点是 host.docker.internal。
在 Windows 和 macOS 的 Docker Desktop 上,host.docker.internal 默认可用。在 Linux 的 Docker Engine 上,不一定默认支持。如果你用 Docker Compose 部署 Dify,需要在 docker-compose 文件里给 Dify 的 api、worker 等服务加上:
yaml复制extra_hosts:
- "host.docker.internal:host-gateway"
加完后重新启动 Dify 容器,host.docker.internal 就能正常解析到宿主机了。
如果不想折腾这个,也可以直接把 Dify 里的 Server URL 写成 http://<宿主机局域网IP>:9997,前提是防火墙放行 9997 端口。这个方案在局域网里更通用。
5.3 在知识库检索设置里启用 rerank
全局配好 Xinference 的 rerank 模型后,还要在具体知识库的设置里开启。
进入你的知识库,点“设置”,找到“检索设置”。在召回模式里,Dify 支持三种:“向量检索”“全文检索”“混合检索”。我一般选混合检索,然后勾选 Rerank 相关选项,选择刚才配置好的 rerank 模型。
这一步完成后,每次用户提问,Dify 会先做召回,再调用 Xinference 的 rerank 接口,对召回结果精排,最后把高分内容交给大模型。
5.4 验证效果:有 rerank 和没 rerank 的差距
配置完之后别急着走,先做一轮对比验证。我常用的方法是:
在同一个知识库下,关闭 rerank,提问一个意图稍微复杂的问题,看回答。然后再开启 rerank,问同样的问题,对比回答质量。
真实案例里,我测试过一个包含产品说明书、售后政策、物流规则的混合知识库。用户问“刚买的机器能退吗”,关闭 rerank 时 Dify 召回的多是产品参数说明,回答基本答非所问;开启 rerank 后,召回结果把“退换货政策”排到了最前面,回答一下子就对了。
另外可以观察 Xinference 容器日志,确认 rerank 接口确实在被调用:
bash复制docker logs xinference --tail 20
能看到近期请求记录就说明整个链路通了。
6. 踩坑笔记:Docker Desktop、镜像源、模型下载中断
6.1 Docker Desktop 起不来的常见原因
热词里有好几个和 Docker Desktop 启动失败相关的搜索,比如 docker desktop failed to start because virtualisation support wasn't detect、virtualization support not detected、incompatible version of windows。这些我全遇到过,集中说一下。
Docker Desktop 在 Windows 上依赖虚拟化技术,底层是 WSL2 或 Hyper-V。如果启动时报“virtualisation support wasn't detect”,第一件事是进 BIOS 确认虚拟化开关。Intel 平台是 VT-x,AMD 平台是 SVM,不同主板菜单不一样,但关键字一般是 Virtualization Technology。开启后保存重启再试。
第二件事是检查 Windows 功能。控制面板 -> 程序 -> 启用或关闭 Windows 功能,确认“适用于 Linux 的 Windows 子系统”和“虚拟机平台”两个选项已经勾选。勾完要重启系统。
第三件事是 WSL2 本身。Docker Desktop 现在默认走 WSL2,老旧的 WSL 内核会导致启动失败。在管理员 PowerShell 里执行:
powershell复制wsl --update
更新完重启 Docker Desktop 就好。
至于 incompatible version of windows,说明你系统的 Windows 版本太老,Docker Desktop 新版本已经不支持了。解决方案是升级 Windows 系统,或者从 Docker 官方归档里找支持你系统的旧版本 Docker Desktop。注意旧版本有安全风险,能用新版尽量升级。
6.2 Docker 镜像下载慢:registry mirror 配置
docker pull xprobe/xinference 拉不动或者慢得离谱,大概率是 Docker Hub 的连接问题。长期有效的做法是给 Docker 配置 registry mirror。
Linux 上编辑 /etc/docker/daemon.json:
json复制{
"registry-mirrors": [
"https://docker.m.daocloud.io"
]
}
保存后重启 Docker:
bash复制sudo systemctl restart docker
Windows 上 Docker Desktop 的设置界面里也有 Registry mirrors 配置项,直接添加镜像源地址,点 Apply & Restart 即可。
配置完再 docker pull 同一个镜像,速度会有明显改善。注意 registry mirror 只对 Docker Hub 官方镜像生效,对第三方源不一定有效。
6.3 模型下载中断后怎么处理
模型下载到一半断了,或者卡在 80%,多半是下载源的问题。处理步骤我建议这样:
第一步,删除卡住的模型缓存。进入 Xinference 容器:
bash复制docker exec -it xinference bash
ls /root/.xinference/models
找到对应模型目录删掉。如果直接删整个 models 目录也行,下次 launch 会重新下载。缓存清理干净后,确保 XINFERENCE_MODEL_SRC=modelscope 环境变量已设置,重新执行 launch。
第二步,如果还是卡,把“删缓存”换成“手动下载”。在宿主机上用 ModelScope 的命令行工具把模型文件拉下来:
bash复制pip install modelscope
modelscope download --model BAAI/bge-reranker-base /data/xinference/models/BAAI/bge-reranker-base
然后回到容器 launch。因为模型文件已经在指定目录里,Xinference 会直接读取本地文件,不再下载。
第三步,检查磁盘空间。有时候下载慢不是网络问题,而是磁盘满了,下载进程写不进去,表现得像卡住一样。df -h 看一下挂载目录的空间,至少预留模型体积两倍以上的余量。
6.4 容器重启后模型状态检查
Xinference 容器重启后,模型文件因为挂载了持久化目录所以不会丢,但要确认模型是不是处于运行状态。
一种情况是模型服务也跟着恢复。多数时候,docker restart xinference 后,Xinference 会从持久化目录恢复元信息,但模型不一定会自动 loading 回来,需要重新执行一次 launch。不过由于模型文件已经在本地,launch 的速度会非常快,几秒到几十秒就好,不会重新下载。
另一种情况是容器启动失败。如果重启后连 9997 端口都访问不到,先看日志:
bash复制docker logs xinference --tail 50
常见原因是挂载目录权限变化或者端口被占用。端口被占用时改映射端口即可,比如 -p 9998:9997,然后 Dify 里的 Server URL 同步改端口。
6.5 最后的经验:把启动命令固化成脚本
部署这套环境时,我习惯把 Docker run 命令和模型 launch 命令写成一份 Shell 脚本放进项目目录,比如 deploy-xinference.sh。换机器部署时直接执行脚本,三分钟就能拉起来一套一模一样的环境,不用靠记忆敲命令。
这里贴一份我常用的脚本模版:
bash复制#!/bin/bash
docker run -d --name xinference \
--restart unless-stopped \
-p 9997:9997 \
-e XINFERENCE_HOME=/root/.xinference \
-e XINFERENCE_MODEL_SRC=modelscope \
-v /data/xinference:/root/.xinference \
xprobe/xinference:latest \
xinference-local --host 0.0.0.0 --port 9997
docker exec xinference xinference launch -d \
--model-type rerank \
--model-name bge-reranker-base
脚本放在那里吃灰也没关系,真正要出问题时,你会发现手里有个固定的恢复方案比什么都强。我自己换了至少三台机器部署这套环境,每一台都是靠这个脚本几分钟搞定的。
Dify 搭配 Xinference 这套组合,说到底是把“模型服务”这件事从云上挪到了本地。Cloud API 省心但费钱,自己搭麻烦但可控。对我来说,知识库内容不出内网这件事,价值远大于省下的那点部署时间。
