媒体 Schema 机制

通过 /v2/media-tool-configs 获取各模型的媒体工具参数 Schema,客户端据此动态生成表单,并用 sidecar 完成强校验调用。

设计意图

不同图像/视频模型的参数差异极大:尺寸枚举、画质档位、参考图数量、厂商特有字段各不相同。 传统做法是客户端硬编码每个模型的参数表单,模型一多就无法维护。

积木的解法是把参数 Schema 作为平台数据下发

  1. 平台为每个媒体模型维护一份工具参数 Schema(input_schema),按模型实时更新
  2. 客户端调用 GET /v2/media-tool-configs 拉取当前令牌可用模型的 Schema
  3. 客户端按 Schema 动态渲染表单(必填项、枚举下拉、数值范围、正则校验都由 Schema 描述)
  4. 提交媒体请求时携带 sidecar(jimu_media_tool),网关按同一份 Schema 做服务端强校验

这样新模型上架、参数调整都不需要客户端发版。

获取媒体工具配置

GET/v2/media-tool-configs
modelstring

可选。筛选指定模型,可重复(?model=a&model=b)或逗号分隔(?model=a,b)。不传则返回当前令牌可用且有媒体配置的全部模型

只返回当前令牌有权访问、已启用媒体能力且配置有效的模型,其余自动省略。

响应结构

响应200
{
  "success": true,
  "data": [
    {
      "model": "g-image-2",
      "revision": "3273a2a67e0e639a9ba9f5dc65f9f637d3e4348dc78e64af58a71667a50a41ac",
      "tools": {
        "jimu_image_generation": {
          "provider": "openai",
          "input_schema": {
            "type": "OBJECT",
            "properties": { ... },
            "required": ["prompt"],
            "additionalProperties": false
          }
        }
      },
      "image_fields": {
        "jimu_image_generation": [
          { "name": "image_uris", "array": true }
        ]
      }
    }
  ]
}
modelstring

模型 ID

revisionstring

该模型当前工具配置的 SHA-256。配置变化时 revision 必然变化,客户端据此判断是否需要刷新表单

toolsobject

工具名 → 工具配置。工具名为 jimu_image_generation(图像)或 jimu_video_generation(视频)

tools.*.providerstring

