HiAPI
博客

教程

在 hiapi 上用单一统一 API 构建多模型 AI 应用

2026年11月3日
在 hiapi 上用单一统一 API 构建多模型 AI 应用
模型
seedance-2.5

你将构建什么

大多数团队最终会为一个产品调用三四个不同的 AI 提供商:用文生图模型做缩略图,用文生视频模型做社交短视频,也许还要用 TTS 模型做旁白。每个提供商都有各自的 SDK、各自的认证方案、各自的轮询逻辑。hiapi 把这一切收拢为一种端点模式:POST /v1/tasks 创建任务,GET /v1/tasks/:id 查询任务,平台上的每个生成模型都适用。

本教程用三个真实且当前在线的模型演示这套集成模式——z-image(文生图)、qwen-image-2.0(文生图,schema 不同)以及 seedance-2.5(文生视频)——让你看清哪些地方 API 完全一致、哪些地方只是每个模型的 input 对象不同。

前置条件

  • 从控制台获取的 hiapi API key
  • curl 或任何能发送 JSON 的 HTTP 客户端
  • 无需 SDK——下面每个示例都是纯 HTTP 调用

每个请求都需要一个请求头:

Authorization: Bearer <your-api-key>

key 无效或缺失时,会在触及任何模型之前返回 401 类错误:

{
  "error": {
    "code": "permission_denied",
    "message": "invalid api key",
    "request_id": "req_...",
    "type": "hiapi_error"
  }
}

不存在无密钥或匿名模式——每次 /v1/tasks 调用都必须携带有效的 bearer token。密钥轮换与作用域请参见认证。

最小可运行示例

1. 创建任务

创建调用的结构始终相同:一个 model id 和一个模型专属的 input 对象。下面是用 z-image 创建图片任务:

curl -s -X POST https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "z-image",
    "input": {
      "prompt": "a minimalist workspace, soft morning light, isometric illustration",
      "aspect_ratio": "16:9"
    }
  }'

响应会立即返回——生成是异步进行的:

{
  "code": 200,
  "message": "ok",
  "data": {
    "taskId": "tk-hiapi-xxxxxxxxxxxx",
    "status": "queued"
  }
}

现在用 qwen-image-2.0 走同样的模式。同样的端点、同样的外层结构——只有 input 不同(该模型接收 size 字符串,而不是 aspect_ratio):

curl -s -X POST https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen-image-2.0",
    "input": {
      "prompt": "a minimalist workspace, soft morning light, isometric illustration",
      "size": "2048*2048"
    }
  }'

再用 seedance-2.5/text-to-video 创建一个视频任务——仍是同样的外层结构,现在多了 duration 和取值更宽的 aspect_ratio 枚举:

curl -s -X POST https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "seedance-2.5/text-to-video",
    "input": {
      "prompt": "a paper airplane gliding through a sunlit office, slow motion",
      "duration": 5,
      "aspect_ratio": "16:9"
    }
  }'

这就是核心要点:任务的外层结构从不改变,只有 input 会变。 hiapi 上每个模型都在其模型页面上记录了自己的 input schema——在构建新的集成之前务必查看具体模型的 schema,因为 aspect_ratio、size 和 duration 这类字段在不同模型之间不可互换。

2. 轮询结果

curl -s https://api.hiapi.ai/v1/tasks/tk-hiapi-xxxxxxxxxxxx \
  -H "Authorization: Bearer $HIAPI_API_KEY"

status 会依次经过 queued → handling → archiving,最终进入 success 或 fail 终态。成功时,data.output 是一个数组——大多数图片/视频模型返回一个条目,但单个任务可以返回多种输出类型(例如视频模型同时返回 video 和 thumbnail):

{
  "code": 200,
  "message": "ok",
  "data": {
    "taskId": "tk-hiapi-xxxxxxxxxxxx",
    "status": "success",
    "output": [
      { "type": "image", "url": "https://...", "expireAt": "2026-10-09T00:00:00Z" }
    ]
  }
}

expireAt 很重要——输出 URL 默认是临时的。任务一完成就下载字节内容(或重新上传到自己的存储)。如果需要平台更长期地保留文件,可在创建时设置 storage: "persistent" 或事后升级——参见存储。

失败时,你会得到 error 对象而不是 output:

{
  "code": 200,
  "message": "ok",
  "data": {
    "taskId": "tk-hiapi-xxxxxxxxxxxx",
    "status": "fail",
    "error": { "code": "...", "message": "..." }
  }
}

下面这个最小的 Python 轮询循环对上面所有模型都同样适用:

import time
import requests

