# YunQi AI 完整 API Reference（供 Agent 读取）

> 文档版本：v1.0.2  
> 更新日期：2026-08-13  
> 本次更新：`gpt-image-2` 新增文生图调用方式，补充 `POST /v1/images/generations`、JSON 参数与完整 cURL 示例；原有参考图编辑方式继续使用 `POST /v1/images/edits`。

本文件汇总 YunQi AI 文档站当前发布的全部接口、参数、模型能力、媒体格式、图片尺寸、返回结构、错误处理和客户端配置。它适合直接交给 Codex、Claude Code、WorkBuddy 或其他开发 Agent，用来完成接入、实现调用、排查错误和解析返回。

## 0. Agent 执行规则

1. 让用户在 YunQi AI 控制台创建 API Key，并将密钥保存在环境变量或客户端私有配置中。
2. 开始实现前调用 `GET /v1/models`，以这把 API Key 实际返回的完整模型 ID 为准。
3. 根据模型和任务选择协议，不要混用不同协议的字段结构。
4. 先发送只含必填字段的最小请求，再加入流式输出、工具、多模态或图片参数。
5. 遍历完整响应数组和内容块，不要只读取第一个图片或第一个内容块。
6. 不要把 API Key 写进仓库、日志、截图或回复正文。

## 1. 连接清单

```yaml
provider: YunQi AI
console: https://www.yunqiai.chat
openai_base_url: https://www.yunqiai.chat/v1
anthropic_base_url: https://www.yunqiai.chat
gemini_generate_content_url: https://www.yunqiai.chat/v1beta/models/{model}:generateContent
models_endpoint: GET https://www.yunqiai.chat/v1/models
authentication:
  openai: "Authorization: Bearer YOUR_API_KEY"
  anthropic: "x-api-key: YOUR_API_KEY"
  gemini: "x-goog-api-key: YOUR_API_KEY"
```

### Base URL 与完整接口地址

- OpenAI SDK、Codex、Cherry Studio、Chatbox 等需要 Base URL 的客户端填写 `https://www.yunqiai.chat/v1`。
- Anthropic SDK 与 Claude Code 填写 `https://www.yunqiai.chat`，客户端会继续请求 `/v1/messages`。
- Gemini 原生调用使用完整地址 `https://www.yunqiai.chat/v1beta/models/{model}:generateContent`。除非客户端明确说明其路径拼接规则，不要把站点根地址直接当作 Gemini SDK Base URL。
- WorkBuddy 的自定义协议字段要求完整地址，填写 `https://www.yunqiai.chat/v1/chat/completions`。
- 不要在已经包含 `/v1` 的 Base URL 后再次拼接 `/v1`。

### 鉴权与 Content-Type

| 协议 | 鉴权请求头 | 常用 Content-Type |
|---|---|---|
| OpenAI Compatible、Responses、Images | `Authorization: Bearer YOUR_API_KEY` | JSON 请求使用 `application/json`；图片编辑使用 `multipart/form-data` |
| Anthropic Messages | `x-api-key: YOUR_API_KEY` | `application/json` |
| Gemini Generate Content | `x-goog-api-key: YOUR_API_KEY` | `application/json` |

Anthropic Messages 还需要：

```text
anthropic-version: 2023-06-01
```

## 2. 当前发布接口

| 场景 | 方法与路径 | 关键输入 | 鉴权 | 适用模型 |
|---|---|---|---|---|
| 获取模型列表 | `GET /v1/models` | 无请求体 | Bearer | 当前 API Key 可调用的模型 |
| OpenAI 对话 | `POST /v1/chat/completions` | `model`、`messages` | Bearer | GPT、Claude、Gemini 文本模型 |
| OpenAI Responses | `POST /v1/responses` | `model`、`input` | Bearer | GPT 系列 |
| Anthropic Messages | `POST /v1/messages` | `model`、`messages`、`max_tokens` | `x-api-key` | Claude 系列 |
| Gemini 文本与多模态 | `POST /v1beta/models/{model}:generateContent` | `contents` | `x-goog-api-key` | Gemini 文本模型 |
| Gemini 生图与参考图编辑 | `POST /v1beta/models/{model}:generateContent` | `contents`、`generationConfig.imageConfig` | `x-goog-api-key` | Gemini Image 模型 |
| OpenAI 图片生成 | `POST /v1/images/generations` | `model`、`prompt` | Bearer | `gpt-image-2-each`、`gpt-image-2` |
| OpenAI 图片编辑 | `POST /v1/images/edits` | `model`、`prompt`、`image` | Bearer | `gpt-image-2-each`、`gpt-image-2` |

Gemini Image 的 `generateContent` 在当前 HTTP 响应中返回结果。GPT Images 在 `stream: false` 时返回一个 JSON 响应，在 `stream: true` 时通过当前 SSE 连接发送图像事件。本页没有发布图片任务查询端点；连接超时时，不能通过不存在的任务状态接口确认结果。

## 3. 模型目录与能力

模型目录用于选型。实现时仍需先调用 `GET /v1/models`，因为不同 API Key 可见的模型可能不同。

| 模型 ID | 输入 | 输出 | 首选协议 | 主要用途或边界 |
|---|---|---|---|---|
| `gpt-5.6-sol` | 文本、图片 | 文本 | Chat Completions | 复杂推理、高难度代码、Agent 工作流与图片理解 |
| `gpt-5.6-terra` | 文本 | 文本 | Chat Completions | 通用对话与 Agent 工作流，兼顾效果、速度与成本 |
| `gpt-5.6-luna` | 文本、图片 | 文本 | Chat Completions | 低延迟、图片理解、分类、提取、改写与高频轻量任务 |
| `gpt-5.5` | 文本、图片、文件 | 文本 | Responses | 图片理解、文件任务、工具调用、结构化输出 |
| `claude-sonnet-4-6` | 文本、图片 | 文本 | Anthropic Messages | 代码、长文本、图片理解与工具调用 |
| `claude-opus-4-6` | 文本 | 文本 | Anthropic Messages | 复杂推理与长上下文任务 |
| `claude-opus-4-7` | 文本、图片、文件 | 文本 | Anthropic Messages | 推理、工具、图片与文件任务 |
| `claude-opus-4-8` | 文本 | 文本 | Anthropic Messages | 高阶推理与大型代码任务 |
| `claude-sonnet-5` | 文本 | 文本 | Anthropic Messages | 日常开发、审阅与通用推理 |
| `claude-fable-5` | 文本 | 文本 | Anthropic Messages | 高难度代码、架构理解与长任务 |
| `gemini-3.5-flash` | 文本、图片、视频、音频、PDF | 文本 | Gemini Generate Content | 低延迟多模态；上下文 1,048,576 tokens；输出上限 65,536 tokens |
| `gemini-3.1-pro-preview` | 文本、图片、视频、音频、PDF | 文本 | Gemini Generate Content | 复杂多模态推理；上下文 1,048,576 tokens；输出上限 65,536 tokens |
| `gemini-3.1-flash-image` | 文本、参考图 | 图片、文本 | Gemini Generate Content | 512、1K、2K、4K；最多 14 张参考图 |
| `gemini-3-pro-image-preview` | 文本、参考图 | 图片、文本 | Gemini Generate Content | 1K、2K、4K；最多 14 张参考图 |
| `gpt-image-2-each` | 文本、参考图 | 图片 | Images Generations / Edits | 文本生图、参考图编辑与画面文字排版；一次请求一张图 |
| `gpt-image-2` | 文本、参考图、蒙版 | 图片 | Images Generations / Edits | 文本生图、参考图编辑、多图合成与局部重绘 |
| `glm-5.2` | 文本 | 文本 | Chat Completions | 通用文本任务；使用包含该模型的智谱分组 API Key |