请求协议(视频工具不支持 open_responses

openai · gemini · open_responses
tools.*.input_schemaobject

参数 Schema(JSON object),描述该模型支持的参数全集

image_fieldsobject

tools 同级的可选字段,指出各工具中哪些参数承载图片输入。仅当 Schema 声明了图片输入字段时出现,不参与 revision 计算

image_fields.*[].namestring

承载图片输入的属性名

image_fields.*[].arrayboolean

该字段是否接受图片数组。为 false 时表示承载单张图片的标量字段,需要多张时填写多个此类字段

provider 决定入口路径

provider 不只是一个标记,它决定了你必须从哪条路径发请求。 服务端按「路径 + 工具名」匹配 provider,只有匹配上的组合才会走 sidecar 校验与原样透传; 路径与 provider 不匹配时 sidecar 不生效,请求会按普通请求处理。

provider工具可用入口路径
openaijimu_image_generation/v1/chat/completions/v1/completions/v1/images/generations/v1/images/edits/v1/edits
geminijimu_image_generation/v1beta/models/{模型}:generateContent/v1beta/models/{模型}:streamGenerateContent
不限jimu_video_generation/v1/video/generations/v1/videos
Schema 请求不能与协议格式转换同时使用。 当请求需要跨协议转换时携带 sidecar 会直接被拒绝—— 请按上表用该 provider 对应的原生入口发起请求,不要依赖网关的格式转换。

用 Schema 动态生成表单

input_schema 遵循一套受控的 JSON Schema 子集:

  • 根节点 type 语义上必须是 object;匹配大小写不敏感,响应字面量可能是 OBJECT 也可能是 object
  • 支持七种语义类型:object、array、string、number、integer、boolean、null——同样不保证响应中的大小写形式
  • properties 中每个参数必带非空 description(可直接用作表单 label/帮助文案)
  • required 数组列出必填参数,其余均为可选
  • 约束关键字:enum(枚举值)、pattern(正则)、minimum / maximummaxLengthitems(数组元素定义)
  • 支持 anyOf / oneOf / allOf 嵌套,不含 $ref
  • 未显式声明 additionalProperties 时按 false 处理——不要提交 Schema 之外的字段
匹配 type 前必须先做大小写归一。 Schema 校验大小写不敏感,本接口又原样回传存储的 Schema, 因此同一语义类型可能以 OBJECTobject 返回,取决于配置当初是怎么存的。 严格比对 OBJECT 的客户端会在配置存为 object 时失败——请先统一转小写(或转大写)再匹配。

真实示例:g-image-2

以下为生产环境实测返回(节选关键属性):

{
  "model": "g-image-2",
  "revision": "3273a2a67e0e639a9ba9f5dc65f9f637d3e4348dc78e64af58a71667a50a41ac",
  "tools": {
    "jimu_image_generation": {
      "provider": "openai",
      "input_schema": {
        "type": "OBJECT",
        "required": ["prompt"],
        "additionalProperties": false,
        "properties": {
          "prompt": {
            "type": "STRING",
            "description": "The desired image description. Maximum 32000 characters for GPT image models.",
            "maxLength": 32000
          },
          "size": {
            "type": "STRING",
            "description": "Use auto or WIDTHxHEIGHT. For gpt-image-2 both dimensions must be divisible by 16, aspect ratio must be between 1:3 and 3:1, and the maximum is 3840x2160.",
            "pattern": "^(auto|[1-9][0-9]*x[1-9][0-9]*)$"
          },
          "quality": {
            "type": "STRING",
            "description": "The generated image quality. Defaults to auto.",
            "enum": ["low", "medium", "high", "auto"]
          },
          "image_uris": {
            "type": "ARRAY",
            "description": "Optional reference images for editing. Maximum 10 images.",
            "items": { "type": "STRING", "description": "A local image file path or an HTTP/HTTPS image URL." }
          }
        }
      }
    }
  }
}

声明图片输入字段

Schema 的属性名直接采用上游原生协议的字段名,中间没有翻译层。因此「参考图」 这一语义在不同模型上的字段名并不统一,平台上同时存在三种形态:

形态字段名示例模型
数组image_urisg-image-2
数组(另一种命名)reference_imagesnova-g-image-2
多个独立标量input_imageinput_image_2input_image_8flux-2-pro、flux-2-max

客户端需要把用户选择的本地图片转成 base64 再填回这些字段,因此必须知道哪些属性 承载图片输入。字段名无法穷举上游的命名空间,所以由 Schema 在 description显式标记

标记含义
[jimu:image]该字段承载图片输入
[jimu:image:array]显式声明为图片数组(通常不必写,是否为数组由 type 推导)
[jimu:image:single]显式声明为单张图片

配置示例:

"input_image": {
  "type": "STRING",
  "description": "[jimu:image] The input image used as a generation or editing reference."
}

平台的处理保证:

  1. 标记在下发前会从 description剥除,客户端与模型看到的描述是干净的;
  2. 标记的增删不改变 revision,不会导致已有客户端出现 revision 失配;
  3. 图片字段清单以 image_fields 顶层字段下发,与 tools 同级——它不进入 input_schema,因此不改变 Schema 的 JSON 结构,也不参与 revision 计算。

响应中的形态:

{
  "model": "flux-2-pro",
  "revision": "50d7f31b...",
  "tools": { "jimu_image_generation": { "provider": "openai", "input_schema": {} } },
  "image_fields": {
    "jimu_image_generation": [
      { "name": "input_image", "array": false },
      { "name": "input_image_2", "array": false }
    ]
  }
}

每项含 name(属性名)与 arrayarrayfalse 表示这是承载单张图片的标量 字段,需要传多张时填写多个这样的字段;标量字段按名称排序下发, input_imageinput_image_2input_image_3 的顺序是稳定的。

若图片字段漏写标记,它不会出现在 image_fields 中,客户端也就不会把本地路径转成 base64,而是把原始路径字符串直接发给上游,导致上游 base64 解码失败 (如 Incorrect padding)或静默忽略该参数。为图片字段配置 Schema 时务必检查标记。
配置了 Schema 的模型只支持 JSON 请求体:multipart 端点(/v1/images/edits)会拒绝 携带 sidecar 的请求。因此参考图必须以 HTTP(S) URL 或 base64 data URI 通过 JSON 下发。

控件映射建议

Schema 特征建议控件
STRING + enum下拉选择
STRING + pattern / maxLength文本输入 + 前端校验
STRING 无约束(如 prompt)多行文本域
INTEGER / NUMBER + minimum/maximum数字输入或滑块
BOOLEAN开关
ARRAY + items多值输入(如多图上传/URL 列表)
参数在 required标记必填并做提交前校验

客户端应缓存 revision:启动时或发现 revision 变化时重新拉取 Schema 并重建表单, 避免平台侧更新参数后客户端还在提交旧字段。

Sidecar 运行时契约

对配置了 Schema 的模型,媒体请求(如 /v1/images/generations)顶层可携带 jimu_media_tool sidecar,让网关执行严格校验:

{
  "model": "g-image-2",
  "prompt": "一座雪山下的湖泊,清晨光线",
  "size": "1536x864",
  "quality": "high",
  "jimu_media_tool": {
    "name": "jimu_image_generation",
    "revision": "3273a2a67e0e639a9ba9f5dc65f9f637d3e4348dc78e64af58a71667a50a41ac",
    "arguments": {
      "prompt": "一座雪山下的湖泊,清晨光线",
      "size": "1536x864",
      "quality": "high"
    }
  }
}

运行时规则(务必逐条遵守):

  1. revision 必须与当前配置一致,不一致直接在请求上游前返回 HTTP 400
  2. arguments 中的字段必须全部在 Schema 中声明,且通过全部约束校验
  3. 请求顶层的同名媒体参数必须与 arguments 中的值 JSON 等值(两边都传且一致)
  4. 校验通过后网关删除 jimu_media_tool 再转发,上游永远不会看到 sidecar
  5. 经 Schema 校验的请求不做跨渠道重试,失败直接返回
  6. 反过来,已配置 Schema 的模型必须携带 sidecar:请求缺少 jimu_media_tool 时直接返回 HTTP 400(jimu_media_tool is required for model <模型名>),不会按宽松模式放行
  7. 只有未配置 Schema 的模型才能不带 sidecar 调用;对这类模型携带 sidecar 同样会 400 (media tool schema is not configured for model <模型名>
  8. sidecar 仅支持 JSON 请求体入口。multipart 端点(/v1/images/edits)不接受 jimu_media_tool,已配置 Schema 的模型因此无法经 multipart 链路调用
对配置了 Schema 的模型,sidecar 校验在计费与请求上游之前执行:参数错误被就地拦截, 返回的 400 错误信息能精确指出哪个字段违反了哪条约束(如 Additional property n is not allowed)。 这同时意味着接这类模型前必须先从 /v2/media-tool-configs 拉到实时 Schema—— Schema 声明的参数集合可能与模型的通用文档不同(例如 g-image-2 的 Schema 不含 nstream)。

完整调用示例

cURL
# 1. 拉取 Schema
curl "https://api.jimu.chat/v2/media-tool-configs?model=g-image-2" \
  -H "Authorization: Bearer $JIMU_API_KEY"

# 2. 携带 sidecar 提交(revision 替换为上一步的返回值)
curl https://api.jimu.chat/v1/images/generations \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $JIMU_API_KEY" \
  -d '{
    "model": "g-image-2",
    "prompt": "一座雪山下的湖泊,清晨光线",
    "size": "1536x864",
    "quality": "high",
    "jimu_media_tool": {
      "name": "jimu_image_generation",
      "revision": "<上一步返回的 revision>",
      "arguments": {
        "prompt": "一座雪山下的湖泊,清晨光线",
        "size": "1536x864",
        "quality": "high"
      }
    }
  }'

管理侧说明

媒体 Schema 由平台管理员在模型管理中维护(media_tool_configs 字段), 没有独立的公开写接口。普通接入方只需要读 /v2/media-tool-configs 并遵守 sidecar 契约。