def run_task(model: str, input_payload: dict, api_key: str) -> list[dict]:
    headers = {"Authorization": f"Bearer {api_key}"}
    create = requests.post(
        "https://api.hiapi.ai/v1/tasks",
        headers=headers,
        json={"model": model, "input": input_payload},
    ).json()
    task_id = create["data"]["taskId"]

    time.sleep(3)  # initial wait before first poll
    while True:
        poll = requests.get(
            f"https://api.hiapi.ai/v1/tasks/{task_id}", headers=headers
        ).json()
        status = poll["data"]["status"]
        if status == "success":
            return poll["data"]["output"]
        if status == "fail":
            raise RuntimeError(poll["data"]["error"])
        time.sleep(4)  # 3-5s between polls; use 5-10s for video models

生产环境模式

在生产环境中使用回调代替轮询

轮询对于脚本或 CLI 工具没问题,但在任何真实流量规模下,更推荐使用回调:创建任务时传入 callback 对象,hiapi 会把终态结果 POST 到你的端点,而不是让你在循环里反复请求 GET /v1/tasks/:id。

{
  "model": "z-image",
  "input": { "prompt": "...", "aspect_ratio": "1:1" },
  "callback": { "url": "https://yourapp.com/webhooks/hiapi", "when": "final" }
}

when: "final" 意味着你只会收到一次 POST,在终态(success 或 fail)时触发——没有中间 handling/archiving 状态带来的噪音。如果你已配置了回调却什么都没收到,请检查你的端点是否可公开访问并快速返回 2xx;关于回调静默丢失最常见的原因,参见这篇相关文章。

幂等重试

网络抖动在所难免。如果在超时后重试 POST /v1/tasks 调用而没有保护措施,你可能会创建(并被计费)重复任务。发送一个 Idempotency-Key 请求头(任意不超过 255 字节的字符串,通常是每个逻辑请求生成的 UUID),同一 key 的重试会返回原始任务而不是创建新任务:

curl -s -X POST https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Idempotency-Key: 8f14e45f-ceea-467e-bd5f-...-9a2c" \
  -H "Content-Type: application/json" \
  -d '{"model": "z-image", "input": {"prompt": "...", "aspect_ratio": "1:1"}}'

按模型处理校验错误

由于每个模型都有自己的 input schema,最常见的失败模式是对某个字段返回 400——该字段对某模型有效、对另一模型无效,例如把 aspect_ratio 发给期望 size 的模型:

{
  "code": 400,
  "data": null,
  "error_code": "INVALID_REQUEST",
  "message": "invalid input: aspect_ratio: value must be one of '1:1', '4:3', '3:4', '16:9', '9:16'"
}

如果你在构建多模型路由器(让用户或你自己的逻辑在运行时选择模型),请维护一个小的按模型输入构建器注册表,而不是一个共享的 payload 结构:

MODEL_INPUT_BUILDERS = {
    "z-image": lambda prompt, **kw: {
        "prompt": prompt, "aspect_ratio": kw.get("aspect_ratio", "1:1")
    },
    "qwen-image-2.0": lambda prompt, **kw: {
        "prompt": prompt, "size": kw.get("size", "2048*2048")
    },
    "seedance-2.5/text-to-video": lambda prompt, **kw: {
        "prompt": prompt,
        "duration": kw.get("duration", 5),
        "aspect_ratio": kw.get("aspect_ratio", "16:9"),
    },
}

def build_task_payload(model: str, prompt: str, **kw) -> dict:
    return {"model": model, "input": MODEL_INPUT_BUILDERS[model](prompt, **kw)}

这样就把每个模型的特殊之处集中在一处,而不是散落在每个调用点。不存在或跨账号的 taskId 会返回普通的 404:

{ "code": 404, "message": "task not found", "data": null }

而临时的 503 应使用指数退避重试,而不是直接暴露给用户——速率限制和容量限制记录在速率限制中。

相关阅读

常见问题

每个模型都需要不同的 SDK 或 API key 吗? 不需要。一个 API key、一种端点模式(/v1/tasks),适用于平台上的每个模型。只有请求体中的 input 对象会变。

为什么刚创建完任务,响应里还没有 output? 生成是异步的。创建调用只返回 taskId 和 status: "queued"——你必须轮询 GET /v1/tasks/:id(或使用回调),直到 status 达到 success 或 fail。

可以为了快速测试而不带认证调用 API 吗? 不可以——每次 /v1/tasks 调用都需要有效的 Authorization: Bearer key。生产调用没有无密钥或演示模式;请先从控制台生成 key。

如果在输出 URL 过期后轮询会怎样? 任务记录本身会保留,但非持久化任务的 output[].url 在 expireAt 之后将不再可解析。成功时请立即下载文件,或者如果需要长期保留,在创建时设置 storage: "persistent"。

如何知道某个模型接受哪些字段? 查看模型下该模型的页面——每个都记录了其确切的 input schema。不要假设 aspect_ratio、size 或 duration 可以在模型之间通用;如上所示,z-image 和 qwen-image-2.0 在如何表达图片形状上就已经不一致了。

立即开始构建持久 AI 产物

获取 API 密钥,通过一个基于任务(task)的 API 调用图像、视频和音频模型。

阅读 API 文档