[Bug]: obj serialization mismatch

用户在使用 LlamaIndex 的 BM25 retriever 时触发问题。该检索器会序列化节点以构建其 corpus 。当输入包含 IndexNode (其 obj 字段为 BaseNode 子类实例)时,检索时底层 TextNode 无法正确反序列化,导致数据丢失或格式错误。

[Bug]: obj serialization mismatch

[Bug]: obj serialization mismatch

快速结论:该报错发生在 LlamaIndex 0.14.21 中,当使用 BM25 retriever 或其它需要序列化 IndexNode(内含 BaseNode 类型的 obj 字段)的功能时。核心原因是 PR #18447 将 node.dict() 替换为 node.model_dump(),但 IndexNode 未提供对应的 @model_serializer 重载,导致反序列化时因缺少 __type__/__data__ 包装而失败。优先排查 node_to_metadata_dictmetadata_dict_to_node 调用路径上的序列化逻辑。

问题场景

用户在使用 LlamaIndexBM25 retriever 时触发问题。该检索器会序列化节点以构建其 corpus。当输入包含 IndexNode(其 obj 字段为 BaseNode 子类实例)时,检索时底层 TextNode 无法正确反序列化,导致数据丢失或格式错误。

报错原文

# 实际发生的异常(根据 Issue 描述,反序列化失败后回退为 TextNode,非显式报错)
# 核心表现为 obj 字段缺少 __type__ 和 __data__ 包装,导致 json_to_doc 抛出异常
# IndexNode 的 obj 字段在反序列化时被替换为包含原始序列化内容的 TextNode 备份方案

原因分析

这是确认的 Bug。PR #18447 在 node_to_metadata_dict() 中将 node.dict() 替换为 node.model_dump(mode="json"),但 IndexNode 仅重写了 dict() 方法(用于通过 doc_to_json() 包装 obj 字段的 __type__),没有提供对应的 @model_serializermodel_dump() 重写。因此 Pydantic 的默认序列化直接执行,obj 字段失去了 __type__/__data__ 包装结构。

反序列化时,metadata_dict_to_node()BaseComponent.from_json()IndexNode.from_dict()json_to_doc() 期望从 obj 中解析出 __type____data__ 键。由于缺少这些键,反序列化失败,并回退为将原始序列化内容作为文本创建新的 TextNode

环境排查

  • LlamaIndex 版本:0.14.21(Issue 中报告的版本,也可能影响后续版本直到修复)
  • Python 版本:无特定要求,但需确保运行 LlamaIndex 兼容环境
  • 相关模块路径
    • llama_index/core/schema.py 中的 IndexNode 类(dict() 重写行 ~886-903,from_dict() 行 ~928-935)
    • llama_index/core/storage/docstore/utils.py 中的 json_to_doc() 函数(行 ~22-46)
    • llama_index/core/storage/docstore/utils.py 中的 doc_to_json() 函数
  • 测试覆盖:现有测试文件 tests/storage/docstore/test_simple_docstore.py 中缺乏 IndexNode 往返序列化(含 BaseNode obj 字段)的测试用例

解决步骤

  1. 定位问题代码:打开 llama_index/core/schema.py 文件,找到 IndexNode 类定义。
  2. 添加自定义序列化器:在 IndexNode 类中添加 @model_serializer(mode="wrap") 重写,复制现有 dict() 方法中的逻辑,确保 obj 字段(当为 BaseNode 实例时)通过 doc_to_json() 进行包装。可优先尝试以下代码(来自 Issue 讨论):
    @model_serializer(mode="wrap")
    def custom_model_dump(self, handler: SerializerFunctionWrapHandler, info: SerializationInfo) -> Dict[str, Any]:
        from llama_index.core.storage.docstore.utils import doc_to_json
    
        data = handler(self)
        try:
            if self.obj is None:
                data["obj"] = None
            elif isinstance(self.obj, BaseNode):
                data["obj"] = doc_to_json(self.obj)
            elif isinstance(self.obj, BaseModel):
                data["obj"] = self.obj.model_dump()
            else:
                data["obj"] = json.dumps(self.obj)
        except Exception:
            raise ValueError("IndexNode obj is not serializable: " + str(self.obj))
        return data
  3. 添加测试用例:在 tests/storage/docstore/test_simple_docstore.py 中增加 IndexNode 往返序列化的测试,验证 BaseNode obj 字段能正确还原。
  4. 提交修复:向 LlamaIndex 仓库提交 PR 或本地应用补丁。

验证方法

运行之前触发问题的 BM25 retriever 工作流:

  • 确认 IndexNode 的内部 BaseNode(如 TextNode)在序列化后能正确反序列化还原,而非回退为文本内容。
  • 添加并运行新的单元测试,验证 IndexNode 序列化/反序列化前后 obj 字段一致。

参考来源

run-llama/llama_index #21611

GamsGo AI

AI 工具推荐

想把多个 AI 模型放在一个入口?

GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。

了解 GamsGo AI

推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。

celebrityanime
celebrityanime
文章: 8837

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注