DifyEmbeddingRAG故障排查Nbility

Dify 更换 Embedding 报维度错误:先查模型、缓存和旧索引

Dify 知识库出现 expected dim 错误时,怎样核对实际向量维度,区分查询缓存、文档缓存和旧索引,并在临时知识库验证迁移。含 1.19.0 源码与近期报告的适用边界。

查看接入文档
Dify 更换 Embedding 报维度错误:先查模型、缓存和旧索引

Dify 能导入文档,聊天模型也能回答,但知识库一检索就报 Vector dimension error: expected dim: 512, got 384。这时先核对写入文档和查询问题用的向量是否匹配。换聊天模型、调提示词,都不会把已经存好的向量变成另一种格式。

更容易漏掉的是缓存:新建知识库、重新索引、等待 Redis 过期,分别影响不同的东西。操作做过一遍,未必说明旧向量已经退出整条链路。

本文于 2026 年 11 月 8 日查阅 Dify 当时的最新正式版 1.19.0、官方知识库文档,以及一条近期跨工作空间缓存报告。范围是经典知识库(Classic Knowledge Base)高质量索引中的文本向量检索;经济索引的关键词检索需要另外判断。本文没有部署 Dify 复现该缺陷,也没有测量检索准确率。初次配置 API 可先看 Dify 接入 Nbility 的基础流程。

维度错误告诉了你什么

Embedding 把一段文字变成一组数字。文档入库时生成文档向量,用户提问时生成查询向量,向量库再比较两者。报错里的 expected 和 got 提示当前操作使用的向量长度不符合目标要求;结合失败发生在写入还是检索阶段,才能判断是哪一端不匹配。

文档向量写入索引,查询向量进入同一索引;两条路径必须保持兼容

先把下面几项并排记下来,凭据只记“使用哪份配置”,不要复制 Key:

要核对的项目文档入库时当前查询时
工作空间、模型供应商与注册模型名当时保存的配置实际选中的配置
模型服务地址与有效模型版本生成旧向量的服务生成查询向量的服务
输出维度与相关参数实际返回的长度实际返回的长度
文本处理方式文档侧的前缀、归一化等模型要求的查询侧处理

维度相同只是必要条件。 两个不同模型都输出 1024 个数字,不代表这些数字处在相同的语义坐标里。有些模型还要求文档和查询采用不同前缀或任务参数,应按该模型的成对用法配置,不能简单要求两边请求逐字相同。

本站 Embeddings API 文档也区分了模型、输出维度和迁移索引:dimensions 只有部分模型支持。不要给不兼容的向量补零、截断,或给所有模型强加同一个 dimensions,只为让报错消失。

近期报告的触发条件比“换模型”更具体

Dify Issue #45223于 11 月 1 日提交。作者使用自部署源码环境,版本接口显示 1.18.0,对应 main@4c521a3c。两个工作空间属于同一个 Dify 部署,共享数据库和 Redis;分别注册相同的 provider/model 名称,实际连接的模型却不同,一个输出 512 维,另一个输出 384 维。

报告给出的结果是:

作者执行的操作作者报告的结果指向的检查范围
B 导入 A 已处理过的同一文本,再用新问题查询expected dim: 512, got 384文档向量可能复用了持久缓存
B 导入独有文本,但重复 A 刚问过的问题expected dim: 384, got 512查询向量可能复用了 Redis 缓存
同一份 B 独有文本,换成 A 没问过的新问题HTTP 200B 的模型与检索路径并非完全不可用

这些是报告作者的记录,不是本文的测试结果。它没有证明不同 Dify 实例之间会相互影响,也没有证明其他工作空间的源文档被泄露;相同维度下的召回影响也未测量。

截至本文查阅,Issue 仍为 Open;三条回复中,两条来自机器人,一条来自作者。关联 PR #45226也仍为 Open、尚未合并。作者对补丁的验证使用了新建临时数据集,说明的是避免新的缓存混用,不能当作旧索引已经修复的证据。该补丁还明确排除了同一工作空间内更换 endpoint/configuration 和模型负载均衡的情况。

因此,遇到类似错误时,可以把这条报告加入检查范围;不能直接给所有维度错误下同一个诊断。

为什么清 Redis、等十分钟、重新索引可能都不够

当天核对的 1.19.0 缓存实现中,文档缓存读取条件是模型名、文本哈希和供应商;查询缓存键也由供应商、模型名和查询哈希组成,没有工作空间字段。懒加载查询路径还会先尝试读取查询缓存,再解析实际模型。

这个实现足以解释为何仅比较模型显示名不够。排障时要区分三层:

查询缓存、文档缓存和向量索引的存放位置、复用路径与不同处理范围

  • Redis 查询缓存保存问题的向量。该版本的 TTL 是 600 秒,每次命中会重新续期。因此,“从第一次查询起等十分钟”不能保证过期;需要这条缓存键持续没有命中的空闲时间。
  • 数据库文档缓存保存文本对应的向量。重新入库仍可能先命中它,跳过真正的模型调用。清 Redis 不会删除这一层。
  • 向量库里的索引或集合保存已经写入的向量及相关结构。缓存不再返回旧值后,已有集合也不会自动变成正确的向量空间;按错误维度建立的集合,可能还需要按所用后端的方式重建。

这是对 1.19.0 对应代码的核对,不是对完整部署故障的独立复现。也不要把这里的 600 秒套到文档缓存或索引上。

官方知识库设置文档说明,切换 Embedding 模型会重新嵌入全部分段。这个正常操作与“复用同名配置、改了实际模型,但缓存身份未区分”的情况需要分开。已确认缓存混用时,只看到重新索引任务完成,还不足以证明每个分段都由预期模型重新计算。

