# OpenAI 批量任务 API

本文档描述通过 ModelVerse 使用 **OpenAI 兼容的批量（Batch）异步任务**接口，适用于对大量请求进行离线、异步、低成本处理的场景（如批量对话补全）。整体流程与 OpenAI / Azure OpenAI 官方 Batch API 保持一致。

> **支持的 batch 模型可以在星图模型广场查看。**

批量任务的完整流程分为 5 步：

```
1. 上传文件 → 2. 查看文件状态 → 3. 创建 batch 任务 → 4. 轮询 batch 任务状态 → 5. 下载任务结果
```

---

## 认证说明

所有接口通过 HTTP 头携带 API Key（请勿在文档或代码中写入真实 Key，使用环境变量或占位符）：

- `Authorization: Bearer <your_api_key>`

Base URL 示例：`https://api.modelverse.cn`（海外可用 `https://api.umodelverse.ai`）。

> 说明：上传文件时，服务会**从输入文件（JSONL）的第一行自动识别 `body.model`**，并据此将后续文件、batch 任务路由到能够服务该模型的供应商。因此上传、创建任务时无需额外指定供应商。

---

## 输入文件格式

批量任务的输入文件为 **JSONL**（每行一个 JSON 对象），每行代表一个独立请求：

| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `custom_id` | string | 是 | 请求的自定义唯一标识，用于在结果文件中与输入一一对应 |
| `method` | string | 是 | 请求方法，固定为 `POST` |
| `url` | string | 是 | 目标接口，如 `/v1/chat/completions` |
| `body` | object | 是 | 具体请求体，其中 `model` 决定路由的模型与供应商 |

**示例（`batch_input.jsonl`）**

```jsonl
{"custom_id": "request-1", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "gpt-5-batch", "messages": [{"role": "system", "content": "你是一个乐于助人的助手。"}, {"role": "user", "content": "请用一句话介绍杭州。"}]}}
{"custom_id": "request-2", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "gpt-5-batch", "messages": [{"role": "user", "content": "1 加 1 等于几？"}]}}
```

> 同一个输入文件内所有请求的 `model` 应保持一致，服务以第一行的 `model` 作为整批任务的路由依据。

---

## 1. 上传文件

将批量任务的输入文件（JSONL）上传到平台，得到 `file_id` 供后续创建任务使用。

**请求**

- **方法 / 路径**：`POST /v1/files`
- **Content-Type**：`multipart/form-data`
- **表单字段**：
  - `purpose`：固定为 `batch`。
  - `file`：输入文件（JSONL）。

**响应字段**

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `id` | string | 文件 ID，用于第 2、3 步 |
| `object` | string | 固定为 `file` |
| `bytes` | int64 | 文件大小（字节） |
| `created_at` | int64 | 创建时间戳 |
| `filename` | string | 文件名 |
| `purpose` | string | 即请求中的 `batch` |
| `status` | string | 文件状态，如 `processed` |

**示例**

```bash
curl -X POST "https://api.modelverse.cn/v1/files" \
  -H "Authorization: Bearer $MODELVERSE_API_KEY" \
  -F "purpose=batch" \
  -F "file=@batch_input.jsonl"
```

**返回**

```json
{
  "id": "file-abc123",
  "object": "file",
  "bytes": 512,
  "created_at": 1781600000,
  "expires_at": 0,
  "filename": "batch_input.jsonl",
  "purpose": "batch",
  "status": "processed"
}
```

---

## 2. 查看文件状态

> **注意**：查看文件状态接口目前仅支持 GPT 系列模型（如 `gpt-5-batch`），其他模型的批量任务不支持通过该接口查询文件状态。

上传后可查询文件状态，确认文件已处理完成（`processed`）再创建 batch 任务。

**请求**

- **方法 / 路径**：`GET /v1/files/{file_id}`
- **路径参数**：`file_id` 为第 1 步返回的 `id`。

**响应字段（主要）**

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `id` | string | 文件 ID |
| `status` | string | 文件状态，`processed` 表示可用 |
| `bytes` | int64 | 文件大小 |
| `purpose` | string | `batch` |

**示例**

```bash
curl -X GET "https://api.modelverse.cn/v1/files/file-abc123" \
  -H "Authorization: Bearer $MODELVERSE_API_KEY"
```

**返回**

```json
{
  "id": "file-abc123",
  "object": "file",
  "bytes": 512,
  "created_at": 1781600000,
  "filename": "batch_input.jsonl",
  "purpose": "batch",
  "status": "processed"
}
```

---

## 3. 创建 batch 任务

使用已上传的文件创建批量任务。

**请求**

- **方法 / 路径**：`POST /v1/batches`
- **Content-Type**：`application/json`

**请求体**

| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `input_file_id` | string | 是 | 第 1 步上传返回的文件 ID |
| `endpoint` | string | 是 | 处理请求的目标接口，如 `/v1/chat/completions` |
| `completion_window` | string | 是 | 任务完成时间窗口，固定为 `24h` |
| `metadata` | object | 否 | 自定义元数据（键值均为字符串） |

**响应字段（主要）**

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `id` | string | batch 任务 ID，用于第 4 步轮询 |
| `object` | string | 固定为 `batch` |
| `status` | string | 任务状态，见下方状态说明 |
| `input_file_id` | string | 输入文件 ID |
| `output_file_id` | string | 结果文件 ID（任务完成后出现），用于第 5 步下载 |
| `error_file_id` | string | 错误明细文件 ID（部分请求失败时出现） |
| `request_counts` | object | 请求计数（`total` / `completed` / `failed`） |