## 4. GET `/v1/models`

返回当前 API Key 可以直接调用的模型。客户端模型选择器应使用 `data[].id`，不要把页面展示名称当作模型 ID。

### 请求

```bash
curl https://www.yunqiai.chat/v1/models \
  -H "Authorization: Bearer YOUR_API_KEY"
```

### 响应结构

```json
{
  "object": "list",
  "data": [
    {"id": "gpt-5.6-sol", "object": "model"},
    {"id": "claude-sonnet-4-6", "object": "model"},
    {"id": "gemini-3.5-flash", "object": "model"}
  ]
}
```

### Agent 处理要求

- 使用 `data[].id` 填充模型列表。
- 切换 API Key 后重新读取模型列表。
- 收到 `model_not_found` 时重新读取列表，并检查是否使用了正确分组的 API Key。

## 5. POST `/v1/chat/completions`

OpenAI 兼容对话接口。GPT、Claude 与 Gemini 文本模型可以使用此接口；模型专属能力优先使用上方模型表中的首选协议。

### 请求参数

| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `model` | `string` | 是 | 使用 `GET /v1/models` 返回的完整模型 ID |
| `messages` | `array` | 是 | `system`、`user`、`assistant`、`tool` 消息数组 |
| `max_completion_tokens` | `integer` | 否 | 最大生成 Token；上限随模型变化 |
| `stream` | `boolean` | 否 | 是否使用 SSE 流式返回；默认 `false` |
| `temperature` | `number` | 否 | `0–2`；推理模型建议省略，使用模型默认值 |
| `top_p` | `number` | 否 | `0–1`；通常与 `temperature` 只设置一个 |
| `n` | `integer` | 否 | 返回候选数量；通常使用 `1` 控制费用 |
| `stop` | `string` 或 `string[]` | 否 | 停止序列；使用模型默认行为时省略 |
| `tools` | `array` | 否 | OpenAI Function Calling 工具定义 |
| `tool_choice` | `string` 或 `object` | 否 | `auto`、`none`、`required` 或指定工具 |
| `response_format` | `object` | 否 | 普通文本或 JSON Schema 结构化输出 |

### 最小请求

```bash
curl --request POST \
  --url https://www.yunqiai.chat/v1/chat/completions \
  --header "Authorization: Bearer YOUR_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "model": "gpt-5.6-sol",
    "messages": [
      {"role": "user", "content": "你好，请介绍一下你自己"}
    ],
    "stream": false
  }'
```

### 图片输入

OpenAI 兼容消息使用 `image_url` 内容块。Base64 必须写成完整 Data URL。

```json
{
  "model": "gpt-5.6-sol",
  "messages": [
    {
      "role": "user",
      "content": [
        {"type": "text", "text": "描述这张图片"},
        {
          "type": "image_url",
          "image_url": {
            "url": "data:image/png;base64,BASE64_IMAGE_DATA",
            "detail": "low"
          }
        }
      ]
    }
  ]
}
```

### 响应结构

```json
{
  "id": "chatcmpl_01JY7X",
  "object": "chat.completion",
  "model": "gpt-5.6-sol",
  "choices": [
    {
      "index": 0,
      "message": {"role": "assistant", "content": "你好！我是一个 AI 助手。"},
      "finish_reason": "stop"
    }
  ]
}
```

非流式文本通常读取 `choices[0].message.content`。如果 `n` 大于 `1`，遍历全部 `choices[]`。

## 6. POST `/v1/responses`

OpenAI Responses 原生请求格式，适用于 GPT 系列。

### 请求参数

| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `model` | `string` | 是 | 要调用的 GPT 模型 ID |
| `input` | `string` 或 `array` | 是 | 文本、消息、图片或 `input_file` 文件输入项 |
| `max_output_tokens` | `integer` | 否 | 从 `16` 起；最大值随模型变化 |
| `stream` | `boolean` | 否 | 是否使用 SSE 流式返回；默认 `false` |
| `temperature` | `number` | 否 | `0–2`；推理模型建议省略，使用模型默认值 |
| `top_p` | `number` | 否 | `0–1`；通常与 `temperature` 只设置一个 |
| `tools` | `array` | 否 | 函数、Web 搜索、图像生成等工具定义 |
| `previous_response_id` | `string` | 否 | 继续上一轮 Responses 会话 |
| `metadata` | `object` | 否 | 业务元数据 |

### 最小请求

```bash
curl --request POST \
  --url https://www.yunqiai.chat/v1/responses \
  --header "Authorization: Bearer YOUR_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "model": "gpt-5.6-sol",
    "input": "用三句话解释量子计算",
    "max_output_tokens": 1024,
    "stream": false
  }'
```

### Base64 图片输入

Responses 的 `input_image.image_url` 使用完整 Data URL，不要只传裸 Base64。

```json
{
  "model": "gpt-5.6-luna",
  "input": [
    {
      "role": "user",
      "content": [
        {"type": "input_text", "text": "描述这张图片"},
        {
          "type": "input_image",
          "image_url": "data:image/png;base64,BASE64_IMAGE_DATA",
          "detail": "low"
        }
      ]
    }
  ],
  "max_output_tokens": 256
}
```

### 文件输入（`gpt-5.5`）

`gpt-5.5` 的 Responses 请求使用 `input_file` 内容项。每个文件只选择一种来源：

| 来源 | 必需字段 | 写法 |
|---|---|---|
| 内联文件 | `type`、`filename`、`file_data` | `file_data` 使用完整 Data URL，例如 `data:application/pdf;base64,...` |
| 外部地址 | `type`、`file_url` | 使用服务端可以访问的完整 HTTPS URL |
| 已有文件 ID | `type`、`file_id` | 填写调用环境中已经取得的有效文件 ID |

内联 PDF 请求示例：

```json
{
  "model": "gpt-5.5",
  "input": [
    {
      "role": "user",
      "content": [
        {
          "type": "input_file",
          "filename": "brief.pdf",
          "file_data": "data:application/pdf;base64,BASE64_FILE_DATA"
        },
        {
          "type": "input_text",
          "text": "提取这份文件的关键结论。"
        }
      ]
    }
  ],
  "max_output_tokens": 1024
}
```

另外两种来源只替换文件项：

```json
{"type": "input_file", "file_url": "https://example.com/brief.pdf"}
```

```json
{"type": "input_file", "file_id": "file_123"}
```

本页未发布文件上传端点，因此不要为取得 `file_id` 自行拼接上传路径。文件类型与大小以当前请求返回为准；收到格式或大小错误时，改用 PDF、减小文件或拆分后重试。

### 响应读取

原始 HTTP JSON 使用类型化的 `output[]`，例如：

```json
{
  "id": "resp_01JY7X",
  "object": "response",
  "model": "gpt-5.5",
  "output": [
    {
      "id": "rs_01JY7X",
      "type": "reasoning",
      "summary": []
    },
    {
      "id": "msg_01JY7X",
      "type": "message",
      "status": "completed",
      "role": "assistant",
      "content": [
        {
          "type": "output_text",
          "text": "这是模型返回的文本。",
          "annotations": []
        }
      ]
    }
  ]
}
```