先用公开文本确认接口真正返回多少维

下面的 Python 示例只请求一次 Nbility Embeddings API,不经过 Dify 的两类缓存。先通过私密方式设置 NBILITY_API_KEY 和 EMBEDDING_MODEL,模型取当前账号可用的真实向量模型 ID。不要填聊天模型,也不要把 Dify 的显示名称直接当作上游请求模型名。

import json
import math
import os
from urllib.request import Request, urlopen

request = Request(
    "https://api.nbility.ai/v1/embeddings",
    data=json.dumps({
        "model": os.environ["EMBEDDING_MODEL"],
        "input": ["Public embedding probe A.", "Public embedding probe B."],
        "encoding_format": "float",
    }).encode("utf-8"),
    headers={
        "Authorization": "Bearer " + os.environ["NBILITY_API_KEY"],
        "Content-Type": "application/json",
    },
)
with urlopen(request, timeout=60) as response:
    result = json.load(response)

rows = sorted(result["data"], key=lambda row: row["index"])
if [row["index"] for row in rows] != [0, 1]:
    raise ValueError("Expected one embedding for each input")
dimensions = []
for row in rows:
    vector = row["embedding"]
    if not vector or not all(math.isfinite(value) for value in vector):
        raise ValueError("Expected a nonempty finite vector")
    dimensions.append(len(vector))
if len(set(dimensions)) != 1:
    raise ValueError("The two vectors have different dimensions")
print("response model:", result.get("model", "not reported"))
print("dimensions:", dimensions)

示例不打印 Key、原始向量或业务文档。如果实际接入的是别的服务,使用自己已确认的 HTTPS 地址与对应凭据;如果 Dify 配置了模型专用参数,探测也要使用同样的有效参数。上面的请求没有额外指定 dimensions。

两条返回均非空、长度相同,说明这次直接调用有可用的向量结构。它仍不能证明 Dify 选中了同一份配置、旧索引维度正确,或检索效果符合要求。响应的 model 字段也只是服务返回的标签,不能单独证明模型身份。

本文只用本地合成响应验证了这段代码的正常与异常分支,没有发送带认证的 Embeddings 请求;真实维度需要读者在自己的配置下核对。

在临时知识库验证,再决定怎样迁移旧库

先记下 Dify、模型插件和 API/worker 的版本,以及原知识库使用的模型配置、向量库类型和失败阶段。保留原文档、应用绑定关系和检索设置,避免一边改模型一边改分段、Rerank 与提示词,最后无法判断是哪项起作用。

保留旧库、在临时库验证、检查实际召回、最后切换应用的迁移顺序

随后用一份临时知识库做小范围检查:

  1. 确认有效模型配置。 对照直接调用的维度、Dify 知识库实际选择的模型和向量集合要求。插件允许时,为不等价的模型配置使用可区分的注册项;不要随意修改服务端不接受的请求模型 ID。
  2. 导入少量公开测试文本。 使用本次独有、容易核对的内容,例如“演示资料 109:退货时限为签收后 7 天,仓库每周三盘点”。等待索引任务完成。新知识库本身不等于新缓存命名空间,因此文本和首次测试问题也应避开已知旧缓存。
  3. 直接看检索分段。 在官方说明的 Retrieval Testing 页面,先问“演示资料 109 规定几天内退货”,再重复原问题、换一种问法。成功要看到正确分段被召回;只看到 HTTP 200,或聊天模型答出“7 天”,都不充分。该页面修改的检索设置仅对当前测试会话有效。
  4. 确认旧数据的处理办法后再切换。 普通模型迁移可按官方设置流程重新嵌入;若已确认缓存身份混用,先核对维护者认可的修复与恢复说明,再处理受影响缓存和索引。保留旧库,完成新库验证后再调整应用绑定,并预留切回路径。

如果临时库正常、旧库仍失败,重点核对旧索引、原分段与旧缓存,但这还不能单独证明根因。若只有重复问题失败,新问题正常,应优先查查询缓存;若导入相同文本才失败,应进一步查文档缓存。把它们当作缩小范围的线索,不当作自动诊断规则。

不要用清空整个 Redis、删除全表或直接删生产向量集合来试运气。 尤其在共享部署中,先确定工作空间、模型配置和受影响范围。当前未合并 PR 的测试也没有提供现有受影响集合的一键恢复证明,不应把补丁直接包装成通用生产修复命令。

什么时候算排查完成

至少核对这几项:实际接口返回的维度符合模型配置;文档与查询使用兼容的向量空间;索引任务完成;原问题、重复问题和改写问题都召回预期分段;应用绑定的是验证过的知识库。若正式应用还有回答质量问题,再沿 Dify 知识库客服流程检查分段、检索与答案引用,不把所有问题都归给聊天模型。

使用 Nbility 接入时,先从 模型目录说明确认账号可用的向量模型,再核对实际 Embeddings 返回。统一 API 入口方便应用接入;已经写进 Dify 的缓存和向量索引,仍需要在 Dify 这一侧完成一致性检查。

核验资料

相关文章

Gemini CLI 聊天正常,摘要却报 503:后台模型怎么配
Gemini CLI模型配置故障排查

Gemini CLI 聊天正常,摘要却报 503:后台模型怎么配

Gemini CLI 主模型能用,后台会话摘要却提示 flash-lite 无可用渠道?对照 v0.67.0,区分聊天、会话摘要和上下文压缩,用任务级配置修改摘要模型,再核对实际请求。

用 Nbility 跑通你的 Agent 工作流

获取 API Key,统一接入 OpenAI 兼容模型和开发工具。

获取 API Key