本文档由 AI 自动翻译。如有任何不准确之处,请参考 英文原版。Dify 1.17.1 将内置的 Weaviate 服务器镜像从
1.27.0 升级到 1.39.2,已有的 Weaviate 数据卷无法一步跨越这段版本差。如果跳过 1.17.1 直接升级到 Dify 1.18.0(内置 1.39.13),同样如此。本流程适用于 Dify 默认的单节点 Docker Compose 部署。全新部署会在空数据卷上直接使用新版本,无需执行本流程。
Weaviate 既未测试也不支持跨小版本升级,任何一个版本都可能包含磁盘数据迁移,而这类迁移要求上一个版本至少运行过一次。
受支持的升级方式是按顺序逐个小版本推进,每次都升到该小版本的最新补丁版本。下面给出完整阶梯,以及升级过程中最容易出问题的两个运维细节。
确认当前版本
从 Dify 仓库根目录进入docker 目录,后续步骤均在该目录下执行。Dify 默认的 docker-compose.yaml 不会为 Weaviate 映射宿主机端口,因此要在 Compose 网络内部执行检查,而不是访问宿主机的 localhost。
如果使用 源码开发的中间件部署,请在本页所有针对 Weaviate 的 docker compose 命令中加上 --env-file middleware.env -f docker-compose.middleware.yaml -p dify。如果启动时使用的项目名称不是 dify,请替换为实际名称。
localhost 指的是 Weaviate 容器自身的回环地址,而不是宿主机。Weaviate 镜像内既没有 curl 也没有 Python,因此请求使用 busybox wget 发出,JSON 则由宿主机上的 Python 格式化。
接下来怎么做,取决于显示的版本:
1.39.2或更高:无需执行本流程。1.27.0:从下面的第一级开始。- 阶梯中的某个中间版本:从下一级继续。
- 早于
1.27.0:先按照 Weaviate v4 迁移指南 完成迁移。
备份数据
对于 Docker 部署,最简单的备份方式是离线复制数据卷。先停止 Dify 的请求入口和 worker 服务以冻结写入,并保持这些服务停止,直到最后一级通过验证: 如果docker-compose.yaml 中没有定义 api_websocket,从下面的命令中去掉该服务名。
cp -a 会保留属主、权限和时间戳。用 sudo 执行的普通 cp -r 会改写这些属性,可能导致还原后的数据卷无法被 Weaviate 容器读取。
生产环境建议使用 Weaviate 的 备份模块 写入 S3、GCS 或 Azure。它生成的是可还原的快照,而不是原始目录副本,并且可以对运行中的实例执行。本地文件系统后端仅供开发使用。
逐个小版本升级
按顺序走完每个小版本,每次都停在该小版本的最新补丁版本上。
镜像仓库在第 1 步发生变化。现有部署从 Docker Hub 拉取
semitechnologies/weaviate,而阶梯使用 Weaviate 自有仓库 cr.weaviate.io/semitechnologies/weaviate,这也是 Dify 新版 Compose 文件所指向的地址。两者镜像相同,因此这里是有意同时变更仓库和版本。
表中的补丁版本为撰写时的最新值。对于中间各级,开始前先确认该小版本是否有更新的补丁,有则优先使用。
逐级升级还能缩小影响范围。某一级出问题时,只需回退一个版本,并且能立刻确定是哪个版本引入的问题,不必在一次跨越所有小版本的升级里二分排查。
紧跟最新版本才能持续拿到修复。Weaviate 只支持 最近的三个小版本,即当前版本及其之前的两个版本。更早的版本已终止支持,不再保证提供缺陷或安全修复。本次迁移完成后也要定期回看,及时升到当前补丁版本。
使用 Docker Compose 升级
Dify 在docker/docker-compose.yaml、docker/docker-compose.middleware.yaml 和 docker/docker-compose-template.yaml 三处固定 Weaviate 镜像版本。修改实际部署所用的文件,然后对每一级重复下面的循环。
1
设置下一级镜像标签
把
weaviate 服务改为下一个小版本的最新补丁,例如 image: cr.weaviate.io/semitechnologies/weaviate:1.28.16。2
优雅停止容器
docker kill 或 docker rm -f。强制杀死的代价参见 优雅停止 Weaviate。3
启动新版本
4
确认无误后再继续
进入下一级前,执行 每一步都要验证。
优雅停止 Weaviate
这是最容易让检索失效、也最容易做错的一个细节。 Weaviate 把 HNSW 向量索引放在内存中,并通过提交日志写入磁盘。容器被强制杀死时(docker kill、docker rm -f、内存溢出被杀,或停止超过 Docker 的宽限期),提交日志可能残缺不全,尚未记录的对象也就不在图中。
丢的不是对象,而是图。在 1.39.2 上实测:向一个共 700 个对象的集合导入 500 个对象后立即强制杀死容器,结果如下:
20 个对象完好地存在于存储中,向量检索却触达不到。
危险之处在于没有任何提示。服务端没有报错,没有告警,关于提交日志更是只字未提,没有任何日志可供排查。而大多数人首先会看的对象数量,显示得完全正常。
它也不会自行恢复。重启之后、优雅停止再启动之后、再来一次之后,以及重新写入同样的对象之后,缺失的仍是同样这 20 个。要修复,需要在 Dify 中对受影响的知识库重新索引,让集合彻底重建。
因此这里的关键在于预防。使用
docker compose stop 或 docker compose down,两者都会发送 SIGTERM,并等待刷写完成。超时值 -1 会无限期等待,不会在超时后改用 SIGKILL:
limit 执行一次 near_vector 查询。返回结果更少,差值就是触达不到的对象。
每次重启后等待索引挂载
在阶梯上的所有版本中,/v1/meta 都会在容器启动约两秒后开始响应。集合挂载则更慢,从 1.31 起慢得多。在整个阶梯上实测,从 /v1/meta 可用到集合查询首次成功之间的间隔为:
在这个窗口内发出的查询不会提示「仍在启动」,而是提示数据不存在:
GET /v1/objects?class=...返回 404,响应体为空。- GraphQL 查询返回 422,内容为
no graphql provider present, this is most likely because no schema is present. Import a schema first!。
/v1/meta。
每一步都要验证
既要确认数据还在,也要确认检索可用。服务能启动并不代表索引是健康的。 先设置密钥和集合名称,再执行 4 项检查。Dify 为集合命名时,会把知识库 ID 中的连字符替换为下划线。从第 2 项检查的结果中复制准确名称,不要自行拼接:docker compose stop -t -1 weaviate || exit 1,然后撤销你对镜像的修改。升级之前不要再运行 Compose:还原后的文件会用 1.27.0 启动,而更新的版本已经写入过这个数据卷。接着按照 Docker Compose 升级说明 升级到目标 Dify 版本。
恢复服务前执行一次测试检索。能召回分段,才说明向量索引完好;仅凭对象计数看不出这一点。
回滚失败的升级
启动新版本 Dify 前,先把 Weaviate 镜像改回semitechnologies/weaviate:1.27.0,然后还原初始备份:
保持不变的部分
集合结构保持原样,因此无需重建索引,知识库照常可用。Dify 把每个数据集存为Vector_index_<dataset_id>_Node 集合,其中 ID 的连字符会替换为下划线,并使用自带命名向量 default。Dify 不设置距离度量,因此集合采用服务器默认的余弦距离。该结构在升级前后完全一致。
Python weaviate-client 同样无需处理:Dify 1.14.0 至 1.18.0 固定的客户端版本都能与阶梯上的所有服务器版本配合工作,因此升级服务器时不必考虑 Dify 的版本。
如果运行的 Weaviate 服务器早于 1.27,或要从客户端 v3 迁移到 v4,请先参考 Weaviate v4 迁移指南,它覆盖 1.19.0 至 1.26.x 以及到 1.27 为止的 schema 迁移,之后再回到本文。