OpenAI SDK 提供的 `response.output_text` 是把文本内容聚合后的便利属性，不是需要从原始 HTTP JSON 顶层读取的独立字段。只需要最终文本时可使用 SDK 的 `output_text`；处理推理、工具或多模态输出时，应遍历 `response.output[]`，按每个 Item 的 `type` 分支，再遍历消息 Item 的 `content[]`。

继续会话时，把上一轮响应的 `id` 填入下一次请求的 `previous_response_id`。

## 7. POST `/v1/messages`

Anthropic 原生 Messages API，适用于 Claude 系列。

### 必需请求头

```text
x-api-key: YOUR_API_KEY
anthropic-version: 2023-06-01
Content-Type: application/json
```

### 请求参数

| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `model` | `string` | 是 | 使用 `GET /v1/models` 返回的完整 Claude 模型 ID |
| `messages` | `array` | 是 | `user` 与 `assistant` 消息数组；图片使用 `image`，文档使用 `document` 内容块 |
| `max_tokens` | `integer` | 是 | 最大输出 Token，填写正整数；上限随模型变化 |
| `system` | `string` 或 `array` | 否 | 顶层系统提示；Messages API 没有 `system` 角色 |
| `stream` | `boolean` | 否 | 是否使用 SSE 流式返回；默认 `false` |
| `temperature` | `number` | 否 | `0–1`；Claude 4.7 及以后模型建议省略采样参数 |
| `top_p` | `number` | 否 | `0–1`；通常与 `temperature` 只设置一个 |
| `stop_sequences` | `string[]` | 否 | 自定义停止序列 |
| `tools` | `array` | 否 | Anthropic 工具定义 |

### 最小请求

```bash
curl --request POST \
  --url https://www.yunqiai.chat/v1/messages \
  --header "x-api-key: YOUR_API_KEY" \
  --header "anthropic-version: 2023-06-01" \
  --header "Content-Type: application/json" \
  --data '{
    "model": "claude-sonnet-4-6",
    "max_tokens": 1024,
    "messages": [
      {"role": "user", "content": "你好"}
    ]
  }'
```

### Base64 图片输入

Claude 图片使用 `image` 内容块。`source.data` 填裸 Base64，MIME 类型单独填写在 `source.media_type`。

```json
{
  "model": "claude-sonnet-4-6",
  "max_tokens": 256,
  "messages": [
    {
      "role": "user",
      "content": [
        {
          "type": "image",
          "source": {
            "type": "base64",
            "media_type": "image/png",
            "data": "BASE64_IMAGE_DATA"
          }
        },
        {"type": "text", "text": "描述这张图片"}
      ]
    }
  ]
}
```

图片输入范围：

- 支持 JPEG、PNG、GIF、WebP。
- 单张图片控制在 `8000×8000` 以内。
- Base64 编码后单张图片小于 `10 MB`。
- 整次请求体控制在 `32 MB` 以内。

### 文档输入（`claude-opus-4-7`）

Anthropic Messages 使用 `document` 内容块。PDF 可以使用以下三种 `source`：

| `source.type` | 必需字段 | 说明 |
|---|---|---|
| `url` | `url` | 指向服务端可以访问的完整 HTTPS PDF 地址 |
| `base64` | `media_type`、`data` | `media_type` 填 `application/pdf`，`data` 填裸 Base64 |
| `file` | `file_id` | 引用调用环境中已经取得的有效文件 ID |

可直接发送的 Base64 PDF 请求：

```json
{
  "model": "claude-opus-4-7",
  "max_tokens": 1024,
  "messages": [
    {
      "role": "user",
      "content": [
        {
          "type": "document",
          "source": {
            "type": "base64",
            "media_type": "application/pdf",
            "data": "BASE64_PDF_DATA"
          }
        },
        {
          "type": "text",
          "text": "总结这份文档，并列出三个关键结论。"
        }
      ]
    }
  ]
}
```

URL 与文件 ID 来源分别写成：

```json
{"type": "document", "source": {"type": "url", "url": "https://example.com/report.pdf"}}
```

```json
{"type": "document", "source": {"type": "file", "file_id": "file_123"}}
```

本页未发布文件上传端点，因此不要为取得 `file_id` 自行拼接上传路径。文档格式、页数和大小以当前请求返回为准；较大的 PDF 可先拆分，再分别提交。

### 响应结构

```json
{
  "id": "msg_01JY7X",
  "type": "message",
  "role": "assistant",
  "model": "claude-sonnet-4-6",
  "content": [
    {"type": "text", "text": "你好！我是一个 AI 助手。"}
  ],
  "stop_reason": "end_turn"
}
```

遍历 `content[]`，分别处理文本块、工具调用块及其他协议内容块。

## 8. POST `/v1beta/models/{model}:generateContent`

Gemini 原生 Generate Content。文本、多模态理解和 Gemini 生图模型共用这一路径；模型 ID 位于 URL 中。

### 文本与多模态参数

| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `contents` | `array` | 是 | Content 数组，每项含 `role` 与 `parts` |
| `systemInstruction` | `object` | 否 | 系统指令，结构同 Content |
| `generationConfig.maxOutputTokens` | `integer` | 否 | 最大输出 Token；上限随模型变化 |
| `generationConfig.temperature` | `number` | 否 | 通常为 `0–2`；默认值和范围以模型为准 |
| `generationConfig.topP` | `number` | 否 | `0–1` 的核采样阈值 |
| `generationConfig.stopSequences` | `string[]` | 否 | 停止序列 |
| `safetySettings` | `array` | 否 | 按危害类别设置安全阈值 |

### 文本请求

```bash
curl --request POST \
  --url https://www.yunqiai.chat/v1beta/models/gemini-3.5-flash:generateContent \
  --header "x-goog-api-key: YOUR_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "contents": [
      {"role": "user", "parts": [{"text": "你好，请介绍一下你自己"}]}
    ],
    "generationConfig": {"maxOutputTokens": 1024}
  }'
```

### 内联媒体格式

媒体放在 `contents[].parts[].inlineData` 中，`data` 只放裸 Base64，`mimeType` 填实际 MIME 类型。媒体、提示词和系统指令合计控制在 `20 MB` 以内。

| 输入 | 支持格式与写法 | 用途 |
|---|---|---|
| 图片 | PNG、JPEG、WebP、HEIC、HEIF；`inlineData` | 识图、OCR、图表与界面分析 |
| 视频 | MP4、MPEG、MOV、AVI、FLV、MPG、WebM、WMV、3GPP；`inlineData` | 摘要、事件提取、时间点问答 |
| 音频 | 使用实际音频 MIME 类型；`inlineData` | 转写、摘要、说话内容分析 |
| PDF | `application/pdf`；`inlineData` | 文档、扫描件与表格理解 |

### 图片输入

```json
{
  "contents": [
    {
      "parts": [
        {"text": "描述这张图片"},
        {
          "inlineData": {
            "mimeType": "image/png",
            "data": "BASE64_IMAGE_DATA"
          }
        }
      ]
    }
  ],
  "generationConfig": {"maxOutputTokens": 256}
}
```

### 视频参数

| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `inlineData.mimeType` | `string` | 是 | 例如 `video/mp4` |
| `inlineData.data` | `string` | 是 | 裸 Base64，不带 `data:video/...` 前缀 |
| `videoMetadata.startOffset` | `duration` | 否 | 分析起点，例如 `40s` |
| `videoMetadata.endOffset` | `duration` | 否 | 分析终点，例如 `80s` |
| `videoMetadata.fps` | `number` | 否 | 默认约 `1 FPS`；长视频可低于 `1`，快速动作可适当提高 |

