非常游戏网
如何在 Vespa 中正确集成 ONNX 模型(使用 pyvespa)

如何在 Vespa 中正确集成 ONNX 模型(使用 pyvespa)

2026-05-29日常编程290500

本文详解在 pyvespa 中部署 onnx 模型时常见的路径引用错误,重点说明为何不能在应用包中直接引用宿主机或 docker 卷中的 onnx 文件,并提供可落地的解决方案:将模型文件嵌入 zip 包、正确配置 schema 与 model 定义、确保资源分配充足。

本文详解在 pyvespa 中部署 onnx 模型时常见的路径引用错误,重点说明为何不能在应用包中直接引用宿主机或 docker 卷中的 onnx 文件,并提供可落地的解决方案:将模型文件嵌入 zip 包、正确配置 schema 与 model 定义、确保资源分配充足。

在使用 pyvespa 将 ONNX 模型集成至 Vespa 向量数据库时,一个高频报错是:

json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

该错误表面看是 JSON 解析失败,但根源往往在于 ONNX 模型文件路径配置不当。Vespa 的应用包(.zip)在部署时会被完整上传并解压到容器内运行;它不支持从外部挂载卷(如 Docker volume)或宿主机绝对路径中动态加载模型文件。也就是说,以下写法是无效的:

# ❌ 错误示例:引用本地/卷路径(部署时不可达)
self.app_package.schema.add_model(
    Model(
        name="finance_onnx",
        model_file="/path/on/host/model.onnx",  # ← Vespa 容器内根本不存在此路径!
        input="input.1",
        output="output.1"
    )
)

✅ 正确做法是:将 ONNX 文件作为资源纳入应用包,并使用相对路径引用。具体步骤如下:

  1. 将 .onnx 文件置于项目目录下(如 models/finance_model.onnx)
  2. 在 app_package.schema.add_model() 中使用相对于 schema.sd 的路径(即包内路径)
  3. 确保 pyvespa 构建 ZIP 时包含该文件(默认会自动包含同目录及子目录下的二进制资源)

示例代码(修正后):

from vespa.package import ApplicationPackage, Schema, Document, Field, RankProfile, Model

def create_finance_app(self):
    self.app_package = ApplicationPackage(name="finance")

    # 定义文档结构(含 embedding 字段)
    self.app_package.schema = Schema(
        name="finance_doc",
        document=Document(
            fields=[
                Field(name="title", type="string"),
                Field(name="embedding", type="tensor(x[1024])"),
            ]
        )
    )

    # 添加 ONNX 模型(路径为包内相对路径)
    self.app_package.schema.add_model(
        Model(
            name="finance_onnx",
            model_file="models/finance_model.onnx",  # ✅ 必须存在于项目目录中,且会被打包进 .zip
            input="input.1",
            output="output.1"
        )
    )

    # 添加 rank profile,调用模型生成 embedding 或打分
    self.app_package.schema.add_rank_profile(
        RankProfile(
            name="default",
            first_phase="closeness(field, embedding)",
            # 若需用 ONNX 做 query encoding,可配合 query pipeline + function
            functions=[
                Function(
                    name="query_embedding",
                    expression="onnx(model, \"finance_onnx\", {\"input.1\": query(query_tensor)})"
                )
            ],
            inputs=[("query(query_tensor)", "tensor(x[1024])")]
        )
    )

    self.app_package.schema.mode = "streaming"
    return self.app_package

? 关键注意事项:

  • ✅ model_file 必须是相对于 application/ 根目录的路径(如 models/xxx.onnx),且该文件必须物理存在于你的 Python 项目目录中;
  • ✅ 部署前请确认 pyvespa 构建的 ZIP 包已包含该 ONNX 文件(可通过 unzip -l app.zip 验证);
  • ⚠️ Docker 环境下需为 Vespa 容器分配足够内存(ONNX 推理需额外资源),建议至少 --memory=4g;
  • ⚠️ ONNX 模型输入/输出张量名、维度必须与 Vespa schema 和 query tensor 定义严格一致,否则 runtime 报错;
  • ? 若仍报 JSON 解析错误,请检查 deploy_app() 中是否误传了空/非法 JSON(如未正确初始化 Vespa() 实例或 deploy() 参数异常)。

总结:Vespa 的模型部署是“静态打包”范式——所有依赖(包括 ONNX、词典、配置)必须内嵌于应用包。理解并遵守这一约束,是成功集成机器学习模型的第一步。