**示例**

```bash
curl -X POST "https://api.modelverse.cn/v1/batches" \
  -H "Authorization: Bearer $MODELVERSE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "input_file_id": "file-abc123",
    "endpoint": "/v1/chat/completions",
    "completion_window": "24h",
    "metadata": {
      "job": "demo-batch"
    }
  }'
```

**返回**

```json
{
  "id": "batch_abc123",
  "object": "batch",
  "endpoint": "/v1/chat/completions",
  "errors": null,
  "input_file_id": "file-abc123",
  "completion_window": "24h",
  "status": "validating",
  "created_at": 1781600010,
  "request_counts": {
    "total": 0,
    "completed": 0,
    "failed": 0
  },
  "metadata": {
    "job": "demo-batch"
  }
}
```

---

## 4. 轮询 batch 任务状态

创建后需要轮询任务状态，直至任务进入终态（`completed` / `failed` / `expired` / `cancelled`）。

**请求**

- **方法 / 路径**：`GET /v1/batches/{batch_id}`
- **路径参数**：`batch_id` 为第 3 步返回的 `id`。

**任务状态（status）**

| status 取值 | 含义 |
| --- | --- |
| `validating` | 批处理开始前，正在校验输入文件 |
| `in_progress` | 输入文件校验通过，批处理执行中 |
| `finalizing` | 批处理已完成，正在准备结果文件 |
| `completed` | 已完成，结果文件已就绪 |
| `failed` | 输入文件校验失败或批处理失败 |
| `expired` | 未能在 24 小时窗口内完成 |
| `cancelling` | 正在取消（最多约需 10 分钟生效） |
| `cancelled` | 已取消 |

任务 `status` 变为 `completed` 后，可从响应中取 `output_file_id`（成功结果）与 `error_file_id`（失败明细，若有）用于第 5 步下载。

**示例**

```bash
curl -X GET "https://api.modelverse.cn/v1/batches/batch_abc123" \
  -H "Authorization: Bearer $MODELVERSE_API_KEY"
```

**返回**

```json
{
  "id": "batch_abc123",
  "object": "batch",
  "endpoint": "/v1/chat/completions",
  "errors": null,
  "input_file_id": "file-abc123",
  "completion_window": "24h",
  "status": "completed",
  "output_file_id": "file-out456",
  "error_file_id": "",
  "created_at": 1781600010,
  "in_progress_at": 1781600030,
  "finalizing_at": 1781600300,
  "completed_at": 1781600360,
  "request_counts": {
    "total": 2,
    "completed": 2,
    "failed": 0
  }
}
```

> 建议轮询间隔不小于 30 秒，避免过于频繁地请求。

---

## 5. 下载任务结果

任务完成后，使用 `output_file_id`（结果）或 `error_file_id`（错误明细）下载对应的 JSONL 文件。

**请求**

- **方法 / 路径**：`GET /v1/files/{file_id}/content`
- **路径参数**：`file_id` 为第 4 步返回的 `output_file_id` 或 `error_file_id`。

**响应**

- 成功：返回 JSONL 文件流（`Content-Type` 通常为 `application/octet-stream` 或 `application/jsonl`）。
- 结果文件中每行对应输入文件的一条请求，通过 `custom_id` 关联。

**示例**

```bash
curl -X GET "https://api.modelverse.cn/v1/files/file-out456/content" \
  -H "Authorization: Bearer $MODELVERSE_API_KEY" \
  -o batch_output.jsonl
```

**结果文件示例（每行一条）**

```jsonl
{"id": "batch_req_1", "custom_id": "request-1", "response": {"status_code": 200, "request_id": "req_aaa", "body": {"id": "chatcmpl-1", "object": "chat.completion", "model": "gpt-5-batch", "choices": [{"index": 0, "finish_reason": "stop", "message": {"role": "assistant", "content": "杭州是浙江省省会，以西湖美景和数字经济闻名。"}}], "usage": {"prompt_tokens": 30, "completion_tokens": 18, "total_tokens": 48}}}, "error": null}
{"id": "batch_req_2", "custom_id": "request-2", "response": {"status_code": 200, "request_id": "req_bbb", "body": {"id": "chatcmpl-2", "object": "chat.completion", "model": "gpt-5-batch", "choices": [{"index": 0, "finish_reason": "stop", "message": {"role": "assistant", "content": "1 加 1 等于 2。"}}], "usage": {"prompt_tokens": 12, "completion_tokens": 6, "total_tokens": 18}}}, "error": null}
```

---

## 小结

| 步骤 | 接口 | 说明 |
| --- | --- | --- |
| 1. 上传文件 | `POST /v1/files` | `purpose=batch`，上传 JSONL，返回 `file_id`；模型由文件首行自动识别 |
| 2. 查看文件状态 | `GET /v1/files/{file_id}` | 确认 `status=processed` |
| 3. 创建 batch 任务 | `POST /v1/batches` | 传 `input_file_id` / `endpoint` / `completion_window` |
| 4. 轮询任务状态 | `GET /v1/batches/{batch_id}` | 轮询至 `completed`，取 `output_file_id` |
| 5. 下载任务结果 | `GET /v1/files/{file_id}/content` | 用 `output_file_id` 下载结果 JSONL |