```json
{
  "contents": [
    {
      "parts": [
        {
          "inlineData": {
            "mimeType": "video/mp4",
            "data": "BASE64_VIDEO_DATA"
          },
          "videoMetadata": {
            "startOffset": "0s",
            "endOffset": "30s",
            "fps": 1
          }
        },
        {"text": "概括视频中的主要事件，并给出对应时间点。"}
      ]
    }
  ],
  "generationConfig": {"maxOutputTokens": 2048}
}
```

较长视频先压缩或按时间段裁切，再使用 `startOffset` 与 `endOffset` 分段分析。复杂视频任务可从 `maxOutputTokens: 2048` 起设置。

### 文本响应结构

```json
{
  "candidates": [
    {
      "content": {
        "role": "model",
        "parts": [{"text": "你好！我是一个 AI 助手。"}]
      },
      "finishReason": "STOP"
    }
  ],
  "modelVersion": "gemini-3.5-flash"
}
```

遍历 `candidates[].content.parts[]`，分别读取 `text` 或 `inlineData`。

## 9. Base64 与文件上传对照

| 协议 | 输入字段 | 传值形式 | 输出图片字段 |
|---|---|---|---|
| Chat Completions | `messages[].content[].image_url.url` | 完整 Data URL：`data:image/png;base64,...` | 视觉理解返回文本 |
| Responses | `input_image.image_url` | 完整 Data URL：`data:image/png;base64,...` | 视觉理解返回文本 |
| Responses 文件 | `input_file.file_data` | 完整 Data URL，并同时填写 `filename` | 文件理解返回文本 |
| Anthropic Messages | `source.data` | 裸 Base64，并填写 `source.media_type` | 视觉理解返回文本 |
| Anthropic PDF | `document.source.data` | 裸 Base64，`source.type` 为 `base64`，`media_type` 为 `application/pdf` | 文档理解返回文本 |
| Gemini Generate Content | `inlineData.data` | 裸 Base64，并填写 `inlineData.mimeType` | Gemini 生图：`parts[].inlineData.data` |
| OpenAI Images Edits | `image` 或重复的 `image[]` | `multipart/form-data` 文件 | `data[].b64_json` 或 `data[].url` |

如果现有图片只有 Base64，而接口要求 multipart 文件，先将 Base64 解码为图片文件，再上传到 `image` 字段。

## 10. Gemini Image：生成与参考图编辑

适用模型：

- `gemini-3.1-flash-image`
- `gemini-3-pro-image-preview`

端点：

```text
POST /v1beta/models/{model}:generateContent
```

只传文字时生成图片；在同一个 `parts` 数组中加入 `inlineData` 时进行参考图生成或编辑。结果在当前请求中直接返回。

### 请求参数

| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `contents` | `array` | 是 | 文本与参考图片输入 |
| `contents[].role` | `string` | 否 | `user` 或 `model`；单轮可省略，多轮按对话顺序填写 |
| `contents[].parts[].text` | `string` | 否 | 提示词；Flash 输入上下文最多 131,072 tokens，Pro 最多 65,536 tokens |
| `contents[].parts[].inlineData` | `object` | 否 | Base64 参考图，可与文字放在同一个 `parts` 数组中 |
| `systemInstruction` | `object` | 否 | 系统指令，计入输入上下文与请求体大小 |
| `generationConfig.responseModalities` | `string[]` | 否 | `TEXT`、`IMAGE` 或二者；只要图片可设为 `["IMAGE"]` |
| `generationConfig.imageConfig.aspectRatio` | `string` | 否 | 从对应模型的比例表中选择 |
| `generationConfig.imageConfig.imageSize` | `string` | 否 | Flash：`512`、`1K`、`2K`、`4K`；Pro：`1K`、`2K`、`4K`；`K` 必须大写 |
| `safetySettings` | `array` | 否 | 安全策略；同一类别不要重复传入 |
| `inlineData.mimeType` | `string` | 图片输入时是 | `image/png`、`image/jpeg`、`image/webp`、`image/heic`、`image/heif` |
| `inlineData.data` | `string` | 图片输入时是 | 裸 Base64，不带 `data:image/...` 前缀 |

### `gemini-3.1-flash-image` 比例与像素

| `aspectRatio` | `512` | `1K` | `2K` | `4K` |
|---|---:|---:|---:|---:|
| `1:1` | 512×512 | 1024×1024 | 2048×2048 | 4096×4096 |
| `1:4` | 256×1024 | 512×2048 | 1024×4096 | 2048×8192 |
| `1:8` | 192×1536 | 384×3072 | 768×6144 | 1536×12288 |
| `2:3` | 424×632 | 848×1264 | 1696×2528 | 3392×5056 |
| `3:2` | 632×424 | 1264×848 | 2528×1696 | 5056×3392 |
| `3:4` | 448×600 | 896×1200 | 1792×2400 | 3584×4800 |
| `4:1` | 1024×256 | 2048×512 | 4096×1024 | 8192×2048 |
| `4:3` | 600×448 | 1200×896 | 2400×1792 | 4800×3584 |
| `4:5` | 464×576 | 928×1152 | 1856×2304 | 3712×4608 |
| `5:4` | 576×464 | 1152×928 | 2304×1856 | 4608×3712 |
| `8:1` | 1536×192 | 3072×384 | 6144×768 | 12288×1536 |
| `9:16` | 384×688 | 768×1376 | 1536×2752 | 3072×5504 |
| `16:9` | 688×384 | 1376×768 | 2752×1536 | 5504×3072 |
| `21:9` | 792×168 | 1584×672 | 3168×1344 | 6336×2688 |

### `gemini-3-pro-image-preview` 比例与像素

| `aspectRatio` | `1K` | `2K` | `4K` |
|---|---:|---:|---:|
| `1:1` | 1024×1024 | 2048×2048 | 4096×4096 |
| `2:3` | 848×1264 | 1696×2528 | 3392×5056 |
| `3:2` | 1264×848 | 2528×1696 | 5056×3392 |
| `3:4` | 896×1200 | 1792×2400 | 3584×4800 |
| `4:3` | 1200×896 | 2400×1792 | 4800×3584 |
| `4:5` | 928×1152 | 1856×2304 | 3712×4608 |
| `5:4` | 1152×928 | 2304×1856 | 4608×3712 |
| `9:16` | 768×1376 | 1536×2752 | 3072×5504 |
| `16:9` | 1376×768 | 2752×1536 | 5504×3072 |
| `21:9` | 1584×672 | 3168×1344 | 6336×2688 |

### 参考图能力与请求大小

| 模型 | 参考图总数 | 物体保持 | 人物一致性 | 风格参考 |
|---|---:|---:|---:|---:|
| `gemini-3.1-flash-image` | 最多 14 张 | 最多 10 个 | 最多 4 个角色 | 随参考图一并描述 |
| `gemini-3-pro-image-preview` | 最多 14 张 | 最多 6 个 | 最多 5 个角色 | 最多 3 张 |

内联图片、提示词和系统指令合计控制在 `20 MB` 以内。

### 文生图请求

```json
{
  "contents": [
    {
      "parts": [
        {"text": "生成一张雨后的未来城市，霓虹倒影，电影感构图"}
      ]
    }
  ],
  "generationConfig": {
    "responseModalities": ["IMAGE"],
    "imageConfig": {
      "aspectRatio": "16:9",
      "imageSize": "2K"
    }
  }
}
```

### 参考图请求

```json
{
  "contents": [
    {
      "parts": [
        {"text": "保留主体，把背景改成夜景"},
        {
          "inlineData": {
            "mimeType": "image/png",
            "data": "BASE64_IMAGE_DATA"
          }
        }
      ]
    }
  ],
  "generationConfig": {
    "responseModalities": ["IMAGE"],
    "imageConfig": {
      "aspectRatio": "1:1",
      "imageSize": "1K"
    }
  }
}
```

多轮连续编辑时，下一轮继续传入上一轮图片和新的文字要求。每轮明确说明“保留什么、只修改什么”。

### 响应结构

```json
{
  "candidates": [
    {
      "content": {
        "role": "model",
        "parts": [
          {
            "inlineData": {
              "mimeType": "image/png",
              "data": "BASE64_IMAGE_DATA"
            }
          }
        ]
      },
      "finishReason": "STOP"
    }
  ],
  "modelVersion": "gemini-3.1-flash-image"
}
```

遍历所有 `candidates[]` 和 `parts[]`；每遇到一个 `inlineData` 就按其 `mimeType` 选择扩展名，并将 `data` 解码保存。

## 11. `gpt-image-2-each`

支持文本生图、单张参考图编辑和画面文字排版。需要在图片中出现准确文字时，把文案、语言、层级、位置和字体气质写进 `prompt`，并在返回后检查实际排版。

### 端点

- 文本生图：`POST /v1/images/generations`
- 参考图编辑：`POST /v1/images/edits`

### 文生图参数

| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `model` | `string` | 是 | 固定为 `gpt-image-2-each` |
| `prompt` | `string` | 是 | `1–32,000` 字符 |
| `size` | `string` | 否 | `1K`、`2K`、`4K`，或下表中的横向与竖向尺寸；无需另传 `resolution` |
| `n` | `integer` | 否 | 固定为 `1`；一次请求返回一张图片 |
| `output_format` | `string` | 否 | `png`、`jpeg`、`webp`；默认 `png` |
| `output_compression` | `integer` | 否 | `0–100`；仅用于 JPEG / WebP |
| `background` | `string` | 否 | `auto` 或 `opaque` |
| `moderation` | `string` | 否 | `auto` 或 `low` |
| `stream` | `boolean` | 否 | 是否流式返回 |
| `partial_images` | `integer` | 否 | `0–3`；仅流式请求 |
| `user` | `string` | 否 | 终端用户标识，用于滥用监测 |

### 尺寸与分辨率档位

`1K`、`2K`、`4K` 是分辨率档位，不是比例限制。方图可直接填写档位；横图和竖图使用具体宽高。

| `size` 请求值 | 输出尺寸 | 比例 | 场景 |
|---|---:|---:|---|
| `1K` | 1024×1024 | 1:1 | 1K 方图 |
| `1536x1024` | 1536×1024 | 3:2 | 1K 横图 |
| `1024x1536` | 1024×1536 | 2:3 | 1K 竖图 |
| `2K` | 2048×2048 | 1:1 | 2K 方图 |
| `2048x1152` | 2048×1152 | 16:9 | 2K 横图 |
| `1152x2048` | 1152×2048 | 9:16 | 2K 竖图 |
| `4K` | 2880×2880 | 1:1 | 最大方图 |

不同分辨率档位采用相同单张价格。输出质量由平台统一配置，请省略 `quality`。

### 文生图请求

```bash
curl --request POST \
  --url https://www.yunqiai.chat/v1/images/generations \
  --header "Authorization: Bearer YOUR_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "model": "gpt-image-2-each",
    "prompt": "一只可爱的熊猫，电影感光线",
    "size": "1K",
    "output_format": "png",
    "n": 1
  }'
```

### 参考图编辑参数

| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `model` | `string` | 是 | 固定为 `gpt-image-2-each` |
| `image` | `file` | 是 | `multipart/form-data` 上传参考图 |
| `prompt` | `string` | 是 | 写明要保留和修改的内容 |
| `size` | `string` | 否 | 输出宽高，例如 `1024x1024` |
| `output_format` | `string` | 否 | `png`、`jpeg`、`webp`；默认 `png` |

```bash
curl --request POST \
  --url https://www.yunqiai.chat/v1/images/edits \
  --header "Authorization: Bearer YOUR_API_KEY" \
  --form "model=gpt-image-2-each" \
  --form "image=@./reference.png" \
  --form "prompt=保留参考图主体，把背景改成柔和的蓝色渐变" \
  --form "size=1024x1024" \
  --form "output_format=png"
```

已有 Base64 参考图时，先解码为图片文件，再上传到 `image`。

### 响应结构

```json
{
  "created": 1785987000,
  "data": [
    {"b64_json": "BASE64_IMAGE_DATA"}
  ],
  "usage": {
    "input_tokens": 17,
    "output_tokens": 1756,
    "total_tokens": 1773
  }
}
```

`data[]` 中的图片项可能使用以下任一种返回形态：

```json
{"b64_json": "BASE64_IMAGE_DATA"}
```

```json
{"url": "https://example.com/generated-image.png"}
```

客户端应逐项判断：有非空 `b64_json` 时进行 Base64 解码；否则在存在 `url` 时下载该地址；两者都没有时，把该项视为无可用图片。不要固定只读取 `data[0].b64_json`。

```python
import base64
import urllib.request
from pathlib import Path


def save_image_item(item, output_path):
    if item.get("b64_json"):
        image_bytes = base64.b64decode(item["b64_json"])
    elif item.get("url"):
        with urllib.request.urlopen(item["url"], timeout=60) as response:
            image_bytes = response.read()
    else:
        raise ValueError("image item contains neither b64_json nor url")

    Path(output_path).write_bytes(image_bytes)


for index, item in enumerate(payload.get("data", []), start=1):
    save_image_item(item, f"result-{index}.png")
```

## 12. `gpt-image-2`

支持文本生图、参考图编辑、图生图、多图合成和蒙版局部重绘。

### 端点

```text
POST /v1/images/generations
POST /v1/images/edits
```

文生图请求使用 `application/json`；参考图编辑请求使用 `multipart/form-data`。

### 文生图参数

| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `model` | `string` | 是 | 固定为 `gpt-image-2` |
| `prompt` | `string` | 是 | `1–32,000` 字符 |
| `size` | `string` | 否 | `auto` 或符合约束的 `WIDTHxHEIGHT`；无需另传 `resolution` |
| `quality` | `string` | 否 | `low`、`medium`、`high`、`auto`；默认 `auto` |
| `n` | `integer` | 否 | `1–10`；生成数量会直接影响费用 |
| `output_format` | `string` | 否 | `png`、`jpeg`、`webp`；默认 `png` |
| `output_compression` | `integer` | 否 | `0–100`；仅 JPEG / WebP，默认 `100` |
| `background` | `string` | 否 | `auto` 或 `opaque`；默认 `auto` |
| `moderation` | `string` | 否 | `auto` 或 `low`；默认 `auto` |
| `stream` | `boolean` | 否 | 是否流式返回 |
| `partial_images` | `integer` | 否 | `0–3`；仅流式请求，默认 `0` |
| `user` | `string` | 否 | 终端用户标识，用于滥用监测 |

### 文生图请求

```bash
curl --request POST \
  --url https://www.yunqiai.chat/v1/images/generations \
  --header "Authorization: Bearer YOUR_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "model": "gpt-image-2",
    "prompt": "雨后的未来城市，霓虹倒影，电影感构图",
    "size": "1536x1024",
    "quality": "medium",
    "output_format": "png",
    "n": 1
  }'
```

### 参考图编辑参数

| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `model` | `string` | 是 | 固定为 `gpt-image-2` |
| `image` / `image[]` | `file` 或 `file[]` | 是 | 上传 `1–16` 张 PNG、JPG 或 WebP 参考图；每张小于 `50 MB` |
| `mask` | `file` | 否 | PNG，小于 `4 MB`；与第一张参考图尺寸一致并含 Alpha 通道 |
| `prompt` | `string` | 是 | `1–32,000` 字符；说明需要保留和修改的画面内容 |

其余可选参数与上方文生图参数相同。

### 自定义尺寸规则

| 约束 | 范围 | 说明 |
|---|---:|---|
| 宽高步进 | 16 px | 宽和高都必须是 16 的倍数 |
| 输出比例 | 1:3–3:1 | 长边与短边之比不超过 3:1 |
| 最长边 | ≤ 3840 px | 横图和竖图使用同一限制 |
| 总像素 | 655,360–8,294,400 | 在范围内可自由组合宽高 |

常用尺寸：

| `size` | 比例 | 场景 |
|---|---:|---|
| `1024x1024` | 1:1 | 方形图片 |
| `1536x1024` | 3:2 | 横向图片 |
| `1024x1536` | 2:3 | 竖向图片 |
| `2048x2048` | 1:1 | 2K 方形图片 |
| `2048x1152` | 16:9 | 2K 横图 |
| `3840x2160` | 16:9 | 最大横图 |
| `2160x3840` | 9:16 | 最大竖图 |

### 质量

| `quality` | 特点 | 场景 |
|---|---|---|
| `auto` | 自动选择 | 不想手动指定质量时 |
| `low` | 速度最快、费用最低、细节较少 | 快速草稿、构图预览 |
| `medium` | 速度、费用与细节较均衡 | 日常生图与常规编辑 |
| `high` | 细节最丰富、生成更慢、费用较高 | 复杂场景、精细纹理与大量细节 |

### 多图与蒙版

- 多张参考图重复填写 `image[]`。
- 蒙版只作用于第一张参考图。
- 主体保持自动按高保真方式处理，无需额外参数。
- 蒙版用于指定主要修改区域；提示词同时写明位置、修改内容和需要保留的主体。

```bash
curl --request POST \
  --url https://www.yunqiai.chat/v1/images/edits \
  --header "Authorization: Bearer YOUR_API_KEY" \
  --form "model=gpt-image-2" \
  --form "image[]=@./scene.png" \
  --form "image[]=@./product.png" \
  --form "mask=@./mask.png" \
  --form "prompt=把第二张图中的商品放到第一张场景中，保持商品外观不变" \
  --form "size=1536x1024" \
  --form "quality=medium" \
  --form "n=1"
```

### 响应结构

```json
{
  "created": 1785987000,
  "data": [
    {"b64_json": "BASE64_IMAGE_DATA"}
  ],
  "output_format": "png",
  "quality": "medium",
  "size": "1536x1024"
}
```

当 `n` 大于 `1` 时，客户端必须遍历完整 `data[]`。不要只读取 `data[0]`。

### Python 解码全部图片

```python
import base64
import requests

for index, item in enumerate(response.data, start=1):
    b64_json = getattr(item, "b64_json", None)
    url = getattr(item, "url", None)
    if b64_json:
        image_bytes = base64.b64decode(b64_json)
    elif url:
        download = requests.get(url, timeout=(10, 300))
        download.raise_for_status()
        image_bytes = download.content
    else:
        raise ValueError("image item contains neither b64_json nor url")

    with open(f"result-{index}.png", "wb") as file:
        file.write(image_bytes)
```

## 13. 工具调用与结构化输出

本节分别采用 OpenAI Chat Completions、OpenAI Responses 与 Anthropic Messages 的原生工具字段，三种结构不能混用。先通过 `GET /v1/models` 确认模型可用，再从一个只含单个函数工具的最小请求开始。

工具只由模型提出调用请求，实际执行必须在应用侧完成。Agent 应校验工具名称和参数，再调用本地函数或外部服务；不要直接执行未经校验的命令或 SQL。

### Chat Completions 工具调用

定义工具：

```json
{
  "model": "gpt-5.6-sol",
  "messages": [
    {"role": "user", "content": "上海今天的天气怎么样？"}
  ],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "查询指定城市的天气",
        "parameters": {
          "type": "object",
          "properties": {
            "city": {"type": "string", "description": "城市名称"}
          },
          "required": ["city"],
          "additionalProperties": false
        }
      }
    }
  ],
  "tool_choice": "auto"
}
```

模型提出调用时，读取 `choices[].message.tool_calls[]`。`function.arguments` 是 JSON 字符串，需要解析并校验。

```json
{
  "choices": [
    {
      "message": {
        "role": "assistant",
        "content": null,
        "tool_calls": [
          {
            "id": "call_01",
            "type": "function",
            "function": {
              "name": "get_weather",
              "arguments": "{\"city\":\"上海\"}"
            }
          }
        ]
      }
    }
  ]
}
```

执行工具后，把原 assistant 消息和工具结果加入下一次请求。工具结果消息的 `tool_call_id` 必须与调用 ID 一致。

```json
{
  "role": "tool",
  "tool_call_id": "call_01",
  "content": "晴，28°C"
}
```

### Responses 工具调用

```json
{
  "model": "gpt-5.6-sol",
  "input": "查询上海天气",
  "tools": [
    {
      "type": "function",
      "name": "get_weather",
      "description": "查询指定城市的天气",
      "parameters": {
        "type": "object",
        "properties": {
          "city": {"type": "string"}
        },
        "required": ["city"],
        "additionalProperties": false
      }
    }
  ]
}
```

遍历 `output[]`，找到 `type` 为 `function_call` 的输出项，读取 `call_id`、`name` 和 `arguments`。执行工具后，用 `function_call_output` 回传，并通过 `previous_response_id` 继续同一轮会话。

```json
{
  "model": "gpt-5.6-sol",
  "previous_response_id": "resp_01JY7X",
  "input": [
    {
      "type": "function_call_output",
      "call_id": "call_01",
      "output": "晴，28°C"
    }
  ]
}
```

### Anthropic Messages 工具调用

```json
{
  "model": "claude-sonnet-4-6",
  "max_tokens": 1024,
  "messages": [
    {"role": "user", "content": "查询上海天气"}
  ],
  "tools": [
    {
      "name": "get_weather",
      "description": "查询指定城市的天气",
      "input_schema": {
        "type": "object",
        "properties": {
          "city": {"type": "string"}
        },
        "required": ["city"]
      }
    }
  ]
}
```

模型提出调用时，遍历 `content[]`，找到 `type` 为 `tool_use` 的内容块，读取 `id`、`name` 和 `input`。下一次请求应保留包含该 `tool_use` 的完整 assistant 消息，再追加一条带 `tool_result` 的 `user` 消息；`tool_use_id` 必须与原调用 ID 一致：

```json
{
  "role": "user",
  "content": [
    {
      "type": "tool_result",
      "tool_use_id": "toolu_01",
      "content": "晴，28°C"
    }
  ]
}
```

### Chat Completions JSON Schema 输出

需要稳定 JSON 时，使用 `response_format`。应用侧仍应解析并校验最终 JSON。

```json
{
  "model": "gpt-5.5",
  "messages": [
    {"role": "user", "content": "提取姓名和年龄：小明今年 18 岁"}
  ],
  "response_format": {
    "type": "json_schema",
    "json_schema": {
      "name": "person",
      "schema": {
        "type": "object",
        "properties": {
          "name": {"type": "string"},
          "age": {"type": "integer"}
        },
        "required": ["name", "age"],
        "additionalProperties": false
      }
    }
  }
}
```

## 14. 流式与非流式返回

### SSE 通用解析规则

- Chat Completions、Responses、Anthropic Messages 与开启流式的 GPT Images 使用 `text/event-stream`。
- 按空行切分 SSE 事件；同一事件有多行 `data:` 时先按换行拼接，再解析 JSON。`event:` 是事件名，冒号开头的行是注释或心跳。
- 一次网络读取可能只有半条事件，也可能包含多条事件，不要把网络分块直接当成 SSE 事件。
- 使用 SDK 时优先遍历 SDK 提供的事件对象；手动解析时仍应按下方各协议的完成标记判断成功。
- 连接在完成标记前断开时，把本次结果视为不完整；保留已经收到的增量，但不要把它当作完整回答。

### Chat Completions 流

每个 JSON 数据块的 `object` 通常为 `chat.completion.chunk`。按 `choices[].index` 分组处理：

| 字段 | 处理方式 |
|---|---|
| `choices[].delta.role` | 初始化该候选的角色 |
| `choices[].delta.content` | 按到达顺序追加文本 |
| `choices[].delta.tool_calls[]` | 先按 `choices[].index` 区分候选，再按工具调用的 `index` 分组；保留 `id` 与函数名，并拼接 `function.arguments` 字符串 |
| `choices[].finish_reason` | 记录该候选的结束原因；不是整个 SSE 的替代终止标记 |
| `data: [DONE]` | Chat Completions 流正常结束 |

```text
data: {"id":"chatcmpl_01","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"你"},"finish_reason":null}]}

data: {"id":"chatcmpl_01","object":"chat.completion.chunk","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}

data: [DONE]
```

工具参数可能跨多个 chunk；只有在对应工具调用结束后，才对拼接完成的 `function.arguments` 做 JSON 解析和参数校验。

### Responses 流

Responses 事件在 JSON 的 `type` 中标识类型。常用事件如下：

| `type` | 关键字段与处理 |
|---|---|
| `response.created` | 初始化响应状态，保存响应 ID |
| `response.output_item.added` | 按 `output_index` 登记新的类型化 Item；函数调用需保存 Item `id`、`name` 与回传结果所需的 `call_id` |
| `response.output_text.delta` | 把 `delta` 追加到对应文本内容 |
| `response.function_call_arguments.delta` | 按 `item_id` 或 `output_index` 找到对应函数调用并拼接 `delta`；完成后再解析 JSON |
| `response.output_item.done` | 用完成后的 Item 替换本地聚合版本；只有 `item.type` 为 `function_call` 时才写入工具调用集合 |
| `response.completed` | 正常结束；其中的 `response.output[]` 是最终完整响应 |
| `response.failed`、`response.incomplete`、`error` | 不要标记为成功；保留事件中的错误或不完整原因 |

`response.output_text.delta` 只用于流式聚合；非流式原始 HTTP 响应仍读取类型化的 `output[]`。SDK 的 `output_text` 是完成后聚合文本的便利属性。

Responses 的 `error` 流事件读取事件顶层的 `code`、`message` 与 `param`；如兼容层同时返回嵌套 `error`，可先取嵌套对象，否则读取事件本身。工具执行完成后，使用先前保存的 `call_id` 构造 `function_call_output`。

### Anthropic Messages 流

Anthropic SSE 同时提供 `event:` 名称和 JSON `data.type`。生命周期顺序为：

```text
message_start
content_block_start
content_block_delta
content_block_stop
message_delta
message_stop
```

一个响应可以包含多组 `content_block_start` → `content_block_delta` → `content_block_stop`。按内容块 `index` 聚合：

- `content_block_start.content_block.type: tool_use`：保存该工具调用的 `id` 与 `name`；后续 `tool_result.tool_use_id` 必须使用这个 `id`。
- `delta.type: text_delta`：追加 `delta.text`。
- `delta.type: input_json_delta`：追加 `delta.partial_json`；到 `content_block_stop` 后再把完整字符串解析为工具参数 JSON。
- `message_delta`：读取最终 `stop_reason` 与增量 usage。
- `ping`：心跳事件，可忽略内容但应保持连接。
- `type: error`：流失败，读取 `error.type`、`error.message` 与可用的 `request_id`。
- 收到 `message_stop` 才表示消息流正常结束。

### GPT Images 流

对支持 `stream` 的 Images Generations / Edits 请求：

- 将 `stream` 设为 `true`，`partial_images` 可设为 `0–3`。
- `partial_images: 0` 只返回最终图；大于 `0` 时可返回中间图，但实际中间图数量可能少于请求值。
- 图像事件的 `type` 为 `image_generation.partial_image`，图片序号在 `partial_image_index`，图片 Base64 在 `b64_json`。
- 中间图和最终图使用同一种事件类型。保存每个事件；流正常结束后，把最后收到的图像事件作为最终图。不要等待未定义的 `image_generation.completed` 事件。
- 若连接异常结束或未收到任何图像事件，本次流不完整，不要把某张中间图标记为最终图。

```json
{
  "type": "image_generation.partial_image",
  "partial_image_index": 0,
  "b64_json": "BASE64_IMAGE_DATA"
}
```

### 非流式图片与超时

- Gemini Image 使用 `generateContent`；HTTP 请求完成后遍历 `candidates[].content.parts[].inlineData`。
- GPT Images 使用 `stream: false` 时遍历 `data[]`，逐项处理 `b64_json` 或 `url`。
- 图片生成通常比文本请求耗时更长，客户端可先把超时设置为 `3–5 分钟`，再按实际请求大小调整。这是客户端等待时间，不是服务端完成时限。
- 如果连接在收到完整非流式响应或流式最终图之前超时，调用结果处于未知状态。本页没有图片任务查询端点，无法在超时后查询该次请求；不要自动立即重试。由调用方确认可以接受重复生成和重复计费后，再发起新请求。

## 15. OpenAI SDK

### Python

```python
from openai import OpenAI

client = OpenAI(
    api_key="YOUR_API_KEY",
    base_url="https://www.yunqiai.chat/v1",
)

response = client.chat.completions.create(
    model="gpt-5.6-sol",
    messages=[{"role": "user", "content": "你好"}],
)

print(response.choices[0].message.content)
```

### Node.js

```javascript
import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env.YUNQI_API_KEY,
  baseURL: "https://www.yunqiai.chat/v1",
});

const response = await client.chat.completions.create({
  model: "gpt-5.6-sol",
  messages: [{ role: "user", content: "你好" }],
});

console.log(response.choices[0].message.content);
```

## 16. Agent 客户端配置

### Codex

`~/.codex/config.toml`：

```toml
model = "gpt-5.6-sol"
model_provider = "yunqi"
model_reasoning_effort = "high"
model_verbosity = "high"
cli_auth_credentials_store = "file"

[model_providers.yunqi]
name = "YunQi AI"
base_url = "https://www.yunqiai.chat/v1"
requires_openai_auth = true
wire_api = "responses"
```

`~/.codex/auth.json`：

```json
{
  "auth_mode": "apikey",
  "OPENAI_API_KEY": "YOUR_API_KEY"
}
```

### Claude Code

`~/.claude/settings.json`：

```json
{
  "$schema": "https://json.schemastore.org/claude-code-settings.json",
  "env": {
    "ANTHROPIC_BASE_URL": "https://www.yunqiai.chat",
    "ANTHROPIC_AUTH_TOKEN": "YOUR_API_KEY",
    "ANTHROPIC_DEFAULT_SONNET_MODEL": "claude-sonnet-4-6",
    "ANTHROPIC_DEFAULT_OPUS_MODEL": "claude-opus-4-8",
    "CLAUDE_CODE_SUBAGENT_MODEL": "claude-sonnet-4-6"
  },
  "model": "claude-sonnet-4-6"
}
```

### WorkBuddy

| 字段 | 值 |
|---|---|
| 提供商 | `自定义 / Custom` |
| 接口地址 | `https://www.yunqiai.chat/v1/chat/completions` |
| API Key | `YOUR_API_KEY` |
| 模型名称 | `gpt-5.6-sol` 或 `GET /v1/models` 返回的其他文本模型 |
| 高级配置 | 勾选“工具调用”和“自定义协议”；图片输入和推理模式按模型能力开启 |

WorkBuddy 填写完整接口地址，不是 Base URL。

### Cherry Studio、Chatbox 与其他 OpenAI Compatible 客户端

| 字段 | 值 |
|---|---|
| 服务名称 | `YunQi AI` |
| Base URL | `https://www.yunqiai.chat/v1` |
| API Key | `YOUR_API_KEY` |
| 默认模型 | `gpt-5.6-sol` |

如果客户端可自动读取模型，使用 `GET /v1/models`；否则手动填写完整模型 ID。

## 17. 错误与重试

### 错误响应结构

先按 HTTP 状态判断成功或失败，再根据所用协议解析错误体。常见 envelope 如下。

OpenAI Compatible、Responses 与 Images：

```json
{
  "error": {
    "message": "The requested model was not found.",
    "type": "invalid_request_error",
    "param": "model",
    "code": "model_not_found"
  }
}
```

Anthropic Messages：

```json
{
  "type": "error",
  "error": {
    "type": "authentication_error",
    "message": "Invalid API key"
  },
  "request_id": "req_01JY7X"
}
```

Gemini Generate Content：

```json
{
  "error": {
    "code": 400,
    "message": "Invalid request.",
    "status": "INVALID_ARGUMENT"
  }
}
```

代码不要只匹配错误文案。OpenAI 风格优先读取 `error.code`、`error.type`、`error.param`、`error.message`；Anthropic 读取顶层 `type`、`error.type`、`error.message`、`request_id`；Gemini 读取 `error.code`、`error.status`、`error.message`。若响应不是 JSON，保留 HTTP 状态、`Content-Type` 和经过长度限制的文本正文。

### Request ID

- OpenAI 风格响应优先读取 `x-request-id` 响应头。
- Anthropic 响应读取 `request-id` 响应头，并兼容错误体中的 `request_id`。
- HTTP 头名称不区分大小写。若上述字段不存在，记录请求时间、模型、方法、路径和 HTTP 状态，不要自行生成一个值冒充服务端 Request ID。

```javascript
function readErrorDetails(response, body) {
  const objectBody = body && typeof body === "object" ? body : {};
  const envelope = objectBody.error && typeof objectBody.error === "object"
    ? objectBody.error
    : objectBody;

  return {
    requestId:
      response.headers.get("x-request-id") ??
      response.headers.get("request-id") ??
      objectBody.request_id ??
      null,
    code: envelope.code ?? envelope.type ?? envelope.status ?? null,
    message: envelope.message ?? response.statusText,
  };
}
```

| HTTP 状态 | 含义 | Agent 处理方式 |
|---:|---|---|
| `400` | 请求错误 | 检查 JSON、必填参数、参数类型、图片尺寸和媒体编码 |
| `401` | 鉴权失败 | 检查 API Key、鉴权头格式和是否混入空格 |
| `404` | 路径或模型不存在 | 检查 Base URL、接口路径，并重新读取 `GET /v1/models` |
| `429` | 限流或额度不足 | 读取错误消息与 `Retry-After`，降低并发后重试 |
| `500` | 服务错误 | 保存 Request ID，稍后重试；持续出现时联系支持 |
| `502` / `503` | 服务暂时不可用 | 使用指数退避与随机抖动后重试，或选择同类模型 |

### 最短排查顺序

1. 调用 `GET /v1/models`，确认 API Key 有效并取得真实可见模型。
2. 用只包含必填字段的最小请求复现。
3. 去掉工具、图片、流式输出和高级采样参数。
4. 记录请求时间、模型、接口、HTTP 状态和 Request ID。
5. 联系支持时不要发送 API Key。

### 重试规则

- `400`、`401`、`404`：先修正请求，不要原样重试。
- `429`：优先遵守 `Retry-After`，再使用指数退避并加入随机抖动。
- `500`、`502`、`503`：使用有上限的指数退避。
- 图片请求可先使用 `3–5 分钟` 的客户端超时。若在完整响应或流式最终图到达前超时，本页没有任务查询端点可用于确认该次调用；不要自动立即重试。只有在调用方接受重复生成和重复计费风险时，才发起新请求。

## 18. Agent 完成检查

- 已调用 `GET /v1/models`，请求中的模型 ID 与返回值完全一致。
- 已按模型选择正确协议和鉴权请求头。
- Base URL 与完整接口地址没有混填。
- API Key 只保存在环境变量或本机私有配置中。
- 已从最小请求开始，再逐项加入高级参数。
- Base64 使用了对应协议要求的 Data URL 或裸 Base64 写法。
- Responses 文件按 `input_file` 的 `file_data`、`file_url` 或 `file_id` 选择一种来源；Anthropic PDF 使用 `document` 内容块。
- multipart 图片编辑已上传实际文件，而不是把 Base64 字符串直接放入文件字段。
- Chat Completions 遍历 `choices[]`；Responses 遍历 `output[]`；Messages 遍历 `content[]`；Gemini 遍历 `candidates[].content.parts[]`；Images 遍历 `data[]`。
- 流式请求按对应协议的完成标记结束；完成标记前断线的结果没有被当作完整回答。
- 图片客户端超时已按请求耗时调整；超时后不会自动重复提交。
- 错误日志保留 Request ID，但不包含 API Key、文件正文或图片 Base64。

## 19. 协议参考

- OpenAI Responses API：<https://developers.openai.com/api/reference/resources/responses/methods/create>
- OpenAI Responses 流式输出：<https://developers.openai.com/api/docs/guides/streaming-responses>
- OpenAI 文件输入：<https://developers.openai.com/api/docs/guides/file-inputs>
- OpenAI 图片与视觉输入：<https://developers.openai.com/api/docs/guides/images-vision>
- OpenAI 图片生成指南：<https://developers.openai.com/api/docs/guides/image-generation>
- OpenAI Images Generations：<https://developers.openai.com/api/reference/resources/images/methods/generate>
- OpenAI Images Edits：<https://developers.openai.com/api/reference/resources/images/methods/edit>
- Anthropic Messages API：<https://platform.claude.com/docs/en/api/messages/create>
- Anthropic Messages 流式输出：<https://platform.claude.com/docs/en/build-with-claude/streaming>
- Anthropic 图片输入：<https://platform.claude.com/docs/en/build-with-claude/vision>
- Anthropic PDF 输入：<https://platform.claude.com/docs/en/build-with-claude/pdf-support>
- Gemini Generate Content：<https://ai.google.dev/api/generate-content>
- Gemini 图片理解：<https://ai.google.dev/gemini-api/docs/image-understanding>
- Gemini 视频理解：<https://ai.google.dev/gemini-api/docs/generate-content/video-understanding>
- Gemini 图片生成：<https://ai.google.dev/gemini-api/docs/generate-content/image-generation>
