# LYRouter 文档(全部中文文章) > 每篇文章以 --- 分隔,开头写有原文地址。英文版见 https://platform.lyrouter.com/llms.txt 的 English 部分。 --- # 认识 LYRouter 来源: https://platform.lyrouter.com/ai_gateway/docs/overview LYRouter 是可信模型服务与 Token 治理平台。 - **可信模型服务**:应用和编程工具通过同一个地址 `https://api.lyrouter.com` 和一把 LYRouter API Key,调用多家厂商的模型。每次调用都经过统一的鉴权、路由与安全围栏,并留有完整的调用日志。 - **Token 治理**:平台模型的 Token 用量按 Credits 计费,所有调用的用量按工作空间、成员、部门和 API Key 归因;可以设置预算与配额控制用量,并通过路由策略与提示词缓存降低成本。 你可以使用平台提供的模型按量付费,也可以接入自己在服务商处的 API Key(BYOK)。 ## LYRouter 能做什么 ### 可信模型服务 | 能力 | 说明 | 详见 | | --- | --- | --- | | 统一接入 | 支持 OpenAI Chat Completions、Responses 和 Anthropic Messages 三种协议,以及向量、重排、图像、视频和语音接口。现有 SDK 和工具只需改地址和密钥 | [接入地址与鉴权](https://platform.lyrouter.com/ai_gateway/docs/call-gateway) | | 两类模型来源 | 平台模型按用量扣除 Credits;BYOK 使用你自己的服务商账号,由服务商直接向你收费 | [平台模型与 BYOK 如何选择](https://platform.lyrouter.com/ai_gateway/docs/byok-choice) | | 路由与容错 | 同一模型的多个通道按价格、延迟或吞吐排序,失败时自动换下一个通道;还可以用虚拟模型固定一组模型和参数,或用 `lyrouter/auto` 按任务自动选模型 | [通道选择与路由策略](https://platform.lyrouter.com/ai_gateway/docs/routing) | | 团队与安全 | 组织、部门和成员管理,工作空间授权,以及模型访问控制、内容安全检测等安全围栏 | [组织、成员与角色](https://platform.lyrouter.com/ai_gateway/docs/organization) | ### Token 治理 | 能力 | 说明 | 详见 | | --- | --- | --- | | 费用与额度 | 统一用 Credits 计费;可以给 API Key 设置预算,给成员、部门或工作空间设置配额 | [计费规则与信用点](https://platform.lyrouter.com/ai_gateway/docs/billing) | | 用量归因与可观测 | 每次调用都有请求日志,可以查看实际模型、Token、费用和失败原因;用量分析按模型、API Key 和成员汇总;服务状态页公开展示各上游线路的健康情况 | [通过日志定位调用问题](https://platform.lyrouter.com/ai_gateway/docs/logs) | | 成本优化 | 按价格选择通道,提高提示词缓存命中率,减少重复输入的计费 | [降低成本与优化缓存](https://platform.lyrouter.com/ai_gateway/docs/cost-practice) | ## 版本 | 版本 | 适合 | 主要特点 | | --- | --- | --- | | 个人版 | 个人开发者 | 免费使用,一个默认工作空间,可以接入 BYOK | | 团队版 | 团队协作 | 按席位订阅,可以邀请成员、划分部门、建立多个工作空间,并使用配额、模型访问控制和客户端访问控制等安全围栏。创建需要账号管理员完成个人实名认证 | | 企业版 | 有合规要求的组织 | 在团队版基础上增加敏感信息、提示词注入和意图安全检测,提供更长的日志与安全事件留存。创建需要账号管理员先完成个人实名认证,再完成企业实名认证 | 各版本的席位、工作空间数量、日志留存等具体额度,以控制台 **订阅充值** 页的套餐卡片为准,见[计费规则与信用点](https://platform.lyrouter.com/ai_gateway/docs/billing)。 ## 从哪里开始 | 你想 | 阅读 | | --- | --- | | 用代码完成第一次调用 | [完成第一次模型调用](https://platform.lyrouter.com/ai_gateway/docs/quickstart) | | 在 Claude Code、Codex 等工具中使用 | [工具兼容性与接入总览](https://platform.lyrouter.com/ai_gateway/docs/tools) | | 创建工作空间和 API Key | [创建工作空间与 API Key](https://platform.lyrouter.com/ai_gateway/docs/api-keys) | | 了解账号、工作空间、模型来源等概念 | [核心概念](https://platform.lyrouter.com/ai_gateway/docs/concepts) | | 接入自己的服务商账号 | [接入供应商与测试连接](https://platform.lyrouter.com/ai_gateway/docs/byok) | | 邀请成员、管理权限 | [组织、成员与角色](https://platform.lyrouter.com/ai_gateway/docs/organization) | | 查一次调用为什么失败 | [通过日志定位调用问题](https://platform.lyrouter.com/ai_gateway/docs/logs) | | 查接口参数和报错含义 | [接入地址与鉴权](https://platform.lyrouter.com/ai_gateway/docs/call-gateway)、[错误码与请求标识](https://platform.lyrouter.com/ai_gateway/docs/errors) | 不同模型支持的参数、上下文长度和输入类型不同,接入前请在工作空间的 **模型广场** 核对,见[如何选择模型](https://platform.lyrouter.com/ai_gateway/docs/choose)。 --- # 完成第一次模型调用 来源: https://platform.lyrouter.com/ai_gateway/docs/quickstart 使用 LYRouter 的 OpenAI 兼容接口完成一次模型调用,再在控制台确认请求结果和用量。 ## 1. 准备账号与 API Key 注册并选择个人版后,使用默认工作空间。团队与企业成员选择被授权的工作空间。 ### 创建并保存 API Key 在当前工作空间的左侧导航选择 **API 密钥**,进入密钥列表,点击右上角的 **创建 API 密钥**,按步骤完成配置并生成密钥。 (截图:API 密钥 WEB 页面,左侧 API 密钥导航已选中,正文显示密钥列表,右上角是创建 API 密钥按钮) 在创建成功的弹窗中点击 **复制**,安全保存完整密钥,再勾选已保存确认;明文只展示一次,关闭后无法再次查看。 (截图:API 密钥创建成功后的保存弹窗,包含一次性展示提示、复制按钮和已保存确认框) ### 选择模型并复制模型标识 在模型广场确认一个模型已启用且有有效来源,复制系统模型标识,替换示例中的 `MODEL_ID`。本篇默认按平台模型接入;已有供应商凭证时阅读[BYOK](https://platform.lyrouter.com/ai_gateway/docs/byok-choice)。 (截图:工作空间模型广场,展示已启用模型、系统模型标识旁的复制按钮和服务商来源) ## 2. 准备调用环境 选择你的操作系统,安装准备使用的调用方式所需工具。使用 cURL 只需准备 cURL;选择 Python 或 Node.js 时,再安装对应运行环境和 SDK。已有工具可跳过安装,先检查版本。 **选择操作系统** Windows: 以下命令在 **PowerShell** 中执行,适用于 Windows 10 / 11。 #### 1. 准备 cURL Windows 10 / 11 通常已自带 cURL,先检查: ```powershell curl.exe --version ``` 若提示找不到命令,通过 WinGet 安装后重新打开终端: ```powershell winget install --id cURL.cURL --exact --source winget ``` 使用 `curl.exe`,避免 Windows PowerShell 将 `curl` 解释为其他命令。没有 WinGet 时可安装 [App Installer](https://learn.microsoft.com/windows/package-manager/winget/),或从 [cURL 官网](https://curl.se/windows/)下载并将解压后的 `bin` 目录加入用户 PATH。 #### 2. 安装 Python 与 SDK(选择 Python 时) ```powershell winget install --id Python.Python.3.14 --exact --source winget ``` 安装后重新打开 PowerShell,在用于示例的项目目录中执行: ```powershell python --version python -m venv .venv .\.venv\Scripts\python.exe -m pip install openai ``` 将下节 Python 示例保存为 `example.py`,使用 `.\.venv\Scripts\python.exe example.py` 运行。这里直接使用虚拟环境中的 Python,无需修改 PowerShell 的脚本执行策略。 #### 3. 安装 Node.js 与 SDK(选择 Node.js 时) 安装 Node.js LTS,npm 会随其安装: ```powershell winget install --id OpenJS.NodeJS.LTS --exact --source winget ``` 安装后重新打开 PowerShell,在用于示例的项目目录中执行。已有 `package.json` 时跳过初始化: ```powershell node --version npm.cmd --version npm.cmd init -y npm.cmd install openai ``` 将下节 Node.js 示例保存为 `example.mjs`,使用 `node example.mjs` 运行。使用 `npm.cmd` 可避免 PowerShell 对 `npm.ps1` 的执行策略限制。没有 WinGet 时,也可使用 [Python](https://www.python.org/downloads/windows/) 和 [Node.js LTS](https://nodejs.org/en/download) 的官方安装程序。 #### 4. 设置当前终端的环境变量 ```powershell $env:LYROUTER_API_KEY="YOUR_LYROUTER_API_KEY" $env:LYROUTER_BASE_URL="https://api.lyrouter.com" ``` Linux: 以下命令在 **Bash** 中执行。系统包安装需要 `sudo` 权限;下面提供 Ubuntu / Debian 与 Fedora / Rocky Linux 的对应命令。 #### 1. 安装 cURL 和 Python Ubuntu / Debian: ```bash sudo apt update sudo apt install -y curl python3 python3-pip python3-venv ``` Fedora / Rocky Linux: ```bash sudo dnf install -y curl python3 python3-pip ``` ```bash curl --version python3 --version ``` 只使用 cURL 时,可在安装命令中仅保留 `curl`。 #### 2. 安装 Python SDK(选择 Python 时) 在用于示例的项目目录中创建并激活虚拟环境: ```bash python3 -m venv .venv source .venv/bin/activate python -m pip install openai ``` 将下节 Python 示例保存为 `example.py`,在已激活虚拟环境的终端中运行 `python example.py`。 #### 3. 安装 Node.js 与 SDK(选择 Node.js 时) 通过 [nvm](https://github.com/nvm-sh/nvm#installing-and-updating) 安装 Node.js LTS,避免系统仓库中的旧版 Node.js。已有 nvm 时跳过第一条命令: ```bash curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.8/install.sh | bash ``` 重新打开终端后执行: ```bash nvm install --lts nvm use --lts node --version npm --version ``` 在用于示例的项目目录中安装 SDK;已有 `package.json` 时跳过初始化: ```bash npm init -y npm install openai ``` 将下节 Node.js 示例保存为 `example.mjs`,运行 `node example.mjs`。以上 Node.js 路径适用于常见的 glibc 发行版;Alpine 等环境请按 [Node.js 下载页](https://nodejs.org/en/download)选择对应安装方式。 #### 4. 设置当前终端的环境变量 ```bash export LYROUTER_API_KEY="YOUR_LYROUTER_API_KEY" export LYROUTER_BASE_URL="https://api.lyrouter.com" ``` macOS: 打开 **终端(Terminal)**,以下命令适用于 Bash / Zsh。 #### 1. 准备 cURL 与 Homebrew macOS 已自带 cURL,先检查;可直接用于本节调用: ```bash curl --version ``` Python 和 Node.js 可以通过 [Homebrew](https://brew.sh/) 安装。若尚未安装 Homebrew,执行其官方安装命令,并按照安装完成后的 **Next steps** 提示配置 PATH: ```bash /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" ``` 若需要单独安装新版 cURL,可执行 `brew install curl`。Homebrew 的 cURL 为 keg-only,按 `brew info curl` 的提示配置 PATH 后重新检查版本。 #### 2. 安装 Python 与 SDK(选择 Python 时) ```bash brew install python python3 --version ``` 在用于示例的项目目录中创建并激活虚拟环境,再安装 SDK: ```bash python3 -m venv .venv source .venv/bin/activate python -m pip install openai ``` 将下节 Python 示例保存为 `example.py`,在已激活虚拟环境的终端中运行 `python example.py`。 #### 3. 安装 Node.js 与 SDK(选择 Node.js 时) 安装 Node.js 24 LTS,并将其加入当前终端的 PATH: ```bash brew install node@24 export PATH="$(brew --prefix node@24)/bin:$PATH" node --version npm --version ``` 在用于示例的项目目录中安装 SDK;已有 `package.json` 时跳过初始化: ```bash npm init -y npm install openai ``` 将下节 Node.js 示例保存为 `example.mjs`,运行 `node example.mjs`。新终端也要使用此 Node.js 版本时,按 `brew info node@24` 的提示配置 shell 启动文件。 #### 4. 设置当前终端的环境变量 ```bash export LYROUTER_API_KEY="YOUR_LYROUTER_API_KEY" export LYROUTER_BASE_URL="https://api.lyrouter.com" ``` 将 `YOUR_LYROUTER_API_KEY` 替换为刚保存的密钥。以上示例使用 LYRouter 公网网关 `https://api.lyrouter.com`;自部署时替换为你的网关地址。环境变量只对当前终端及其启动的程序生效;重新打开终端后需再次设置。Base URL 保存网关根地址,不带末尾 `/v1`,不要使用控制台 `/ai_gateway/` 页面地址。 参考:[Python 虚拟环境](https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/)、[Windows Python 安装](https://learn.microsoft.com/windows/dev-environment/python)、[Node.js 下载](https://nodejs.org/en/download)、[Homebrew](https://brew.sh/)。 ## 3. 发起请求 **选择调用语言** cURL: **Linux / macOS(Bash / Zsh)** ```bash curl "$LYROUTER_BASE_URL/v1/chat/completions" \ -H "Authorization: Bearer $LYROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"MODEL_ID","messages":[{"role":"user","content":"请回复 OK"}]}' ``` **Windows(PowerShell)** 通过标准输入传递 JSON,避免 PowerShell 的引号转义差异。将 `MODEL_ID` 替换为你的系统模型标识: ```powershell $body = @' {"model":"MODEL_ID","messages":[{"role":"user","content":"Reply OK"}]} '@ $body | curl.exe "$env:LYROUTER_BASE_URL/v1/chat/completions" ` -H "Authorization: Bearer $env:LYROUTER_API_KEY" ` -H "Content-Type: application/json" ` --data-binary "@-" ``` Python: ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["LYROUTER_API_KEY"], base_url=os.environ["LYROUTER_BASE_URL"] + "/v1", ) result = client.chat.completions.create( model="MODEL_ID", messages=[{"role": "user", "content": "请回复 OK"}], ) print(result.choices[0].message.content) ``` Node.js: ```javascript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.LYROUTER_API_KEY, baseURL: process.env.LYROUTER_BASE_URL + "/v1", }); const result = await client.chat.completions.create({ model: "MODEL_ID", messages: [{ role: "user", content: "请回复 OK" }], }); console.log(result.choices[0].message.content); ``` ## 4. 验证结果 确认返回回复,再进入日志分析核对生成请求的状态、模型和 Token 用量。找不到模型时检查工作空间来源与[模型标识](https://platform.lyrouter.com/ai_gateway/docs/model-names);401 / 403 见[鉴权排查](https://platform.lyrouter.com/ai_gateway/docs/auth-errors),429 见[配额排查](https://platform.lyrouter.com/ai_gateway/docs/rate-errors)。 下一步可以[接入编程工具](https://platform.lyrouter.com/ai_gateway/docs/tools),或查看[API 文档](https://platform.lyrouter.com/ai_gateway/docs/chat-completions)中的参数和进阶调用方式。 --- # 创建工作空间与 API Key 来源: https://platform.lyrouter.com/ai_gateway/docs/api-keys API Key 是应用调用 LYRouter 网关的凭证。创建前先选择正确的账号与工作空间,确保密钥、模型来源和费用归属一致。 ## 选择或创建工作空间 个人版使用系统预置的唯一默认空间。团队或企业账号管理员可在工作空间页面创建新空间;普通成员需要已有访问授权。 (截图:工作空间 WEB 页面,左侧工作空间导航已选中,正文显示工作空间卡片、进入按钮和右上角的新建工作空间按钮) 工作空间可以按组织、部门共享,也可以只向指定成员开放。先确认共享范围和角色,再创建用于应用的 Key。 团队或企业账号管理员点击 **新建工作空间**,填写名称与说明,选择共享范围及共享角色后点击 **保存**。进入新空间后再创建 API Key。 (截图:新建工作空间表单,已选中指定部门,展示可见部门、包含子部门、共享成员角色和指定成员设置) ## 创建 API Key 1. 进入工作空间的 API 密钥页面。 2. 使用有创建权限的账号点击创建,填写名称与所需过期时间。 3. 按界面设置费用或 Token 预算;Token 输入以百万为单位。 4. 生成密钥并立即复制一次性明文,完成已保存确认。 (截图:API 密钥 WEB 页面,展示工作空间内的密钥列表、启用状态和创建 API 密钥按钮) (截图:API Key 创建成功后的保存弹窗,显示一次性明文提示、复制按钮和已保存确认框) 明文关闭后无法再次查看;丢失时创建新 Key。模型范围从工作空间模型广场及[安全策略](https://platform.lyrouter.com/ai_gateway/docs/authorization)管理,不在 Key 上维护第二套模型授权。 ## 管理与轮换 有管理能力的成员可以编辑、启停或删除授权范围内的 Key。启用状态表示允许调用,不表示已经使用过。轮换时先创建新 Key、更新应用并验证,再停用旧 Key。 ## 用量与验证 列表与详情区分本月及累计 Token / 费用,数据不完整时以实际状态提示为准。共享 Key 只能可靠归因到创建人。使用[快速开始](https://platform.lyrouter.com/ai_gateway/docs/quickstart)完成调用,在[日志](https://platform.lyrouter.com/ai_gateway/docs/logs)核对生成请求。 --- # 核心概念 来源: https://platform.lyrouter.com/ai_gateway/docs/concepts 使用 LYRouter 先要分清三层关系:账号和工作空间决定资源归谁,API Key 决定谁在调用,模型和服务来源决定请求最终发往哪个上游。本页介绍贯穿整套文档的概念,以及一次请求在网关里经过的处理步骤。 ## 账号、工作空间与 API Key | 概念 | 说明 | 详见 | | --- | --- | --- | | 账号(Account) | 个人、团队或企业。订阅、Credits 余额和成员都属于账号;同一个用户可以同时属于多个账号,在控制台顶部切换 | [组织、成员与角色](https://platform.lyrouter.com/ai_gateway/docs/organization) | | 成员角色 | 账号层只有账号管理员和成员两种。账号管理员管理成员、订阅和全部工作空间;成员只能进入被授权的工作空间 | [组织、成员与角色](https://platform.lyrouter.com/ai_gateway/docs/organization) | | 工作空间 | 账号下隔离应用环境的单位。模型开通、API Key、BYOK、路由设置和请求日志都按工作空间划分。工作空间内的角色有查看者、编辑者和管理员 | [创建工作空间与 API Key](https://platform.lyrouter.com/ai_gateway/docs/api-keys) | | API Key | 应用调用网关的凭证,属于一个工作空间。明文只在创建时显示一次;可以设置到期时间、预算和 IP 白名单 | [创建工作空间与 API Key](https://platform.lyrouter.com/ai_gateway/docs/api-keys) | 客户端里填写的永远是 LYRouter API Key。你在服务商处申请的 API Key 用于 BYOK,在控制台配置,不要填到客户端里。 ## 模型与服务来源 | 概念 | 说明 | 详见 | | --- | --- | --- | | 模型 ID | 请求中 `model` 字段的值,形如 `deepseek/deepseek-v4-flash`。从工作空间的 **模型广场** 复制,或调用 `GET /v1/models` 查询;不要填模型的展示名称 | [如何选择模型](https://platform.lyrouter.com/ai_gateway/docs/choose) | | 服务来源 | 一个模型可以由平台来源(平台的服务商账号,按 Credits 计费)或 BYOK 来源(你自己的服务商账号)提供,两者可以同时存在 | [平台模型与 BYOK 如何选择](https://platform.lyrouter.com/ai_gateway/docs/byok-choice) | | 服务商与通道 | 服务商是模型厂商的身份;通道是该服务商的一个具体接入点,包括地址、协议和接入方式。同一服务商的按量 API 和 Coding Plan 是两个通道 | [通道选择与路由策略](https://platform.lyrouter.com/ai_gateway/docs/routing) | | 凭证 | 通道下实际用来调用上游的 API Key。同一通道内,你的 BYOK 凭证排在平台凭证前面 | [BYOK 费用与凭证管理](https://platform.lyrouter.com/ai_gateway/docs/byok-cost) | | 虚拟模型 | 把主模型、备用模型、参数和系统提示词打包成一个名称,用 `@vmodel/<名称>` 调用 | [虚拟模型](https://platform.lyrouter.com/ai_gateway/docs/presets) | | Auto 智能路由 | 用 `lyrouter/auto` 调用,网关按任务难度在已开通的模型中挑选 | [Auto 智能路由](https://platform.lyrouter.com/ai_gateway/docs/auto) | | 默认模型 | 工作空间的一项路由设置:请求没写 `model`,或请求的模型全部失败时,由它接手 | [通道选择与路由策略](https://platform.lyrouter.com/ai_gateway/docs/routing) | ## 费用与治理 | 概念 | 说明 | 详见 | | --- | --- | --- | | Credits | 平台的计费单位。平台模型按用量扣除 Credits,BYOK 调用按次收取服务费。余额分为充值余额和赠送余额 | [计费规则与信用点](https://platform.lyrouter.com/ai_gateway/docs/billing) | | 订阅版本 | 个人版免费;团队版和企业版按席位订阅,到期且过了宽限期后调用会被拒绝 | [计费规则与信用点](https://platform.lyrouter.com/ai_gateway/docs/billing) | | 预算与配额 | API Key 可以设置 Token 或费用预算;安全围栏可以给成员、部门或工作空间设置配额。触顶后调用返回 429 | [预算、配额与限流](https://platform.lyrouter.com/ai_gateway/docs/quota) | | 安全围栏 | 按成员、部门、API Key 或工作空间生效的策略,包括模型访问控制、客户端访问控制和内容安全检测 | [安全围栏与语义审计](https://platform.lyrouter.com/ai_gateway/docs/guardrails) | | 请求日志 | 每次调用一条记录,详情顶部的 Request ID 是排查和提交问题时引用的编号 | [通过日志定位调用问题](https://platform.lyrouter.com/ai_gateway/docs/logs) | ## 一次请求的处理过程 一次调用在网关中大致经过以下步骤,任何一步被拒绝都会直接返回错误: 1. **识别身份**:网关根据 API Key 找到它所属的工作空间和账号。Key 无效返回 401;Key 已过期、来源 IP 不在白名单,或账号订阅已到期,会在这一步被拒绝。 2. **安全与额度检查**:执行该工作空间生效的安全围栏策略(客户端访问控制、内容安全检测)和配额。命中阻断策略返回 403,配额用完返回 429。 3. **确定模型**:`@vmodel/<名称>` 展开为虚拟模型的模型列表,`lyrouter/auto` 按任务难度挑选模型,没写 `model` 时使用默认模型。 4. **选择通道与凭证**:按工作空间的多渠道选路策略和 BYOK 偏好给通道排序,依次尝试。每次尝试前检查 Credits 余额(不足返回 402),并按实际选中的模型检查安全围栏的模型访问控制(禁止时返回 403);当前通道失败时自动换下一个。 5. **调用上游并返回结果**:把请求转换成上游需要的协议后发出,再把结果按你调用的协议返回,支持流式输出。 6. **计费与记录**:按实际调用的模型和用量扣除 Credits,并写入请求日志。日志通常在调用结束后几秒内可以查到。 各步骤的报错原文和处理方法见[错误码与请求标识](https://platform.lyrouter.com/ai_gateway/docs/errors);失败时如何换通道见[失败重试与备用模型](https://platform.lyrouter.com/ai_gateway/docs/fallback)。 --- # 工具兼容性与接入总览 来源: https://platform.lyrouter.com/ai_gateway/docs/tools 工具接入 LYRouter 的关键是协议、接入地址、网关 API Key 和模型标识。各工具页面都从安装前提和安装步骤开始,已安装用户可以直接跳到配置部分。 ## 选择接入指南 | 工具 | 主要接入方式 | | --- | --- | | [Claude Code](https://platform.lyrouter.com/ai_gateway/docs/claude-code) | Anthropic Messages,Base URL 为网关根地址 | | [Codex CLI](https://platform.lyrouter.com/ai_gateway/docs/codex) | Responses,Base URL 为网关地址加 /v1 | | [ChatGPT](https://platform.lyrouter.com/ai_gateway/docs/chatgpt) | 桌面应用本地工作,配置 Responses 模型服务与 API Key | | [OpenCode](https://platform.lyrouter.com/ai_gateway/docs/opencode) | 自定义提供商,按所选适配包匹配协议 | | [TRAE](https://platform.lyrouter.com/ai_gateway/docs/trae) | 自定义 OpenAI 兼容模型 | | [WorkBuddy](https://platform.lyrouter.com/ai_gateway/docs/workbuddy) | 自定义模型,区分 Base URL 与完整端点 | | [CC Switch](https://platform.lyrouter.com/ai_gateway/docs/ccswitch) | 管理工具配置,地址随目标工具协议变化 | | [其他 OpenAI 兼容客户端](https://platform.lyrouter.com/ai_gateway/docs/openai-clients) | Cherry Studio、Chatbox、Cline 等,添加 OpenAI 类型服务商,Base URL 为网关地址加 /v1 | ## 安装与调用的前提 安装工具可能要求操作系统、运行环境、权限和工具账号;调用 LYRouter 则需要已启用的网关 API Key、可用模型与有效服务来源。两类条件应分别确认。 ## 验证方式 先运行最小文本请求,再尝试工具调用。客户端生成请求应出现在 LYRouter 请求日志中;仅拉取模型列表或只测试连接不代表生成能力已验证。 --- # Claude Code 接入 LYRouter:安装、配置与故障排查 来源: https://platform.lyrouter.com/ai_gateway/docs/claude-code Claude Code 可以通过自定义模型服务接入 LYRouter。本文从安装前提开始,说明如何配置并完成第一次调用。 已安装应用?直接查看[配置 LYRouter](#配置-lyrouter)。 ## 前提条件 选择操作系统,准备对应的终端与依赖。原生安装不要求先安装 Node.js;设备需至少 4 GB 内存、联网环境和安装目录写权限。 **选择操作系统** Windows: #### 1. 确认系统与终端 使用 Windows 10 1809+ / Windows Server 2019+,按 x64 / ARM64 选择环境。在 **PowerShell** 中检查系统: ```powershell Get-CimInstance Win32_OperatingSystem | Select-Object Caption, Version, OSArchitecture ``` #### 2. 准备可选的 Git Bash 原生安装可直接使用 PowerShell;需要 Bash 工具时,安装 [Git for Windows](https://git-scm.com/downloads/win),再重新打开终端: ```powershell winget install --id Git.Git --exact --source winget git --version ``` 使用 WSL 时,在 WSL 的 Linux 终端按 Linux 页签准备环境;不需要另装 Git for Windows。 Linux: #### 1. 确认系统与终端 官方支持 Ubuntu 20.04+、Debian 10+ 等环境。打开 **Bash** 终端,确认发行版、架构及安装目录写权限: ```bash cat /etc/os-release uname -m bash --version ``` #### 2. 准备 cURL ```bash curl --version ``` 缺少依赖时,Ubuntu / Debian 可执行: ```bash sudo apt update sudo apt install -y curl bash ``` Alpine / musl 环境需要额外运行库,按[官方系统要求](https://code.claude.com/docs/en/setup#alpine-linux-and-musl-based-distributions)准备后再安装。 macOS: #### 1. 确认系统与终端 使用 macOS 13+,支持 Intel 与 Apple Silicon。在 **终端(Terminal)** 中检查: ```bash sw_vers -productVersion uname -m ``` #### 2. 检查 cURL macOS 通常已自带 cURL,可使用 Bash / Zsh 运行下节原生安装命令: ```bash curl --version ``` 确认当前用户可以写入安装目录,并能访问官方安装地址。 接入 LYRouter 还需要一把已启用的 API Key 和当前工作空间可用的模型。示例中的 `MODEL_ID` 必须替换为实际系统模型标识;工具账号与 LYRouter 账号是两个独立身份。 ## 安装应用 **按系统安装** macOS / Linux / WSL: ```bash curl -fsSL https://claude.ai/install.sh | bash claude --version ``` Windows PowerShell: ```powershell irm https://claude.ai/install.ps1 | iex claude --version ``` 使用官方安装器,完成后运行 `claude --version` 确认版本。 ## 配置 LYRouter 在 `~/.claude/settings.json` 的已有 `env` 中合并以下字段,保留其他设置: ```json { "env": { "ANTHROPIC_BASE_URL": "https://api.lyrouter.com", "ANTHROPIC_AUTH_TOKEN": "YOUR_LYROUTER_API_KEY", "ANTHROPIC_MODEL": "MODEL_ID", "ANTHROPIC_DEFAULT_OPUS_MODEL": "MODEL_ID", "ANTHROPIC_DEFAULT_SONNET_MODEL": "MODEL_ID", "ANTHROPIC_DEFAULT_HAIKU_MODEL": "FAST_MODEL_ID", "CLAUDE_CODE_SUBAGENT_MODEL": "MODEL_ID", "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1" } } ``` 把 `MODEL_ID` 换成工作空间模型广场中已开通的模型 ID,`FAST_MODEL_ID` 换成一个速度快、价格低的模型 ID(也可以与 `MODEL_ID` 相同)。各字段的作用: | 字段 | 作用 | | --- | --- | | `ANTHROPIC_BASE_URL` | 网关根地址,不加 `/v1`,Claude Code 会自己拼接 `/v1/messages` | | `ANTHROPIC_AUTH_TOKEN` | LYRouter API Key,Claude Code 以 `Authorization: Bearer` 头发送 | | `ANTHROPIC_MODEL` | 本次会话使用的主模型 | | `ANTHROPIC_DEFAULT_OPUS_MODEL`、`ANTHROPIC_DEFAULT_SONNET_MODEL` | 在 `/model` 中选择 `opus`、`sonnet` 别名时实际使用的模型 | | `ANTHROPIC_DEFAULT_HAIKU_MODEL` | `haiku` 别名以及后台任务(如生成会话标题)使用的模型 | | `CLAUDE_CODE_SUBAGENT_MODEL` | 子代理默认使用的模型 | | `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC` | 关闭自动更新检查、遥测等非必要的网络请求 | **模型字段都要填 LYRouter 的模型 ID。** Claude Code 的后台任务、模型别名和子代理默认使用 Claude 官方的模型名,这些名称不是 LYRouter 的模型 ID。没有配置对应字段时,这部分请求会返回 403 `Model is not available in the model plaza`;如果工作空间设置了[默认模型](https://platform.lyrouter.com/ai_gateway/docs/routing),则会改由默认模型回答。所选模型需要支持工具调用和流式输出。 ## 验证首次调用 启动应用,显式选择刚配置的模型,发送“请回复 OK”这样的最小任务。再到 LYRouter 的[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)检查生成端点、状态和实际模型。连接测试成功不等于完整生成或工具调用已通过。 ## 日常使用与故障排查 ### 安装后提示找不到命令,怎么办? **答:** 重新打开终端,执行本页安装步骤中的版本检查命令,并核对安装目录是否在 PATH 中。使用与安装步骤一致的终端和运行环境;仍不可用时,按官方安装指南检查安装结果。 ### Base URL 应该怎么填,为什么会出现地址错误? **答:** `ANTHROPIC_BASE_URL` 使用 `https://api.lyrouter.com`,不添加 `/v1`;客户端会拼接 Messages 路径。不要填控制台页面地址,也不要重复拼接端点。 ### 切换模型前需要检查什么? **答:** 确认新模型已在当前工作空间启用、至少有一个有效服务来源,并支持应用所需的协议和工具能力。使用系统模型标识,不使用展示名称。 ### 应用更新后,原来的配置为什么不生效? **答:** 先核对当前应用版本和实际读取的配置位置,再对照本页“配置 LYRouter”检查提供商、地址、密钥和模型。不同版本的配置要求以本页链接的官方资料为准。 ### 请求返回 401 / 403,应该先检查什么? **答:** 确认填写的是已启用的 LYRouter API Key,并检查该 Key 所属工作空间的模型来源与访问策略。结合具体错误和日志判断拒绝来源,详见[鉴权与权限 FAQ](https://platform.lyrouter.com/ai_gateway/docs/auth-errors)。 ### 请求返回 429,反复重试有用吗? **答:** 先确认是平台限制还是上游额度耗尽,再调整并发、调用频率或资源配置。使用有上限的退避重试,避免立即密集重试,详见[限流与配额 FAQ](https://platform.lyrouter.com/ai_gateway/docs/rate-errors)。 ### 主对话正常,但日志里有 403 `Model is not available in the model plaza`,是什么原因? **答:** 通常是后台任务、模型别名或子代理用 Claude 官方模型名发出了请求。按本页「配置 LYRouter」补齐 `ANTHROPIC_DEFAULT_OPUS_MODEL`、`ANTHROPIC_DEFAULT_SONNET_MODEL`、`ANTHROPIC_DEFAULT_HAIKU_MODEL` 和 `CLAUDE_CODE_SUBAGENT_MODEL`,全部填 LYRouter 的模型 ID。在[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)中查看「模型(请求)」列,可以确认是哪个名称没有配置。 ### 缓存命中率很低甚至为 0,怎么办? **答:** 先升级 Claude Code。部分版本会在系统提示词开头写入一行每个请求都变化的标记,使提示词缓存从第一个字节起就无法命中,日志中的「输入(缓存命中)」长期为 0。升级到最新版本后即可恢复。会话中途增删工具或 MCP 服务器也会降低命中率,更多做法见[降低成本与优化缓存](https://platform.lyrouter.com/ai_gateway/docs/cost-practice)。 ### 应用有回复,但 LYRouter 日志里找不到请求,怎么办? **答:** 确认当前生效的是本页配置的 LYRouter 提供商和模型,并核对网关地址。用最小生成任务验证后,在正确工作空间按时间和 Key 查询[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)。仅拉取模型列表不会出现在普通调用列表中。 ## 官方资料 下列要求和安装方式来自工具官方资料,后续版本以官方说明为准。 - [Claude Code 安装与系统要求](https://code.claude.com/docs/en/setup) - [模型配置](https://code.claude.com/docs/en/model-config) --- # Codex CLI 接入 LYRouter:安装、配置与故障排查 来源: https://platform.lyrouter.com/ai_gateway/docs/codex Codex CLI 可以通过自定义模型服务接入 LYRouter。本文从安装前提开始,说明如何配置并完成第一次调用。 已安装应用?直接查看[配置 LYRouter](#配置-lyrouter)。 ## 前提条件 本页针对 Codex CLI 的自定义模型提供商接入,采用 npm 安装方式。选择操作系统,准备 Node.js LTS / npm、联网环境及用户全局安装目录写权限;模型服务需要支持 Responses。 **选择操作系统** Windows: #### 1. 选择终端环境 可在 **PowerShell** 中原生运行 Codex CLI;项目和依赖位于 WSL 时,在 WSL 终端运行,并按 Linux 页签准备环境。Windows 的运行与隔离方式参见[官方 OpenAI 文档](https://developers.openai.com/codex/windows/)。 #### 2. 准备 Node.js 与 npm 未安装时,先按[快速开始的环境准备](https://platform.lyrouter.com/ai_gateway/docs/quickstart)安装 Windows Node.js LTS,重新打开 PowerShell 后检查: ```powershell node --version npm.cmd --version npm.cmd config get prefix ``` 确认显示了版本号,且全局安装目录可写。Windows 使用 `npm.cmd`,避免 PowerShell 对 `npm.ps1` 的执行策略限制。 Linux: #### 1. 准备终端与项目目录 在 **Bash** 终端运行,准备可读写的本地项目目录、联网环境及用户级工具安装目录。先检查系统与架构: ```bash cat /etc/os-release uname -m ``` #### 2. 准备 Node.js 与 npm 未安装时,按[快速开始的 Linux 环境准备](https://platform.lyrouter.com/ai_gateway/docs/quickstart)安装 Node.js LTS,再检查: ```bash node --version npm --version npm config get prefix ``` 使用可写的用户级安装目录;安装权限问题先检查 Node.js / npm 的路径与安装方式。 macOS: #### 1. 准备终端与项目目录 打开 **终端(Terminal)**,使用 Bash / Zsh,准备可读写的项目目录及联网环境: ```bash sw_vers -productVersion uname -m ``` #### 2. 准备 Node.js 与 npm 未安装时,按[快速开始的 macOS 环境准备](https://platform.lyrouter.com/ai_gateway/docs/quickstart)安装 Node.js LTS;确认 PATH 已配置后检查: ```bash node --version npm --version npm config get prefix ``` 本页使用 npm 路径;使用官方独立安装器或 Homebrew 的用户以[官方 CLI 指南](https://developers.openai.com/codex/cli/)为准。 接入 LYRouter 还需要一把已启用的 API Key 和当前工作空间可用的模型。示例中的 `MODEL_ID` 必须替换为实际系统模型标识;工具账号与 LYRouter 账号是两个独立身份。 ## 安装应用 **按系统安装** Windows PowerShell: ```powershell npm.cmd install -g @openai/codex@latest codex --version ``` Linux / WSL: ```bash npm install -g @openai/codex@latest codex --version ``` macOS: ```bash npm install -g @openai/codex@latest codex --version ``` 安装后重新打开终端并检查版本。采用其他安装方式时,参见下方官方指南。 ## 配置 LYRouter 在 `~/.codex/config.toml` 合并自定义提供商配置: ```toml model = "MODEL_ID" model_provider = "lyrouter" [model_providers.lyrouter] name = "LYRouter" base_url = "https://api.lyrouter.com/v1" env_key = "LYROUTER_API_KEY" wire_api = "responses" ``` 当前官方配置中 `wire_api` 只支持 `responses`,不使用旧的 `chat` 值。密钥放入配置指定的环境变量: **设置密钥** macOS / Linux / WSL: ```bash export LYROUTER_API_KEY="YOUR_LYROUTER_API_KEY" codex ``` Windows PowerShell: ```powershell $env:LYROUTER_API_KEY="YOUR_LYROUTER_API_KEY" codex ``` 模型和来源必须实际支持[Responses](https://platform.lyrouter.com/ai_gateway/docs/responses-api),选择 Chat-only 来源会导致调用失败。 ## 验证首次调用 启动应用,显式选择刚配置的模型,发送“请回复 OK”这样的最小任务。再到 LYRouter 的[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)检查生成端点、状态和实际模型。连接测试成功不等于完整生成或工具调用已通过。 ## 日常使用与故障排查 ### 安装后提示找不到命令,怎么办? **答:** 重新打开终端,执行本页安装步骤中的版本检查命令,并核对安装目录是否在 PATH 中。使用与安装步骤一致的终端和运行环境;仍不可用时,按官方安装指南检查安装结果。 ### Base URL 和调用协议应该如何配置? **答:** 本页的 `base_url` 使用 `https://api.lyrouter.com/v1`,`wire_api` 使用 `responses`。确认选择了 `lyrouter` 提供商,且模型与服务来源支持[Responses](https://platform.lyrouter.com/ai_gateway/docs/responses-api);不要在地址中重复添加 `/v1`。 ### 切换模型前需要检查什么? **答:** 确认新模型已在当前工作空间启用、至少有一个有效服务来源,并支持应用所需的协议和工具能力。使用系统模型标识,不使用展示名称。 ### 应用更新后,原来的配置为什么不生效? **答:** 先核对当前应用版本和实际读取的配置位置,再对照本页“配置 LYRouter”检查提供商、地址、密钥和模型。不同版本的配置要求以本页链接的官方资料为准。 ### 请求返回 401 / 403,应该先检查什么? **答:** 确认填写的是已启用的 LYRouter API Key,并检查该 Key 所属工作空间的模型来源与访问策略。结合具体错误和日志判断拒绝来源,详见[鉴权与权限 FAQ](https://platform.lyrouter.com/ai_gateway/docs/auth-errors)。 ### 请求返回 429,反复重试有用吗? **答:** 先确认是平台限制还是上游额度耗尽,再调整并发、调用频率或资源配置。使用有上限的退避重试,避免立即密集重试,详见[限流与配额 FAQ](https://platform.lyrouter.com/ai_gateway/docs/rate-errors)。 ### 应用有回复,但 LYRouter 日志里找不到请求,怎么办? **答:** 确认当前生效的是本页配置的 LYRouter 提供商和模型,并核对网关地址。用最小生成任务验证后,在正确工作空间按时间和 Key 查询[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)。仅拉取模型列表不会出现在普通调用列表中。 ## 官方资料 下列要求和安装方式来自工具官方资料,后续版本以官方说明为准。 - [Codex CLI](https://developers.openai.com/codex/cli/) - [当前配置参考](https://developers.openai.com/codex/config-reference/) - [Codex 开源仓库与 npm 安装说明](https://github.com/openai/codex) --- # ChatGPT 接入 LYRouter:安装、配置与故障排查 来源: https://platform.lyrouter.com/ai_gateway/docs/chatgpt 本页介绍官方 ChatGPT 桌面应用的本地工作模式(Codex)如何配置 LYRouter 模型服务,参见[官方网关配置指南](https://learn.chatgpt.com/docs/enterprise/connect-to-a-gateway)。网页版聊天不读取本机的 `config.toml`,以下配置适用于桌面应用的本地工作。 已安装应用?直接查看[配置 LYRouter](#配置-lyrouter)。 ## 前提条件 本页使用官方桌面应用的本地工作(Codex)。准备联网环境、可写的用户配置目录,以及与当前操作系统和处理器匹配的官方安装包;桌面应用安装无需先安装 Codex CLI。 **选择操作系统** Windows: 使用官方 Windows 桌面应用,准备 PowerShell 和安装权限。从[官方 Windows 指南](https://learn.chatgpt.com/docs/windows/windows-app)进入下载入口;采用命令行安装时先确认 `winget` 可用: ```powershell winget --version ``` 本页按原生 Windows 环境配置;WSL 中的 CLI 使用独立的 Linux 用户目录,不自动共享本页配置。 Linux: 官方 Linux 桌面应用目前为预览版。按[官方 Linux 指南](https://learn.chatgpt.com/docs/linux/linux-app)确认发行版和处理器受支持,准备图形桌面、终端及软件包安装权限: ```bash cat /etc/os-release uname -m ``` 根据发行版选择 `.deb`、`.rpm` 或官方 Arch 安装路径;按 x64 / ARM64 选择对应包。 macOS: 从[官方桌面应用入口](https://learn.chatgpt.com/docs/app)选择适合设备的安装包;当前页面提供 Apple Silicon 下载入口。准备终端及应用安装目录写权限,检查系统与架构: ```bash sw_vers -productVersion uname -m ``` 下载前以官方页面列出的系统和处理器要求为准。 LYRouter 侧需要一把已启用的 [API Key](https://platform.lyrouter.com/ai_gateway/docs/api-keys),以及该 Key 所属工作空间中支持 [Responses](https://platform.lyrouter.com/ai_gateway/docs/responses-api) 的可用模型和服务来源。应用账号与 LYRouter 账号分别管理权限。 ## 安装应用 **按系统安装** Windows: 从[官方 Windows 指南](https://learn.chatgpt.com/docs/windows/windows-app)进入 Microsoft Store 下载并安装,也可以在 PowerShell 中执行官方命令: ```powershell winget install --id 9PLM9XGG6VKS -s msstore ``` 安装完成后,从开始菜单打开 ChatGPT。 Linux: 从[官方 Linux 指南](https://learn.chatgpt.com/docs/linux/linux-app)下载对应架构的安装包。Ubuntu / Debian 的 x64 示例: ```bash cd ~/Downloads sudo apt install ./chatgpt_amd64.deb chatgpt ``` ARM64 使用 `chatgpt_arm64.deb`。Fedora 的 x64 示例: ```bash cd ~/Downloads sudo dnf install ./chatgpt.x86_64.rpm chatgpt ``` ARM64 使用 `chatgpt.aarch64.rpm`。Arch 安装按官方指南执行。 macOS: 1. 在[官方桌面应用页面](https://learn.chatgpt.com/docs/app)下载 macOS 安装包。 2. 打开安装包,将应用放入“应用程序”目录。 3. 从“应用程序”打开 ChatGPT,完成首次启动提示。 确认应用能正常打开,在应用中进入本地工作(Codex)并准备本地项目或文件夹;随后按下节配置 LYRouter。 ## 配置 LYRouter ### 1. 配置模型服务 打开用户级配置文件,合并以下内容。已有相同配置项时修改原值,不要重复添加。 | 系统 | 配置文件 | | --- | --- | | macOS / Linux | `~/.codex/config.toml` | | Windows | `%USERPROFILE%\.codex\config.toml` | ```toml model = "MODEL_ID" model_provider = "lyrouter" web_search = "disabled" [model_providers.lyrouter] name = "LYRouter" base_url = "https://api.lyrouter.com/v1" wire_api = "responses" env_key = "LYROUTER_API_KEY" ``` - 将 `MODEL_ID` 替换为当前工作空间可用、支持 [Responses](https://platform.lyrouter.com/ai_gateway/docs/responses-api) 的系统模型标识,详见[模型命名与查询](https://platform.lyrouter.com/ai_gateway/docs/model-names)。 - `model`、`model_provider` 和 `web_search` 放在第一个 TOML 表头之前。 - `base_url` 包含 `/v1`,不填写控制台地址或完整的 `/v1/responses` 端点。 - 首次配置关闭网页搜索;需要启用时先确认模型及来源支持对应能力。 ### 2. 设置 API Key 将已启用的 LYRouter [API Key](https://platform.lyrouter.com/ai_gateway/docs/api-keys) 设置为 `LYROUTER_API_KEY`。密钥由应用进程的环境变量提供,不写入项目配置或仓库。 **设置密钥** macOS: 在终端执行以下命令,然后完全退出桌面应用并重新打开: ```bash launchctl setenv LYROUTER_API_KEY "YOUR_LYROUTER_API_KEY" ``` 该设置用于当前登录会话;重新登录后需重新设置。 Windows: 在 PowerShell 中设置用户环境变量: ```powershell [Environment]::SetEnvironmentVariable("LYROUTER_API_KEY", "YOUR_LYROUTER_API_KEY", "User") ``` 重新登录 Windows 后再打开桌面应用,使启动进程读取新的用户环境变量。 Linux: 在启动桌面应用的终端中执行: ```bash export LYROUTER_API_KEY="YOUR_LYROUTER_API_KEY" chatgpt ``` 通过桌面图标启动时,需要在应用的启动环境中设置该变量;仅在另一个终端执行 `export` 不会传给已经运行的应用。 ## 验证首次调用 完全退出并重新打开 ChatGPT 桌面应用,在本地工作中新建任务,确认生效的模型服务为 `LYRouter`、模型为配置的 `MODEL_ID`。发送“请只回复 OK”,再到 LYRouter [请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)按时间和 API Key 确认实际调用。 ## 日常使用与故障排查 ### 安装后应用无法打开,怎么办? **答:** 确认使用官方安装包,并检查操作系统与处理器架构。Linux 还需确认发行版受支持、安装的软件包正确且图形桌面可用。按本页“官方资料”中的对应系统指南核对安装结果。 ### 修改配置后,为什么没有使用 LYRouter? **答:** 确认进入桌面应用的本地工作(Codex),配置写入用户级 `config.toml`;检查是否选中了其他配置档,顶层 `model` 和 `model_provider` 是否放在第一个表头之前。完全退出并重新启动应用后再验证。网页版聊天不读取本机配置。 ### Base URL 和模型应该怎么填写? **答:** `base_url` 使用 `https://api.lyrouter.com/v1`,`wire_api` 使用 `responses`。模型填写工作空间可用的系统标识,并确认至少有一个支持 Responses 的有效来源;不填写展示名称,也不重复拼接 `/v1`。详见[模型命名与查询](https://platform.lyrouter.com/ai_gateway/docs/model-names)和 [Responses](https://platform.lyrouter.com/ai_gateway/docs/responses-api)。 ### 请求返回 401 / 403,应该先检查什么? **答:** 确认 Key 已启用,`LYROUTER_API_KEY` 已传入桌面应用进程。macOS 重新登录后需重新设置本页的会话环境变量;Windows 设置用户变量后需重新登录再打开应用。再检查 Key 的工作空间模型权限,详见[鉴权与权限 FAQ](https://platform.lyrouter.com/ai_gateway/docs/auth-errors)。 ### 请求返回 429,怎么办? **答:** 先确认是限流、预算限制还是上游额度问题,再调整调用频率、并发或资源配置。避免连续密集重试,详见[限流与配额 FAQ](https://platform.lyrouter.com/ai_gateway/docs/rate-errors)。 ### 应用有回复,但 LYRouter 日志里找不到请求,怎么办? **答:** 检查当前任务生效的模型服务、模型标识和网关地址,再按正确工作空间、调用时间和 Key 查询[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)。使用最小文本任务验证实际生成请求,不能只凭应用回复判断接入成功。 ## 官方资料 安装方式、支持环境和配置项以后续官方 OpenAI 文档为准。 - [ChatGPT 桌面应用与 macOS 下载入口](https://learn.chatgpt.com/docs/app) - [Windows 安装指南](https://learn.chatgpt.com/docs/windows/windows-app) - [Linux 安装指南](https://learn.chatgpt.com/docs/linux/linux-app) - [模型网关配置](https://learn.chatgpt.com/docs/enterprise/connect-to-a-gateway) - [配置项参考](https://learn.chatgpt.com/docs/config-file/config-reference) --- # OpenCode 接入 LYRouter:安装、配置与故障排查 来源: https://platform.lyrouter.com/ai_gateway/docs/opencode OpenCode 可以通过自定义模型服务接入 LYRouter。本文从安装前提开始,说明如何配置并完成第一次调用。 已安装应用?直接查看[配置 LYRouter](#配置-lyrouter)。 ## 前提条件 本页配置适用于官方 OpenCode 1 文档中的 CLI,使用 npm 安装。OpenCode 1 与 OpenCode 2 共用 `opencode` 命令,安装前先确认目标版本与已有安装。 **选择操作系统** Windows: #### 1. 选择终端环境 官方推荐在 **WSL** 中使用 OpenCode。已有 WSL 时可先检查: ```powershell wsl --status ``` 在 WSL 中安装时,依赖和后续命令均在 Linux 终端准备,不使用 Windows 的 Node.js / npm。原生 Windows 可使用官方提供的 npm 安装方式。 #### 2. 检查 Node.js 与 npm 原生 Windows 用户先按[快速开始](https://platform.lyrouter.com/ai_gateway/docs/quickstart)安装 Node.js LTS,然后在 PowerShell 中检查: ```powershell node --version npm.cmd --version npm.cmd config get prefix ``` 准备支持交互界面的终端、联网环境及可写的全局安装目录;Windows 使用 `npm.cmd`。 Linux: #### 1. 准备终端与安装目录 使用支持交互界面的终端和 Bash,准备联网环境、可读写的项目与工具安装目录: ```bash cat /etc/os-release uname -m ``` #### 2. 检查 Node.js 与 npm 按[快速开始](https://platform.lyrouter.com/ai_gateway/docs/quickstart)准备 Node.js LTS,再检查 npm 安装所需环境: ```bash node --version npm --version npm config get prefix ``` 采用原生安装脚本时,另按[官方安装指南](https://opencode.ai/docs/)准备 cURL;本页 npm 路径不要求先使用原生脚本。 macOS: #### 1. 准备终端 打开支持交互界面的终端,使用 Bash / Zsh,并确认系统与处理器架构: ```bash sw_vers -productVersion uname -m ``` #### 2. 检查 Node.js 与 npm 按[快速开始](https://platform.lyrouter.com/ai_gateway/docs/quickstart)准备 Node.js LTS,确认全局安装目录可写: ```bash node --version npm --version npm config get prefix ``` 若选择 Homebrew 或其他安装方式,按[官方指南](https://opencode.ai/docs/)操作;安装后仍需核对 OpenCode 版本。 接入 LYRouter 还需要一把已启用的 API Key 和当前工作空间可用的模型。示例中的 `MODEL_ID` 必须替换为实际系统模型标识;工具账号与 LYRouter 账号是两个独立身份。 ## 安装应用 **按系统安装** Windows PowerShell: ```powershell npm.cmd install -g opencode-ai opencode --version ``` Linux / WSL: ```bash npm install -g opencode-ai opencode --version ``` macOS: ```bash npm install -g opencode-ai opencode --version ``` 安装后重新打开终端并检查版本。采用其他安装方式时,参见下方官方指南。 ## 配置 LYRouter 先运行 `opencode`,通过 `/connect` → Other 添加提供商 ID `lyrouter` 及 LYRouter API Key。随后创建或更新 `~/.config/opencode/opencode.json`: ```json { "$schema": "https://opencode.ai/config.json", "provider": { "lyrouter": { "npm": "@ai-sdk/openai-compatible", "name": "LYRouter", "options": { "baseURL": "https://api.lyrouter.com/v1" }, "models": { "MODEL_ID": { "name": "MODEL_ID" } } } } } ``` 提供商 ID 必须与 `/connect` 一致。运行 `/models` 选择 `lyrouter` 下的模型。此配置使用 Chat Completions;若使用 Responses 来源,按官方提供商指南选择对应适配包。 ## 验证首次调用 启动应用,显式选择刚配置的模型,发送“请回复 OK”这样的最小任务。再到 LYRouter 的[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)检查生成端点、状态和实际模型。连接测试成功不等于完整生成或工具调用已通过。 ## 日常使用与故障排查 ### 安装后提示找不到命令,怎么办? **答:** 重新打开终端,执行本页安装步骤中的版本检查命令,并核对安装目录是否在 PATH 中。使用与安装步骤一致的终端和运行环境;仍不可用时,按官方安装指南检查安装结果。 ### 自定义提供商配置了却调用失败,应该检查什么? **答:** 核对所选适配包对应的协议、`baseURL`、API Key 和系统模型标识。本页 OpenAI 兼容配置的地址是 `https://api.lyrouter.com/v1`;切换适配包时不能沿用不匹配的协议配置。 ### 切换模型前需要检查什么? **答:** 确认新模型已在当前工作空间启用、至少有一个有效服务来源,并支持应用所需的协议和工具能力。使用系统模型标识,不使用展示名称。 ### 应用更新后,原来的配置为什么不生效? **答:** 先核对当前应用版本和实际读取的配置位置,再对照本页“配置 LYRouter”检查提供商、地址、密钥和模型。不同版本的配置要求以本页链接的官方资料为准。 ### 请求返回 401 / 403,应该先检查什么? **答:** 确认填写的是已启用的 LYRouter API Key,并检查该 Key 所属工作空间的模型来源与访问策略。结合具体错误和日志判断拒绝来源,详见[鉴权与权限 FAQ](https://platform.lyrouter.com/ai_gateway/docs/auth-errors)。 ### 请求返回 429,反复重试有用吗? **答:** 先确认是平台限制还是上游额度耗尽,再调整并发、调用频率或资源配置。使用有上限的退避重试,避免立即密集重试,详见[限流与配额 FAQ](https://platform.lyrouter.com/ai_gateway/docs/rate-errors)。 ### 应用有回复,但 LYRouter 日志里找不到请求,怎么办? **答:** 确认当前生效的是本页配置的 LYRouter 提供商和模型,并核对网关地址。用最小生成任务验证后,在正确工作空间按时间和 Key 查询[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)。仅拉取模型列表不会出现在普通调用列表中。 ## 官方资料 下列要求和安装方式来自工具官方资料,后续版本以官方说明为准。 - [安装指南](https://opencode.ai/docs/) - [自定义提供商](https://docs.opencode.ai/docs/providers/) - [配置位置](https://docs.opencode.ai/docs/config/) --- # TRAE 接入 LYRouter:安装、配置与故障排查 来源: https://platform.lyrouter.com/ai_gateway/docs/trae TRAE 可以通过自定义模型服务接入 LYRouter。本文从安装前提开始,说明如何配置并完成第一次调用。 已安装应用?直接查看[配置 LYRouter](#配置-lyrouter)。 ## 前提条件 准备 TRAE 账号、联网环境及本地安装权限。选择操作系统,检查系统版本和处理器架构,并确认客户端提供自定义模型配置入口。 **选择操作系统** Windows: #### 1. 检查系统版本与架构 使用 Windows 10 / 11 的 **x64** 环境,在 PowerShell 中检查: ```powershell Get-CimInstance Win32_OperatingSystem | Select-Object Caption, Version, OSArchitecture ``` #### 2. 准备安装与登录 从[TRAE 下载中心](https://www.trae.cn/download)选择 Windows 安装包,确认安装目录可写,并能完成 TRAE 登录。项目自身需要的编译器、Python 或 Node.js 按项目要求另行准备。 Linux: #### 1. 确认发行版与架构 官方安装指南列出 Ubuntu 20.04+ / Debian 10+ 的 `.deb` 包,以及 Fedora 42 / RHEL 9.x 的 `.rpm` 包;按下载页选择 x64 / ARM64 架构: ```bash cat /etc/os-release uname -m ``` #### 2. 准备桌面与安装权限 需要可运行图形应用的桌面环境、联网环境和软件包安装权限。发行版与安装包格式需匹配,依赖以安装器及[官方指南](https://docs.trae.cn/ide_get-started-with-trae)提示为准;纯 SSH 终端不能直接显示本地图形界面。 macOS: #### 1. 确认系统与处理器 使用 macOS 12+,支持 Apple Silicon 与 Intel: ```bash sw_vers -productVersion uname -m ``` #### 2. 准备安装与登录 在[下载中心](https://www.trae.cn/download)选择与处理器对应的 macOS 安装包,确认能安装到应用目录,并准备 TRAE 登录账号及可访问的网络。 接入 LYRouter 还需要一把已启用的 API Key 和当前工作空间可用的模型。示例中的 `MODEL_ID` 必须替换为实际系统模型标识;工具账号与 LYRouter 账号是两个独立身份。 ## 安装应用 1. 打开[TRAE 下载中心](https://www.trae.cn/download)。 2. 选择操作系统与架构对应的安装包,完成安装。 3. 首次启动选择语言与主题,并完成 TRAE 登录。 4. 在“关于”或更新信息中确认客户端版本,再打开一个测试项目。 ## 配置 LYRouter 进入模型设置,添加自定义 / OpenAI 兼容模型: | 字段 | 填写内容 | | --- | --- | | 提供商 / 显示名称 | LYRouter | | API 格式 | OpenAI 兼容 | | Base URL | https://api.lyrouter.com/v1 | | API Key | LYRouter API Key | | 模型 ID | 当前工作空间实际系统模型标识 | 保存后显式选择该自定义模型。TRAE 内置 Auto 不等同于 LYRouter Auto,也不保证使用自定义模型。 ## 验证首次调用 启动应用,显式选择刚配置的模型,发送“请回复 OK”这样的最小任务。再到 LYRouter 的[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)检查生成端点、状态和实际模型。连接测试成功不等于完整生成或工具调用已通过。 ## 日常使用与故障排查 ### 安装后无法启动应用,应该如何检查? **答:** 按本页“前提条件”核对操作系统、处理器架构和安装权限,再按对应系统的安装指南检查安装结果。使用官方提供的安装包,具体系统要求以本页链接的官方资料为准。 ### 自定义模型的 Base URL 应该怎么填? **答:** 本页 OpenAI 兼容配置使用 `https://api.lyrouter.com/v1`,并填写 LYRouter API Key 和系统模型标识。不要重复追加 `/v1`,保存后在会话中显式选中自定义模型。 ### 切换模型前需要检查什么? **答:** 确认新模型已在当前工作空间启用、至少有一个有效服务来源,并支持应用所需的协议和工具能力。使用系统模型标识,不使用展示名称。 ### 应用更新后,原来的配置为什么不生效? **答:** 先核对当前应用版本和实际读取的配置位置,再对照本页“配置 LYRouter”检查提供商、地址、密钥和模型。不同版本的配置要求以本页链接的官方资料为准。 ### 请求返回 401 / 403,应该先检查什么? **答:** 确认填写的是已启用的 LYRouter API Key,并检查该 Key 所属工作空间的模型来源与访问策略。结合具体错误和日志判断拒绝来源,详见[鉴权与权限 FAQ](https://platform.lyrouter.com/ai_gateway/docs/auth-errors)。 ### 请求返回 429,反复重试有用吗? **答:** 先确认是平台限制还是上游额度耗尽,再调整并发、调用频率或资源配置。使用有上限的退避重试,避免立即密集重试,详见[限流与配额 FAQ](https://platform.lyrouter.com/ai_gateway/docs/rate-errors)。 ### 应用有回复,但 LYRouter 日志里找不到请求,怎么办? **答:** 确认会话选中了刚配置的自定义模型,而不是内置或 Auto 模式,再发送最小生成请求。在正确工作空间按时间和 Key 查询[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs);刚结束的请求可能需要稍后刷新。 ## 官方资料 下列要求和安装方式来自工具官方资料,后续版本以官方说明为准。 - [安装前提与步骤](https://docs.trae.cn/ide_get-started-with-trae) - [自定义模型](https://docs.trae.cn/ide_models) --- # WorkBuddy 接入 LYRouter:安装、配置与故障排查 来源: https://platform.lyrouter.com/ai_gateway/docs/workbuddy WorkBuddy 可以通过自定义模型服务接入 LYRouter。本文从安装前提开始,说明如何配置并完成第一次调用。 已安装应用?直接查看[配置 LYRouter](#配置-lyrouter)。 ## 前提条件 本页针对 WorkBuddy 桌面应用。准备应用登录账号、联网环境和本地安装权限;按所用操作系统选择对应说明。 **选择操作系统** Windows: #### 1. 确认系统与架构 官方要求 Windows 10 1809+ / Windows 11、64 位系统(x64 / ARM64)、至少 4 GB 内存及 500 MB 可用磁盘空间。在 PowerShell 中检查系统: ```powershell Get-CimInstance Win32_OperatingSystem | Select-Object Caption, Version, OSArchitecture ``` #### 2. 准备安装与登录 选择[官方下载](https://www.workbuddy.ai/)提供的 Windows 安装包,准备安装目录写权限和登录账号。具体要求参见[Windows 安装指南](https://www.workbuddy.ai/docs/workbuddy/From-Beginner-to-Expert-Guide/Installation-Win-Guide)。 Linux: #### 1. 确认桌面版安装支持 当前[官网桌面下载入口](https://www.workbuddy.ai/)列出 Windows 与 macOS 安装包,本页不提供 Linux 桌面版安装步骤。 #### 2. 选择可用的环境 使用 Windows 或 macOS 环境继续本页指南。需要在 Linux 本地接入 LYRouter 时,可查看 [Claude Code](https://platform.lyrouter.com/ai_gateway/docs/claude-code)、[Codex CLI](https://platform.lyrouter.com/ai_gateway/docs/codex)或 [OpenCode](https://platform.lyrouter.com/ai_gateway/docs/opencode);这些工具的 Linux 前提条件在各自页签中说明。 macOS: #### 1. 确认系统与处理器 在终端中检查 macOS 版本与处理器,按[官方安装说明](https://www.workbuddy.ai/docs/workbuddy/From-Beginner-to-Expert-Guide/Installation-Mac-Guide)确认系统版本要求: ```bash sw_vers -productVersion uname -m ``` #### 2. 准备安装与登录 从[官网](https://www.workbuddy.ai/)选择 Mac ARM64(Apple Silicon)或 Mac x64(Intel)安装包,确认应用目录可写,并准备应用登录账号和可访问的网络。 接入 LYRouter 还需要一把已启用的 API Key 和当前工作空间可用的模型。示例中的 `MODEL_ID` 必须替换为实际系统模型标识;工具账号与 LYRouter 账号是两个独立身份。 ## 安装应用 1. 打开[WorkBuddy 官网](https://www.workbuddy.ai/),选择 macOS 或 Windows 安装包。 2. macOS 打开 DMG 并拖入 Applications;Windows 运行安装器并完成向导。 3. 启动应用完成登录,在应用信息中记录版本。 4. 仅按实际任务需要授权本地文件与其他系统权限。 ## 配置 LYRouter 在 Settings → Model 添加 Custom 模型:URL 使用 `https://api.lyrouter.com/v1`,API Key 使用 LYRouter API Key,模型名使用系统模型标识。 默认的标准协议模式会补全 Chat Completions 路径。若显式开启 Custom Protocol,应用直接请求填写的 URL,此时使用完整 `https://api.lyrouter.com/v1/chat/completions`,不能把 Base URL 当成完整端点。保存后在会话中选中自定义模型。 ## 验证首次调用 启动应用,显式选择刚配置的模型,发送“请回复 OK”这样的最小任务。再到 LYRouter 的[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)检查生成端点、状态和实际模型。连接测试成功不等于完整生成或工具调用已通过。 ## 日常使用与故障排查 ### 安装后无法启动应用,应该如何检查? **答:** 按本页“前提条件”核对操作系统、处理器架构和安装权限,再按对应系统的安装指南检查安装结果。使用官方提供的安装包,具体系统要求以本页链接的官方资料为准。 ### Base URL 和 Custom Protocol 的 URL 有什么区别? **答:** 默认标准协议模式使用 `https://api.lyrouter.com/v1`,应用会补全 Chat Completions 路径。开启 Custom Protocol 后应填写完整端点 `https://api.lyrouter.com/v1/chat/completions`;不要把根地址或 Base URL 当作完整请求端点。 ### 切换模型前需要检查什么? **答:** 确认新模型已在当前工作空间启用、至少有一个有效服务来源,并支持应用所需的协议和工具能力。使用系统模型标识,不使用展示名称。 ### 应用更新后,原来的配置为什么不生效? **答:** 先核对当前应用版本和实际读取的配置位置,再对照本页“配置 LYRouter”检查提供商、地址、密钥和模型。不同版本的配置要求以本页链接的官方资料为准。 ### 请求返回 401 / 403,应该先检查什么? **答:** 确认填写的是已启用的 LYRouter API Key,并检查该 Key 所属工作空间的模型来源与访问策略。结合具体错误和日志判断拒绝来源,详见[鉴权与权限 FAQ](https://platform.lyrouter.com/ai_gateway/docs/auth-errors)。 ### 请求返回 429,反复重试有用吗? **答:** 先确认是平台限制还是上游额度耗尽,再调整并发、调用频率或资源配置。使用有上限的退避重试,避免立即密集重试,详见[限流与配额 FAQ](https://platform.lyrouter.com/ai_gateway/docs/rate-errors)。 ### 应用有回复,但 LYRouter 日志里找不到请求,怎么办? **答:** 确认会话选中了刚配置的自定义模型,而不是内置或 Auto 模式,再发送最小生成请求。在正确工作空间按时间和 Key 查询[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs);刚结束的请求可能需要稍后刷新。 ## 官方资料 下列要求和安装方式来自工具官方资料,后续版本以官方说明为准。 - [Windows 安装指南](https://www.workbuddy.ai/docs/workbuddy/From-Beginner-to-Expert-Guide/Installation-Win-Guide) - [macOS 安装指南](https://www.workbuddy.ai/docs/workbuddy/From-Beginner-to-Expert-Guide/Installation-Mac-Guide) - [自定义模型和协议](https://www.workbuddy.ai/docs/workbuddy/From-Beginner-to-Expert-Guide/Function-Description/Model) --- # CC Switch 接入 LYRouter:安装、配置与故障排查 来源: https://platform.lyrouter.com/ai_gateway/docs/ccswitch CC Switch 是管理 Claude Code、Codex 等工具服务商配置的桌面应用,本身不调用模型。把 LYRouter 添加为它管理的服务商并启用后,目标工具就会通过 LYRouter 调用模型。本文从安装前提开始,说明如何配置并完成第一次调用。 已安装应用?直接查看[配置 LYRouter](#配置-lyrouter)。 ## 前提条件 CC Switch 用于管理编程工具配置,本身不执行模型任务,也不需要额外的 Node.js 运行环境。选择操作系统,准备相应安装条件;使用配置前需安装目标工具,例如 [Claude Code](https://platform.lyrouter.com/ai_gateway/docs/claude-code)或 [Codex CLI](https://platform.lyrouter.com/ai_gateway/docs/codex)。 **选择操作系统** Windows: #### 1. 检查系统与架构 使用 Windows 10+,支持 x64 / ARM64。在 PowerShell 中检查: ```powershell Get-CimInstance Win32_OperatingSystem | Select-Object Caption, Version, OSArchitecture ``` #### 2. 准备安装目录与目标工具 从[官方 Releases](https://github.com/farion1231/cc-switch/releases)选择对应架构的 MSI 或便携版,确认安装或解压目录可写。目标工具需在同一运行环境中安装;CC Switch 自身不要求登录账号。 Linux: #### 1. 检查系统依赖 要求 **glibc 2.35+ 与 WebKitGTK 4.1**,支持 x64 / ARM64;可使用 Ubuntu 22.04+、Debian 12+ 等符合要求的桌面环境: ```bash cat /etc/os-release uname -m ldd --version ``` #### 2. 准备 WebKitGTK 与桌面环境 Ubuntu / Debian 缺少 WebKitGTK 4.1 时,可按系统仓库安装: ```bash sudo apt update sudo apt install -y libwebkit2gtk-4.1-0 ``` 其他发行版参见[官方安装要求](https://github.com/farion1231/cc-switch/blob/main/docs/user-manual/en/1-getting-started/1.2-installation.md)。RHEL / Rocky / Alma 8–9 的系统库不满足当前要求;安装包必须与发行版和架构匹配。 macOS: #### 1. 检查系统与处理器 使用 macOS 12+,支持 Intel 与 Apple Silicon: ```bash sw_vers -productVersion uname -m ``` #### 2. 准备安装方式与目标工具 可直接下载官方 DMG;若采用下节 Homebrew 方式,先按 [Homebrew 官方说明](https://brew.sh/)准备 Homebrew。配置用于目标工具实际运行的环境,工具尚未安装时可先阅读其安装指南。 接入 LYRouter 还需要一把已启用的 API Key 和当前工作空间可用的模型。示例中的 `MODEL_ID` 必须替换为实际系统模型标识。CC Switch 自身不需要账号,调用凭证用于它所管理的目标工具。 ## 安装应用 1. 从[官方 Releases](https://github.com/farion1231/cc-switch/releases)下载安装包。 2. Windows 安装 MSI 或解压便携版;macOS 打开 DMG 并拖入 Applications;Linux 按发行版选择 deb、rpm 或 AppImage。 3. 启动 CC Switch,确认要管理的工具已安装。 macOS 也可按官方说明使用 `brew install --cask cc-switch`。 ## 配置 LYRouter 选择要管理的工具,再添加 LYRouter 提供商: | 目标工具 | 协议与地址 | | --- | --- | | Claude Code | Anthropic,https://api.lyrouter.com | | Codex CLI | Responses,https://api.lyrouter.com/v1 | 填写 LYRouter API Key 与可用模型,启用新提供商并重启目标工具。切换配置前保留原有工具配置;Codex 的具体字段参见[Codex 指南](https://platform.lyrouter.com/ai_gateway/docs/codex),Claude 字段参见[Claude Code 指南](https://platform.lyrouter.com/ai_gateway/docs/claude-code)。 ## 验证首次调用 在 CC Switch 中启用 LYRouter 服务商后,重启目标工具(如 Claude Code 或 Codex),在目标工具里发送“请回复 OK”这样的最小任务。再到 LYRouter 的[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)检查生成端点、状态和实际模型。CC Switch 里的连接测试成功,不等于目标工具的生成或工具调用已经可用。 ## 日常使用与故障排查 ### 装好了 CC Switch,为什么仍找不到 Claude Code 或 Codex 命令? **答:** CC Switch 不代替目标工具的安装。先按[Claude Code](https://platform.lyrouter.com/ai_gateway/docs/claude-code)、[Codex CLI](https://platform.lyrouter.com/ai_gateway/docs/codex)或对应工具指南完成安装,重新打开终端并检查 PATH,再核对 CC Switch 管理的配置。 ### 切换提供商后,为什么目标工具仍调用失败? **答:** 先核对 CC Switch 管理的目标工具与配置位置,再检查协议和地址:Claude Code 使用根地址 `https://api.lyrouter.com`,Codex CLI 使用 `https://api.lyrouter.com/v1` 和 Responses。CC Switch 管理配置,目标工具仍需已安装并使用正确模型与 LYRouter API Key。 ### 切换模型前需要检查什么? **答:** 确认新模型已在当前工作空间启用、至少有一个有效服务来源,并支持应用所需的协议和工具能力。使用系统模型标识,不使用展示名称。 ### 应用更新后,原来的配置为什么不生效? **答:** 先核对当前应用版本和实际读取的配置位置,再对照本页“配置 LYRouter”检查提供商、地址、密钥和模型。不同版本的配置要求以本页链接的官方资料为准。 ### 请求返回 401 / 403,应该先检查什么? **答:** 确认填写的是已启用的 LYRouter API Key,并检查该 Key 所属工作空间的模型来源与访问策略。结合具体错误和日志判断拒绝来源,详见[鉴权与权限 FAQ](https://platform.lyrouter.com/ai_gateway/docs/auth-errors)。 ### 请求返回 429,反复重试有用吗? **答:** 先确认是平台限制还是上游额度耗尽,再调整并发、调用频率或资源配置。使用有上限的退避重试,避免立即密集重试,详见[限流与配额 FAQ](https://platform.lyrouter.com/ai_gateway/docs/rate-errors)。 ### 切换成功后,为什么 LYRouter 仍没有生成日志? **答:** 确认目标工具实际读取了切换后的配置,正在使用 LYRouter 提供商和模型,再发送最小生成请求。在正确工作空间按时间和 Key 查询[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs),不能只凭配置切换成功判断调用已经经过网关。 ## 官方资料 下列要求和安装方式来自工具官方资料,后续版本以官方说明为准。 - [官方安装指南](https://github.com/farion1231/cc-switch/blob/main/docs/user-manual/en/1-getting-started/1.2-installation.md) --- # 其他 OpenAI 兼容客户端接入 LYRouter:配置与故障排查 来源: https://platform.lyrouter.com/ai_gateway/docs/openai-clients Cherry Studio、Chatbox、LobeChat、NextChat、Cline、Continue 等支持「自定义 OpenAI 接口」的客户端,接入 LYRouter 的方法都一样:添加一个 OpenAI 类型的自定义服务商,地址填 `https://api.lyrouter.com/v1`,密钥填 LYRouter API Key,再添加要用的模型 ID。本页说明通用的填写方法和常见问题。 已经知道怎么添加自定义服务商?直接查看[配置 LYRouter](#配置-lyrouter)。 ## 适用的客户端 只要客户端满足下面任一条件,就可以按本页接入: - 能添加自定义服务商,并选择 **OpenAI** 或 **OpenAI 兼容** 类型; - 能修改 OpenAI 的 **API 地址**(也可能叫 Base URL、API Host、接口地址或端点)。 开始前准备好两样东西:一把 LYRouter API Key,见[创建工作空间与 API Key](https://platform.lyrouter.com/ai_gateway/docs/api-keys);以及要使用的模型 ID,从工作空间的 **模型广场** 复制,见[如何选择模型](https://platform.lyrouter.com/ai_gateway/docs/choose)。Claude Code、Codex 等工具有单独的接入指南,见[工具兼容性与接入总览](https://platform.lyrouter.com/ai_gateway/docs/tools)。 ## 配置 LYRouter 在客户端的服务商设置中添加一个自定义服务商,按下表填写: | 字段 | 填写 | | --- | --- | | 服务商类型 | OpenAI 或 OpenAI 兼容 | | API 地址 | `https://api.lyrouter.com/v1` | | API 密钥 | LYRouter API Key(`sk-` 开头) | | 模型 | 手动添加模型 ID,例如 `deepseek/deepseek-v4-flash`;也可以填 `@vmodel/<名称>` 或 `lyrouter/auto` | - **地址是否带 `/v1`**:多数客户端需要填 `https://api.lyrouter.com/v1`。少数客户端会自动在地址后面补 `/v1`,这时只填根地址 `https://api.lyrouter.com`。如果字段要求填写完整请求地址,就填 `https://api.lyrouter.com/v1/chat/completions`。 - **模型列表**:客户端「获取模型列表」时调用的是 `GET /v1/models`,返回的是这把 API Key 所属工作空间已开通的模型,以及已启用的虚拟模型和 `lyrouter/auto`。客户端不支持获取列表时,手动添加模型 ID。模型 ID 区分大小写,包含的斜杠要原样保留。 - **客户端支持 Anthropic 类型时**:如果服务商类型选的是 Anthropic,地址填根地址 `https://api.lyrouter.com`,不加 `/v1`。 ## 验证首次调用 在客户端中选中刚添加的模型,发送「请回复 OK」这样的简短消息。收到回复后,到工作空间的 **日志分析** 页按 API Key 找到这次请求,确认「API 路径」为 `/v1/chat/completions`、状态码为 200。日志在调用结束后几秒内可以查到。 只点「检查连接」或获取模型列表,不会产生对话请求,也不能证明对话已经可以正常使用。 ## 日常使用与故障排查 ### 返回 404,地址应该怎么改? **答:** 地址少写了 `/v1`,或者客户端自动补了一次 `/v1` 导致路径重复。在 `https://api.lyrouter.com/v1` 和 `https://api.lyrouter.com` 之间切换试一次。能在日志中查到请求时,「API 路径」应为 `/v1/chat/completions`。 ### 模型列表里没有想用的模型,怎么办? **答:** 先确认模型已在这把 API Key 所属工作空间的模型广场中开通,再在客户端里手动添加模型 ID。安全围栏的模型策略禁止的模型不会出现在列表中,见[模型授权](https://platform.lyrouter.com/ai_gateway/docs/authorization)。 ### 返回 401,应该检查什么? **答:** 确认填的是 LYRouter API Key,而不是服务商的 API Key 或控制台登录密码,并检查复制时没有多余的空格或换行。各报错原文的含义见[401 / 403:鉴权与权限](https://platform.lyrouter.com/ai_gateway/docs/auth-errors)。 ### 返回 403 `Model is not available in the model plaza`,是什么原因? **答:** 请求的模型在这把 API Key 所属的工作空间里没有开通,或者模型 ID 写错了。核对模型 ID 的拼写和大小写,或请工作空间管理员在模型广场开通该模型,见[模型不可用](https://platform.lyrouter.com/ai_gateway/docs/unavailable)。 ### 流式回复中途断开或格式错乱,怎么办? **答:** 确认客户端开启的是流式输出,并检查网络代理是否会缓冲或截断长连接。网关在输出开始后不会切换通道,中途失败时会在流的末尾补发一个错误事件,见[超时与流式中断](https://platform.lyrouter.com/ai_gateway/docs/stream-errors)。 ### 应用有回复,但 LYRouter 日志里找不到请求,怎么办? **答:** 确认客户端当前使用的是刚添加的 LYRouter 服务商,而不是其他服务商。日志按工作空间显示,请在 API Key 所属的工作空间中按时间和 API Key 查找,见[通过日志定位调用问题](https://platform.lyrouter.com/ai_gateway/docs/logs)。 --- # 如何选择模型 来源: https://platform.lyrouter.com/ai_gateway/docs/choose 在工作空间的 **模型广场** 选择模型:先用左侧筛选缩小范围,再打开模型详情比较各服务商的状态、价格和计费单位,确认后复制模型 ID 填进请求的 `model`。只有「专属可用模型」中的模型可以用本工作空间的 API Key 调用;需要的模型不在其中时,由当前账号管理员或工作空间管理员开通,普通成员可以在详情页点击 **申请开通**。 ## 在模型广场找到模型 进入工作空间后,点击左侧菜单 **模型广场**。页面把模型分为三部分: | 分区 | 含义 | 本工作空间的 API Key 能否调用 | | --- | --- | --- | | 专属可用模型 | 至少有一个来源已在本工作空间开通 | 能 | | 可启用 N | 有可用来源,但在本工作空间处于停用状态 | 开通后才能 | | 需接入 N | 本工作空间没有可用来源,需要先通过 BYOK 接入 | 接入后才能 | - **来源**指提供该模型的一个服务商通道,可以是平台提供的通道,也可以是你用 BYOK 接入的通道。分区按来源划分:同一模型开通了一个服务商、另一个服务商未开通时,会同时出现在「专属可用模型」和「可启用」中,每张卡片只列出本分区的服务商。 - 平台新上架的模型默认在工作空间中开通;被手动停用过的模型保持停用。BYOK 配置生效后,对应模型也默认开通。 - 搜索框按模型名称、模型 ID、作者和服务商名称匹配。左侧「筛选」有「模型厂商」「输入模态」「输出模态」「接入来源」四组,每组可多选,选「全部」表示不限;「接入来源」中「三方服务」指平台提供的通道,「BYOK」指本工作空间用自带密钥接入的通道。点击 **重置** 清空全部筛选和搜索词。 (截图:模型广场左侧按模型厂商、输入模态和输出模态筛选;卡片显示能力标签、起步价、服务商和可复制的模型 ID。) 卡片适合初选:能力标签最多显示两个(如「深度思考」「工具调用」);「输入」「输出」后带「起」的价格是本分区各服务商中最低的起步单价,没有服务商报价时显示官方价格;「上新」角标表示新上架的模型。完整价格以模型详情为准。 ## 在模型详情里比较服务商 点击卡片或 **查看详情** 打开模型详情。页头显示模型名称、作者、可复制的模型 ID 和「当前可用」或「当前不可用」:只要有一个已开通且你有权调用的来源,就显示「当前可用」。「服务商与价格」页签按服务商逐一列出: | 内容 | 怎么看 | | --- | --- | | 状态 | 「当前可用」可以调用;「已禁用」未在本工作空间开通;「成员访问受限」已开通,但安全围栏的模型策略限制了你;「仅允许 BYOK」同一通道开启了「仅用此 BYOK」,平台来源不参与调用;「服务商暂不可用」来源当前无法使用 | | 来源标签 | 同一服务商有多个来源时,分别标为「平台价」(标签 `API · 通道名`)和「BYOK 参考价」(标签 `BYOK · 通道名`) | | 盾牌图标 | 悬停查看该服务商是否会把提示词用于模型训练:不会、可能会,或尚未披露 | | 价格表 | 表头写明计价方式,如「固定单价」「Token 长度计价」「分时计价」;每列是一个计费项的单价 | | 官方参考价 | 模型厂商公开的定价,仅供比较 | (截图:模型详情的「服务商与价格」按来源列出状态、开关和价格表,价格保留原始币种与计费单位。) ## 比较价格时看清计费单位 - **Token 计费项**:价格表的「输入」「输入(缓存命中)」「输出」「显式缓存创建」与日志的 Token 分类对应,其中「输入」对应日志的「输入(缓存未命中)」,均按每百万 Token 计价。命中缓存的输入按「输入(缓存命中)」单价计,不再按「输入」单价重复计费。 - **其他计费单位**:图像、视频、语音模型按「张」「秒」「分钟」「万字符」「次」等计费,单位写在列名或价格后面。不同单位的单价不能直接比较,请按一次典型任务估算总价,例如每次请求的平均输入、输出 Token 数乘以单价,或生成张数乘以每张单价。 - **标记**:「—」表示暂无报价,不是免费;「价格暂未公布」表示该来源还没有价格;「每次前 N … 免费」是每次请求的免费额度;有划线价时,旁边是折后价。订阅类 BYOK 来源显示「订阅接入,按服务商套餐计费,不按 Token 单价结算。」 - **币种**:价格保留服务商的原始币种(`¥` 或 `$`),实际扣费以 Credits 结算,见[计费规则与信用点](https://platform.lyrouter.com/ai_gateway/docs/billing)和[调用费用与缓存计费](https://platform.lyrouter.com/ai_gateway/docs/estimate)。 模型详情没有列出上下文长度。需要时用 API Key 调用 [`GET /v1/models`](https://platform.lyrouter.com/ai_gateway/docs/models),模型目录有这些信息时,条目中会带 `context_length` 和 `max_output_tokens`。 ## 复制模型 ID 并调用 点击卡片或详情页头模型 ID 旁的复制按钮,把它原样填进 `model`。模型 ID 形如 `deepseek/deepseek-v4-flash`,斜杠前是模型厂商,不是服务商;同一模型由多个服务商提供时也只有一个模型 ID,具体走哪个通道由网关选择,见[通道选择与路由策略](https://platform.lyrouter.com/ai_gateway/docs/routing)。环境变量的设置见[完成第一次模型调用](https://platform.lyrouter.com/ai_gateway/docs/quickstart): ```bash curl "$LYROUTER_BASE_URL/v1/chat/completions" \ -H "Authorization: Bearer $LYROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"deepseek/deepseek-v4-flash","messages":[{"role":"user","content":"你好"}]}' ``` 协议、输入类型和参数是否适用,请对照[模型能力与兼容性](https://platform.lyrouter.com/ai_gateway/docs/capabilities)。 ## 开通与停用模型 个人版账户本人,以及团队、企业中的当前账号管理员和工作空间管理员,可以在卡片右上角的开关开通或停用整个模型,也可以在模型详情中用每个来源的开关单独操作。 - 开关不可点击时,表示该模型当前没有可以切换的来源:来源暂不可用,或对应通道开启了「仅用此 BYOK」。 - 停用后该模型在本工作空间不再剩任何已开通来源时,会先弹出「确认停用最后一个服务来源」,确认后本工作空间的 API Key 就不能再调用它。 - 两人同时修改同一模型时,后保存的一方会看到「服务状态已变化,页面已刷新」,按刷新后的状态重新操作即可。 - 开通和停用只影响当前工作空间,保存后同步到网关,不需要更换 API Key。 - 「需接入」的模型没有开关。账号管理员在详情页点击 **接入 BYOK**,会打开预选该模型的 BYOK 配置,见[BYOK 接入与测试连接](https://platform.lyrouter.com/ai_gateway/docs/byok)。 ## 成员申请开通 普通成员看不到开关,可以在模型详情中申请: - 模型在本工作空间没有可用来源时,页头显示 **申请开通**;某个服务商为「已禁用」或「成员访问受限」时,该服务商一行显示 **申请开通该服务商**。 - 申请以站内信发给当前账号管理员,出现在对方的「消息中心」;发送后按钮变为「已通知管理员」。24 小时内重复申请同一模型或服务商,页面提示「管理员已收到该通知」。 - 状态为「成员访问受限」时,模型已经开通,需要调整的是安全围栏的模型策略,见[模型授权](https://platform.lyrouter.com/ai_gateway/docs/authorization)。 ## 验证选择 用真实任务调用候选模型,在[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)中查看「模型(实际)」「服务商」、状态和耗时,再在[用量分析](https://platform.lyrouter.com/ai_gateway/docs/analytics)中按模型比较同一时间段的 Token 和费用。上线后需要更换版本时,见[模型版本与下线](https://platform.lyrouter.com/ai_gateway/docs/versions)。 --- # 模型能力与兼容性 来源: https://platform.lyrouter.com/ai_gateway/docs/capabilities LYRouter 用同一个地址提供 Chat Completions、Anthropic Messages 和 Responses 三种对话接口,以及图像、视频、语音等接口;一次调用能否成功、参数是否生效,取决于所选模型和实际服务它的通道。网关会在 Chat Completions 与 Anthropic Messages 之间自动转换,Responses 请求则原样转发到通道的 Responses 接口。模型不支持请求的接口或输入时,网关直接返回 400;图像、视频接口会丢弃部分模型不支持的参数,并在响应头中列出。 ## 接口与通道协议 每个通道使用一种上游协议:OpenAI 兼容或 Anthropic。网关按通道协议决定是否转换请求: | 客户端调用的接口 | 网关的处理 | 选择模型时注意 | | --- | --- | --- | | [Chat Completions](https://platform.lyrouter.com/ai_gateway/docs/chat-completions)(`/v1/chat/completions`) | OpenAI 兼容通道直接发送;Anthropic 协议通道先转换成 Messages 请求,响应再转换回来 | 对话模型都可以使用 | | [Anthropic Messages](https://platform.lyrouter.com/ai_gateway/docs/anthropic-messages)(`/v1/messages`) | 先转换成内部的 Chat Completions 结构,再按通道协议发出 | 对话模型都可以使用,不要求模型来自 Anthropic | | [Responses](https://platform.lyrouter.com/ai_gateway/docs/responses-api)(`/v1/responses`) | 不做协议转换,原样转发到通道的 Responses 接口 | 通道必须提供 Responses 接口,Anthropic 协议通道没有该接口 | 通过 `/v1/messages` 调用时,错误响应也会转换成 Anthropic 格式,只有 `error.type` 和 `error.message`,没有 `error.code`。 ### 转换时的参数处理 跨协议转换只保留双方都有对应含义的字段,其余字段会被去掉,这类去掉不会写进响应头。依赖下列参数的应用,请确认实际服务的通道协议: | 方向 | 处理 | | --- | --- | | Chat Completions → Anthropic 协议通道 | 去掉 `n`、`logprobs`、`top_logprobs`、`response_format`、`frequency_penalty`、`presence_penalty`、`seed`、`parallel_tool_calls`、`logit_bias`、`reasoning_effort` 等字段;`stop` 转为 `stop_sequences`;没有 `max_tokens` 时补 4096;`enable_thinking`、`thinking_budget` 转为 Anthropic 的 `thinking` 设置 | | Anthropic Messages → OpenAI 兼容通道 | `model`、`messages`、`system`、`max_tokens`、`stop_sequences`、`tools`、`tool_choice`、`thinking` 按含义转换;`stream`、`temperature`、`top_p`、`top_k`、`service_tier` 原样保留;其他字段去掉,消息和工具上的 `cache_control` 标记也会去掉 | `reasoning_effort`、`enable_thinking`、`thinking_budget` 三个推理参数分属不同服务商,网关不在它们之间换算;对已适配的服务商,会去掉它不认识的那几个。同一模型由多个通道提供时,请对每个通道验证 JSON 输出、推理和缓存行为,见[应用接入多个服务商](https://platform.lyrouter.com/ai_gateway/docs/multi-provider)。 ## 网关拒绝的请求 网关在发出请求前,按模型目录中声明的能力检查接口和输入,不符合时直接返回 400,不调用上游,也不改用备用模型: | 报错原文(`error.message`) | `error.code` | 原因与处理 | | --- | --- | --- | | `This model does not support the <接口> API` | `unsupported_model_api` | 模型声明的接口不含当前接口,例如对话模型调用 `/v1/images/generations`,或只声明了 Chat Completions 的模型调用 `/v1/responses`。`<接口>` 为 `chat_completions`、`responses`、`embeddings`、`rerank`、`images`、`videos`、`audio` 之一。换用支持该接口的模型 | | `This model does not support the <操作> operation` | `unsupported_model_operation` | 接口家族支持,但不支持具体操作,例如只会文生图的模型调用 `/v1/images/edits` | | `This model accepts text input only` | `unsupported_model_input` | 输入和输出都只有文本的模型收到了图片、音频、视频或文件 | 模型目录没有声明接口范围时,网关通常放行,由上游决定是否接受。备用模型应与主模型支持相同的接口和输入类型,见[失败重试与备用模型](https://platform.lyrouter.com/ai_gateway/docs/fallback)。 ## 视觉输入与图像生成 两者是不同的能力,使用不同的接口: - **视觉理解**:在对话接口的消息中放入图片,模型输出文本。模型的输入模态需要包含图像,只接受文本的模型会返回 400 `This model accepts text input only`。 - **图像生成与编辑**:调用 `/v1/images/generations` 或 `/v1/images/edits`,使用输出模态包含图像的模型,模型输出图片。 - **视频生成**:调用 `/v1/videos` 提交异步任务。 在模型广场左侧用「输入模态」「输出模态」筛选,就能区分这几类模型。各模型的接口、参数和计费见[多模态能力](https://platform.lyrouter.com/ai_gateway/docs/multimodal)。 (截图:公开模型广场列出网关已完成适配的模型,可按输入和输出模态筛选;能否调用以工作空间模型广场为准。) ## 图像与视频接口的参数 在图像、视频接口上,网关会丢弃部分所选模型不支持的参数后照常调用,并在响应头 `X-Gateway-Unsupported-Parameters` 中列出被丢弃的参数名。希望这类情况直接报错时,在请求中加上: ```bash curl "$LYROUTER_BASE_URL/v1/images/generations" \ -H "Authorization: Bearer $LYROUTER_API_KEY" \ -H "Content-Type: application/json" \ -H "X-Gateway-Strict-Parameters: true" \ -d '{"model":"google/gemini-3-pro-image","prompt":"一只坐在窗边的猫"}' ``` 开启严格模式后,出现会被丢弃的参数时返回 400 `unsupported parameters for this model: <参数名>`,`error.code` 为 `unsupported_parameters`,不调用上游。各模型支持哪些参数、会丢弃哪些参数,见[多模态能力](https://platform.lyrouter.com/ai_gateway/docs/multimodal)。环境变量的设置见[完成第一次模型调用](https://platform.lyrouter.com/ai_gateway/docs/quickstart)。 ## 查询模型声明的能力 用 API Key 调用 [`GET /v1/models`](https://platform.lyrouter.com/ai_gateway/docs/models),列表中的模型条目在模型目录有相应信息时会带上: | 字段 | 含义 | | --- | --- | | `api_types` | 模型声明支持的接口,如 `chat_completions`、`responses`、`images` | | `input_modalities` / `output_modalities` | 输入、输出模态,如 `text`、`image` | | `context_length` / `max_output_tokens` | 上下文长度和最大输出长度 | | `supported_params` | 模型声明支持的参数,仅供参考,网关不据此删减对话请求的参数 | 上下文长度、工具调用和结构化输出由上游最终判定。更换模型、服务商或通道后,请用真实请求重新验证参数、流式事件和工具调用,见[模型版本与下线](https://platform.lyrouter.com/ai_gateway/docs/versions)。 ## 常见问题 ### 设置了 `response_format`,为什么有时没有返回 JSON? **答:** 请求被路由到 Anthropic 协议的通道时,`response_format` 会在转换中被去掉。在[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)中查看这次请求的「服务商」,并对照「原始报文」中的「上游请求」。需要稳定的 JSON 输出时,在提示词中明确要求输出格式;也可以请账号管理员在模型详情中停用不需要的来源,见[应用接入多个服务商](https://platform.lyrouter.com/ai_gateway/docs/multi-provider)。 ### Codex 调用返回错误,但同一个模型用 Chat Completions 正常,怎么办? **答:** Codex 使用 Responses 接口,请求会原样转发给通道的 Responses 接口。返回 400 `This model does not support the responses API` 时换用声明支持 Responses 的模型;返回上游的 404 等错误时,可能是服务这次请求的通道没有提供 Responses 接口,请换用其他模型,或请账号管理员调整该模型的来源。 --- # 多模态能力 来源: https://platform.lyrouter.com/ai_gateway/docs/multimodal 除文本对话与向量外,网关还支持**视觉理解**(图片输入)、**图像生成与编辑**、**视频生成**。文本类接口(`chat/completions`、`embeddings`)见 [调用网关](https://platform.lyrouter.com/ai_gateway/docs/call-gateway)。 本文覆盖网关上**当前全部可调用的多模态模型**,逐个列出接口、全部参数(含取值范围与默认值)、计费口径和可直接运行的示例。 > [!note] > 模型的增减以控制台**模型广场**与 `/v1/models` 为准。本文随模型上架定期更新,短期内可能有个别新模型尚未写入。 ## 模型总览 ### 图像生成 / 编辑(同步,直接在响应里拿图) | 模型 | 接口 | 请求处理 | 计费 | |------|------|------|------| | `bytedance/doubao-seedream-5.0-pro` | `/v1/images/generations` | 透传 | 按张,分档 | | `bytedance/doubao-seedream-5.0-lite` | `/v1/images/generations` | 透传 | 按张,不分档 | | `openai/gpt-image-2` | `/v1/images/generations`
`/v1/images/edits` | 透传 | 按 token,四项 | | `openai/gpt-image-2.5-flare` | 同上 | 透传 | 按 token,三项 | | `openai/gpt-image-2.5-sunburst` | 同上 | 透传 | 同上 | | `google/gemini-3-pro-image` | 同上 | **契约转换** | 按 token,三项 | | `google/gemini-3.1-flash-image` | 同上 | **契约转换** | 按 token,两项 | **透传**的在生成接口(`/v1/images/generations`)上也会丢掉几个参数:GPT-Image 系列固定丢 `response_format`,2.5 两个还丢 `stream` / `stream_options`。被丢的参数会在响应头 `X-Gateway-Unsupported-Parameters` 里列出。编辑接口(`/v1/images/edits`)不丢,这几个参数会转发给上游(只传 `stream: true` 时网关目前还会补上 `stream_options`,上游返回 400),不要传。 GPT-Image 的「四项」是输入文本 / 输入图片 / 输出 / 缓存命中,2.5 系列的 `usage` 不含缓存字段,只有前三项;Gemini 的「三项」是输入 / 输出 / 思考,只有 Pro 产生思考 token,Flash 只有前两项。Seedream pro 的参考图(输入图片)另计一项,每次请求第 1 张不收费。分档维度见各模型详情。 ### 视频生成(异步任务) | 模型 | 接口 | 请求处理 | 计费 | |------|------|------|------| | `bytedance/doubao-seedance-2.5` | `/v1/videos` | 契约转换 | 按 token,分辨率 × 视频输入分档 | | `bytedance/doubao-seedance-2.0-fast` | `/v1/videos` | 契约转换 | 按 token,按视频输入分档 | | `bytedance/doubao-seedance-2.0-mini` | `/v1/videos` | 契约转换 | 同上 | | `minimax/minimax-h3` | `/v1/videos`
`/v1/videos/regenerations`
`/v1/videos/context` | 契约转换 | 按秒,按分辨率分档 | | `minimax/minimax-h3-max`
⚠️ 已被服务商下线,目前不可用,请改用 `minimax/minimax-h3` | `/v1/videos` | 契约转换 | 按秒,按分辨率分档 | MiniMax 的升清(`/videos/regenerations`)单独一档,参考图单独计一项;上下文增强(`/videos/context`)产出的是文本,按 token 计。 > [!important] > **本文不写具体单价。** 价格随运营调整,不同环境(测试 / 生产)也不相同 —— 请以**控制台模型广场**上该模型的实时价格为准,逐次调用的实际扣费见[查看日志](https://platform.lyrouter.com/ai_gateway/docs/logs)。 > > 这里只说明**计费口径**:按什么计量(张 / token / 秒 / 字符)、分成哪几项、按什么维度分档。口径是接口契约的一部分,不随调价变化。 ### 视觉理解(图片输入、输出文本) 走标准 `/v1/chat/completions`,模型为带「视觉」能力标签的对话模型,见下文「视觉理解」一节。 鉴权与其它调用一致——始终用你的**网关密钥**作为 Bearer token,网关据此识别工作空间并注入上游凭据(你的密钥不会透传给上游): ``` Authorization: Bearer sk-你的密钥 ``` (截图:在输出模态中选择图像和视频,查看当前工作空间可用的多模态模型与计费单位。) ## 请求处理模式:透传与契约转换 **读参数表之前先看这一节**——同一个参数在不同模型上会不会生效,取决于这个模型走哪种模式。 | 模式 | 网关做什么 | 你该照谁的文档写参数 | |------|-----------|---------------------| | **透传** | 请求体原样转发给上游,只改写模型名 | **厂商原生参数**,厂商支持什么你就能用什么 | | **契约转换** | 把网关的统一参数翻译成厂商的私有形状 | **网关契约**(下文每个模型都列全了) | 两种模式都不会静默吞掉参数: - 契约转换时,契约外的参数会被丢弃,并在响应头 `X-Gateway-Unsupported-Parameters` 里逐个列出(Gemini 图像模型只转发 `prompt`、`model`、`image`、`size`,其余都按此处理);视频模型对契约内但这个模型不支持的参数直接返回 400 并说明原因。例外见下文「视频通用参数(网关契约)」:Seedance 的 `reference_audio` 会被静默丢弃,用表单提交时也有几个字段不会按预期处理。 - 不想要这种"丢了也继续"的行为,请求时带上 `X-Gateway-Strict-Parameters: true`,被丢弃的参数会让请求直接返回 400,错误码 `unsupported_parameters`。 > [!warning] > 有一类参数即使在透传模型上也会被**有意丢弃**:转发给上游只会让请求失败,而它又改变不了结果。目前只在 GPT-Image 系列的生成接口上:`response_format`(该系列固定返回 base64,上游对这个参数时灵时不灵),以及 2.5 两个模型的 `stream` / `stream_options`(上游会开启流式,导致请求失败)。丢弃同样会写进 `X-Gateway-Unsupported-Parameters`,带 `X-Gateway-Strict-Parameters: true` 时同样返回 400。编辑接口不做这种丢弃。 ## 视觉理解(图片输入对话) 图片输入走标准的 `chat/completions`,在 `content` 里以 `image_url` 携带图片(`data:` 内联 base64 或公网 URL),与 OpenAI 多模态格式一致: ```bash curl https://api.lyrouter.com/v1/chat/completions \ -H "Authorization: Bearer sk-你的密钥" \ -H "Content-Type: application/json" \ -d '{ "model": "支持视觉的模型名", "messages": [{ "role": "user", "content": [ { "type": "text", "text": "这张图里有什么?" }, { "type": "image_url", "image_url": { "url": "https://example.com/cat.jpg" } } ] }] }' ``` > [!tip] > 需要选用**支持视觉**的模型(模型广场里带「视觉」能力标签)。给纯文本模型发图片会被上游拒绝。 ## 图像生成与编辑(同步) 两个端点与 OpenAI 的图像 API 一致,请求发出后直接在响应里拿到图片,不需要轮询: ``` POST /v1/images/generations 文生图 POST /v1/images/edits 图生图 / 图像编辑 ``` > [!warning] > **各模型耗时差别很大。** Seedream 约 20 秒;GPT-Image 系列一次生成实测约 20~60 秒(最长一次约 83 秒),生成接口上参数错误的 400 实测在 2 秒内返回;Gemini 3 Pro 实测 20~250 秒,偶有超过 300 秒仍未返回。客户端超时请按分钟级设置,不要沿用文本接口的 30 秒。 响应是 OpenAI 形状,产物固定在顶层 `data[]` 数组里: ```json { "created": 1760000000, "data": [ { "b64_json": "…" } ], "usage": { "input_tokens": 13, "output_tokens": 196, "total_tokens": 209 } } ``` ### 基本用法 **文生图**: ```bash curl https://api.lyrouter.com/v1/images/generations \ -H "Authorization: Bearer sk-你的密钥" \ -H "Content-Type: application/json" \ -d '{ "model": "bytedance/doubao-seedream-5.0-lite", "prompt": "一只戴墨镜的柴犬坐在冲浪板上,黄昏海面,电影感", "size": "2K" }' ``` **图像编辑**(`multipart/form-data`,把原图作为文件段上传): ```bash curl https://api.lyrouter.com/v1/images/edits \ -H "Authorization: Bearer sk-你的密钥" \ -F model=openai/gpt-image-2 \ -F quality=medium \ -F image=@cat.png \ -F prompt="把背景换成雪山" ``` **图像编辑(JSON 形态)**——把图片作为 base64 放在 JSON 体里: ```bash curl https://api.lyrouter.com/v1/images/edits \ -H "Authorization: Bearer sk-你的密钥" \ -H "Content-Type: application/json" \ -d '{ "model": "google/gemini-3-pro-image", "prompt": "把背景换成雪山", "image": "data:image/png;base64,iVBORw0KGgo…" }' ``` `image` 可以是单个字符串,也可以是字符串数组(多张参考图)。 > [!note] > **Gemini 两个模型现在两种形态都收**(2026-10-09 起)。它们的上游是 Google 原生 > `generateContent`,只认 JSON(图片要落成 `inlineData`)—— 收到 multipart 时网关会先把它 > 归一成字段表,再按契约翻译过去,所以官方 OpenAI SDK 的 `images.edit()` 也能直接驱动它们。 > > 在此之前这条路走不通。旧文档、旧版规格附件里「Gemini 只能用 JSON」的说法**已经过期**。 两种请求体的支持情况(2026-10-09 实测): | 模型 | multipart(文件上传) | JSON(base64) | |---|---|---| | `openai/gpt-image-2` | ✅ | ✅ | | `openai/gpt-image-2.5-flare` | ✅ | ✅ | | `openai/gpt-image-2.5-sunburst` | ✅ | ✅ | | `google/gemini-3-pro-image` | ✅ | ✅ | | `google/gemini-3.1-flash-image` | ✅ | ✅ | > [!note] > **透传模型**(GPT-Image 系列)的 multipart 路径上,网关只定位并改写 `model` 字段, > **文件段一个字节都不动**。**契约转换模型**(Gemini 系)则相反:网关会解析 multipart、 > 把文件段转成 base64,再按该模型的契约重组请求体 —— 这也是它为什么有 30 MB 的内联上限。 > JSON 路径同理:GPT-Image 系列的 JSON 请求体原样转发,图片由上游校验;Gemini 系的图片格式 > 优先取 data URI 里声明的 MIME,传裸 base64 时按 PNG / JPEG / WEBP / GIF 的字节特征识别, > 都认不出时返回 400 并指明是第几张图 —— 网关**不会**替你挑一个默认格式。 > 另外请注意上游会校验图片本身:文件损坏或色彩模式不受支持的图片会被退回 > `Invalid image file or mode`,那是图片的问题,不是接口没接通。 > Seedream 的图生图不走这个端点,走 `/v1/images/generations` 的 `image` 参数。 下面按模型列出全部参数。**先看这个模型走哪种处理模式**——透传的照厂商文档写,契约转换的照网关契约写。 --- ### Seedream 5.0 pro / lite(火山方舟) 两个模型都是**透传**——下表的参数原样送到上游,厂商支持什么就能用什么。 #### 能力对比 | 能力 | `doubao-seedream-5.0-pro` | `doubao-seedream-5.0-lite` | |------|---------------------------|----------------------------| | 文生图 | ✓ | ✓ | | 文生组图(一次出多张) | 暂不支持 | ✓ | | 单图 / 多图生图 | ✓ | ✓ | | 单图 / 多图生组图 | 暂不支持 | ✓ | | **交互编辑**(坐标定位编辑) | ✓ | ✗ | | **图层拆分**(拆成底图 + 最多 16 图层) | ✓ | ✗ | | 流式输出 | 暂不支持 | ✓ | | 联网搜索 | 暂不支持 | ✓ | | 可选分辨率档位 | `1K`、`1.5K`、`2K` | `2K`、`3K`、`4K` | | 输出格式 | `png`、`jpeg` | `png`、`jpeg` | | 提示词优化模式 | 标准、极速 | 标准 | | 生成数量限制 | 单图,或 1 底图 + 最多 16 图层 | 参考图数 + 生成图数 ≤ 15 | | 限流 | 500 张/分钟 | 500 张/分钟 | #### 参数 | 参数 | 类型 | 默认 | 取值 | 说明 | |------|------|------|------|------| | `model` | string | — | 见上表 | 必填 | | `prompt` | string | — | — | 提示词。图层拆分时可省略(不传则模型自动识别要拆的元素) | | `image` | string / string[] | — | 图片 URL 或 `data:image/<格式>;base64,<编码>` | 参考图。生图场景建议不超过 10 张(超过时服务商目前不拒绝,但输出可能异常);图层拆分仅支持 1 张 | | `size` | string | `2K`(生图)/ `auto`(图层拆分) | 见下 | 两种写法不可混用 | | `response_format` | string | `url` | `url`、`b64_json` | | | `output_format` | string | — | `png`、`jpeg` | 图层拆分时只控制底图格式,**图层恒为 png** | | `background` | string | `opaque` | `transparent`、`opaque` | 透明通道。仅图生图、且只支持输入 1 张带透明通道的图 | | `watermark` | boolean | `true` | `true`、`false` | `true` 在右下角加「AI生成」水印;不传时默认加,不需要时传 `false` | | `layer_decomposition` | boolean | `false` | `true`、`false` | **仅 pro**。开启后 `image` 变为必填且只能 1 张 | | `optimize_prompt_options.mode` | string | `standard` | `standard`、`fast` | **仅 pro**。`fast` 更快、质量略低 | **`size` 的两种写法** 方式 1,**指定档位(推荐)**:传 `1K` / `1.5K` / `2K`(pro)或 `2K` / `3K` / `4K`(lite),宽高比在 `prompt` 里用自然语言描述,由模型决定具体像素。pro 的档位映射(常见值,不限于此): | 档位 | 1:1 | 4:3 | 16:9 | 9:16 | 3:2 | 21:9 | |------|-----|-----|------|------|-----|------| | 1K | 1024×1024 | 1152×864 | 1424×800 | 800×1424 | 1248×832 | 1568×672 | | 1.5K | 1536×1536 | 1792×1344 | 2048×1152 | 1152×2048 | 1872×1248 | 2352×1008 | | 2K | 2048×2048 | 2368×1776 | 2816×1584 | 1584×2816 | 2496×1664 | 3136×1344 | > [!tip] > `1.5K` 与 `1K` **价格相同**,但出图效果更好。 方式 2,**指定宽高像素**(`宽x高`,如 `2048x1024`): - 总像素(宽 × 高):pro 范围 **[921600, 4624220]**;lite 不少于 **3686400**(最小正方形是 `1920x1920`,常见的 `1024x1024` 会被拒绝) - 宽高比(宽/高)范围 **[1/16, 16]** - 两条必须同时满足。`512x512` 总像素 262144,低于两款的下限,无效 图层拆分场景只支持档位写法,默认 `auto`:输入图在 [921600, 4624220] 之间按原尺寸输出;小于 1K 按 1K;大于 2K 按 2K。 #### 交互编辑(仅 pro) 在 `prompt` 里用坐标标签指定编辑位置,坐标**归一化到 0~999**(左上角 0,0,右下角 999,999): - 点选:`x y`,由模型判断影响范围 - 框选:`x1 y1 x2 y2`,精确控制区域 换算:`x = round(x_px / 展示宽 * 1000)`,`y` 同理。 | 场景 | 提示词写法 | |------|-----------| | 编辑指定点附近的对象 | `把图1520 460位置换成皇冠` | | 编辑指定区域的对象 | `把图1120 180 640 760区域替换成花园` | | 跨图片编辑 | `将图1179 283 796 986的主体放到图2118 331 933 871位置` | > [!tip] > 框选区域内有多个主体时,在提示词里补一句说明要编辑哪个(「左侧的人」「戴帽子的猫」)。需要保持不变的物体也可以一并框出来并写明「保持不变」。 也可以不用坐标,直接在参考图上手绘草图 / 涂鸦 / 圈选,再用自然语言描述标记位置。 #### 图层拆分(仅 pro) `layer_decomposition: true` 把单张图拆成 1 张底图和最多 16 个带透明通道的 PNG 图层。 ```bash curl https://api.lyrouter.com/v1/images/generations \ -H "Authorization: Bearer sk-你的密钥" \ -H "Content-Type: application/json" \ -d '{ "model": "bytedance/doubao-seedream-5.0-pro", "image": "https://example.com/poster.png", "size": "2K", "layer_decomposition": true, "watermark": false }' ``` 响应的 `data[]` 同时包含底图与图层: | 字段 | 出现在 | 含义 | |------|--------|------| | `url` | 底图、图层 | 下载链接,**仅保留 24 小时** | | `z_index` | 底图、图层 | 叠放顺序。底图固定 `0`,图层递增 | | `bounding_box.absolute` | 图层 | `[left, top, right, bottom]`,输出底图坐标系中的绝对像素位置 | | `bounding_box.normalized` | 图层 | 同上但归一化(0~1000),用于还原到任意尺寸画布 | | `name`、`description` | 图层 | 图层名称与内容描述 | 还原到底图:`x = left`,`y = top`,`w = right - left`,`h = bottom - top`,按 `z_index` 从小到大叠放。 还原到 `W × H` 的画布:`x = left / 1000 × W`,其余同理(归一化坐标是整数,换算有取整误差)。 拆出的图层可以作为输入图再次送进模型单独编辑;想保留透明背景就同时传 `background: transparent` 和 `output_format: png`。 > [!note] > 图层拆分每次请求**预扣 17 张的限流额度**(按最大输出张数预留),生成完成后按实际张数返还。 #### 输入图限制 | 约束 | 生图场景 | 图层拆分场景 | |------|----------|--------------| | 格式 | jpeg、png、webp、bmp、tiff、gif、heic、heif | png、jpeg | | 总像素(宽×高) | [196, 36,000,000] | [262144, 36,000,000] | | 宽高长度 | ≥ 14 px | — | | 宽高比(宽/高) | [1/16, 16] | [1/16, 16] | | 单张大小 | ≤ 30 MB | ≤ 30 MB | | 张数 | 建议不超过 10 张(超过时服务商目前不拒绝,但输出可能异常) | 仅 1 张 | base64 需遵循 `data:image/<格式>;base64,<编码>`,`<格式>` 必须小写。 #### 计费 按**张**计,分档维度是**分辨率档位**与**是否图层拆分**: | 模型 | 分档 | |------|------| | `doubao-seedream-5.0-pro` | 1K / 1.5K(≤ 261 万像素)一档,2K 一档 | | `doubao-seedream-5.0-pro` | 图层拆分时另有两档(同样按 1K/1.5K 与 2K 分) | | `doubao-seedream-5.0-lite` | 不分档 | `seedream-5.0-pro` 的**参考图**单独计一项:每次请求的第 1 张参考图不收费,超出部分按张计费。这里数的是输入的参考图,不是出图张数。图层拆分按实际产出的图片张数(底图 + 各图层)计费。 > [!tip] > `1.5K` 与 `1K` **同档同价**,出图更好——没有特殊理由时优先用 `1.5K`。 --- ### GPT-Image-2 / 2.5-flare / 2.5-sunburst **透传**,参数与 OpenAI 图像 API 一致。 | 参数 | 类型 | 必填 | 取值 | 说明 | |------|------|------|------|------| | `model` | string | 是 | `openai/gpt-image-2`、`openai/gpt-image-2.5-flare`、`openai/gpt-image-2.5-sunburst` | | | `prompt` | string | 是 | — | | | `quality` | string | 见说明 | 逐模型不同,见下表 | `gpt-image-2` **必填**;建议所有 GPT-Image 模型都显式传入 | | `size` | string | 否 | `宽x高` | 只接受 `宽x高`,不接受档位名;须满足下文四条硬约束,否则 400 | | `n` | integer | 否 | 最大 10 | 出图张数 | | `user` | string | 否 | — | 终端用户标识 | **`quality` 逐模型取值**: | 模型 | 取值 | 默认 | |------|------|------| | `gpt-image-2` | `low`、`medium`、`high`、`auto` | 无,**必填**:不传会间歇性返回 400(`INVALID_REQUEST_BODY`);`auto` 实测等同 `low` | | `gpt-image-2.5-flare`、`gpt-image-2.5-sunburst` | `low`、`medium`、`high`、`xhigh`、`max`、`auto` | `low`(`auto` 实测等同 `low`) | `xhigh`、`max` 两档是否可用由上游账号能力决定,可能被拒;收到 `Invalid value: 'xhigh'` 时改用 `high`。 **`size` 的四条硬约束**(由服务商校验,任一不满足返回 400): | 约束 | 服务商报错原文 | 示例 | |------|---------------|------| | 宽和高都能被 16 整除 | `Invalid size '<宽>x<高>'. Width and height must both be divisible by 16.` | `1008x1008` ✓;`1254x1254`、`1312x1199` ✗ | | 最长边 ≤ 3840 | `Invalid size '<宽>x<高>'. The longest edge must be less than or equal to 3840.` | `3840x2160` ✓;`4096x4096`、`1024x4096` ✗ | | 总像素不少于约 100 万 | `Invalid size '<宽>x<高>'. Requested resolution is below the current minimum pixel budget.` | `1008x1008`(约 102 万)✓;`512x1024`(约 52 万)✗ | | 总像素不超过约 830 万 | `Invalid size '<宽>x<高>'. Requested resolution exceeds the current pixel budget.` | `3840x2160`(约 829 万)✓;`3840x2176`(约 836 万)✗ | GPT-Image 不接受档位名:传 `4K` 返回 `Invalid size '4K'. Expected WIDTHxHEIGHT, for example '1824x1024'.` > [!warning] > **生成接口上 `response_format` 会被丢弃。** 这个系列固定返回 base64,而上游对该参数的处理不稳定(实测同一模型、同一套参数,21 分钟内在 400 与 200 之间来回翻)。网关统一丢弃它并在 `X-Gateway-Unsupported-Parameters` 里说明,把「随机失败」换成「确定行为」。2.5 系列同时丢弃 `stream` / `stream_options`——传了上游会开启流式,导致请求失败(500)。 > > **编辑接口(`/v1/images/edits`)上网关不丢弃这几个参数**,会转发给上游,请不要传:只传 `stream: true` 时网关目前还会自行补上 `stream_options`,上游返回 400 `Unknown parameter: 'stream_options'.` > [!warning] > **一次生成要几十秒。** 实测约 20~60 秒(最长一次约 83 秒,`gpt-image-2.5-flare`);参数错误导致的 400 实测在 2 秒内返回。客户端超时仍请按分钟设置。 #### 计费 按 token 计:**输入文本**、**输入图片**、**输出**各有独立单价。**缓存命中**另有一项单价,但 2.5 系列的 `usage` 不含缓存字段,不产生这一项。 上游在 `usage.input_tokens_details` 里分开报文字与图片 token,网关按两个单价分别计费 —— 所以同样长度的提示词,带图片和不带图片的费用不同。 输出 token 主要由 `quality` 决定:`1024x1024` 时 2.5 系列 `low` 输出 196 token、`max` 输出 7024 token,最高档约为最低档的 36 倍。同名档位在两代模型上不是同一个量 —— 2.5 系列的 `high` 与 `gpt-image-2` 的 `medium` 输出 token 相同,跨模型比较请比 token,不要比档位名。 > [!note] > **GPT-Image 不是像素越多越贵**(只适用于 GPT-Image):输出 token 不随像素增加,例如 `1024x1536`(约 157 万像素)的输出 token 比 `1024x1024`(约 105 万像素)还少。 --- ### Gemini 3 Pro Image / 3.1 Flash Image 这两个走**契约转换**——网关把统一参数翻译成 Gemini 原生的 `generateContent` 形状。因此**只有下表这些参数会被送出去**: | 参数 | 是否生效 | 说明 | |------|---------|------| | `model` | ✓ | `google/gemini-3-pro-image`、`google/gemini-3.1-flash-image` | | `prompt` | ✓ | 翻译成 `contents[].parts[].text`。必填,不写或为空返回 400 | | `size` | ✓ | 见下,两种写法行为不同 | | `image` | ✓ | 参考图 / 待编辑图,一张或多张,翻译成 `inlineData`。data URI 取其中声明的格式;裸 base64 按 PNG / JPEG / WEBP / GIF 的字节特征识别,认不出时返回 400 并指明第几张图。不接受图片 URL | | `n` | **丢弃** | Gemini 的候选数参数属于文本生成,图像端点上是否生效没有证据。宁可明示丢弃,也不编一个「请求 200、设置静默不生效、账单照出」的映射 | | `quality` | **丢弃** | Gemini 契约里没有这个概念 | | `response_format` | **丢弃** | 只能返回 base64(`b64_json`) | | `user` 及其他参数 | **丢弃** | — | 被丢弃的参数会出现在响应头 `X-Gateway-Unsupported-Parameters` 里;带 `X-Gateway-Strict-Parameters: true` 则直接 400。 #### `size`:档位名或宽高 | 写法 | 映射到 | 实际效果 | |------|--------|---------| | 档位名(`1K`、`2K`、`4K`) | `imageConfig.imageSize` | **只控制分辨率**,宽高比由上游默认。各档输出 token 见下表 | | 宽高(`1376x768`) | `imageConfig.aspectRatio` + `imageConfig.imageSize` | 先匹配最接近的支持比例(误差 2% 以内),再按长边**向上**取分辨率档位,**比例与分辨率都生效** | | 宽高比超出 2% 误差(如 `1000x700`) | 整个 `size` 不下发 | 比例和分辨率档都被丢弃,按上游默认的比例和分辨率出图。请求仍返回 200、仍出图、仍计费,唯一的信号是响应头 `X-Gateway-Unsupported-Parameters: size`;严格模式下返回 400 | > [!warning] > **不要使用 `512` 档。** `512` 档在生产环境被服务商拒绝(两个模型都是)。写宽高时长边不超过 704 会被网关映射到 `512` 档,同样可能被拒绝,请让长边大于 704。 写宽高时按长边向上取档,超过 4K 的按 4K。同一档位在两个模型上的输出 token 不同: | 长边 | 档位 | `gemini-3-pro-image` 输出 token | `gemini-3.1-flash-image` 输出 token | |------|------|------|------| | ≤ 1376 | `1K` | 1120 | 1120 | | ≤ 2816 | `2K` | 1120(2K 档不生效,与 1K 相同) | 1680 | | 更大(封顶) | `4K` | 2000 | 2520 | 出图尺寸由服务商按比例档和分辨率档决定,不等于请求的宽高,例如 `gemini-3-pro-image` 请求 `4096x2304` 实际出图 `5504x3072`;请以返回图片的实际宽高为准。 例如 `1024x1024` 映射为 1:1 + `1K`,`2048x2048` 映射为 1:1 + `2K`。 > [!warning] > 向上取档意味着长边略超过某一档时会落到下一档:`1500x1500` 取的是 `2K` 档,账单按实际输出的 token 收。想精确控制分辨率就直接传档位名。 > > 比例偏差超过 2% 时整个 `size` 被丢弃、请求照常成功,生产环境建议带 `X-Gateway-Strict-Parameters: true`,让这种请求改为返回 400。要 16:9 + 4K 请写 `4096x2304`,不要照抄 `5632x3072`(比例 1.833,偏离 16:9 超过 2%,会被丢弃)。 > > `size` 不接受比例字符串:`16:9` 会被当作档位名原样传给上游,上游不认识,返回 400(`upstream_rejected`)。要 16:9 请写该比例的宽高,如 `1376x768`。 支持的宽高比:`1:1`、`2:3`、`3:2`、`3:4`、`4:3`、`4:5`、`5:4`、`9:16`、`16:9`、`21:9`、`1:4`、`4:1`、`1:8`、`8:1`。传宽高时匹配误差 2% 以内的最接近比例,超出误差则比例和分辨率档都不下发,`size` 计入丢弃参数。 #### 计费 按 token 计:**输入**、**输出**各有独立单价;`gemini-3-pro-image` 另有**思考**一项(`usage.output_tokens_details.reasoning_tokens`,`usage.total_tokens` 包含它),`gemini-3.1-flash-image` 不产生思考 token。带参考图时,输入图片并入「输入」。 > [!note] > **思考 token(Pro)单独计费且不可预测。** 只有 `gemini-3-pro-image` 产生思考 token。生产实测每次 115~316 个、中位约 220,由模型自行决定,不随输出分辨率档位或提示词长度变化;它约占单次费用的 1.5%,预算时可按每次约 220 个估算。 ## 视频生成(异步任务) 视频生成耗时以分钟计,走**异步任务**:提交拿任务 ID,轮询到终态,再取产物。 ``` POST /v1/videos 提交任务 GET /v1/videos/{id} 查询任务 GET /v1/videos/{id}/content 取产物 POST /v1/videos/regenerations 视频升清(仅 MiniMax H3) POST /v1/videos/context 上下文增强(仅 MiniMax H3) ``` ### 三步流程 **第一步,提交**: ```bash curl https://api.lyrouter.com/v1/videos \ -H "Authorization: Bearer sk-你的密钥" \ -H "Content-Type: application/json" \ -d '{ "model": "bytedance/doubao-seedance-2.0-mini", "prompt": "一只柯基在草地上奔跑,阳光穿过树叶", "size": "1280x720", "seconds": 5 }' ``` 返回任务对象,`status` 为 `queued`: ```json { "id": "aigwt_…", "object": "video", "model": "…", "status": "queued", "created_at": 1760000000 } ``` **第二步,轮询**:`GET /v1/videos/{id}`,直到 `status` 变成 `completed` 或 `failed`。建议 10~30 秒一次。 **第三步,取产物**:`GET /v1/videos/{id}/content` 返回 302,跳转到产物地址下载。任务还没完成时返回 409,`error.code` 为 `not_ready`,继续轮询到 `completed` 再取。 > [!warning] > 产物地址**有效期很短**(厂商侧通常 24 小时),请及时下载或转存。 ### 视频通用参数(网关契约) 下面这些参数对**所有**视频模型通用,网关会翻译成各厂商的私有形状: | 参数 | 类型 | 说明 | |------|------|------| | `model` | string | 模型名 | | `prompt` | string | 提示词 | | `seconds` | integer | 时长(秒),正整数 | | `size` | string | `宽x高`(如 `1280x720`)或档位名(如 `720p`、`2K`) | | `first_frame` | string | 首帧图片 | | `last_frame` | string | 尾帧图片 | | `reference_image` | string / string[] | 参考图 | | `input_reference` | string / string[] | 参考**视频** | | `reference_audio` | string / string[] | 参考音频(目前仅 MiniMax H3 支持,不会转发给 Seedance) | | `generate_audio` | boolean | 生成有声视频。Seedance 不传时默认生成有声视频 | | `watermark` | boolean | 加水印 | | `output_format` | string | 输出容器格式 | | `omni_reference_task_type` | string | 全模态任务类型(Seedance 使用;2.5 和 2.0 系列传入都会被受理) | | `source_video` | string | 升清源视频(仅 `/v1/videos/regenerations`) | 不在这张表里的字段会被丢弃并写进 `X-Gateway-Unsupported-Parameters`;表里的字段若该模型不支持,会被**显式拒绝**并说明原因,不会悄悄忽略。JSON 请求体里目前已知的例外只有 `reference_audio`:传给 Seedance 时被静默丢弃,既不报错,也**不会**写进 `X-Gateway-Unsupported-Parameters`。用表单提交时的例外见下一段。 用 `multipart/form-data` 提交 `/v1/videos` 时(OpenAI 官方 SDK 的 `videos.create()` 就用这种格式),表单里能正常使用的只有 `model`、`prompt`、`seconds`、`size`、`input_reference`、`watermark`、`generate_audio`、`output_format`、`omni_reference_task_type`,其中 `input_reference` 只能填可公开访问的 `https://` 地址。目前表单里的 `input_reference` 如果是上传的文件,网关会忽略这个文件、按没有参考视频处理并照常计费,不会报错;只有写成非 URL 的文本值时才返回 400 `input_reference must be a URL; …`。`first_frame`、`last_frame`、`reference_image`、`reference_audio` 请用 JSON 请求体提交:目前写在表单里时,网关会把它们换成占位值转给服务商,例如 Seedance 带 `first_frame` 时返回 400 ``The parameter `content[1].image_url` specified in the request is not valid.``,MiniMax 带 `reference_audio` 时任务提交成功、随后异步失败(`content[1].audio_url: invalid param: audio url must be http(s):// or data:...;base64`)。 > [!note] > 厂商文档里的 `duration` / `resolution` / `ratio` / `content` 对应网关的 `seconds` / `size` / 由 `size` 推导 / 由上面的参考字段组装。**请用网关的名字**,厂商原名不在契约里,会被丢弃。 --- ### Seedance 2.5 / 2.0-fast / 2.0-mini(火山方舟) #### 能力对比 | 能力 | `doubao-seedance-2.5` | `doubao-seedance-2.0-fast` | `doubao-seedance-2.0-mini` | |------|----------------------|---------------------------|---------------------------| | 文生视频 | ✓ | ✓ | ✓ | | 首帧 / 首尾帧生视频 | ✓ | ✓ | ✓ | | 图片参考 / 视频参考 | ✓ | ✓ | ✓ | | **音频参考** | ✗ 网关目前不转发 | ✗ 同左 | ✗ 同左 | | 编辑视频 / 延长视频 | ✓ | ✓ | ✓ | | 生成有声视频 | ✓ | ✓ | ✓ | | **参考素材上限** | **30 图 + 1 视频** | 9 图 + 1 视频 | 9 图 + 1 视频 | | **输出分辨率** | 480p、720p、1080p(10bit) | 480p、720p | 480p、720p | | 输出宽高比 | 21:9、16:9、4:3、1:1、3:4、9:16、自适应 | 同左 | 同左 | | **输出时长** | **4~30 秒** | 4~15 秒 | 4~15 秒 | | **输出格式** | mp4、**mov** | mp4 | mp4 | - `reference_audio`(参考音频)目前不会转发给 Seedance:传了不报错,也不会出现在 `X-Gateway-Unsupported-Parameters` 中。需要参考音频时请改用 MiniMax H3。 - 参考视频 `input_reference` 每次只能传一个地址,写成数组返回 400。 - 服务商的联网搜索、返回尾帧等能力没有对应的网关参数,目前无法通过 LYRouter 使用。 > [!note] > Seedance 2.5 的 1080p 采用 **10bit 位深 + H.265/HEVC** 编码,少数播放器不兼容;`mov` 采用 H.264 + yuv444p + PCM,建议用 VLC / mpv / ffplay / IINA 播放。 #### `size` 的两种写法 | 写法 | 网关怎么处理 | |------|-------------| | `宽x高`(如 `1280x720`) | 取**短边**作为分辨率档(→ `720p`),并按宽高比就近匹配到厂商支持的比例 | | 档位名(如 `720p`、`1080p`) | 原样送出,宽高比由厂商按提示词自适应 | #### 任务类型与特殊限制 Seedance 会根据输入素材和提示词**自动判断任务类型**,不同类型有不同的硬限制: | 任务类型 | 怎么触发 | 限制 | |---------|---------|------| | 文生视频 | 只传 `prompt` | 无特殊限制 | | 首帧 / 首尾帧 | 传 `first_frame`(+ `last_frame`) | 输出宽高比自动跟随首帧图片 | | 参考生视频 | 传 `reference_image` / `input_reference` | 无特殊限制 | | **视频编辑** | 传 `input_reference` + 提示词表达编辑意图 | **不要传 `seconds`**;输出宽高比与时长自动跟随源视频;源视频时长须 4~30 秒 | | **视频延长** | 传 `input_reference` + 提示词表达延长意图 | 输出宽高比自动跟随源视频 | > [!warning] > **视频编辑任务不能指定时长。** 厂商要求该场景时长固定跟随源视频,网关的 `seconds` 只接受正整数,所以**编辑任务请直接不传 `seconds`**,让厂商用默认值。传了会被厂商拒绝(`InvalidParameter.TaskTypeConstraint`)。 用 `omni_reference_task_type` 显式声明任务类型,可以把厂商的**异步报错提前成同步报错**(提交时就失败,而不是任务跑到一半失败): | 值 | 含义 | 提示词需包含的关键词 | |----|------|---------------------| | `auto`(默认) | 由模型判断 | — | | `reference` | 参考生视频 | — | | `edit` | 视频编辑 | 编辑视频 / 增加 / 加上 / 删除 / 去掉 / 修改 / 替换 / 改成 | | `extend` | 视频延长 | 向前延长 / 向后延长 / 延续 / 续写 | 服务商只在多模态参考场景接受 `edit`、`extend`:用在文生视频(只传 `prompt`)上会在提交时返回 400 `InvalidParameter.TaskTypeConstraint`。 声明的类型与模型实际判定的不一致时,可能异步失败(`InvalidParameter.TaskTypeMismatch`),也可能按声明的类型执行并计费:实测声明 `edit`、提示词不含编辑关键词时,任务按编辑完成。提示词里用 `@视频1`、`@图像1` 指代参考素材。 #### 输入素材限制(Seedance 2.5) | | 限制 | |---|---| | **图片** | jpeg、png、webp、bmp、tiff、gif、heic、heif;宽高 [300, 6000] px;宽高比 [0.4, 2.5];单张 ≤ 30 MB;首帧 1 张 / 首尾帧 2 张 / 参考图 1~30 张 | | **视频** | mp4、mov(H.264 或 H.265,音频 AAC/MP3/PCM);分辨率 480p 或 720p;时长 [2,30] 秒(编辑任务 [4,30]);宽高 [300,6000] px;宽高比 [0.4,2.5];单个 ≤ 200 MB;帧率 [24,60] | | **请求体** | 总大小 ≤ 64 MB,大文件请用公网 URL,不要用 base64 | > [!warning] > Seedance **不接受含真人人脸的参考图 / 参考视频**,会被输入审核拦截。 #### 计费 按输出 token 计(任务对象中的 `usage.completion_tokens`),分档维度是**分辨率**与**有无视频输入**: | 模型 | 分档 | |------|------| | `doubao-seedance-2.5` | 480p/720p 与 1080p 两档,每档再按有无视频输入分 | | `doubao-seedance-2.0-fast` | 只按有无视频输入分两档 | | `doubao-seedance-2.0-mini` | 同上 | 「有视频输入」指请求带了参考视频 `input_reference`(参考视频、视频编辑、视频延长);只传首帧 / 首尾帧的图生视频不算。**有视频输入时按另一档单价计费,单价更低,但总价更高**:带参考视频时计量的 token 大约翻倍(见下文「等效秒」)。 > [!note] > token 数 = 固定开销 + 每秒 token × 等效秒,已经完整体现了分辨率与时长的差异(实测 480p 4 秒 ≈ 40,594 token,8 秒 ≈ 80,770,720p 4 秒 ≈ 87,300),所以不需要再按时长分档。不带参考视频时,等效秒就是输出秒数。 **带参考视频时,计量的是「等效秒」,不是输出时长**: | 输出时长 | 等效秒 | |------|------| | ≤ 6 秒 | 输出秒数 + 参考视频秒数 | | > 6 秒 | 1.5 × 输出秒数 + 2,与参考视频时长无关 | 6 秒是拐点。例如参考视频 5 秒时,输出 5 秒按 10 秒计量,输出 10 秒按 17 秒计量。 --- ### MiniMax H3 / H3-Max > [!warning] > `minimax/minimax-h3-max` **已被服务商下线,目前不可用,请改用 `minimax/minimax-h3`**。现在提交 H3-Max 任务会返回 HTTP 200,但任务对象是空的、没有任务 ID,无法轮询,也不扣费。本节保留 H3-Max 的差异说明,仅供对照。 #### 能力对比 | | `minimax/minimax-h3` | `minimax/minimax-h3-max`(已下线) | |---|---|---| | 定位 | 标准版 | **极速版** | | 分辨率 | `480P`、`768P`、`2K` | `480P`、`768P`(**不支持 2K**) | | 时长 | 4~15 秒 | 5~15 秒(**不支持 4 秒**) | | 文生视频 / 图生视频(首尾帧) | ✓ | ✓ | | 多模态参考(图 / 视频 / 音频) | ✓ | ✓,但**不支持多张参考图**(服务商会拒绝并建议改用 H3) | | 视频升清 `/v1/videos/regenerations` | ✓ | ✗ | | 上下文增强 `/v1/videos/context` | ✓ | ✗ | #### `size`:短边必须正好落在档位上 | 写法 | 网关怎么处理 | |------|-------------| | 档位名(`480P`、`768P`、`2K`) | 原样送出 | | `宽x高` | 取**短边**查档位表:短边必须**精确**是 `480` 或 `768`,否则网关直接拒绝并告诉你合法值;宽高比按就近匹配 | > [!note] > 网关在这里替你拒,而不是把一个拼出来的档位发给厂商——厂商只会回一句「ratio 非法」,看不出是尺寸引起的。 `size` 和 `seconds` 在 MiniMax 上都要显式传:服务商要求提供分辨率和时长,网关不补默认值。 `480P` 档实际产物的短边是 576:实测文生视频用 `480P`、多模态参考生视频用 `854x480`,产物都是 1038×576。 #### 三种输入场景与 `ratio` 规则 | 场景 | 怎么传 | 宽高比 | |------|--------|--------| | 文生视频 | 只传 `prompt` | **必须显式指定**,不能自适应。`size` 写 `宽x高` 时网关按就近比例推导;写档位名或不写时按 16:9 | | 图生视频 | `first_frame`(+ `last_frame`) | 由输入图决定,传了也会被忽略。实测 1:1 的首尾帧加 `854x480` 产出 768×768 | | 多模态参考生视频 | `reference_image` / `input_reference` / `reference_audio` | 可选,默认自适应 | > [!warning] > **图生视频与多模态参考互斥**:传了 `reference_*` 就不能再传 `first_frame` / `last_frame`,反之亦然。 #### 这个模型明确不支持的参数 以下参数在网关契约里存在(别的模型用得上),但 MiniMax 没有对应概念,传了会被**显式拒绝**并说明原因,不会悄悄忽略: `generate_audio`(有声由参考音频承载)、`output_format`(没有容器格式选项)、`omni_reference_task_type`(没有全模态任务类型)、`source_video`(只属于升清接口)。 #### 输入素材限制 | | 限制 | |---|---| | **图片** | JPG、JPEG、PNG、WEBP、HEIC、HEIF;宽高 [256, 5760] px;宽高比 [0.4, 2.5];≤ 30 MB;首帧 ≤ 1、尾帧 ≤ 1、参考图 ≤ 9 | | **视频** | MP4、MOV(视频 H.264/H.265,音频 AAC/MP3);≤ 50 MB;≤ 3 个;单段 [2,15] 秒且总时长 ≤ 15 秒;宽高 [256,5760] px;宽高比 [0.4,2.5];帧率 [23.976, 60] | | **音频** | WAV、MP3;≤ 15 MB;≤ 3 个;单段 [2,15] 秒且总时长 ≤ 15 秒 | | **请求体** | 总大小 ≤ 64 MB,大文件请用公网 URL | #### 视频升清(`/v1/videos/regenerations`) 把一条 **H3 768P** 产物重新生成为 2K。只支持 H3 自己产出的、符合 768P 规格的视频,不是通用的视频放大。 ```bash curl https://api.lyrouter.com/v1/videos/regenerations \ -H "Authorization: Bearer sk-你的密钥" \ -H "Content-Type: application/json" \ -d '{ "model": "minimax/minimax-h3", "prompt": "生成那条 768P 时实际送入模型的最终提示词", "source_video": "https://example.com/h3-768p.mp4", "size": "2K" }' ``` 源视频必须满足:含音轨、24 fps、宽和高都能被 32 整除、面积在 589,824 ~ 1,032,192 像素之间、总帧数 107~362(每档递增 17 帧,约 4~15 秒)。 > [!warning] > **`prompt` 必须是生成 768P 时实际送入模型的最终提示词**,参考素材也要与当时一致。任何输入不一致都可能拿不到预期效果。如果当时用过上下文增强,要用增强**之后**的提示词。 #### 上下文增强(`/v1/videos/context`) 把多模态上下文理解成一段结构化的、语义更丰富的提示词。**这个接口只返回文本,不生成视频**。 ```bash curl https://api.lyrouter.com/v1/videos/context \ -H "Authorization: Bearer sk-你的密钥" \ -H "Content-Type: application/json" \ -d '{ "model": "minimax/minimax-h3", "prompt": "史诗级太空歌剧预告:女舰长独自站在观景窗前", "seconds": 5 }' ``` 同样是异步任务,轮询到终态后产物是**文本**(增强后的提示词),拿去喂给 `/v1/videos` 即可。这个接口的 `seconds` 是**必填**的(4~15)。 > [!warning] > 目前网关不会拒绝用其他模型调用这个接口:用 Seedance 模型调用会生成一条普通视频并按视频计费,拿不到增强后的提示词。上下文增强请只用 `minimax/minimax-h3`。 #### 计费 视频按**秒**计,按**分辨率**分档: | 模型 | 分档 | |------|------| | `minimax-h3` | 480P / 768P / 2K 三档;升清(`/videos/regenerations`)单独一档 | | `minimax-h3-max`(已被服务商下线,目前不可用,请改用 `minimax-h3`) | 480P / 768P 两档 | **参考图单独计一项**(两个模型的参考图单价不同):`minimax-h3` 的参考图前 5 张免费,超出部分按张计费。 **上下文增强**(`/videos/context`)按 token 计,输入与输出两项分开 —— 它产出的是文本,不是视频。 > [!note] > 计费秒数是**输入 + 输出**的总和(任务对象中的 `usage.duration_seconds`)。传了参考视频时,参考视频的秒数同样计入。升清(`/videos/regenerations`)例外:`duration_seconds` 只计源视频的秒数(源视频 4 秒计 4 秒)。 --- ## 在代码里调用 前面每一节给的都是 `curl`,便于逐个参数对照。下面按任务分组,点开即可取用 —— 每组内切换语言。 所有接口共用同一个 base 与同一把密钥: ```text base_url = https://api.lyrouter.com/v1 header = Authorization: Bearer sk-你的密钥 ``` > [!warning] > **超时按分钟设。** 图像同步接口实测最长约 250 秒(Gemini 3 Pro),偶有超过 300 秒仍未返回;沿用文本接口的 30 秒会在成功返回之前就被客户端切断。视频一律走异步轮询。 **文生图** Python: ```python import httpx BASE = "https://api.lyrouter.com/v1" H = {"Authorization": f"Bearer {KEY}"} r = httpx.post(f"{BASE}/images/generations", headers=H, timeout=300, json={ "model": "bytedance/doubao-seedream-5.0-lite", "prompt": "一只戴墨镜的柴犬坐在冲浪板上,黄昏海面,电影感", "size": "2K", }) r.raise_for_status() # Seedream 默认返回图片地址(约 24 小时后失效),拿到就下载 url = r.json()["data"][0]["url"] open("out.png", "wb").write(httpx.get(url, timeout=120).content) ``` Node: ```js import { writeFileSync } from "node:fs"; const BASE = "https://api.lyrouter.com/v1"; const H = { Authorization: `Bearer ${process.env.LYROUTER_KEY}` }; const r = await fetch(`${BASE}/images/generations`, { method: "POST", headers: { ...H, "Content-Type": "application/json" }, body: JSON.stringify({ model: "bytedance/doubao-seedream-5.0-lite", prompt: "一只戴墨镜的柴犬坐在冲浪板上", size: "2K", }), signal: AbortSignal.timeout(300_000), }); const { data } = await r.json(); // Seedream 默认返回图片地址(约 24 小时后失效),拿到就下载 const img = await fetch(data[0].url); writeFileSync("out.png", Buffer.from(await img.arrayBuffer())); ``` 图像编辑有两种请求体,选哪种取决于模型(支持矩阵见上面「图像生成与编辑」一节): **图像编辑** Python · multipart: 文件上传形态,五个模型都可用(Gemini 系自 2026-10-09 起也支持)。 ```python r = httpx.post(f"{BASE}/images/edits", headers=H, timeout=300, files={"image": open("cat.png", "rb")}, data={"model": "openai/gpt-image-2", "prompt": "把背景换成雪山", "quality": "medium"}) ``` Python · JSON: 图片转 base64 放进请求体。五个模型都可用。 ```python import base64 b64 = base64.b64encode(open("cat.png", "rb").read()).decode() r = httpx.post(f"{BASE}/images/edits", headers=H, timeout=300, json={ "model": "google/gemini-3-pro-image", "prompt": "把背景换成雪山", # 单张传字符串;多张参考图传数组 "image": f"data:image/png;base64,{b64}", }) ``` Node · JSON: ```js import { readFileSync } from "node:fs"; const b64 = readFileSync("cat.png").toString("base64"); const r = await fetch(`${BASE}/images/edits`, { method: "POST", headers: { ...H, "Content-Type": "application/json" }, body: JSON.stringify({ model: "google/gemini-3-pro-image", prompt: "把背景换成雪山", image: `data:image/png;base64,${b64}`, }), signal: AbortSignal.timeout(300_000), }); ``` **视觉理解(读本地图片)** Python: ```python import base64, mimetypes p = "cat.jpg" mime = mimetypes.guess_type(p)[0] or "image/jpeg" b64 = base64.b64encode(open(p, "rb").read()).decode() r = httpx.post(f"{BASE}/chat/completions", headers=H, timeout=120, json={ "model": "<带「视觉」能力标签的模型>", "messages": [{"role": "user", "content": [ {"type": "text", "text": "这张图里有什么?"}, {"type": "image_url", "image_url": {"url": f"data:{mime};base64,{b64}"}}, ]}], }) print(r.json()["choices"][0]["message"]["content"]) ``` Node: ```js import { readFileSync } from "node:fs"; const b64 = readFileSync("cat.jpg").toString("base64"); const r = await fetch(`${BASE}/chat/completions`, { method: "POST", headers: { ...H, "Content-Type": "application/json" }, body: JSON.stringify({ model: "<带「视觉」能力标签的模型>", messages: [{ role: "user", content: [ { type: "text", text: "这张图里有什么?" }, { type: "image_url", image_url: { url: `data:image/jpeg;base64,${b64}` } }, ]}], }), signal: AbortSignal.timeout(120_000), }); const j = await r.json(); console.log(j.choices[0].message.content); ``` **视频:提交 → 轮询 → 下载** Python: ```python import time, httpx # 1 提交 r = httpx.post(f"{BASE}/videos", headers=H, timeout=120, json={ "model": "bytedance/doubao-seedance-2.0-mini", "prompt": "一只柯基在草地上奔跑,阳光穿过树叶", "size": "1280x720", "seconds": 5, }) r.raise_for_status() task_id = r.json()["id"] # 2 轮询到终态。10~30 秒一次即可,不要更密。 while True: time.sleep(15) task = httpx.get(f"{BASE}/videos/{task_id}", headers=H, timeout=60).json() print(task["status"]) if task["status"] in ("completed", "failed"): break if task["status"] == "failed": raise SystemExit(task) # 失败原因在任务对象里 # 3 取产物。默认 302 到产物地址,所以要跟随重定向; # 产物地址有效期通常 24 小时,拿到就存。 v = httpx.get(f"{BASE}/videos/{task_id}/content", headers=H, timeout=600, follow_redirects=True) open("out.mp4", "wb").write(v.content) ``` Node: ```js import { writeFileSync } from "node:fs"; const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); // 1 提交 const sub = await fetch(`${BASE}/videos`, { method: "POST", headers: { ...H, "Content-Type": "application/json" }, body: JSON.stringify({ model: "bytedance/doubao-seedance-2.0-mini", prompt: "一只柯基在草地上奔跑,阳光穿过树叶", size: "1280x720", seconds: 5, }), }); const created = await sub.json(); // 提交失败时没有任务 ID,不要继续轮询 if (!sub.ok || !created.id) throw new Error(JSON.stringify(created)); const { id } = created; // 2 轮询到终态 let task; for (;;) { await sleep(15_000); task = await (await fetch(`${BASE}/videos/${id}`, { headers: H })).json(); console.log(task.status); if (task.status === "completed" || task.status === "failed") break; } if (task.status === "failed") throw new Error(JSON.stringify(task)); // 3 取产物(fetch 默认跟随重定向) const v = await fetch(`${BASE}/videos/${id}/content`, { headers: H }); writeFileSync("out.mp4", Buffer.from(await v.arrayBuffer())); ``` ### 用 OpenAI 官方 SDK 对外契约是 OpenAI 形状,所以官方 SDK 大部分能直接用 —— 把 `base_url` 指到网关即可: ```python from openai import OpenAI client = OpenAI(api_key=KEY, base_url="https://api.lyrouter.com/v1", timeout=300) ``` | SDK 方法 | 能不能用 | |---|---| | `client.chat.completions.create(...)` | ✅ 文本与视觉理解都可以 | | `client.images.generate(...)` | ✅ 全部图像模型 | | `client.images.edit(...)` | ✅ 全部图像模型(含 Gemini,2026-10-09 起) | | `client.videos.create(...)` | ✅ 需要较新版本的 openai Python SDK(实测 1.58.1 没有 `client.videos`,2.48.0 可用)。SDK 以 multipart 提交,网关会转换成上游需要的格式;URL 形式的 `input_reference` 要写成 `extra_body={"input_reference": url}`,直接传字符串会在客户端报 `RuntimeError: Expected entry at input_reference to be bytes, an io.IOBase instance, PathLike or a tuple…`;`first_frame`、`last_frame`、`reference_image`、`reference_audio` 请用 JSON 提交,写在表单里目前会出错(见「视频通用参数」);查询与下载用上面的 HTTP 写法 | > [!note] > `images.edit()` 无条件发 `multipart/form-data`。Gemini 的上游只认 JSON,但网关会替你把 multipart 归一并翻译过去,所以**现在用它驱动 Gemini 也可以**(2026-10-09 起)。此前这条路会失败。 要发网关的扩展参数、或想完全控制请求体时,SDK 自带调任意端点的逃生舱: **SDK 逃生舱:用 client.post 发任意请求体** Python: ```python import httpx resp = client.post( "/images/edits", cast_to=httpx.Response, # 拿原始响应,不走 SDK 的模型解析 body={"model": "google/gemini-3-pro-image", "prompt": "把背景换成雪山", "image": f"data:image/png;base64,{b64}"}, ) img_b64 = resp.json()["data"][0]["b64_json"] ``` ## 常见错误 ### 返回 400 `unsupported_parameters`,应该如何处理? **答:** 请求启用了 `X-Gateway-Strict-Parameters: true`,且含有不受支持的参数。按错误信息列出的参数名删除参数,或改用接口契约中的名称。 ### 请求成功,但响应头有 `X-Gateway-Unsupported-Parameters`,是什么意思? **答:** 有参数被丢弃,但请求仍按剩余参数执行。检查这些参数是否必要;需要时改用契约中的名称,不要把请求成功当作全部参数已经生效。 ### GPT-Image 返回 400 `INVALID_REQUEST_BODY`,应该检查什么? **答:** 检查是否传入 `quality`。`gpt-image-2` 必须传 `quality`(`low`、`medium`、`high` 或 `auto`),不传会间歇性返回 400。其他 GPT-Image 模型也建议显式传入。结合具体错误核对请求正文。 ### GPT-Image 提示宽高必须能被 16 整除,怎么办? **答:** `Invalid size '<宽>x<高>'. Width and height must both be divisible by 16.` 表示尺寸不符合约束。将宽和高都设置为 16 的倍数,再按模型支持的尺寸规则调用。 ### GPT-Image 提示 `longest edge`、`pixel budget` 或 `Invalid size '4K'`,怎么办? **答:** `size` 违反了其余几条硬约束:最长边不能超过 3840(`Invalid size '<宽>x<高>'. The longest edge must be less than or equal to 3840.`),总像素要在约 100 万到约 830 万之间(`Invalid size '<宽>x<高>'. Requested resolution is below the current minimum pixel budget.` / `Invalid size '<宽>x<高>'. Requested resolution exceeds the current pixel budget.`),并且只能写 `宽x高`,不能写档位名(`Invalid size '4K'. Expected WIDTHxHEIGHT, for example '1824x1024'.`)。对照 GPT-Image 小节的 `size` 约束表调整尺寸,例如要接近 4K 的 16:9 图写 `3840x2160`。 ### GPT-Image 提示 `Invalid value: 'xhigh'`,怎么办? **答:** `xhigh`、`max` 只有 2.5 系列支持,而且是否可用由上游账号能力决定,可能被拒。改用 `high`。 ### Gemini 返回 200,但图片比例或分辨率不是请求的,怎么办? **答:** 先看响应头 `X-Gateway-Unsupported-Parameters` 是否含 `size`:宽高比与支持比例的偏差超过 2% 时,整个 `size`(比例和分辨率档)都被丢弃,请求按服务商默认值出图并照常计费。改写成与支持比例精确一致的宽高,例如 16:9 + 4K 写 `4096x2304`。如果没有被丢弃,再核对档位:`gemini-3-pro-image` 的 `2K` 档不生效(输出 token 与 `1K` 相同);出图尺寸本身也不一定等于请求的宽高,以返回图片的实际宽高为准。生产环境建议带 `X-Gateway-Strict-Parameters: true`,让被丢弃的 `size` 直接返回 400。 ### Seedream 提示 `image size must be at least 3686400 pixels`,怎么办? **答:** 请求低于 Seedream lite 的最小像素约束(3686400,最小正方形是 `1920x1920`)。使用 `2K` 档位或更大的宽高,并核对该模型的尺寸规则。 ### MiniMax 提示短边必须是 480 或 768,怎么办? **答:** 模型档位是离散集合。使用档位名(如 `768P`、`2K`),或使用短边精确为 480 / 768 的尺寸,并核对所选任务的支持范围。 ### 任务失败并返回 `InvalidParameter.TaskTypeConstraint`,怎么办? **答:** Seedance 的任务类型与参数冲突。对照本页“任务类型与特殊限制”检查参数;编辑任务不要传 `seconds`,文生视频不要把 `omni_reference_task_type` 设为 `edit` 或 `extend`。 ### 任务失败并返回 `InvalidParameter.TaskTypeMismatch`,怎么办? **答:** 显式声明的 `omni_reference_task_type` 与模型判定不一致。按本页任务类型表中的关键词写提示词,或改用 `auto`。 ### 多模态调用出现 504 或客户端超时,应该怎样检查? **答:** 先确认客户端是否沿用了文本接口的 30 秒超时。图像请求按分钟级设置等待时间,视频使用异步任务轮询;查询超时不等于任务失败,避免立即重复提交。 ### 产物地址打不开(返回 403 或 404),怎么办? **答:** 检查链接是否过期:服务商签发的产物地址通常 24 小时后失效,过期后访问返回 403 或 404。及时下载或转存产物。视频的产物地址在任务完成时写入一次,重新查询任务拿到的仍是同一个地址;链接过期后需要重新提交任务。 ### 多模态错误正文是什么结构? **答:** 错误响应使用 OpenAI 形状,读取 `error.message`、`error.type` 与 `error.code`,并结合 HTTP 状态和请求日志定位: ```json { "error": { "message": "…", "type": "invalid_request_error", "code": "unsupported_parameters" } } ``` ## API 规格与代码生成 多模态接口的完整规格可直接下载,喂给代码生成器就能得到你所用语言的客户端: 这两个文件由**控制台**提供(就是你正在看这篇文档的站点),不在网关地址上 —— 下面示例里的 `` 因此与别处的 `api.lyrouter.com` 不是同一个域名。 | 文件 | 用途 | |------|------| | [OpenAPI 规格(YAML)](https://platform.lyrouter.com/ai_gateway/api-spec/multimodal-openapi.yaml) | 机器读;可直接用于 openapi-generator、openapi-typescript 等工具 | | [接口参考(Markdown)](https://platform.lyrouter.com/ai_gateway/api-spec/multimodal-api-reference.md) | 人读的完整参考,含每个参数的取值范围与计费口径 | 生成 TypeScript 客户端: ```bash npx openapi-typescript https:///ai_gateway/api-spec/multimodal-openapi.yaml \ -o ./src/gateway-api.d.ts ``` 生成 Python 客户端: ```bash openapi-generator-cli generate \ -i https:///ai_gateway/api-spec/multimodal-openapi.yaml \ -g python -o ./gateway-client ``` > [!note] > 对外契约是 **OpenAI 形状**:产物固定在顶层 `data[]` 数组里,`usage` 固定在顶层。可以直接用 OpenAI 官方 SDK 调用图像接口,创建视频任务也可以用 SDK 的 `videos.create()`;查询和下载视频建议用 HTTP 直调。 ## 接下来 - [调用网关](https://platform.lyrouter.com/ai_gateway/docs/call-gateway):文本对话、向量、通用请求格式 - [查看日志](https://platform.lyrouter.com/ai_gateway/docs/logs):逐次调用的用量与费用 - [用量分析](https://platform.lyrouter.com/ai_gateway/docs/analytics):按模型 / 工作空间的费用视角 --- # 模型版本与下线 来源: https://platform.lyrouter.com/ai_gateway/docs/versions 请求中的 `model` 写的是模型 ID(如 `deepseek/deepseek-v4-pro`),不是模型广场上显示的名称。更换模型版本就是改用另一个模型 ID:先用真实任务验证,再更新应用配置。把模型名集中写在虚拟模型里,切换时只需改一处。模型在工作空间被停用或被平台下线后,调用会返回 403 `Model is not available in the model plaza`;工作空间设置了默认模型时,则可能改由默认模型回答。 ## 模型 ID 与显示名称 | 名称 | 示例 | 在哪里看到 | 用途 | | --- | --- | --- | --- | | 模型名称 | DeepSeek V4 Pro | 模型广场卡片标题、模型详情页头 | 仅用于展示 | | 模型 ID | `deepseek/deepseek-v4-pro` | 卡片标题下方、详情页头(带复制按钮);`GET /v1/models` 返回的 `id` | 填进请求的 `model` | | 上游模型名 | 服务商自己的模型名或接入点编号 | BYOK 配置的「模型与费用」步骤 | 由网关转换,客户端无需填写 | - 模型 ID 区分大小写,请从模型广场复制或用 [`GET /v1/models`](https://platform.lyrouter.com/ai_gateway/docs/models) 查询,不要自己拼写或加服务商前缀。斜杠前是模型厂商,不是服务商。 - `GET /v1/models` 的条目在模型目录有信息时带 `display_name`,这是显示名称,调用时仍使用 `id`。 - 同一模型的不同版本以不同的模型 ID 区分,命名与查询规则见[模型命名与查询](https://platform.lyrouter.com/ai_gateway/docs/model-names)。 (截图:更换版本前,在模型详情核对模型 ID、各服务商的状态和价格表。) ## 更换版本的验证步骤 1. **确认可调用**:在工作空间的 **模型广场** 确认新版本在「专属可用模型」中,复制它的模型 ID。在「可启用」中时,请当前账号管理员或工作空间管理员开通。团队和企业建议先在测试用的工作空间中开通和验证。 2. **核对详情**:在模型详情比较各服务商的状态、价格表和计费单位;用 `GET /v1/models` 查看 `context_length`、`max_output_tokens`、`input_modalities`、`api_types` 等字段(模型目录有信息时返回)。 3. **用真实任务验证**:使用应用实际调用的接口(Chat Completions、Anthropic Messages 或 Responses),覆盖长上下文、图片输入、工具调用、JSON 输出和流式输出,检查流式输出是否正常结束(Chat Completions 为 `data: [DONE]`,Anthropic Messages 为 `message_stop`,Responses 为 `response.completed`)。各接口的差异见[模型能力与兼容性](https://platform.lyrouter.com/ai_gateway/docs/capabilities)。 4. **对比结果**:在[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)中查看「模型(实际)」「服务商」、状态、Token、首 Token 和总延迟;在[用量分析](https://platform.lyrouter.com/ai_gateway/docs/analytics)中按模型比较同一时间段的请求数、成功率和费用。 5. **切换并保留回退**:更新应用配置或虚拟模型,旧版本在一段时间内作为备用模型保留,确认稳定后再移除。 ## 用虚拟模型降低切换成本 让应用调用 `@vmodel/<名称>`,而不是直接写模型 ID。之后换版本只需当前账号管理员在 **虚拟模型** 页面修改「默认模型」,保存后新请求按新配置执行,应用和工具配置都不用改: - 把旧版本填进「备用模型」,新版本失败时网关按顺序改用旧版本。 - 备用模型应与主模型支持相同的接口、输入类型和工具调用。模型不支持请求的输入或接口时,网关直接返回 400,不再尝试备用模型。 - 虚拟模型可用于 `/v1/chat/completions`、`/v1/messages` 和 `/v1/responses`;图像、视频和语音接口请直接写模型 ID。 - 日志的「虚拟模型」显示调用的虚拟模型名称,「模型(实际)」显示实际回答的模型,便于确认切换是否生效。 创建和配置方法见[虚拟模型](https://platform.lyrouter.com/ai_gateway/docs/presets)。工作空间在[通道选择与路由策略](https://platform.lyrouter.com/ai_gateway/docs/routing)中设置的「默认模型」是另一层兜底:请求没写 `model`,或请求的模型全部失败、未开通时,由它回答。它适合作为安全网,不适合用来管理版本,因为请求会在你不知情时改由另一个模型回答。 ## 模型停用或下线后的表现 | 情况 | 调用结果 | 处理 | | --- | --- | --- | | 工作空间停用了该模型的全部来源 | 403 `Model is not available in the model plaza`(`error.code` 为 `model_not_available`);设置了默认模型时,对话请求改由默认模型回答 | 在模型广场重新开通,或改用其他模型 | | 平台下线了该模型 | 同上;模型从模型广场和 `GET /v1/models` 中消失 | 改用替代模型的模型 ID | | 模型仍开通,但没有可用的通道或凭证 | 503 `all routed candidates exhausted` 或 `No configured credential can serve this model`(`error.code` 为 `no_route_candidate`) | 请账号管理员检查服务来源和 BYOK 凭证 | | 虚拟模型的「默认模型」已不可用 | 改用「备用模型」;都不可用时改用工作空间默认模型,仍没有时返回 503 `all routed candidates exhausted` | 请账号管理员修改虚拟模型配置 | - 被下线的模型如果配置在 BYOK 中,账号管理员在 BYOK 配置的「模型与费用」步骤会看到它标有「目录已下架」。 - 请求由默认模型回答时不会报错,请在日志的「模型(实际)」中确认。 - 各报错的完整处理见[模型不可用](https://platform.lyrouter.com/ai_gateway/docs/unavailable)。平台公告会发到「消息中心」。 ## 常见问题 ### 模型突然调不通,应该先检查什么? **答:** 先按报错原文对照上表。返回 403 `Model is not available in the model plaza` 时,在模型广场确认该模型还在「专属可用模型」中;不在时,可能被工作空间停用或已被平台下线。用 `GET /v1/models` 可以确认当前 Key 还能调用哪些模型。 ### 调用没有报错,但回答风格突然变了,是什么原因? **答:** 在日志中打开这条请求,查看「模型(实际)」。它与请求的模型不同时,说明原模型不可用,请求由虚拟模型的备用模型或工作空间默认模型回答;不需要这种兜底时,请账号管理员清空智能路由中的默认模型。模型相同而「服务商」不同时,说明请求落到了同一模型的另一个通道,见[应用接入多个服务商](https://platform.lyrouter.com/ai_gateway/docs/multi-provider)。 ### 下线前能否直接把模型 ID 换成任意新模型? **答:** 先按上面的验证步骤确认新模型支持应用使用的接口、输入类型、工具调用和输出格式,再更新配置。只按名称相近替换,可能在工具调用或 JSON 输出上失败。 --- # 通道选择与路由策略 来源: https://platform.lyrouter.com/ai_gateway/docs/routing 每个工作空间有一份智能路由设置,决定网关为一次调用选择哪个通道。同一个模型通常由多个通道提供,平台通道和你的 BYOK 通道都算在内。「多渠道选路策略」决定这些通道的尝试顺序;「默认模型」在请求没写 `model`,或请求的模型全部失败时接手。设置对工作空间内所有 API Key 生效,保存后几秒内同步到网关。 ## 工作空间设置 当前账号管理员在工作空间的 **智能路由** 页面修改设置。页面只有一张「通用设置」卡片: | 设置 | 作用 | 新建工作空间的默认值 | 保存方式 | | --- | --- | --- | --- | | 多渠道选路策略 | 直接调用模型 ID 时,该模型的多个通道按什么顺序尝试 | 最低价 | 选择后自动保存 | | 默认模型 | 请求没写 `model` 时使用;请求的模型全部失败后兜底 | 暂不设置 | 选择或清空后自动保存 | | Auto 智能路由 | `lyrouter/auto` 的候选模型范围,见[Auto 智能路由](https://platform.lyrouter.com/ai_gateway/docs/auto) | 全部已开通模型 | 在「高级设置」抽屉中点击 **保存 Auto 设置** | (截图:智能路由中分别设置多渠道排序和默认模型,Auto 高级设置独立打开。) 三项设置分别保存,修改其中一项不会覆盖另外两项。普通成员看不到这个菜单,直接打开页面链接会提示「当前组织角色无权访问该页面」。成员用自己的 API Key 调用时,同样按这些设置选路。 ## 模型、通道与凭证 网关先确定模型,再为模型选择通道,最后选择通道下的凭证。服务商代表厂商身份;协议、地址和接入方式属于通道,所以同一家服务商的按量服务和 Coding Plan 是两个不同的通道。一个通道下可以有多个凭证:你的 BYOK 凭证按你在 BYOK 中设置的顺序在前,平台凭证在后。 ## 多渠道选路策略 直接调用模型 ID(例如 `deepseek/deepseek-v4-flash`)时,网关按这项设置给该模型的通道排序,再依次尝试: | 选项 | 日志中的「路由策略」 | 排序方式 | | --- | --- | --- | | 最低价 | `cost` | 按预估的单次请求实付价从低到高排序。预估价根据该模型平均每次请求的输入、输出 Token,该通道的缓存命中率和调用时的价格计算;算不出价格的通道排在最后 | | 负载均衡 | `balanced` | 先按实测延迟排序,再按「API Key + 模型」把调用稳定地分配到一个通道(按平台为通道设置的权重),分到的通道排第一,其余通道按延迟顺序作为回退 | | 最高吞吐 | `throughput` | 按实测输出速度从高到低排序,没有测量数据的通道排在最后 | | 最低延迟 | `latency` | 按实测延迟从低到高排序,没有测量数据的通道排在最后 | - **会话保持**:「最低价」和「负载均衡」会把同一个 API Key 对同一模型的调用保持在同一个通道上,以提高上游提示词缓存的命中率。保持期为 30 分钟,每次调用都会续期;该通道返回 429、408、5xx 或连接失败时改绑到其他通道。缓存优化见[降低成本与优化缓存](https://platform.lyrouter.com/ai_gateway/docs/cost-practice)。 - **自定义服务商优先**:在「负载均衡」「最高吞吐」「最低延迟」下,工作空间自定义服务商的通道没有可比较的平台测量数据,始终排在平台通道前面。 - **适用范围**:这项设置只对直接写模型 ID 的调用生效。[虚拟模型](https://platform.lyrouter.com/ai_gateway/docs/presets)使用自己的「Channel 排序策略」,`lyrouter/auto` 不使用这项设置。 - **不能按请求覆盖**:选项说明中的「单个请求可覆盖此设置」目前没有实现,请求里没有可以覆盖路由的参数。需要让一部分调用使用不同的排序时,为它们创建虚拟模型并设置「Channel 排序策略」。 ## 默认模型 默认模型有两个用途: 1. **请求没写模型**:请求体没有 `model`,或写成 `""`、`null` 时,改用默认模型。没有设置默认模型时,这类请求返回 400 `you must provide a model parameter`(`error.code` 为 `missing_model`)。 2. **全部失败后兜底**:请求的模型所有通道都失败后,网关最后尝试默认模型。请求的模型在本工作空间没有开通时,也会由默认模型回答,而不是返回 403。 使用默认模型前请注意: - **新建工作空间不预填**:新建工作空间默认「暂不设置」。较早创建的工作空间可能已预填 `qwen/qwen3.7-plus`,请在页面上确认;不需要兜底时清空即可。 - **必须在本工作空间可用**:选择框列出平台模型目录,也可以直接输入模型 ID,保存时不检查是否可用。默认模型没有在模型广场开通、也没有可用 BYOK 时,不写 `model` 的请求返回 403 `Model is not available in the model plaza`,兜底也不会发生。 - **只为对话类接口兜底**:图像、视频和语音接口失败后不会改用默认模型。向量(embeddings)请求也会改用默认模型,但默认模型通常是对话模型,结果多为 400 `unsupported_model_api`,所以向量请求请始终写明可用的模型 ID。 - **在日志中确认**:请求由默认模型回答时,[日志](https://platform.lyrouter.com/ai_gateway/docs/logs)详情的「模型(实际)」显示默认模型。 ## BYOK 通道规则 在 [BYOK](https://platform.lyrouter.com/ai_gateway/docs/byok) 的使用配置中,可以为某个通道设置两种偏好,它们优先于多渠道选路策略: - **优先使用此 Channel**:把这个通道排在最前,失败后照常回退到其他通道和默认模型。 - **仅用此 BYOK**:该模型只使用这个通道下的 BYOK 凭证,不使用平台凭证、其他通道或默认模型,全部失败即结束。通过虚拟模型或 `lyrouter/auto` 调用时,被限定的模型失败后仍会尝试下一个候选模型,但整个请求不会再回退到默认模型。 (截图:在 BYOK 使用配置中核对调用范围及优先、独占使用规则。) ## 验证 调整设置后发送一次测试调用,在[查看实际路由](https://platform.lyrouter.com/ai_gateway/docs/route-log)中核对日志详情:「路由追踪」的「路由策略」显示上表中的取值,「模型(实际)」和「服务商」显示最终命中的模型与通道。「全部候选」只是排好序的候选列表,不代表每个候选都被调用过;实际调用记录在「上游调用尝试」中。失败时如何换通道,见[失败重试与备用模型](https://platform.lyrouter.com/ai_gateway/docs/fallback)。 --- # 虚拟模型 来源: https://platform.lyrouter.com/ai_gateway/docs/presets 虚拟模型把主模型、备用模型、Channel 排序策略、推理参数和系统提示词打包成一个名称。客户端把请求的 `model` 写成 `@vmodel/<名称>`,网关先调用主模型,失败时按顺序改用备用模型,并把参数和系统提示词合并进发给上游的请求。之后更换模型或调整参数,只需修改虚拟模型,客户端代码不用改。 ## 适用场景 - 多个应用共用同一套模型和参数,需要集中调整。 - 主模型不可用时自动改用其他模型,客户端不必自己换模型重试。 - 统一并锁定 `temperature`、`max_tokens`、输出格式等参数。 - 为没有自带系统提示词的请求补上统一的系统提示词。 如果只需要在同一模型的多个通道之间选路,直接调用模型 ID 即可,见[通道选择与路由策略](https://platform.lyrouter.com/ai_gateway/docs/routing)。 ## 调用虚拟模型 把 `model` 写成 `@vmodel/<名称>`,其他写法与调用普通模型相同。下例调用名为 `support-bot` 的虚拟模型,环境变量的设置见[完成第一次模型调用](https://platform.lyrouter.com/ai_gateway/docs/quickstart): ```bash curl "$LYROUTER_BASE_URL/v1/chat/completions" \ -H "Authorization: Bearer $LYROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"@vmodel/support-bot","messages":[{"role":"user","content":"用一句话介绍你自己"}]}' ``` - **支持的接口**:`/v1/chat/completions`、`/v1/messages` 和 `/v1/responses`。图像、视频和语音接口不支持虚拟模型,会返回 403 `Model is not available in the model plaza`,请改用具体的模型 ID。 - **名称区分大小写**:名称只含小写字母、数字和连字符,`@vmodel/Support-Bot` 找不到 `support-bot`。旧前缀 `@preset/<名称>` 与 `@vmodel/<名称>` 等价。 - **按工作空间区分**:虚拟模型属于一个工作空间,该工作空间的任何有效 API Key 都可以调用它,没有单独的 Key 级授权。 - **查询可用名称**:`GET /v1/models` 会以 `@vmodel/<名称>` 列出工作空间中已启用的虚拟模型。看不到虚拟模型页面的成员可以从这里查到名称。 - **上游与计费**:上游收到的 `model` 是实际调用的模型 ID,费用也按实际模型计算。 ## 创建虚拟模型 当前账号管理员在工作空间的 **虚拟模型** 页面点击 **创建虚拟模型**。普通成员看不到这个菜单,但可以调用已经启用的虚拟模型。表单分为「基础信息」「模型与路由」「推理参数」「系统提示词」四部分,只有「虚拟模型名称」和「默认模型」是必填项。 | 字段 | 说明 | | --- | --- | | 虚拟模型名称 | 调用名,即 `@vmodel/` 后面的部分。只能用小写字母、数字和连字符,以字母或数字开头,在工作空间内唯一 | | 默认模型 | 优先使用的模型,列表中显示为「主模型」 | | 备用模型 | 可选,可填多个,主模型不可用时按填写顺序尝试 | | Channel 排序策略 | 同一模型有多个通道时的排序:按价格优先、按吞吐量优先、按延迟优先、负载均衡(默认) | | 推理参数 | 七组共 17 个参数,每个参数可以单独锁定,见下文 | | 系统提示词 | 客户端请求没有系统提示词时由网关补上,见下文 | (截图:虚拟模型列表展示可复制的调用名称、主模型、锁定参数和启用状态。) - 「默认模型」和「备用模型」可以从模型目录中选择,也可以直接输入模型 ID。保存时不检查这些模型在本工作空间是否可用,调用时会跳过不可用的模型。保存前请确认它们已在[模型广场](https://platform.lyrouter.com/ai_gateway/docs/choose)开通,或已配置可用的 [BYOK](https://platform.lyrouter.com/ai_gateway/docs/byok)。 - 保存后虚拟模型即为「已启用」,几秒内同步到网关,不需要更换 API Key。「保存并测试」按钮暂不可用,请直接发送一次调用验证。 (截图:虚拟模型配置中设置主模型、备用模型和推理参数;按实际名称调用。) ### 保存失败的常见提示 | 提示 | 原因 | | --- | --- | | 虚拟模型名称需匹配 ^[a-z0-9][a-z0-9-]*$ | 名称含大写字母、空格或中文,或以连字符开头 | | 请选择默认模型 | 没有填写「默认模型」 | | `slug already in use in this workspace` | 本工作空间已有同名虚拟模型 | | JSON Schema 不是合法的 JSON,请检查语法。 | 「响应格式」的 JSON Schema 文本有语法错误 | | `invalid preset params: response_format.json_schema.name is required ...` | JSON Schema 对象缺少非空的 `name`,见下文「推理参数」 | | 请填写指定函数的名称 | 「工具选择」选了指定函数,但没有填写函数名 | ## 实际调用哪个模型 网关按以下顺序尝试,前一个模型的所有通道都失败后,才进入下一个模型: 1. 虚拟模型的「默认模型」(主模型)。 2. 「备用模型」,按填写顺序。网关不会因为某个备用模型更快或更便宜就把它提前。 3. 工作空间的默认模型,前提是已在[智能路由](https://platform.lyrouter.com/ai_gateway/docs/routing)中设置。 同一个模型由多个通道提供时,按虚拟模型的「Channel 排序策略」排序;在 BYOK 中设置的「优先使用此 Channel」「仅用此 BYOK」仍然优先。完整的回退规则和不会回退的情况见[失败重试与备用模型](https://platform.lyrouter.com/ai_gateway/docs/fallback),其中两种最常见: - 安全围栏的模型策略禁止了实际选中的模型时,请求立即返回 403 `Request blocked by guardrail policy`,不再尝试备用模型。围栏按实际模型 ID 检查,在模型策略里填写 `@vmodel/...` 不起作用。 - 当前模型不支持请求的输入或接口时(例如给只接受文本的模型发送图片),请求立即返回 400,不再尝试备用模型。因此备用模型应与主模型支持相同的输入类型和工具调用能力。 ## 推理参数:默认值与锁定 每个参数在未锁定时是默认值,锁定后是强制值: | 状态 | 客户端没传该参数 | 客户端传了该参数 | | --- | --- | --- | | 未锁定 | 使用虚拟模型的值 | 使用客户端的值 | | 已锁定 | 使用虚拟模型的值 | 使用虚拟模型的值,覆盖客户端的值 | | 分组 | 参数 | 取值 | | --- | --- | --- | | 采样 | `temperature`、`top_p`、`top_k`、`seed` | 0~2;0~1;≥0 的整数;整数 | | 长度 | `max_tokens`、`stop` | ≥1 的整数;字符串或字符串数组 | | 惩罚 | `frequency_penalty`、`presence_penalty`、`repetition_penalty` | -2~2;-2~2;大于 0 | | 输出格式 | `response_format` | `text`、`json_object`、`json_schema` | | 推理控制 | `reasoning_effort`、`enable_thinking`、`thinking_budget` | `minimal`/`low`/`medium`/`high`;是或否;≥0 的整数 | | 工具 | `tool_choice`、`parallel_tool_calls` | `auto`、`none`、`required` 或指定函数;是或否 | | 流式 | `stream`、`stream_options.include_usage` | 是或否;是或否 | - 只有设置了值的参数才能锁定。`response_format`、`tool_choice` 这类对象参数整体替换,不逐字段合并。 - 未锁定的默认值不适用时会自动跳过:请求没有 `tools` 时不补 `tool_choice`;`response_format` 为 `json_object` 而对话中没有出现 "json" 字样时不补。锁定的参数总是写入。 - 参数按 Chat Completions 的字段名原样合并,`/v1/responses` 请求也是如此,例如 `max_tokens` 不会换成 `max_output_tokens`,上游可能因此返回 400。给 Responses 客户端使用的虚拟模型,建议只设置 `temperature`、`top_p` 这类两种协议通用的参数。 - `stream` 会改变响应形式:设为「是」并生效时,非流式请求也会收到 SSE 事件流。 - `reasoning_effort`、`enable_thinking`、`thinking_budget` 分属不同厂商,网关不会相互换算,请按主模型所属厂商支持的那一个填写。 - 「响应格式」选择 JSON Schema 时,要填 OpenAI `response_format.json_schema` 的完整对象,例如 `{"name": "answer", "schema": {"type": "object", "properties": {"text": {"type": "string"}}}}`。只粘贴 Schema 本身会保存失败。 - 控件变灰并提示「当前主模型不支持该参数」只是控制台提示,网关不会按模型能力删减参数。 ## 系统提示词何时注入 | 接口 | 注入规则 | | --- | --- | | `/v1/chat/completions` | `messages` 中没有 `role` 为 `system` 的消息时,插到最前面;已有则不注入 | | `/v1/messages` | 请求没有 `system` 时注入;已有则不注入 | | `/v1/responses` | `instructions` 为空时直接填入;已有内容时空一行后追加 | 系统提示词不能锁定:Chat 和 Messages 请求自带系统提示词时,虚拟模型的提示词不生效。`developer` 角色的消息不算系统提示词。改用备用模型时会重新注入一次,不会重复叠加。 ## 编辑、停用和删除 | 操作 | 对调用的影响 | | --- | --- | | 编辑 | 保存后新请求按新配置执行。修改名称等于修改调用名,旧名称立即失效 | | 禁用 | 状态变为「已停用」,网关不再识别该名称,`GET /v1/models` 也不再列出 | | 启用 | 原名称恢复可用 | | 克隆 | 打开预填全部配置的创建表单,名称加 `-copy` 后缀,点击保存后才创建 | | 删除 | 输入名称确认后永久删除,之后可以用同一名称重新创建 | 虚拟模型被禁用、删除或改名后,旧名称的请求不再匹配任何虚拟模型。工作空间设置了默认模型时,这类对话请求会改由默认模型回答;没有设置时返回 503 `all routed candidates exhausted`。 ## 验证与常见问题 调用后在[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)中打开这条记录,「路由追踪」的「虚拟模型」显示虚拟模型名称(不带 `@vmodel/` 前缀),「模型(实际)」显示实际回答的模型,详见[查看实际路由](https://platform.lyrouter.com/ai_gateway/docs/route-log)。 ### 调用返回 503 `all routed candidates exhausted`,应该检查什么? **答:** 先核对 `@vmodel/<名称>` 的拼写和大小写,再用 `GET /v1/models` 确认它在列表中,即处于已启用状态。名称无误时,请账号管理员确认「默认模型」和「备用模型」已在模型广场开通或配置了可用的 BYOK。 ### 为什么回答来自虚拟模型之外的模型? **答:** 主模型和备用模型都失败后,网关会使用工作空间的默认模型。名称写错或虚拟模型已停用时,对话请求也会直接由默认模型回答。在日志的「模型(实际)」中可以确认,不需要兜底时请账号管理员清空智能路由中的默认模型。 ### 锁定参数后上游返回 400,怎么办? **答:** 锁定的参数总是写入请求,上游不支持时会拒绝。打开日志的「原始报文」,对比「上游请求」与「上游响应」找到被拒绝的参数,再取消锁定或删除该参数。 --- # Auto 智能路由 来源: https://platform.lyrouter.com/ai_gateway/docs/auto 把请求的 `model` 写成 `lyrouter/auto`,网关会按这次请求的任务难度,在工作空间已开通的模型中挑选实际调用的模型。它适合允许模型变化的对话和编程助手等场景;对输出结构或模型行为要求严格的应用,请直接写模型 ID,或使用[虚拟模型](https://platform.lyrouter.com/ai_gateway/docs/presets)固定模型。 ## 调用 Auto 每个工作空间都可以直接调用 `lyrouter/auto`,`GET /v1/models` 也会列出这个名称。环境变量的设置见[完成第一次模型调用](https://platform.lyrouter.com/ai_gateway/docs/quickstart): ```bash curl "$LYROUTER_BASE_URL/v1/chat/completions" \ -H "Authorization: Bearer $LYROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"lyrouter/auto","messages":[{"role":"user","content":"用 Python 写一个快速排序函数"}]}' ``` - **支持的接口**:`/v1/chat/completions`、`/v1/messages` 和 `/v1/responses`。图像、视频和语音接口不支持 Auto,会返回 403 `Model is not available in the model plaza`,请改用具体的模型 ID。 - **首字延迟**:网关先识别任务类型,再转发请求,因此首字延迟会比直接调用模型略长。 ## 如何挑选模型 1. **识别任务类型**:网关根据最后一条用户消息判断意图,例如「开发调试」「内容转换」。 2. **映射到难度层**:每类意图对应一个难度层。 3. **排序候选**:该难度层的模型按平台设定的优先级排在前面,候选范围内的其他模型按模型 ID 的字母顺序排在后面。识别不出任务类型时,全部候选按字母顺序排列。 | 难度层 | 意图类别 | 优先选择的模型类型 | | --- | --- | --- | | 困难(`hard`) | 开发调试、分析计算、决策规划、流程自动化、审阅校验、治理合规 | 旗舰推理与编程模型,例如 `deepseek/deepseek-v4-pro`、`qwen/qwen3.7-max` | | 中等(`medium`) | 内容创作、总结归纳、抽取结构化、创意媒体、沟通与工单、学习练习 | 均衡的主力模型,例如 `anthropic/claude-sonnet-4.6`、`qwen/qwen3.7-plus` | | 简单(`easy`) | 咨询解答、内容转换 | 速度快、价格低的小模型,例如 `anthropic/claude-haiku-4.5`、`deepseek/deepseek-v4-flash` | - 优先级清单由平台维护,工作空间不能修改。清单中的模型只有在候选范围内、并且本工作空间已开通时才会被选中。 - 网关按排序依次尝试候选模型,一个模型的所有通道都失败后才进入下一个模型,最后是工作空间的[默认模型](https://platform.lyrouter.com/ai_gateway/docs/routing)。 - 同一模型的多个通道不按「多渠道选路策略」排序;BYOK 中的「优先使用此 Channel」「仅用此 BYOK」仍然生效。 ## 设置候选范围 当前账号管理员在 **智能路由** 页面「Auto 智能路由」一行点击 **高级设置**,在抽屉中设置候选范围,再点击 **保存 Auto 设置**。普通成员看不到这个页面,但可以直接调用 `lyrouter/auto`。 - **全部已开通模型**(默认):本工作空间在模型广场中已开通的全部模型都是候选。 - **指定模型范围**:勾选已开通的模型,或在搜索框输入模型 ID 或通配规则后按 Enter 录入,例如 `anthropic/*` 匹配所有以 `anthropic/` 开头的模型。手动录入项带「手动」标记。 (截图:Auto 高级设置中的候选范围决定可选模型;成本 / 质量权衡与请求覆盖开关目前不影响调用。) - **只在已开通模型里筛选**:录入本工作空间没有开通的模型 ID,它不会成为候选。范围内没有任何可用模型时,请求返回 503 `all routed candidates exhausted`;设置了默认模型时,改由默认模型回答。 - **建议只保留对话模型**:选中的模型不支持当前接口时(例如向量或图像模型被选到对话接口上),请求直接返回 400 `unsupported_model_api`,不会改用下一个候选。使用「全部已开通模型」且工作空间开通了非对话模型时,建议改为「指定模型范围」。 - **只影响 `lyrouter/auto`**:直接写模型 ID 的调用不受候选范围限制。要限制工作空间能调用哪些模型,请在模型广场停用模型,或使用[模型授权](https://platform.lyrouter.com/ai_gateway/docs/authorization)。 抽屉中的「成本 / 质量权衡」滑块和「允许请求覆盖空间路由设置」开关目前只保存、不影响调用:Auto 只按任务难度挑选模型,请求中也没有可以覆盖路由设置的参数。 ## 验证 调用后在[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)中打开这条记录,「路由追踪」中: - 「虚拟模型」显示 `lyrouter/auto`; - 「路由策略」显示 `intent:hard`、`intent:medium` 或 `intent:easy`,没有识别出任务类型时显示 `intent`; - 「模型(实际)」显示实际回答的模型。 建议用一组固定的测试任务比较实际模型、延迟和费用,再决定是否在生产中使用 Auto。 --- # 失败重试与备用模型 来源: https://platform.lyrouter.com/ai_gateway/docs/fallback 一次调用失败时,网关会在开始向客户端输出内容之前,自动改用下一个凭证、通道或模型,直到成功或候选用完。客户端只收到最终结果,所以一次请求成功,不代表过程中没有发生上游失败;每次实际尝试都记录在请求日志中。 ## 回退顺序 直接调用模型 ID 时,网关按以下顺序尝试: 1. 按「多渠道选路策略」排好序的第 1 个通道: - 先用该通道下的 BYOK 凭证,按你在 BYOK 中设置的顺序; - 再用该通道的平台凭证(工作空间在模型广场开通了该通道时)。 2. 第 2 个、第 3 个……通道,每个通道内同样先用 BYOK 凭证、再用平台凭证。 3. 最后是工作空间「默认模型」的通道(设置了默认模型、且与请求的模型不同时)。 - **哪些失败会换下一个**:上游返回任何非 2xx 状态码、连接上游失败或等待超时,都会换下一个凭证或通道。 - **已达限额的凭证先被跳过**:达到限额的凭证或通道在排序时就被移出。全部因限额被移出、也没有默认模型可以接手时,返回 429 `all upstream credentials for this model are rate limited`。 - **全部失败时**:返回最后一次尝试的上游状态码和响应体。 - **通道排序与 BYOK 偏好**:见[通道选择与路由策略](https://platform.lyrouter.com/ai_gateway/docs/routing)。「优先使用此 Channel」只把通道提到最前,失败后照常回退;「仅用此 BYOK」会限制回退范围,见下表。 ## 跨模型的备用模型 需要在一个模型失败后改用另一个模型时,有两种做法: - **[虚拟模型](https://platform.lyrouter.com/ai_gateway/docs/presets)**:按「默认模型 → 备用模型(按填写顺序)→ 工作空间默认模型」的顺序尝试,前一个模型的所有通道都失败后才进入下一个模型。 - **工作空间[默认模型](https://platform.lyrouter.com/ai_gateway/docs/routing)**:作为所有对话类请求的最后兜底。 [`lyrouter/auto`](https://platform.lyrouter.com/ai_gateway/docs/auto) 也按模型依次尝试,最后同样是工作空间默认模型。 (截图:在虚拟模型配置中确认主模型和备用模型;备用模型还需支持原请求的关键能力。) 备用模型必须支持原请求使用的接口、输入类型和工具调用。网关不会因为备用模型能力不足而跳过它;模型不支持请求的输入时,请求会直接返回 400,不再尝试后面的模型。 ## 不会回退的情况 | 情况 | 结果 | | --- | --- | | 流式请求(`stream: true`)已经开始输出后,上游中断或超时 | 不换通道。在流末尾补发一个错误事件后结束:Chat Completions 中 `error.code` 为 `stream_interrupted`,Responses 中是 `response.failed` 事件,见[超时与流式中断](https://platform.lyrouter.com/ai_gateway/docs/stream-errors) | | 通道开启了「仅用此 BYOK」 | 只尝试该通道的 BYOK 凭证,全部失败即结束,不使用平台凭证、其他通道或默认模型。通过虚拟模型或 `lyrouter/auto` 调用时,仍会尝试下一个候选模型,但不再回退到默认模型 | | 网关拒绝了这次尝试:余额不足(402)、安全围栏的模型策略禁止所选模型(403 `Request blocked by guardrail policy`)、所选模型不支持当前接口或输入(400 `unsupported_model_api`、`unsupported_model_input`) | 直接返回该错误,不换下一个候选 | | 上游以约定格式声明生成失败(`error.code` 为 `upstream_rejected` 或 `upstream_no_artifact`,常见于图像生成) | 直接返回,不换通道 | | 图像、视频和语音接口 | 只在同一模型的通道之间回退,不改用默认模型或其他模型 | ## 客户端的重试 网关已经在内部回退,客户端不需要对每个错误都自动重试: - 对 400、401、402、403 这类请求或配置问题,修正后再调用;同样的请求重试会得到同样的结果。 - 对 429 和 503,按[429:限流与配额](https://platform.lyrouter.com/ai_gateway/docs/rate-errors)和[模型不可用](https://platform.lyrouter.com/ai_gateway/docs/unavailable)的说明处理,使用有上限的退避重试。 - 同一个 API Key 在 60 秒内至少有 100 次请求、且 90% 以上失败时会被临时熔断,网关自己返回的 4xx 也计入失败。持续失败的程序不停重试,会很快把密钥熔断,多次熔断后会被永久封禁。 ## 定位一次回退 ### 怎么判断一次请求是否发生了回退? **答:** 在[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)中打开这条记录,查看「路由追踪」中的「上游调用尝试」,它记录每一次实际尝试的状态码、耗时和换下一个候选的原因;只尝试了一次的请求不显示这一块。「各阶段耗时」的「④ 上游调用」旁显示「N 次尝试」时,也说明发生过重试。「全部候选」只是排好序的候选列表,不能证明候选都被调用过。「路由追踪」只对账号管理员和工作空间管理员显示,其他成员可以把日志详情顶部的 Request ID 发给账号管理员协助核查。 (截图:日志详情的路由追踪显示实际模型、服务商和上游调用尝试。) ### 为什么回答来自请求之外的模型? **答:** 请求的模型全部失败,或在本工作空间未开通时,网关会改用工作空间的默认模型。日志的「模型(实际)」显示实际回答的模型。不需要这种兜底时,请账号管理员在智能路由中清空默认模型。 ### 流式输出已经开始,断开后可以直接重试吗? **答:** 网关不会在输出开始后换通道。收到 `stream_interrupted` 错误事件或 `response.failed` 事件,或没有收到结束标记(`data: [DONE]`、`message_stop` 或 `response.completed`)时,应把这次调用视为失败。重新调用可能重复生成内容或再次触发工具,应用需要自行处理取消、重试和去重,详见[超时与流式中断](https://platform.lyrouter.com/ai_gateway/docs/stream-errors)。 --- # 查看实际路由 来源: https://platform.lyrouter.com/ai_gateway/docs/route-log 一次调用最终由哪个模型、哪个服务商回答,中途是否换过通道、为什么换,都记录在日志详情的「路由追踪」中。当前账号管理员和工作空间管理员在 **日志分析** 中打开一条日志即可查看。调整[智能路由](https://platform.lyrouter.com/ai_gateway/docs/routing)、[虚拟模型](https://platform.lyrouter.com/ai_gateway/docs/presets)或 [BYOK](https://platform.lyrouter.com/ai_gateway/docs/byok) 后,用它确认设置是否按预期生效。 ## 先看基本信息 日志详情顶部的基本信息对所有能看到这条日志的成员可见,可以先回答「最终是谁回答的」: | 字段 | 用来判断 | | --- | --- | | 「模型(请求)」 | 请求中写的模型,例如 `deepseek/deepseek-v4-flash`、`@vmodel/<名称>` 或 `lyrouter/auto` | | 「模型(实际)」 | 实际回答的模型。与请求的模型不同时,通常是虚拟模型或 `lyrouter/auto` 选择了具体模型,或者请求的模型全部失败、由工作空间默认模型兜底 | | 「服务商」 | 实际调用的服务商。日志列表的「服务商」列在使用 BYOK 凭证时带「BYOK」标记 | ## 路由追踪的各部分 在日志详情的「概览」中,「路由追踪」按时间顺序列出以下几部分: | 部分 | 显示内容 | 说明 | | --- | --- | --- | | 「请求进入」 | 日志时间、API 路径和请求的模型 | 确认是你要找的那次请求 | | 「路由选择」 | 「路由策略」、通过虚拟模型调用时的「虚拟模型」、使用 BYOK 凭证时的「BYOK:名称」 | 「路由策略」的取值见[通道选择与路由策略](https://platform.lyrouter.com/ai_gateway/docs/routing#多渠道选路策略) | | 「命中上游」 | 服务商 · 模型,以及来源标签:「平台」是平台目录中的通道,「用户」是工作空间自定义的服务商或模型映射 | 没有记录到候选时显示「无路由候选」 | | 「全部候选 N」 | 按选路策略排好序的候选,选中的标「已选中」;候选多于命中时才出现,需要展开 | 只是候选顺序,实际调用以「上游调用尝试」为准 | | 「上游调用尝试」 | 每次实际尝试:「第 N 次」、服务商、状态码(没有状态码时显示「超时」「连接失败」「网络错误」等)、耗时,以及换下一个候选的原因或终止原因 | 只在一次请求发生了两次及以上尝试时出现 | | 「最终结果」 | 返回给客户端的状态码,以及完成原因(如 `stop`)或失败原因代码(如 `upstream_timeout`) | 与日志列表的「状态」一致 | 「上游调用尝试」中常见的写法: - 「因 HTTP 503 继续至第 2 次」:第 1 次尝试返回 503,网关改用下一个候选。连接失败或等待超时的尝试没有状态码,状态显示为「连接失败」「超时」等。 - 「终止:调用成功」:这次尝试成功,请求结束。 - 「终止:状态码不在回退策略内」:这次失败属于不换通道的情况,例如余额不足或安全围栏拦截,网关直接返回。 - 最后一次尝试之后没有「继续至第 N 次」:候选已经用完,「最终结果」就是返回给客户端的结果。 - 标题旁的「已记录 X/Y 次」是已记录的尝试数和实际尝试数。两者不等时会提示「仅记录了部分尝试(X/Y),以下信息可能不完整。」;显示「尝试记录暂时无法加载,主请求日志不受影响。」时,稍后重新打开详情。 (截图:日志详情顶部是基本信息,「概览」中的「路由追踪」显示请求进入、路由选择和最终结果。) ## 各阶段耗时与按次报文 - **各阶段耗时**:「④ 上游调用」旁显示「· N 次尝试,最长 X」时,说明这次请求重试过上游,显示的耗时是各次尝试之和,「最长」是耗时最长的那一次。用它判断时间是否花在失败的尝试上。 - **原始报文**:发生多次尝试时,「② 上游请求」和「③ 上游响应」按每次尝试分组,标题为「<服务商> 的上游请求 · 第 N 次」。为避免重复存储,较早的尝试只保留请求的「目标」「方法」「Content-Type」「正文大小(字节)」「正文 SHA-256」,完整的上游请求只显示最后一次。「③ 上游响应」逐次列出,内容过长时标注「记录内容已按大小上限截断。」 ## 与路由设置的对应关系 | 你在日志中看到的 | 对应的设置 | | --- | --- | | 「路由策略」和候选顺序 | 直接调用模型 ID 时是工作空间智能路由的「多渠道选路策略」;通过虚拟模型调用时是该虚拟模型的「Channel 排序策略」,见[通道选择与路由策略](https://platform.lyrouter.com/ai_gateway/docs/routing)和[虚拟模型](https://platform.lyrouter.com/ai_gateway/docs/presets) | | 某个通道总是排在最前,或只出现 BYOK 凭证 | BYOK 使用配置中的「优先使用此 Channel」或「仅用此 BYOK」,见[通道选择与路由策略](https://platform.lyrouter.com/ai_gateway/docs/routing#byok-通道规则) | | 「上游调用尝试」中换了通道或模型 | 失败后的回退规则,见[失败重试与备用模型](https://platform.lyrouter.com/ai_gateway/docs/fallback) | | 「模型(实际)」是工作空间默认模型 | 智能路由中的「默认模型」兜底 | ## 常见问题 ### 「全部候选」里有多个服务商,是否都被调用过? **答:** 不是。「全部候选」只是排好序的候选列表,网关按顺序尝试,成功即停止。实际调用过哪些候选,以「上游调用尝试」为准;没有这一部分时,说明只调用了「命中上游」中的那一个。 ### 为什么有的日志没有「上游调用尝试」? **答:** 只调用了一次上游的请求不显示这一部分。此外,日志超过留存期后,候选和尝试记录与正文一样不再显示,见[数据保留、导出与删除](https://platform.lyrouter.com/ai_gateway/docs/retention)。 ### 怎样确认这次调用用的是我的 BYOK 凭证? **答:** 看「路由选择」中是否有「BYOK:名称」,日志列表的「服务商」列也会带「BYOK」标记。凭证没有被使用时,检查 BYOK 的调用范围和模型映射,见 [BYOK](https://platform.lyrouter.com/ai_gateway/docs/byok)。 ### 能只按 HTTP 状态码判断错误来自网关还是上游吗? **答:** 不建议。同样是 503,可能是网关找不到可用通道,也可能是上游服务商返回的。请看日志列表的「状态说明」:来源「网关」表示网关拒绝或连接上游失败,来源「上游」表示服务商返回了错误,详见[通过日志定位调用问题](https://platform.lyrouter.com/ai_gateway/docs/logs)。 ### 普通成员如何核查路由? **答:** 普通成员的日志详情不显示「路由追踪」,但可以看到「模型(实际)」「服务商」和「原始报文」。需要核查路由时,把日志详情顶部的 Request ID、调用时间和模型发给当前账号管理员或工作空间管理员。 --- # 平台模型与 BYOK 如何选择 来源: https://platform.lyrouter.com/ai_gateway/docs/byok-choice LYRouter 的模型有两种来源:平台来源使用 LYRouter 提供的服务商通道和凭证,按用量从 Credits 余额扣费;BYOK(Bring Your Own Key,自带密钥)使用你在服务商处的 API Key,上游费用由服务商向你收取,LYRouter 对每次成功的 BYOK 调用收取一笔固定服务费。两种来源用同一个 LYRouter API Key、同一个模型 ID 调用,可以同时存在,由网关按路由规则选择。 ## 两种来源对比 | 比较项 | 平台来源 | BYOK | | --- | --- | --- | | 需要准备 | Credits 余额 | 服务商账号和 API Key(按量 API 或 Coding Plan) | | 在哪里配置 | **模型广场** 开通模型 | **自带密钥(BYOK)** 添加通道 | | 上游费用 | 按平台价从 Credits 扣除 | 服务商按你的账户收取 | | LYRouter 收费 | 按用量扣 Credits | 每次成功调用扣一笔固定的服务费 | | 支持的模型 | 平台提供的全部模型,包括图像、视频、语音和向量模型 | 只支持输出为文本的对话模型 | | 可接入的服务商 | 平台已上架的服务商 | 「模型官方服务商」列表中的服务商,以及任意自定义服务商 | | 额度与并发 | 平台通道的额度 | 你在服务商处的账户额度和并发 | | 模型广场「接入来源」 | 「三方服务」 | 「BYOK」 | (截图:模型广场的「接入来源」可以按「三方服务」或「BYOK」筛选模型来源。) ## 什么时候用哪种 适合直接使用平台来源: - 不想管理服务商账号,开通模型即可调用。 - 需要图像、视频、语音或向量模型。 - 希望所有费用都用 Credits 统一结算。 适合接入 BYOK: - 已有服务商的按量额度、折扣或 Coding Plan 订阅,希望继续使用。 - 需要平台没有提供的服务商,或要接入企业自建代理、聚合平台,用「自定义服务商」接入。 - 有合规要求,调用必须经过指定的服务商账号,配合「仅用此 BYOK」使用。 - 需要更高并发,可以在一个 BYOK 下添加多个不同账户的 API Key。 ## 两种来源如何一起工作 - **同一个模型 ID**:客户端不需要区分来源。BYOK 配置生效后,模型在模型广场自动获得 BYOK 来源并默认开通;可以在模型详情页的「服务商与价格」中按来源开关。 - **同一通道内 BYOK 在前**:内置服务商的 BYOK 与平台来源共用该服务商的通道。网关进入一个通道后,先按你设置的顺序尝试 BYOK 凭证,再尝试平台凭证。自定义服务商是独立的通道,与其他通道一起按多渠道选路策略排序,见[通道选择与路由策略](https://platform.lyrouter.com/ai_gateway/docs/routing)。 - **固定使用 BYOK**:在 BYOK 的「使用配置」中开启「优先使用此 Channel」,让所选模型先走这个通道;开启「仅用此 BYOK」则不再使用平台凭证、其他通道或默认模型,模型广场中该通道的平台来源显示「仅允许 BYOK」。 - **余额仍然需要**:BYOK 调用前网关会从余额中预留服务费,余额不足时返回 402 `insufficient credit balance`,不会改用平台来源,见[BYOK 费用与凭证管理](https://platform.lyrouter.com/ai_gateway/docs/byok-cost)。 ## 开始接入 BYOK 1. 准备服务商的 API Key。服务商同时提供按量 API 和 Coding Plan 时,先确认要接入哪一种,见[API 按量服务与 Coding Plan](https://platform.lyrouter.com/ai_gateway/docs/coding-plan)。 2. 由当前账号管理员在工作空间的 **自带密钥(BYOK)** 页面接入,步骤见[接入 BYOK 与测试连接](https://platform.lyrouter.com/ai_gateway/docs/byok)。普通成员看不到这个页面,用自己的 API Key 即可调用账号管理员配置好的 BYOK 来源。 3. 自定义服务商需要把上游模型对应到系统模型,见[模型映射与来源配置](https://platform.lyrouter.com/ai_gateway/docs/mapping)。 只能使用服务商发放的 API Key。网页版账号的登录态或 Cookie 不能作为 BYOK 凭证。 (截图:接入 BYOK 的第一步:选择服务商和计费方式。) ## 常见问题 ### 同一个模型既有平台来源又有 BYOK,调用时先用哪个? **答:** 内置服务商的同一个通道内先用 BYOK 凭证,再用平台凭证;不同通道之间按多渠道选路策略排序。需要固定先走 BYOK 时,在 BYOK 中开启「优先使用此 Channel」。调用后在[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)中查看,「服务商」旁带「BYOK」标记的就是走了 BYOK。 ### 我要的服务商不在「模型官方服务商」列表中,怎么接入? **答:** 选择「自定义服务商」,填写服务商的 Base URL 和接口类型。OpenAI、Anthropic 等服务商也通过这种方式接入。上游模型必须对应到平台模型目录中已有的文本对话模型,见[模型映射与来源配置](https://platform.lyrouter.com/ai_gateway/docs/mapping)。 ### 图像生成模型能用 BYOK 吗? **答:** 不能。BYOK 只支持输出为文本的对话模型(可以接受图片输入),图像、视频、语音和向量模型请使用平台来源。 --- # 接入供应商与测试连接 来源: https://platform.lyrouter.com/ai_gateway/docs/byok 当前账号管理员在工作空间的 **自带密钥(BYOK)** 页面,把自己在服务商处的 API Key 接入为一个 BYOK 通道。编辑器分「服务商与计费方式」「接入凭证」「模型与费用」「使用配置」四步,保存前用 **测试连接** 确认每个凭证都能访问服务商。保存后几秒内同步到网关,工作空间内所有 API Key 都可以通过它调用所选模型。 ## 开始之前 - **权限**:只有当前账号管理员能看到和管理这个页面;普通成员看不到菜单,但可以用自己的 API Key 调用已配置好的 BYOK 来源。 - **准备**:服务商的 API Key;接入自定义服务商时,还需要 Base URL 和接口类型。接入 Coding Plan 前先阅读[API 按量服务与 Coding Plan](https://platform.lyrouter.com/ai_gateway/docs/coding-plan)。 - **数量**:同一工作空间中,每个服务商通道只能接入一个 BYOK,已接入的服务商卡片会变灰;一个 BYOK 下可以添加多个 API Key。个人版账号最多创建 3 个 BYOK(所有工作空间合计)。 点击 **添加自带密钥(BYOK)** 打开编辑器。完成一步后点 **下一步**,已完成的步骤可以随时点开回看。 ## 第 1 步:服务商与计费方式 | 选项 | 说明 | | --- | --- | | 「模型官方服务商」 | 平台认定的官方模型服务商,地址和可选模型由平台维护。OpenAI、Anthropic 等不在列表中的服务商,用自定义服务商接入 | | 「自定义服务商」 | 接入聚合平台、企业代理或列表外的服务商,填写「服务商名称」「接口类型」「Base URL」。创建过的自定义服务商会作为卡片保留在列表中 | | 计费方式 | 「API 按量计费」或「订阅计费」,区别见[API 按量服务与 Coding Plan](https://platform.lyrouter.com/ai_gateway/docs/coding-plan) | | 「当前接入配置」 | 显示所选计费方式对应的 Base URL。内置服务商的地址只读,自定义服务商可以修改 | 自定义服务商的「接口类型」决定 Base URL 的写法: | 接口类型 | Base URL 示例 | | --- | --- | | OpenAI 兼容 | `https://provider.example/v1` | | Anthropic 原生 | `https://provider.example/v1`(网关会在后面拼接 `/messages`,所以要带 `/v1`;编辑器的占位示例没有 `/v1`,以本表为准) | | OpenAI Responses API | `https://provider.example/v1` | (截图:第 1 步选择服务商和计费方式,并核对「当前接入配置」中的 Base URL。) ## 第 2 步:接入凭证 每行是一个 API Key,点 **添加其他账户凭证** 增加一行: | 列 | 说明 | | --- | --- | | 「优先级」 | 1、2、3…,数字小的先尝试 | | 「启用」 | 关闭后该凭证不参与调用 | | 「凭证备注」 | 便于识别,例如「生产主凭证」 | | 「API Key」 | 服务商密钥。已保存的凭证显示「留空保持原密钥」,不回显明文 | | 「连接检测」 | 点 **检测** 单独测试这一行 | | 「用量与费用限额」 | 仅「API 按量计费」显示,见[BYOK 费用与凭证管理](https://platform.lyrouter.com/ai_gateway/docs/byok-cost) | | 「顺序」 | 用上移、下移调整优先级,保存后生效 | - 网关在同一通道内按优先级尝试凭证,前一个失败或已达限额时换下一个,规则见[失败重试与备用模型](https://platform.lyrouter.com/ai_gateway/docs/fallback)。 - 多数服务商按上游账户限制并发,同一账户多建几个 Key 不会提高总并发;需要更高并发时,添加不同账户生成的 Key。 - 新添加的凭证保存后均为启用状态。需要先停用的,保存后再编辑关闭「启用」。 (截图:第 2 步按优先级管理凭证,已保存的密钥留空即保持不变。) ## 第 3 步:模型与费用 - **内置服务商**:表格列出平台为该通道发布的模型,标注「系统内置,不需要映射」。新建时默认全选,取消勾选不需要的模型。「API 按量计费」时显示输入、输出刊例价和「Channel 价格折扣(%)」(100 表示原价);刊例价显示「待补充」的模型不能保存,请取消勾选。 - **自定义服务商**:点 **获取服务商模型列表**,把上游模型对应到系统模型,见[模型映射与来源配置](https://platform.lyrouter.com/ai_gateway/docs/mapping)。 - **订阅计费**:填写「订阅金额」「币种」「周期」「开始日期」。 刊例价乘以折扣就是该通道在「最低价」排序中的价格,也用于估算 BYOK 费用。 ## 第 4 步:使用配置 | 开关 | 效果 | | --- | --- | | 「优先使用此 Channel」 | 所选模型优先走这个通道,失败后照常回退到其他通道和默认模型 | | 「仅用此 BYOK」 | 所选模型只使用这个通道的 BYOK 凭证,不使用平台凭证、其他通道或默认模型,全部失败即结束。通过虚拟模型或 `lyrouter/auto` 调用时,被限定的模型失败后仍会尝试下一个候选模型,但整个请求不再回退到默认模型。开启后「优先使用此 Channel」随之开启并置灰,模型广场中该通道的平台来源显示「仅允许 BYOK」 | | 「请求头适配」 | 按平台维护的规则调整发往该服务商的请求头,上游对请求头有特殊要求时开启 | 这两种偏好按模型生效:同一工作空间里,一个模型只能由一个 BYOK 设置「优先」或「仅用」。它们优先于多渠道选路策略,见[通道选择与路由策略](https://platform.lyrouter.com/ai_gateway/docs/routing)。 (截图:第 4 步区分优先使用此 Channel 与仅用此 BYOK。) ## 测试连接 - 底部 **测试连接** 测试全部凭证,「连接检测」列的 **检测** 只测一行。 - 测试用该凭证读取服务商的模型列表,内置服务商使用「当前接入配置」中的地址。每行显示「连接正常 · N ms」或「鉴权失败」,底部汇总「测试完成:N/M 个凭证可用」。 - 「鉴权失败」包含所有失败原因:Key 无效、地址或接口类型不对、网络不通,或服务商没有模型列表接口,请逐项核对。 - 测试只用于提示,不阻止保存。有未测试或测试失败的凭证时,需要在「使用配置」中勾选「我已了解连接测试失败或被跳过,仍确认保存此配置」。编辑已有 BYOK 时,本次没有重新测试的凭证也算未测试。 ## 保存与验证 点击 **保存配置**,提示「自带密钥(BYOK)配置「名称」已保存,正在后台健康检查…」后回到列表。新增的凭证会自动检测一次,结果显示在「状态」列。所选模型会在模型广场获得 BYOK 来源并默认开通。 用该工作空间的 API Key 调用一次所选模型,环境变量的设置见[完成第一次模型调用](https://platform.lyrouter.com/ai_gateway/docs/quickstart): ```bash curl "$LYROUTER_BASE_URL/v1/chat/completions" \ -H "Authorization: Bearer $LYROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"deepseek/deepseek-v4-pro","messages":[{"role":"user","content":"ping"}]}' ``` 在[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)中,这次调用的「服务商」旁带「BYOK」标记;日志详情「路由追踪」的「命中上游」中,来源显示「用户」。 ## 保存失败的常见提示 | 提示 | 处理 | | --- | --- | | 以下模型暂无运营刊例价,无法保存:… | 取消勾选列出的模型 | | 请完成自定义服务商模型映射 | 为每个已选上游模型选择系统模型 | | `该 Channel 已绑定 BYOK 凭证组;同一 Provider 的其他 Channel 仍可独立绑定` | 本工作空间已接入过这个服务商,在列表中编辑原有 BYOK | | `BYOK group limit reached (max 3 for personal tier)` | 个人版 BYOK 数量已满,删除不用的 BYOK | | `channel_policy_conflict` | 另一个 BYOK 已对相同模型开启「优先」或「仅用」,先关闭其中一个 | | `routing policy requires selected models and an active BYOK credential` | 「仅用此 BYOK」需要至少一个启用的凭证 | | `model is unavailable for text chat completions` | 映射的系统模型不是文本对话模型,见[模型映射与来源配置](https://platform.lyrouter.com/ai_gateway/docs/mapping) | | `the selected model has no active operations pricing strategy: <模型>` | 该模型没有可用于 BYOK 按量计费的价格,取消选择或联系支持 | ## 管理已有 BYOK 列表每行的操作按钮依次是编辑、启用 / 停用、删除。停用后立即不再接收新请求,进行中的请求不受影响,可以随时重新启用;删除需要输入服务商名称确认并点击 **永久删除**,已产生的用量和日志保留。替换密钥、调整顺序和设置限额,见[BYOK 费用与凭证管理](https://platform.lyrouter.com/ai_gateway/docs/byok-cost)。 --- # 模型映射与来源配置 来源: https://platform.lyrouter.com/ai_gateway/docs/mapping 客户端始终用系统模型 ID(例如 `deepseek/deepseek-v4-pro`)调用,模型映射决定网关把它换成哪个上游模型名发给服务商。内置服务商的映射由平台维护,在 BYOK 的「模型与费用」步骤中勾选模型即可;自定义服务商需要先读取上游模型列表,再把每个上游模型对应到一个系统模型。保存后,这些模型在模型广场获得 BYOK 来源。 ## 系统模型 ID 与上游模型名 | 名称 | 示例 | 用在哪里 | | --- | --- | --- | | 系统模型 ID | `deepseek/deepseek-v4-pro` | 请求中的 `model`、模型广场、请求日志、虚拟模型、安全围栏 | | 上游模型名 | `deepseek-v4-pro`、火山方舟的 `ep-*` 接入点 ID | 只出现在网关发给服务商的请求中 | 请求中的 `model` 必须写系统模型 ID。直接写上游模型名(例如 `ep-*`)会被当作未开通的模型,返回 403 `Model is not available in the model plaza`;工作空间设置了默认模型时,会改由默认模型回答。可用的系统模型 ID 用 [`GET /v1/models`](https://platform.lyrouter.com/ai_gateway/docs/models) 查询。 ## 内置服务商:勾选模型 「模型与费用」表格列出平台为该服务商通道发布的模型: - 「系统内置模型」列显示系统模型 ID 和模型名称,并注明「系统内置,不需要映射」。 - 勾选要使用的模型;「API 按量计费」时可为每个模型设置「Channel 价格折扣(%)」。 - 标记「目录已下架」的是之前选过、平台已不再发布的模型,可以取消勾选。 - 表格显示「该服务商没有符合本期发布范围的目录模型」时,这个通道暂时没有可接入的模型。 (截图:内置模型显示系统模型 ID、刊例价和 Channel 折扣,不需要手动映射。) ## 自定义服务商:映射上游模型 1. 在「接入凭证」中至少填写一个 API Key。 2. 在「模型与费用」点击 **获取服务商模型列表**。控制台用第一个填写了 Key 的凭证(没有时用已保存的凭证)读取上游模型列表,成功后提示「已获取 N 个上游模型」。新建自定义服务商时,如果 Base URL 缺少 `/v1`、补上后才读取成功,控制台会自动把 Base URL 改为补全后的地址。 3. 在「上游服务商模型」中选择要接入的模型,只能从读取到的列表中选择。 4. 为每个上游模型选择「系统内建统一模型名称」。名称一致时会自动预选,版本号中的 `.` 和 `-` 视为相同,例如 `claude-opus-4-6` 会匹配 `anthropic/claude-opus-4.6`。下拉只列出平台模型目录中的模型,不能输入新名称。 5. 「API 按量计费」时,每行显示该系统模型的「运营平台刊例价」,可以设置「Channel 价格折扣(%)」。 ## 映射规则 - **只限文本对话模型**:系统模型必须是输出为文本的对话模型,可以接受图片输入。图像、视频、语音和向量模型不能通过 BYOK 接入,保存时提示 `model is unavailable for text chat completions`。 - **一一对应**:一个 BYOK 内,每个系统模型只能映射一次,每个上游模型名也只能使用一次,重复时提示 `invalid BYOK billing configuration: duplicate model` 或 `invalid BYOK billing configuration: duplicate upstream model name`。 - **按量计费需要价格**:「API 按量计费」时,映射的系统模型必须有平台发布的价格,否则提示 `the selected model has no active operations pricing strategy: <模型>`。折扣以这个价格为基准。 - **多个来源并存**:同一个系统模型可以同时由平台来源和多个 BYOK 提供,网关按[通道选择与路由策略](https://platform.lyrouter.com/ai_gateway/docs/routing)在它们之间选择。 ## 在模型广场核对来源 - 保存后,映射的模型自动获得 BYOK 来源并默认开通,出现在模型广场的「专属可用模型」中。在左侧「接入来源」中选择「BYOK」,只看 BYOK 来源。 - 模型详情页的「服务商与价格」逐个列出来源及状态。关闭某个 BYOK 来源后,网关不再通过它调用该模型。 - 「需接入」页签中的模型在本工作空间还没有可用来源。在模型详情页点击 **接入 BYOK**,会打开新建 BYOK 的编辑器。 - 在 BYOK 中取消勾选或删除映射后,对应的 BYOK 来源随之移除。 ## 验证映射 用该工作空间的 API Key 调用系统模型 ID,在[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)中打开这条记录:「模型(实际)」显示系统模型 ID,「服务商」旁带「BYOK」标记。需要核对实际发给服务商的模型名时,查看日志详情「原始报文」中的上游请求,其中的 `model` 是上游模型名。 ## 常见问题 ### 点击「获取服务商模型列表」后提示「获取服务商模型失败」,怎么办? **答:** 依次核对 Base URL、「接口类型」和 API Key。OpenAI 兼容、Responses API 和 Anthropic 原生的地址通常都以 `/v1` 结尾;网关会在 Anthropic 原生地址后面拼接 `/messages`,少了 `/v1` 时测试连接可能通过,真实调用却返回 404。服务商需要提供模型列表接口,控制台只能从读到的列表中选择上游模型。 ### 下拉中找不到想要的系统模型,怎么办? **答:** 下拉只列出平台模型目录中的模型。目录中没有的模型暂时不能通过 BYOK 接入,请联系支持说明服务商和模型名称;不要把上游模型名当作系统模型 ID 使用。 ### 调用后「模型(实际)」不是我映射的模型,为什么? **答:** 这个模型的 BYOK 凭证都失败后,网关按回退规则改用了其他通道或默认模型,见[失败重试与备用模型](https://platform.lyrouter.com/ai_gateway/docs/fallback)。在日志详情的「路由追踪」中查看每次尝试的结果;需要只用这个 BYOK 时,在其「使用配置」中开启「仅用此 BYOK」。 --- # API 按量服务与 Coding Plan 来源: https://platform.lyrouter.com/ai_gateway/docs/coding-plan 很多服务商同时提供两种 API 接入:按 Token 用量付费的 API 服务,和按月订阅的 Coding Plan(编程套餐)。两者的地址、API Key、可用模型和额度规则通常不同,接入前先确认手里的是哪一种。在 BYOK 中,按量服务选「API 按量计费」,Coding Plan 选「订阅计费」;两种都用同一个 LYRouter API Key 调用,平台对每次成功调用收取相同的服务费。 ## 两种服务的区别 下表是常见情况,具体以服务商的说明为准: | 比较项 | API 按量服务 | Coding Plan | | --- | --- | --- | | 服务商收费 | 按实际 Token 用量 | 固定订阅费,按月、季或年 | | 额度 | 账户余额和速率限制 | 套餐内按时间窗口计算的请求或 Token 额度,用完后上游返回 429 | | 地址与 Key | API 地址和 API Key | 常有单独的地址,Key 也可能与 API Key 不通用 | | 可用模型 | 服务商的 API 模型 | 套餐包含的模型 | | 使用范围 | 任意应用 | 部分服务商限定在编程工具中使用 | | BYOK 计费方式 | 「API 按量计费」 | 「订阅计费」 | ## 两种计费方式在 BYOK 中的差别 在 BYOK 编辑器第一步的「服务商与计费方式」中选择: | | 「API 按量计费」 | 「订阅计费」 | | --- | --- | --- | | 界面说明 | 「使用运营平台发布的服务商原价,并按每个模型设置折扣。」 | 「记录固定订阅金额与周期,Token 用量只做统计。」 | | 「模型与费用」 | 每个模型显示刊例价,可设置「Channel 价格折扣(%)」;没有刊例价的模型不能保存 | 填写「订阅金额」「币种」「周期」(月、季度、年)「开始日期」,不需要模型价格 | | 凭证限额 | 可设置「用量与费用限额」 | 不显示 | | 费用统计 | 按刊例价 × 折扣估算每次调用的服务商成本,计入「BYOK Token 费用」 | 订阅金额按月折算计入「BYOK 订阅费用」,单次调用不计成本 | | 平台服务费 | 每次成功调用收取 | 每次成功调用收取 | ## 核对接入地址 - **内置服务商**:选好计费方式后,查看「当前接入配置」中的 Base URL。地址由平台维护,不能修改,界面提示「内置服务商地址由计费方式对应的接入配置决定;未配置订阅地址时沿用 API 地址。」 - **Coding Plan 有单独地址时**:如果「订阅计费」下显示的仍是 API 地址,而服务商为 Coding Plan 提供了单独的地址,改用「自定义服务商」接入:填写 Coding Plan 文档中的地址,选择对应的「接口类型」,计费方式选「订阅计费」,再把上游模型映射到系统模型,见[模型映射与来源配置](https://platform.lyrouter.com/ai_gateway/docs/mapping)。 - **同时使用两种**:同一工作空间里,一个内置服务商只能接入一个 BYOK。要同时使用同一服务商的按量 Key 和 Coding Plan Key,一个用内置服务商接入,另一个用自定义服务商接入。 - **先测试再上线**:保存前用 **测试连接** 确认 Key 与地址匹配;保存后发送一次真实调用,在[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)中确认调用成功,且「服务商」旁带「BYOK」标记。 (截图:在「服务商与计费方式」中区分 API 按量计费与订阅计费,并核对当前接入配置中的地址。) ## 接入 Coding Plan 的建议 - **只选套餐包含的模型**:在「模型与费用」中取消勾选套餐不支持的模型,避免调用到套餐外的模型时被上游拒绝。 - **额度用完后的去向**:套餐额度用完后上游返回 429,网关会换下一个凭证或通道。希望这时由平台来源接手,使用「优先使用此 Channel」而不要开启「仅用此 BYOK」;接手的调用按平台价扣 Credits。开启「仅用此 BYOK」时,凭证全部失败后请求直接结束,客户端收到上游返回的 429。 - **多个套餐账户**:在「接入凭证」中添加多个账户的 Key,网关按优先级依次使用。 - **续费或升级后**:编辑 BYOK 更新「订阅金额」和「周期」,保存后按新金额计入费用统计。 - **使用条款**:确认服务商允许在你的使用场景中调用该套餐,例如通过网关或在编程工具以外的应用中使用。 ## 费用核对 - 「订阅计费」的订阅金额按月折算:季度金额除以 3,年度金额除以 12,开始日期所在月按生效天数比例计算。折算结果计入[用量分析](https://platform.lyrouter.com/ai_gateway/docs/analytics)的「BYOK 订阅费用」,只统计在工作空间总额中,不分摊到成员或 API Key。 - 「订阅计费」的凭证在 BYOK 列表中的费用列显示「统计待接入」,Token 用量照常统计。 - 两种计费方式都要另付平台服务费,余额不足时 BYOK 调用返回 402,见[BYOK 费用与凭证管理](https://platform.lyrouter.com/ai_gateway/docs/byok-cost)。 - 服务商实际收取的费用以服务商账单为准。 ## 常见问题 ### 测试连接显示「鉴权失败」,Key 是刚复制的,为什么? **答:** 常见原因是 Key 与地址不匹配,例如把 Coding Plan 的 Key 用在了 API 地址上。核对「当前接入配置」中的 Base URL 是否是该 Key 对应的地址;不一致时按上文改用自定义服务商接入。 ### 白天调用正常,一段时间后开始返回 429,是 LYRouter 限流吗? **答:** 在[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)的「状态说明」中查看来源。来源为「上游」时,是服务商返回的 429,通常是套餐在当前时间窗口内的额度已用完,等窗口重置或添加其他账户的 Key。来源为「网关」时,按[429:限流与配额](https://platform.lyrouter.com/ai_gateway/docs/rate-errors)排查。 --- # BYOK 费用与凭证管理 来源: https://platform.lyrouter.com/ai_gateway/docs/byok-cost 使用 BYOK 有两笔费用:服务商按你的账户收取上游费用,LYRouter 对每次成功的 BYOK 调用从 Credits 余额扣一笔固定服务费,实际扣除额见「消费明细」。BYOK 列表按凭证统计服务商成本估算和 Token 用量;凭证的替换、启停、排序和限额都在 BYOK 编辑器的「接入凭证」步骤中管理。 ## 费用构成 | 费用 | 收取方 | 在哪里查看 | | --- | --- | --- | | 上游 Token 费用(「API 按量计费」) | 服务商 | 服务商账单;LYRouter 的估算见 BYOK 列表和[用量分析](https://platform.lyrouter.com/ai_gateway/docs/analytics)的「BYOK Token 费用」 | | Coding Plan 订阅费(「订阅计费」) | 服务商 | 用量分析的「BYOK 订阅费用」,按 BYOK 中填写的金额折算 | | 平台服务费 | LYRouter,从 Credits 余额扣除 | **订阅充值** 的「消费明细」 | ## 平台服务费 - **何时收取**:请求最终由 BYOK 凭证成功完成时收取。BYOK 调用失败不收;BYOK 失败后改由平台凭证完成时,按平台价扣费,不收服务费。 - **适用范围**:「API 按量计费」和「订阅计费」、内置服务商和自定义服务商都收取。 - **余额要求**:网关在发出第一个 BYOK 请求前,先从余额中预留这笔服务费。余额不足以支付时返回 402 `insufficient credit balance`(`error.code` 为 `insufficient_credit_balance`),请求不会发往服务商,也不会改用平台来源;账户从未充值时 `error.code` 为 `balance_missing`。在 **订阅充值** 页面充值后恢复。 - **订阅到期**:账户订阅过期且超过宽限期后,包括 BYOK 在内的所有调用返回 402 `subscription expired; renew to continue`,见[模型不可用](https://platform.lyrouter.com/ai_gateway/docs/unavailable)。 ## BYOK 列表中的用量与费用 | 位置 | 显示内容 | | --- | --- | | 「累计费用」「累计 Token」卡片 | 所有 BYOK 凭证的累计合计 | | 服务商通道行 | 「全部费用」「全部 Token」为该通道全部凭证之和;「本月费用」「本月 Token」显示「—」,卡片旁提示「月度统计待接入」 | | 凭证行 | 「本月费用」「全部费用」「本月 Token」「全部 Token」显示「已用 / 上限」和百分比,未设上限时显示「不限」 | - **费用怎么算**:按「模型与费用」中的刊例价 × 折扣,以及输入(缓存未命中)、输入(缓存命中)、输出、显式缓存创建四类 Token 估算的服务商成本,不含平台服务费和订阅费。Token 数为四类之和。 - **「统计待接入」**:该凭证还没有可统计的调用,或其中有调用的费用无法计算,例如「订阅计费」的凭证。 - **「部分数据加载失败」**:部分通道的凭证统计没有取到,合计显示「—」,展开该通道点击 **重试**。 - **刷新方式**:数据在打开或刷新页面时读取,不是实时的。 (截图:BYOK 列表按服务商通道和凭证展示费用、Token 用量与状态。) ## 管理凭证 在列表中点击编辑按钮,打开「接入凭证」步骤: | 操作 | 做法 | | --- | --- | | 替换密钥 | 在「API Key」中输入新密钥。留空表示保留原密钥(提示「留空保持原密钥」)。已保存的密钥只显示脱敏前缀,例如 `sk-demo****`,无法查看明文 | | 停用 / 启用 | 切换「启用」开关。新添加的凭证保存后均为启用状态,需要停用的,保存后再编辑关闭 | | 调整顺序 | 在「顺序」列上移、下移,数字小的先尝试 | | 增加凭证 | 点击 **添加其他账户凭证** | | 删除凭证 | 点击行末删除按钮,至少保留一个;要暂停整个通道,在列表中点击停用按钮 | 所有修改在点击 **保存配置** 后生效,几秒内同步到网关。替换密钥后用 **检测** 或 **测试连接** 确认新密钥可用。排障时提供凭证备注和脱敏前缀即可,不需要提供完整密钥。 (截图:在「接入凭证」中替换、停用和排序凭证,已有密钥留空即保持不变。) ## 健康状态 - 新增的凭证保存后自动检测一次,检测方式是读取服务商的模型列表。凭证行的「状态」显示「正常」「检测中」「错误」或「已停用」。 - 服务商通道行在全部凭证检测失败时显示「错误」,点击可查看异常凭证、失败原因和「最近检测」时间,并可 **重新检测** 或 **检查配置**;部分凭证失败时显示「接近限额」,展开通道查看各凭证的状态。 - 状态只用于提示,不影响选路:显示「错误」的凭证仍会被尝试。确认密钥失效后,及时替换或停用。替换密钥后列表中的状态不会自动更新;通道显示「错误」时,点击它并选择 **重新检测**。 ## 凭证限额 「API 按量计费」的凭证可以设置限额:在「用量与费用限额」列点击 **设置限额**,按「费用限额(¥)」和「Token 限额(百万)」分别填写「月度」「累计」上限,留空或填写 0 表示不限。 - **达到上限时**:该凭证在选路时被跳过,网关继续尝试同一通道的下一个凭证、平台凭证和其他通道。所有可用凭证都达到限额时,返回 429 `all upstream credentials for this model are rate limited`(`error.code` 为 `upstream_quota_exhausted`),见[429:限流与配额](https://platform.lyrouter.com/ai_gateway/docs/rate-errors)。 - **计数方式**:用量在请求完成后计入,越过上限的那次请求会正常完成;计数有短暂延迟,请给上限留出余量。月度上限每月 1 日重置,累计上限不会重置。 - **Token 限额的单位**:「Token 限额(百万)」按百万 Token 填写,例如 `10` 表示 1000 万 Token、`1.25` 表示 125 万 Token。保存后可在凭证行的「本月 Token」中核对上限。 - **控制服务商花费**:需要严格控制服务商侧的花费时,同时在服务商控制台为该账户设置额度上限。 ## 常见问题 ### 列表中的费用与服务商账单对不上,以哪个为准? **答:** 以服务商账单为准。列表中的费用是按 BYOK 中设置的刊例价和折扣估算的,服务商的实际价格、优惠和计费规则可能不同;平台服务费也不在其中,请在 **订阅充值** 的「消费明细」中核对。 ### BYOK 用的是自己的 Key,为什么还会返回 402? **答:** BYOK 调用要从 Credits 余额中支付平台服务费。看 `error.message`:`insufficient credit balance` 表示余额低于这次调用要预留的服务费,或账户从未充值(`error.code` 为 `balance_missing`),充值后恢复;`subscription expired; renew to continue` 表示账户订阅已过期,续费后恢复。详见[模型不可用](https://platform.lyrouter.com/ai_gateway/docs/unavailable)。 ### 设置了 Token 限额,调用很快就返回 429,怎么办? **答:** 先看限额是不是早期版本保存的。早期版本把「Token 限额(百万)」按 Token 个数保存,当时填写的 `10` 实际只允许 10 个 Token,第一次调用后就会触顶;现在编辑器按百万 Token 显示,这类历史值会显示成很小的小数,不会自动放大。编辑 BYOK,在「设置限额」中按百万 Token 重新填写后保存,例如 1000 万 Token 填 `10`。 --- # 计费规则与信用点 来源: https://platform.lyrouter.com/ai_gateway/docs/billing LYRouter 用 Credits(信用点)计费:一个组织只有一个 Credits 余额,组织下所有工作空间和 API Key 共用。调用平台模型按实际用量扣 Credits,BYOK 调用按次收取平台服务费;余额降到 0 及以下时,调用返回 402。团队版和企业版另按席位订阅,到期后有 7 天宽限期,之后控制台只能查看、调用返回 402 `subscription expired; renew to continue`。 ## Credits 余额 当前账号管理员在左侧「组织管理」分组的 **订阅充值** 页面查看余额:「购买充值」标签顶部的「Credits 余额」卡片显示「总 Credits」、按汇率折算的约合人民币金额,以及「充值余额」和「赠送余额」两部分。普通成员看不到这个页面,遇到余额不足或订阅到期时请联系账号管理员。 | | 充值余额 | 赠送余额 | | --- | --- | --- | | 来源 | 购买资源包的面额部分 | 注册与实名认证赠送、订阅套餐的「包含 Credits」、资源包中的赠送部分、核销的权益码和代金券 | | 调用时的扣减顺序 | 赠送余额用完后再扣 | 先扣 | | 抵扣续费、增购席位、自动续费 | 可以 | 不可以 | | 退款 | — | 不参与退款 | - **余额可能为负**:一次调用可能把余额扣成负数,负数记在充值余额上,充值后先补足负数部分。赠送余额不会为负。 - **订阅赠送一次到账**:订阅套餐的「包含 Credits」在支付成功时一次性计入赠送余额,不按月分批,也不随周期重置。 (截图:「购买充值」标签顶部分别显示订阅信息和 Credits 余额,余额拆成充值余额与赠送余额。) ## 调用怎样扣费 | 调用情况 | 是否扣 Credits | 扣多少 | | --- | --- | --- | | 平台模型调用成功 | 扣 | 按这次调用的实际用量和模型价格折算成 Credits | | BYOK 调用成功 | 扣 | 不按 Token 扣(服务商费用由你直接与服务商结算),每次收一笔平台服务费,见 [BYOK 费用与凭证管理](https://platform.lyrouter.com/ai_gateway/docs/byok-cost) | | 上游返回错误或连接失败 | 不扣 | — | | 网关自动换凭证、通道或备用模型重试 | 只扣一次 | 只按最终成功的那一次计费,失败尝试不收费 | - **价格按请求发生时冻结**:每次调用按请求发生时有效的价格和汇率计算,之后调价不会改变已经发生的调用。费用的估算方法见[调用费用与缓存计费](https://platform.lyrouter.com/ai_gateway/docs/estimate)。 - **BYOK 服务费先预留**:网关把 BYOK 请求发给服务商之前,先从余额中预留这笔服务费,调用成功才扣除,失败时退回。余额不足以支付服务费时,请求不会发往服务商,直接返回 402。 ## 余额不足与 402 网关在每次调用前检查组织余额:余额大于 0 就放行,余额小于或等于 0 时返回 402 `insufficient credit balance`(`error.type` 为 `insufficient_quota`)。检查只发生在调用之前,所以最后一次放行的调用可能把余额扣成负数,之后的调用才会被拒绝。余额不足时,网关不会改走其他通道或其他计费方式。 | `error.code` | 含义 | 处理 | | --- | --- | --- | | `insufficient_credit_balance` | 余额已用完;或调用 BYOK 时余额不足以支付平台服务费 | 在「资源包购买」中充值 | | `balance_missing` | 组织还没有余额记录,通常是从未充值 | 充值;已经充值仍出现时联系支持 | | `billing_entity_missing` | 网关找不到这个 API Key 对应的计费账户 | 平台侧数据问题,联系支持 | 充值到账、余额重新大于 0 后调用即恢复,不需要更换 API Key。另外两类报错与余额不足不同:503 `billing balance is temporarily unavailable` 表示网关暂时无法确认余额,见[模型不可用](https://platform.lyrouter.com/ai_gateway/docs/unavailable);429 中带 `credits` 的报错是配额或 Key 预算用完,见[预算、配额与限流](https://platform.lyrouter.com/ai_gateway/docs/quota)。 ## 页面余额与网关判断不一致 网关按实时余额判断是否放行,而「Credits 余额」卡片在取不到实时余额时,会改用对账账本中的数据,可能滞后几分钟。此时卡片下方会提示: > 余额来自对账账本,可能有数分钟延迟;网关按实时余额判定,可能出现「显示有余额但请求被拒」的情况。 看到这条提示时,以调用结果为准并及时充值。刚完成充值或核销时,卡片可能提示「信用点变更正在同步,当前显示的余额可能暂时延迟。」,稍后点 **刷新** 即可。总额会先于「充值余额」「赠送余额」两项更新,短时间内三者对不上属于正常现象。 ## 订阅:版本、席位与试用 - **谁能订阅**:订阅面向团队版和企业版组织,团队版组织只能订阅团队版套餐,企业版组织只能订阅企业版套餐。个人版免费使用,订阅卡片显示「个人免费版」;点任意套餐会提示「个人版不支持套餐订阅」,并提供 **创建团队** 和 **创建企业** 入口。团队版需要账号管理员完成个人实名认证,企业版还需要企业实名认证,见[组织、成员与角色](https://platform.lyrouter.com/ai_gateway/docs/organization)。 - **套餐卡**:在「订阅套餐」中按「按月 / 按年」切换计费周期,每张卡显示每席位单价,以及「Credits/席位」「日志详情条数」「日志留存」「席位区间」。在卡上选择「席位数」和「订阅时长」(1~36 个计费周期),「应付金额」即单价 × 席位数 × 周期数。具体价格以卡片为准。 - **试用**:带「试用版」标签的卡片提供试用,按钮为 **免费试用**(无需付款,立即开通)或 **付费试用**(按正式套餐流程付款)。每个组织每个版本只能试用一次,团队版试用还按账号管理员本人的实名身份限一次;已试用过的卡片按钮显示「已使用试用」。试用不会自动续费。 - **席位**:组织的成员数加上尚未接受的邀请数不能超过席位数,席位满后需要先增购席位才能继续邀请,见[组织、成员与角色](https://platform.lyrouter.com/ai_gateway/docs/organization)。 订阅信息卡片的状态标签有「免费版」「试用中」「生效中」「宽限期」「订阅失效」,并显示剩余天数、有效期和席位数。下单、续费、增购席位和自动续费的操作见[购买、账单与发票](https://platform.lyrouter.com/ai_gateway/docs/orders)。 ## 到期、宽限期与冻结 | 阶段 | 订阅信息卡片 | 控制台 | API 调用 | | --- | --- | --- | --- | | 到期前 | 「生效中」或「试用中」 | 正常 | 正常 | | 到期后 7 天内 | 「宽限期」,**订阅充值** 页提示「订阅已进入宽限期,N 天后停用,请及时续费。」 | 正常 | 正常 | | 宽限期结束后 | 「订阅失效」 | 各页面可以查看,不能操作 | 402 `subscription expired; renew to continue` | | 续费成功后 | 「生效中」 | 恢复 | 恢复 | - **冻结期间的控制台**:各页面顶部显示「订阅已过期:各页面仅可查看,请续费以恢复操作。」,点任何新增、修改或删除操作都会提示「订阅已过期,请续费后再操作。」。**订阅充值** 页面的续费、充值、核销、开票照常可用;导出日志等只读操作、修改密码、实名认证、接受邀请、消息已读也不受影响。 - **冻结期间的调用**:402 对组织下所有工作空间和 API Key 生效,BYOK 调用也一样。这时充值解决不了问题,需要续费。 - **余额保留**:冻结不会清零 Credits 余额,续费后继续使用。 ## 余额与订阅提醒 当前账号管理员在 **消息中心** 点 **告警设置**,进入「告警通知」页,在「账务」类告警规则中设置提醒: | 规则 | 触发时机 | | --- | --- | | 订阅到期前 7 天、订阅到期前 1 天 | 订阅周期结束前 | | 试用到期前 7 天、试用到期前 1 天 | 试用期结束前 | | 自动续费前 7 天、自动续费前 1 天 | 通知预计续费金额以及 Credits 是否充足 | | 自动续费成功、自动续费失败 | 自动续费完成或失败时 | | 订阅进入宽限期、订阅已到期 | 订阅状态变化时 | | 信用点余额不足 | 余额低于你设置的「低余额阈值」 | | 信用点已耗尽 | 余额耗尽时 | ## 核对实际扣费 每次调用实际扣了多少 Credits,以 **订阅充值** 页「消费明细」标签为准。表格按请求列出「请求时间」「API Key」「工作空间」「创建人」「部门」「模型」「消费 Credits」和「请求 ID」,顶部的「总消费」是所选时间范围内的合计。 - **时间范围**:默认最近 30 天,单次查询不能超过 90 天。 - **只含已结算的请求**:刚发生的调用要等结算后才出现。页面提示「消费归因仍在同步,当前分项合计可能暂时与结算总额不一致」时,稍后刷新即可。 - **定位到单次请求**:复制「请求 ID」,进入对应工作空间,在[日志](https://platform.lyrouter.com/ai_gateway/docs/logs)的搜索框中查找这次请求。 - **「创建人」是 API Key 的创建人**:多人共用一个 Key 时,看不出是谁发起的调用。需要按人核算时,为每个人分别创建 Key。 (截图:「消费明细」按请求列出时间、API Key、工作空间、创建人、部门、模型和消费 Credits。) [用量分析](https://platform.lyrouter.com/ai_gateway/docs/analytics)和日志中的「费用」是人民币金额,用于分析用量和成本;核对账户扣了多少 Credits,请看「消费明细」。 ## 常见问题 ### 控制台显示还有余额,调用却返回 402,为什么? **答:** 先看报错原文。`subscription expired; renew to continue` 表示订阅已过宽限期,需要续费,与余额无关。`insufficient credit balance` 时,网关按实时余额判断,而余额卡片可能来自滞后几分钟的对账账本(卡片下方会有提示),实际余额已经用完,请充值。 ### 充值后多久可以恢复调用? **答:** 订单变为「已完成」后 Credits 计入余额,余额重新大于 0 时调用即恢复,不需要更换 API Key。订单仍是「处理中」时请稍候;充值后仍返回 `balance_missing`,请带上订单号联系支持。 ### 赠送余额可以用来续费吗? **答:** 不可以。续费、增购席位和自动续费只能用充值余额抵扣,赠送余额只用于支付调用费用。续费前请确认充值余额足够,或直接扫码付款。 --- # 调用费用与缓存计费 来源: https://platform.lyrouter.com/ai_gateway/docs/estimate 一次文本调用的费用由四类 Token 分别计价后相加:「输入(缓存未命中)」按价格表的「输入」单价,「输入(缓存命中)」「输出」「显式缓存创建」按价格表中同名一项的单价。单价以工作空间 **模型广场** 中模型详情的「平台价」为准,长上下文分档、分时计价、服务档位等条件会改变适用的单价。只有成功的调用扣费,估算结果可以用[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)的「费用」和 **订阅充值** 的「消费明细」核对。 ## Token 的四个计费项 日志详情「Token 消耗」把一次调用的 Token 分成四项,四项互不重叠: | 日志中的名称 | 含义 | 价格表中对应的列 | | --- | --- | --- | | 输入(缓存未命中) | 本次输入中没有命中上游提示词缓存、需要重新计算的部分 | 「输入」 | | 输入(缓存命中) | 命中上游提示词缓存的输入 | 「输入(缓存命中)」;没有单独标价时按「输入」 | | 输出 | 模型生成的 Token,包括思考(推理)过程 | 「输出」 | | 显式缓存创建 | 通过 `cache_control` 写入上游缓存的输入,只在 Anthropic 协议的上游出现 | 「显式缓存创建」;没有单独标价时按「输入」 | - **输入要拆开算**:「输入(缓存未命中)」加「输入(缓存命中)」是这次调用的全部输入。OpenAI 兼容响应里的 `prompt_tokens` 通常已经包含缓存命中部分,估算时先减去命中量,再分别乘两种单价,不要把命中部分再按输入单价算一遍。 - **两个合计不同**:「Token 消耗」的「总计」是四项之和;日志列表的「总 Token」和详情的「Token 总量」是输入加输出,不含「显式缓存创建」,所以可能比「总计」小。 - **在列表中查看**:日志列表默认只显示「总 Token」,可以在「自定义列」中打开「输入(缓存未命中)」「输入(缓存命中)」「输出」和「费用」;「显式缓存创建」只在详情中显示。 (截图:日志详情的 Token 消耗分四项列出数量和占比,基本信息中的费用是这次调用的实际扣费。) ## 估算一次调用的费用 1. 在工作空间的 **模型广场** 中打开模型,进入「服务商与价格」,找到要使用的来源。平台通道看「平台价」;「BYOK 参考价」「官方参考价」只供比较,不是平台扣费价。 2. 确认价格单位。文本模型通常是「/ 百万 Token」,图片、视频、语音可能按「张」「秒」「分钟」「万字符」「次」计价。 3. 按表格的「适用条件」找到这次调用落在哪一行,再按下式计算: ```text 费用 = 输入(缓存未命中) × 输入单价 + 输入(缓存命中) × 输入(缓存命中)单价 + 输出 × 输出单价 + 显式缓存创建 × 显式缓存创建单价 (按百万 Token 计价时,各项 Token 数先除以 1,000,000) ``` 有权限查看折扣时,价格表会同时显示划线原价和折扣后的价格,按折扣后的价格估算。价格表中的「—」表示暂无报价,不代表免费。 (截图:模型详情的服务商与价格按来源列出平台价、计价方式和适用条件。) ## 价格表上的计价条件 价格表标题显示计价方式,「适用条件」列显示每行单价的适用范围: | 计价方式或条件 | 如何影响费用 | | --- | --- | | 固定单价 | 所有调用使用同一组单价 | | Token 长度计价 | 按单次请求的 Token 长度选档,整次请求都按该档单价计费。判断输入长度时使用全部输入 Token,**包括缓存命中的部分**,所以缓存命中率再高,长上下文请求也按长上下文档计价 | | 分时计价 | 按请求发生的星期和时段乘以对应系数。时段含开始、不含结束,按价格表标注的时区判断;只区分星期几,不区分法定节假日和调休 | | 条件计价 | 按服务档位、模态、分辨率、时长等条件选价。例如「服务档位」按上游实际使用的档位计价,「每次前 N … 免费」表示每次调用先扣除这部分数量再计费 | | 复杂计价 | 页面提示「存在未完整展示的计价条件,请核对完整定价规则后使用。」,请联系支持确认后再估算 | ## 哪些调用会扣费 - **只按成功的调用扣费**:上游返回错误或连接失败的调用不扣费。网关自动换通道或改用备用模型时,只按最终成功的那一次计费,失败尝试的费用不会转给你,见[失败重试与备用模型](https://platform.lyrouter.com/ai_gateway/docs/fallback)。 - **BYOK 调用**:Token 费用由你直接与服务商结算,平台对每次成功调用扣一笔按订阅版本确定的平台服务费,日志「费用」显示的就是这笔服务费,见[BYOK 费用与凭证管理](https://platform.lyrouter.com/ai_gateway/docs/byok-cost)。通过 BYOK 接入的 Coding Plan 按服务商套餐计费,不按 Token 单价结算,见[API 按量服务与 Coding Plan](https://platform.lyrouter.com/ai_gateway/docs/coding-plan)。 - **异步任务**:视频等异步生成在任务完成后结算。创建任务的请求本身不产生费用,日志列表在结算前显示「结算中」,见[多模态能力](https://platform.lyrouter.com/ai_gateway/docs/multimodal)。 ## 显式缓存的计费 在请求里用 `cache_control` 标记缓存断点、且这次调用由 Anthropic 协议的上游服务时,写入缓存的部分记为「显式缓存创建」,按「显式缓存创建」单价计费;Anthropic 的缓存写入单价高于普通输入。之后几分钟内发送相同前缀的请求,这部分记为「输入(缓存命中)」,按「输入(缓存命中)」单价计费。前缀会被反复使用时,写入的额外费用通常在一两次命中后就能收回。 上游使用 OpenAI 兼容协议时,网关会在发送前删除请求中的 `cache_control`,这时只有上游自动进行的隐式缓存,不产生「显式缓存创建」。标记规则和提高命中率的方法见[降低成本与优化缓存](https://platform.lyrouter.com/ai_gateway/docs/cost-practice)。 ## 用日志和消费明细核对 - **日志「费用」**:这次调用实际扣除的 Credits 折算成的人民币金额,在调用时按当时的价格计算并固定下来,之后调价不会改变历史日志的金额。显示「未计算」表示这次调用没有产生扣费,例如调用失败;显示「无权限查看」表示当前账号不能查看这条日志的费用。 - **消费明细**:当前账号管理员在 **订阅充值** 的「消费明细」中按请求查看「消费 Credits」,其中的「请求 ID」与日志详情顶部的 Request ID 相同,可以逐条对应。单次查询的时间范围不能超过 90 天,刚完成的调用可能要几分钟后才出现。 金额对不上时的排查方法见[费用异常与缓存未命中](https://platform.lyrouter.com/ai_gateway/docs/cache-errors),Credits 与订阅的规则见[计费规则与信用点](https://platform.lyrouter.com/ai_gateway/docs/billing)。 (截图:消费明细按请求列出时间、API Key、工作空间、模型和消费 Credits,可按请求 ID 与日志对应。) --- # 预算、配额与限流 来源: https://platform.lyrouter.com/ai_gateway/docs/quota LYRouter 有两种用量上限:API Key 的「预算限额」只约束这一把 Key,由 Key 创建者或当前账号管理员在 Key 设置中填写;安全围栏的「配额管理」策略由当前账号管理员按工作空间、部门、组织成员或 API Key 设置,可以按信用点或百万 Token 计量、按月或按天清零,并给个别成员设例外。任一上限用完,之后的请求返回 429,到 `reset_at` 之后恢复。配额只限制用量,与组织的信用点余额是两回事。 ## Key 预算与配额策略 | | API Key 预算 | 安全围栏配额策略 | | --- | --- | --- | | 在哪里设置 | **API 密钥** 页创建或编辑 Key 时的「预算限额」步骤 | **安全围栏** 的「配额管理」页签 | | 谁能设置 | Key 的创建者(在该工作空间是编辑者或管理员)和当前账号管理员 | 当前账号管理员,团队版起可用 | | 约束谁 | 这一把 Key | 工作空间、部门、组织成员或 API Key | | 计量 | 「费用预算(元)」和「Token 预算(百万 Token)」 | 「信用点」或「Token」(按百万 Token 填写) | | 周期 | 「每月」(每月 1 日 0 点重置)和「总计」(不重置),留空表示不限制 | 「每月」(可设清零日)、「每天」、「累计总量」 | | 多人分摊与例外 | 无 | 「共享」「按用户」「按 API Key」,可给成员设例外 | | 速率限制 | 无 | 可选每分钟请求数(RPM)、每分钟 Token 数(TPM) | | 触顶后 | 拒绝请求 | 「阻断」拒绝请求,或「告警」只通知不拦截 | - **同时生效**:Key 预算、各层配额策略和 BYOK 通道自身的额度相互独立,任一项用完都会拒绝调用。 - **费用预算换算**:「费用预算(元)」按平台汇率换算成信用点执行,所以触顶报错中的指标是 `credits`,`limit`、`used` 也以信用点为单位。 - **时间按北京时间**:每月、每天的清零时间都按北京时间计算。 ## 配置配额策略 当前账号管理员在 **安全围栏** 的「配额管理」页签点「新建配额管理策略」: 1. **生效对象**:选择「工作空间」「部门」「组织成员」或「API Key」。选工作空间或部门时,还要选「配额模式」,见下节。 2. **策略规则**: - 「计量单位」:「信用点」直接按信用点填写;「Token」以百万 Token 为单位,填 `10` 即 1000 万 Token,下方显示「实际 Token 数」。 - 「额度上限」:正整数。 - 「统计周期」:「每月」在「清零日」00:00(Asia/Shanghai)清零,清零日可填 1~28,默认 1;「每天」每日 00:00 清零;「累计总量」不自动清零。 - 「触顶预警阈值」:默认 80%,用量达到这个比例时发一次提醒:「按用户」「按 API Key」的配额同时提醒对应成员和管理员,「共享」配额只提醒管理员;填 0 关闭,最大 99。 - 「例外成员」:见下文「配额例外」。 - 「限流设置(可选)」:RPM、TPM 按每分钟计算,独立于主额度,不受例外影响。 - 「执行动作」:「阻断」或「告警」。 3. **生效时间**:立即或定时生效,可设失效时间。 (截图:配额策略的规则:计量单位、额度上限、统计周期、清零日、触顶预警阈值与执行动作。) ### 计数方式 | 配额模式 | 含义 | 例:上限 5000 信用点 / 每月 | | --- | --- | --- | | 共享 | 范围内所有调用合计一份额度 | 全空间合计 5000,用完后范围内所有人都被拒绝 | | 按用户 | 范围内每个成员各一份额度 | 每个成员每月各 5000 | | 按 API Key | 范围内每把 Key 各一份额度 | 每把 Key 每月各 5000 | - 生效对象是「组织成员」时,统计该成员创建的全部 Key 的用量合计;是「API Key」时,统计这把 Key 自己的用量。 - 生效对象是「部门」时,只统计创建人主部门恰好是该部门的 Key,不含子部门。 - 「共享」模式的策略可以在策略详情的「共享池用量」查看已用量;计数暂时读不到时显示「暂不可用」。 (截图:生效对象选择部门,并在「共享」「按用户」「按 API Key」三种配额模式中选择。) ### 配额例外 配额例外用来给少数成员一个不同于默认值的额度,可以更高,也可以更低。它只出现在生效对象为「工作空间」或「部门」、配额模式为「按用户」的策略中;「共享」是一个总额,不支持例外,要单独放开某人请改用「按用户」。 - **添加**:在「例外成员」中点「添加成员」或「按部门添加」,为每人填写「额度」。未列出的成员按默认额度执行。 - **有效期默认「到本周期结束」**:例外与配额清零同时到期,到期时用量也一起归零,不会有人因此被突然拒绝。也可以选「长期有效」,或选「指定日期」设置一个未来的到期时间。「累计总量」没有周期边界,没有设置「指定日期」时,例外一直有效,直到删除。 - **按部门添加是一次性快照**:默认包含子部门,把所选部门当下的成员逐一加为例外。之后新加入部门的人不会自动获得例外,调离的人仍保留例外并标注「已调岗」,可以点「重新同步该部门」。生效对象是部门时,只会加入主部门恰好是该部门的成员。 - **上限 80 条**:单条策略最多 80 条例外,已失效的也计入。已失效的例外折叠在列表底部,可以「延期」到下一个周期边界,或删除。 - **删除或调低立即生效**:上限马上回落,而本周期已用的量不清零。已用量超过新上限的成员,下一个请求就会被拒绝,直到本周期重置;控制台会在删除或调低前再确认一次。 ### 修改统计周期会清零用量 修改「统计周期」或「清零日」后,本周期已统计的用量归零,所有人从 0 重新计算,保存前控制台会再确认一次。只调整「额度上限」或例外额度不会清零用量。 ## 用完之后 阻断型配额或 Key 预算用完后,请求返回 429: | 字段 | 含义 | | --- | --- | | `error.message` | `rate limit exceeded on <对象> <指标>/<窗口>`,例如 `rate limit exceeded on ws credits/month` | | `limit`、`used` | 上限和已用量 | | `reset_at` | 恢复时间;「总计」「累计总量」没有恢复时间 | | `policy_code`、`policy_name` | 只在安全围栏配额策略触发时出现,可据此区分配额策略与 Key 预算 | - 用量在请求完成后才计入,越过上限的那次请求会正常完成,下一次才被拒绝。 - 「告警」动作的配额触顶后不拦截,只记录安全事件并通知;同时适用的其他阻断型限制照常生效。 - 对象、指标、窗口的取值和重试方法见[429:限流与配额](https://platform.lyrouter.com/ai_gateway/docs/rate-errors)。需要提高额度时,Key 预算请 Key 创建者或账号管理员修改,配额策略请账号管理员调高上限或添加例外。 ## 成员查看「我的配额」 成员在控制台 **概览** 页的「我的配额」卡片查看适用于自己的配额,每个可访问的工作空间各一张卡片: - 「按用户」的配额显示已用量、上限、「剩余 N」和重置时间,剩余比例最低的一条排在最前,有多条时可以「展开全部」。 - 「共享」的配额显示「共享」和「本空间共用 X 信用点 / 本月」,不显示个人用量。全空间额度用完后,范围内的调用都会被拒绝。 - 成员有例外时显示「专属额度」;例外到期时间与重置时间不同时,卡片会提示到期后上限回落到默认额度。 - 没有任何适用配额时显示「无限额」。挂在单个 API Key 上的配额和 Key 预算不在卡片中,「按 API Key」计数的配额也只显示上限,已用量位置显示「暂不可用」。 - 程序也可以读取响应头 `x-aigw-quota-<指标>-remaining` 等获取剩余量,见[429:限流与配额](https://platform.lyrouter.com/ai_gateway/docs/rate-errors)。 ## 配额与余额 配额是调用上限,余额是组织的信用点余额,两者分别检查。配额还有剩余时,余额不足仍会返回 402 `insufficient credit balance`;余额充足时,配额用完照样返回 429。充值不会增加配额,调高配额也不会增加余额,见[计费规则与信用点](https://platform.lyrouter.com/ai_gateway/docs/billing)。 ## 常见问题 ### 「我的配额」显示「无限额」,为什么还收到 429? **答:** 看报错原文中的对象。`apikey` 表示这把 Key 自己的预算或挂在 Key 上的配额已用完,这些不显示在卡片中,请 Key 创建者在 **API 密钥** 页查看预算;`api_key_circuit_open` 是错误率熔断,与配额无关,见[429:限流与配额](https://platform.lyrouter.com/ai_gateway/docs/rate-errors)。 ### 调高上限后多久生效? **答:** 保存后几秒内同步到网关。调高上限不会清零已用量,已用量低于新上限后即可继续调用,不需要更换 API Key。 --- # 用量归因与分析 来源: https://platform.lyrouter.com/ai_gateway/docs/analytics 用量分析按工作空间汇总一段时间内的请求数、Token、缓存命中率和费用,并按 API Key、部门、用户、模型和意图拆分,用来回答「谁在用、用在哪些模型上、花了多少」。用量按 API Key 归到 Key 的创建人及其部门;普通成员只能看到自己创建的 Key。费用以人民币显示:平台请求按实际扣费金额计算,BYOK 按服务商成本计算。核对单次请求请看[日志](https://platform.lyrouter.com/ai_gateway/docs/logs),核对 Credits 扣费请看[消费明细](https://platform.lyrouter.com/ai_gateway/docs/billing)。 ## 打开用量分析 进入工作空间,在左侧「用量日志」分组点 **用量分析**。数据范围是当前工作空间;要看组织下全部工作空间的合计,回到控制台的 **概览** 页。 页面顶部有三个筛选项,所有标签页都跟随它们: | 筛选项 | 选项 | 说明 | | --- | --- | --- | | 「时间范围」 | 今天、昨天、近 7 天、近 30 天、近 90 天、自定义 | 指标卡同时显示与上一个等长周期的对比 | | 「模态」 | 文本、图片生成、视频生成 | 文本按 Token 统计;图片按张、视频按秒统计,用量和费用同时显示 | | 「统计视角」 | 用量、费用 | 只在「文本」下可用,切换后各标签页改为按费用展示 | 数据为近实时,页面加载或点 **刷新** 时重新拉取。刚发出的请求如果还没出现,稍后刷新即可。 (截图:用量分析先选时间范围、模态和统计视角,总览显示 Token、请求、成功率、缓存命中率和活跃 Key。) ## 谁能看到哪些数据 | 身份 | 能看到的用量 | 「按部门」「按用户」 | | --- | --- | --- | | 个人版的账号管理员 | 工作空间的全部用量 | 不显示 | | 团队版、企业版的当前账号管理员 | 工作空间的全部用量,含总览的「Top 部门」「Top 用户」 | 显示 | | 普通成员(包括担任工作空间管理员的成员) | 只有自己创建的 API Key 的用量和费用 | 不显示 | 普通成员还没有创建过 API Key 时,页面没有数据。团队版和企业版的「按 API Key」明细带「创建者」列。 ## 标签页 | 标签 | 内容 | | --- | --- | | 「总览」 | 指标卡、用量趋势,以及模型、服务商、客户端、意图分布和 Top 排行;「服务商分布」可按平台或 BYOK 来源筛选 | | 「按 API Key」 | 各 Key 的用量趋势和明细,选中一个 Key 可下钻其模型、意图构成 | | 「按部门」「按用户」 | 各部门、各用户的用量与下钻 | | 「按模型」 | 分模型的用量趋势与明细,含服务商、来源、缓存命中率、成功率、「P95 首字延迟」和吞吐,覆盖平台与 BYOK 来源 | | 「按意图」 | 开发调试、咨询解答等请求意图的占比与明细 | | 「自定义统计」 | 自选分组和细分维度查询,并导出 CSV,见下文 | 「P95 首字延迟」只统计成功的流式请求。 ## 用量指标怎么算 - **Token**:用量分析展示「输入(缓存未命中)」「输入(缓存命中)」「输出」三项,三项互不重叠,相加即 Token 总量。「显式缓存创建」不在用量分析中统计,请在[日志](https://platform.lyrouter.com/ai_gateway/docs/logs)详情中查看。 - **缓存命中率**:输入(缓存命中)÷(输入(缓存未命中)+ 输入(缓存命中)),按 Token 数加权。汇总行的命中率由合计 Token 算出,不是各行百分比的平均,所以 Token 多的行影响更大。提高命中率的方法见[降低成本与优化缓存](https://platform.lyrouter.com/ai_gateway/docs/cost-practice)。 - **请求总数与成功率**:HTTP 状态码小于 400 的请求算成功。被网关直接拒绝、没有发往上游的请求不计入请求数和成功率,例如 API Key 无效或过期、订阅过期、余额不足、限流、安全围栏拦截、模型未开通;这些请求可以在日志中查到。`GET /v1/models` 查询模型列表的请求也不计入。 - **Token 与活跃 Key**:只统计成功请求。「活跃 Key」显示为「区间内有成功调用的 Key 数 / 当前启用的 Key 数」。 ## 费用视角 把「统计视角」切到「费用」后,页面说明为「以人民币查看 Token 费用:平台请求按客户实付金额计算(与账单同一口径),BYOK 按服务商成本计算。」总览的「Token 费用」卡片拆成三部分: | 项目 | 含义 | | --- | --- | | 「平台 Token 费用」 | 平台请求实际扣除的 Credits,按每次请求结算时冻结的汇率换算成人民币,与消费明细逐条一致 | | 「BYOK Token 费用」 | 按服务商价格估算的 BYOK 调用成本,由你直接向服务商支付,不从 Credits 扣除 | | 「BYOK 订阅费用」 | 按订阅付费的 BYOK 凭证(例如 [Coding Plan](https://platform.lyrouter.com/ai_gateway/docs/coding-plan))的订阅费,按天折算计入 | - **BYOK 订阅费用不分摊**:它只计入工作空间的总额,不分到模型、API Key、部门、用户、意图或单次请求上,因此各维度的费用之和会小于总额。普通成员的费用不含这部分。 - **缺少价格的请求不计入**:个别请求缺少计费信息时按 0 计入合计,费用合计可能略低于实际。 - **较早的历史数据**:平台启用「按实付金额」统计之前的时间段,平台请求的金额是服务商成本估算,与账单不完全一致。 - **按模型拆分**:「按模型」在费用视角下列出输入费用、输出费用、缓存费用和请求固定成本。 ## 用量归在谁名下 - **按 API Key 归因**:每次调用记在所用的 API Key 上,再归到 Key 的创建人和创建人的主部门。多人共用一个 Key 时,无法区分是谁发起的调用;需要按人核算时,为每个人分别创建 Key,见[创建工作空间与 API Key](https://platform.lyrouter.com/ai_gateway/docs/api-keys)。 - **共享 Key 单列**:可见范围是成员或全工作空间的共享 Key,其用量在「按用户」「按部门」中单列为「共享应用 · 未归属」,不归到任何人或部门名下。点这一行可以查看明细。 - **失效成员保留历史**:成员离开后,历史用量仍保留在原来的用户和部门下。「按用户」中用标签区分「已移出」(已退出本组织,账号仍在,可重新邀请)和「已删除」(账号已被平台删除)。已删除的 API Key 同样保留用量,并标记「已删除」。 ## 自定义统计与导出 CSV 在「自定义统计」中选择「分组」(模型、意图、API Key、服务商、客户端、时间;当前账号管理员还有部门、用户),可选一个「细分(下钻)」维度,再选「排序依据」,需要时打开「筛选条件」和「显示图表」,点 **查询** 得到明细表和合计行。 - **组合限制**:不能同时用 API Key、用户、部门中的两个做分组和细分;意图只能与模型、API Key、用户、部门组合;按时间分组时不能细分。 - **细分行属于父分组**:例如按模型分组、按服务商细分时,细分行是这个模型在各服务商上的用量,与模型级的合计相比较时注意范围。 - **导出 CSV**:查询出结果后点 **导出 CSV**,导出当前表格的分组行和细分行。用量视角导出请求数、Token 各项、缓存命中率和成功率;费用视角导出请求数、金额和费用占比。 ## 与日志、消费明细的区别 | | 用量分析 | 日志 | 消费明细 | | --- | --- | --- | --- | | 范围 | 当前工作空间的汇总 | 当前工作空间的逐条请求 | 整个组织的逐条扣费 | | 包含哪些请求 | Token 只算成功请求;请求数不含被网关直接拒绝的请求 | 包括失败和被网关拒绝的请求 | 已结算、扣过 Credits 的请求 | | 金额 | 人民币:平台按实付,BYOK 按服务商成本 | 每条请求的费用 | Credits | | 谁能看 | 所有成员,普通成员只看自己的 Key | 所有成员,普通成员只看自己的 Key | 仅当前账号管理员 | (截图:「消费明细」按 Credits 逐条记录实际扣费,可与用量分析的平台 Token 费用对照。) ## 常见问题 ### 用量分析的费用和消费明细对不上,为什么? **答:** 先对齐范围:用量分析只统计当前工作空间,消费明细覆盖整个组织;消费明细只包含已结算的请求,最近几分钟的调用可能还没进入。其次,用量分析的「BYOK Token 费用」「BYOK 订阅费用」是服务商成本,不从 Credits 扣除,消费明细里没有对应金额。只比较「平台 Token 费用」与消费明细换算后的金额。 ### 为什么看不到「按部门」和「按用户」? **答:** 这两个标签只对团队版、企业版的当前账号管理员显示。普通成员和个人版不显示,普通成员在其他标签中看到的也只是自己创建的 Key 的数据。 ### 日志里有失败请求,成功率却没有下降? **答:** 被网关直接拒绝的请求(例如 Key 无效、余额不足、限流、安全围栏拦截)不计入请求数和成功率,只在日志中可见。排查这类请求,请按日志中的报错原文处理,见[401 / 403](https://platform.lyrouter.com/ai_gateway/docs/auth-errors)和[429:限流与配额](https://platform.lyrouter.com/ai_gateway/docs/rate-errors)。 --- # 购买、账单与发票 来源: https://platform.lyrouter.com/ai_gateway/docs/orders 订阅套餐、购买资源包、续费、增购席位、核销兑换码和申请发票,都由当前账号管理员在 **订阅充值** 页面完成。下单后用微信或支付宝扫码付款,团队版和企业版组织还可以对公转账;没付完的订单可以从「订单记录」继续支付,不必重新下单。实际付款的人民币订单完成后,可以在「订单记录」中申请发票。 ## 页面结构 **订阅充值** 在左侧「组织管理」分组下,普通成员看不到这个页面。页面有四个标签: | 标签 | 用途 | | --- | --- | | 「购买充值」 | 订阅信息卡、Credits 余额卡,以及「订阅套餐」「资源包购买」「券核销」三个区块 | | 「订单记录」 | 查看全部订单、继续支付、申请发票、查看开票记录 | | 「消费明细」 | 每次调用扣了多少 Credits,见[计费规则与信用点](https://platform.lyrouter.com/ai_gateway/docs/billing) | | 「核销记录」 | 代金券和权益券的核销记录 | (截图:「购买充值」标签:顶部是订阅信息与 Credits 余额,下方在订阅套餐、资源包购买和券核销之间切换。) ## 下单 1. **选择商品** - 订阅套餐:在「订阅套餐」中切换「按月 / 按年」,在卡片上选择「席位数」和「订阅时长」,核对「应付金额」后点 **订阅**(比当前档位高时按钮为 **升级**)。个人版组织不能订阅,订阅条件见[计费规则与信用点](https://platform.lyrouter.com/ai_gateway/docs/billing)。 - 资源包:在「资源包购买」中选择「数量」(1~999 份),带赠送的资源包会显示「含赠送 X,实得 Y Credits」,点 **立即购买**。 2. **确认订单**:结算页列出订单内容和「订单汇总」(商品金额、优惠减免、应付金额);资源包还会列出「充值 Credits」「赠送 Credits」和「到账合计」。升级套餐时显示的是套餐总价,下单后按原订阅的剩余周期计算实际差价。 3. **选择支付方式并下单**:在「支付方式」中选择,点 **确认下单**,再按下文完成支付。 | 支付方式 | 谁可以用 | 适用订单 | | --- | --- | --- | | 微信/支付宝扫码支付 | 所有组织 | 订阅、资源包、续费、增购席位 | | 对公转账 | 团队版、企业版组织 | 订阅、资源包 | | 余额抵扣 | 有订阅的组织 | 续费、增购席位、自动续费;只能用充值余额 | 资源包订单不能用余额抵扣。支付成功后权益自动到账:订阅立即生效,Credits 按「到账说明」分别计入充值余额和赠送余额。 ### 扫码支付 页面显示二维码和「剩余支付时间」倒计时,用微信或支付宝扫码,在倒计时结束前付款,支付结果会自动同步。付款后页面没有变化时,点 **已支付?刷新状态**。 - 离开结算页不会取消订单,之后可以从「订单记录」继续支付。 - 扫码订单不能手动取消。超过支付时限仍未付款的订单,平台向支付机构确认未付款后自动关闭,状态变为「已取消」。 ### 对公转账 1. 选择「对公转账」并 **确认下单** 后,页面给出这笔订单的开户行、开户支行、账户名、账号、「精确转账金额」和「转账识别码」,可以点 **复制全部收款信息**。 2. 按「精确转账金额」转账,并在转账备注中填写页面「备注」栏的内容,平台凭它认领这笔款项。 3. 在页面显示的截止时间之前完成转账,然后点 **我已支付** 并确认。订单进入「审核中」,之后不能取消。 4. 平台核对到账后,订单变为「已完成」,权益自动到账;审核未通过时订单变为「审核已驳回」,需要重新下单。 还没有转账时,可以点 **取消订单** 并选择「确认尚未付款并取消」。已经转账的,请点 **我已支付** 等待审核,不要取消。 ## 订单记录与继续支付 「订单记录」默认显示最近 90 天的订单,清空日期即可查看全部历史。可以按「全部订单类型」(订阅套餐、资源包、套餐升级、订阅续费、增购席位)、「全部状态」和「精确搜索订单号」筛选。扫码订单在待支付期间,状态栏会显示「支付剩余 mm:ss」。 点任意一行打开「订单详情」,可以看到商品快照、订单金额、实付金额、支付渠道、渠道流水号、购买人以及创建、支付、完成时间。待支付的订单在这里继续处理: - **扫码订单**:在支付时限内点 **继续支付**,回到原订单的支付页面。继续支付沿用原订单和原金额,不会重新计价,也不会延长支付时限。 - **对公转账订单**:详情中显示收款信息,可以点 **我已支付** 或 **取消订单**。 | 状态 | 含义 | 可以做什么 | | --- | --- | --- | | 待支付 | 订单已创建,尚未付款 | 扫码订单继续支付;对公转账订单点我已支付或取消 | | 审核中 | 已点我已支付,等待平台核对转账 | 等待结果 | | 审核已驳回 | 对公转账未通过审核,订单终止 | 重新下单 | | 处理中 | 已收到付款,权益正在发放 | 稍候刷新 | | 已完成 | 已付款,权益已到账 | 申请发票 | | 失败 | 支付或处理失败 | 重新下单 | | 已取消 | 已取消,或超时未付款被关闭 | 重新下单 | (截图:「订单记录」按日期、订单类型、状态和订单号筛选,在操作列申请开票。) ## 续费、增购席位与自动续费 这三项都在「购买充值」顶部的「订阅信息」卡片上操作: - **续费**:选择续费的计费周期数(1~36),席位数沿用当前订阅。订阅处于「生效中」或「宽限期」时,新周期接在当前到期时间之后;已经失效时,从续费生效时重新计算。弹窗会显示「续费后到期日期」。 - **增购席位**:只在订阅「生效中」时可用。新增席位与当前订阅同时到期,按剩余天数折算付款,弹窗的「官网价」会列出计算式。处于宽限期或已失效时,需要先续费。 - **余额抵扣**:续费和增购弹窗默认勾选「使用余额抵扣」,「仅充值所得 Credits 可抵扣,赠送 Credits 不参与抵扣。」全额抵扣时订单立即完成,支付渠道显示「余额抵扣」;仍有「待支付金额」时,点 **去支付** 扫码付清剩余部分。 - **自动续费**:打开卡片上的「自动续费」开关后,到期前会用充值余额自动续 1 个计费周期,从到期前 1 小时开始尝试,进入宽限期后继续每小时尝试一次。充值余额不够全额支付时不会下单,只发送「自动续费失败」提醒,卡片下方也会提示「下次自动续费预计需 ¥X,当前可抵扣余额不足,请充值 Credits。」试用订阅不会自动续费。 ## 核销邀请码与代金券 邀请码、权益码和代金券都在「购买充值」的「券核销」中使用:把码粘贴到「输入核销码」框(连字符和大小写不影响识别),点 **查看** 预览内容,确认后点 **立即核销**,权益直接发放到当前组织。 | 码的类型 | 形式 | 核销后得到 | | --- | --- | --- | | 代金券 | 16 位,形如 `XXXX-XXXX-XXXX-XXXX` | Credits,计入赠送余额 | | 邀请码、权益码 | 新码为 20 位,形如 `XXXX-XXXX-XXXX-XXXX-XXXX`,也可能是较短的旧码或自定义码 | Credits(计入赠送余额)或试用订阅 | - **试用权益**:只能在对应版本的组织核销,团队版试用码用于团队版组织,企业版试用码用于企业版组织,并且需要先完成对应的实名认证;个人版组织不能核销。试用只会延后当前订阅的到期时间,席位只增不减。每个组织最多核销 3 次试用权益,同一张试用码对同一个组织只能核销一次。 - **代金券**:同一张代金券,每个登录账号只能兑换一次。 - **查看次数**:邀请码、权益码的「查看」每人每小时最多 6 次、每天最多 20 次,超出时提示「核销码查询次数过多,请在 N 分钟后再试」。代金券的查看与兑换另有频率限制。 - **输错保护**:邀请码、权益码连续输错 3 次后,页面出现「安全验证」:点 **获取验证码**,先完成滑块验证,再输入发到本人手机的 6 位短信验证码并点 **验证**。验证通过后 10 分钟内最多可以再尝试 5 次。 核销结果可在「核销记录」标签查看,列出核销时间、券类型、券码、到账额度、权益和核销人。券码只显示末 4 位。 ## 申请发票 满足以下条件的订单,在「订单记录」操作列显示 **申请开票**:状态为「已完成」、实付金额大于 0 的人民币订单,且尚未关联有效的开票申请。全额用余额抵扣、实付为 0 的订单不能开票。不可选的行把鼠标悬停在勾选框上可以看到原因。 1. 点单个订单的 **申请开票**,或勾选多笔订单后点 **批量申请开票(N)**,打开「发票管理」。 2. 选择「抬头类型」:「企业单位」或「个人 / 非企业单位」;选择「发票类型」:「增值税普通发票」或「增值税专用发票」,专用发票只能开给企业单位。 3. 企业单位填写「企业名称」和 18 位「统一社会信用代码」;所有抬头都要填写「接收邮箱」。注册地址、注册电话、开户银行、银行账号和备注在选填信息中。 4. 核对「开票金额」后点 **提交开票申请**。金额等于所选订单实付金额之和,不能修改。 开票信息提交后不能修改;申请处于「待处理」时可以取消后重新提交。点「订单记录」上方的 **开票记录** 查看全部申请,状态有「待处理」「处理中」「已开具」「已驳回」「已取消」「已作废」。已开具的电子发票发送到接收邮箱,也可以在开票记录中下载 PDF。 ## 常见问题 ### 付款后权益没有到账,怎么办? **答:** 在「订单记录」中打开这笔订单查看状态。扫码付款后仍是「待支付」时,在结算页点 **已支付?刷新状态**,或重新打开订单详情,系统会再次向支付机构查询结果;「处理中」表示权益正在发放,稍候刷新;「已完成」时回到「购买充值」点 **刷新** 查看余额。不要为同一笔购买重复下单。长时间没有变化时,带上订单号联系支持。 ### 扫码订单过期了,还能付款吗? **答:** 不能。订单关闭后请重新下单。如果过期前已经扫码付款,平台会向支付机构确认,确认已付款的订单会继续完成,不需要再付一次。 ### 订单可以退款吗? **答:** 控制台没有退款操作,需要退款时请联系支持。赠送余额不参与退款。 --- # 组织、成员与角色 来源: https://platform.lyrouter.com/ai_gateway/docs/organization 团队版和企业版的组织由当前账号管理员负责管理:在 **组织管理** 页搭建部门、用邮箱邀请或邀请链接招募成员,并决定每位成员能进入哪些工作空间、以什么角色使用。组织层面只有账号管理员和普通成员两种角色;每个工作空间里另有查看者、编辑者、管理员三种角色,决定成员在该空间内能做什么。成员人数受订阅席位数限制,账号管理员身份暂不支持转让。 ## 个人版、团队版与企业版 | 版本 | 开通条件 | 成员 | | --- | --- | --- | | 个人版 | 注册后即可使用,不需要实名认证 | 只有本人,不能邀请成员;**组织管理** 页只有「概览」 | | 团队版 | 账号管理员完成个人实名认证 | 可以邀请成员、搭建部门 | | 企业版 | 账号管理员先完成个人实名认证,再完成本企业的企业实名认证 | 同团队版 | - **创建组织**:在「选择组织」页或顶栏的「切换组织」窗口点「创建组织」,选择团队或企业并填写名称。账号管理员尚未完成所需认证时,组织状态为「待认证」;团队版在账号管理员完成个人实名后自动变为「正常」,企业版在企业实名认证通过后变为「正常」。 - **受邀成员不需要认证**:实名认证只针对账号管理员,成员加入组织不需要做个人或企业实名。 - **多个组织**:一个登录账号可以同时属于多个组织(个人版只能有一个)。每个浏览器标签页单独选择当前组织;在控制台内用「切换组织」换到另一个组织时,需要先用登录手机号接收短信验证码。 - **功能差异**:团队版起可以使用安全围栏的配额、模型和客户端访问控制,企业版另有敏感信息、提示词注入和意图安全检测,见[安全围栏与语义审计](https://platform.lyrouter.com/ai_gateway/docs/guardrails)。 (截图:组织管理的「概览」显示名称、版本、状态、我的角色与企业实名认证状态。) ## 组织角色与工作空间角色 组织角色决定成员能进入控制台的哪些页面: | 组织角色 | 说明 | | --- | --- | | 当前账号管理员(成员列表显示为「所有者」) | 创建组织的人,每个组织只有一位。管理部门、成员、邀请与审批,在组织内所有工作空间中都是「所有者」,负责 BYOK、智能路由、虚拟模型、安全围栏和订阅充值 | | 普通成员 | 通过邮箱邀请或邀请链接加入,只能进入获得授权的工作空间 | 普通成员的侧栏只有「概览」「工作空间」「模型广场」「API 密钥」「用量分析」「多媒体生成」「日志分析」。「自带密钥(BYOK)」「智能路由」「虚拟模型」「安全围栏」「安全事件」「订阅充值」「组织管理」只对账号管理员显示;普通成员直接打开这些页面的链接,会提示「当前组织角色无权访问该页面」并回到概览。获得工作空间管理员角色也不会开放这些页面。 工作空间角色决定成员在某个工作空间里能做什么: | 工作空间角色 | 能做什么 | | --- | --- | | 查看者 | 查看空间内已授权的资源,不能创建 API Key | | 编辑者 | 创建和编辑资源,例如创建、编辑自己的 API Key,不包含成员管理 | | 管理员 | 在编辑者的基础上,可以在模型广场开通或停用模型,并在日志分析中查看本空间所有 API Key 的调用记录 | 通过邀请或审批加入的人一律是普通成员。账号管理员身份暂不支持转让,成员列表中没有转让入口。 ## 搭建部门 账号管理员在 **组织管理** 的「部门」页签维护部门树:点「新建顶级部门」创建一级部门;选中部门后可以「新建子部门」「编辑」(改名或移动到其他上级部门)、「删除」和「添加成员」。 - **一人多部门,一个主部门**:同一成员可以属于多个部门,但只有一个主部门。添加成员时打开「设为这些成员的主部门」,或在部门成员列表的「主部门」列切换。 - **主部门的作用**:安全围栏中以「部门」为生效对象的策略,按 API Key 创建人的主部门匹配,不包含子部门。 - **删除部门**:部门下还有子部门或成员时不能删除,会提示「该部门下还有子部门或成员,请先清空后再删除」。 (截图:部门页左侧是部门树,右侧是所选部门的成员和主部门开关。) ## 邀请成员 **组织管理** 的「邀请」页签提供两种方式: | | 邮箱邀请 | 邀请链接 | | --- | --- | --- | | 发给谁 | 每个邮箱一份邀请,一次可以填多个邮箱 | 一条链接可以分享给多人 | | 是否审批 | 不需要,对方接受即加入 | 需要,账号管理员在「审批队列」点「通过」后才加入 | | 有效期 | 7 天 | 「有效天数(可选)」,留空为永不过期;还可设「最大注册数(可选)」 | | 部门 | 「默认部门(可选)」,接受后自动加入 | 链接可设默认部门,审批时确认「主部门」 | | 工作空间权限 | 发送时确认,单独授权可选查看者或编辑者 | 审批时确认,单独授权可选查看者或编辑者 | | 占用席位 | 发出后即占一个席位,直到被接受、撤销或过期 | 申请不占席位,通过审批时才占 | ### 邮箱邀请 点「邮箱邀请」,填写邮箱(逐个回车,或用逗号、空格、分号分隔粘贴),按需选择「默认部门(可选)」,在「工作空间权限」中确认对方加入后能进入的空间,再点「邮箱邀请」。 - **邮件在后台发送**:提示「已发送 N 封邀请邮件」表示邀请已创建,邮件可能稍后才到达。邀请列表的「邮件发送」列显示「待发送」「已发送」或「发送失败」;控制台不显示邮件里的邀请链接。对方迟迟收不到或显示「发送失败」时,请先检查垃圾邮件箱和邮箱拼写,再在列表中点「吊销」后重新邀请,或改用邀请链接。 - **对方如何加入**:打开邮件中的链接后,已登录且账号邮箱与受邀邮箱一致时点「确认加入」;账号还没绑定邮箱时,验证当前手机号后绑定受邀邮箱并加入;未登录时先验证手机号,已注册的直接加入,未注册的设置密码后点「创建账号并加入」。页面提示「当前账号绑定的邮箱与受邀邮箱不一致」时,需要退出后用受邀邮箱对应的账号登录。 - **发送失败**:同一邮箱已有待接受的邀请时返回 `a pending invitation already exists for this email`;该邮箱已是组织成员时返回 `invitation email already belongs to an active member`。 (截图:邮箱邀请中填写邮箱、选择默认部门,并核对共享授权、单独授权与生效权限。) ### 邀请链接 在「邀请链接」区块点「创建链接」,按需填写「默认部门(可选)」「最大注册数(可选)」「有效天数(可选)」后点「创建」。完整链接只在创建成功的弹窗中显示一次,请点「复制链接并关闭」保存;之后列表只显示「完整链接仅在创建时显示」,遗失后只能「吊销」并重新创建。 申请人打开链接后,已登录的点「申请加入」;未登录的先验证手机号,未注册的设置密码后点「创建账号并提交申请」。页面显示「申请已提交,等待管理员审批」,此时申请人还不是成员。账号管理员在「审批队列」中点「通过」,在「审批通过并分配部门」窗口确认「主部门」和工作空间权限后再点「通过」;也可以点「拒绝」。链接被吊销、过期或达到最大注册数后,其下尚未处理的申请也不能再通过,会提示「邀请链接无效、已过期或已用尽」。 ## 席位上限 团队版和企业版的成员数受订阅席位数限制。已占用席位等于现有成员(含账号管理员)加上「待接受」的邮箱邀请;待审批的加入申请不占席位,通过时才计入。达到上限后,发送邮箱邀请或通过加入申请都会失败,提示原文: ```text 当前订阅共 N 个席位,已占用 M 个(含待接受的邀请),请先增购席位后再邀请成员 ``` - 没有有效订阅的组织按 1 个席位计算,由账号管理员占用,因此无法邀请成员。 - 吊销「待接受」的邀请或移除不再需要的成员可以腾出席位;过期的邀请不再占用席位。 - 需要更多席位时,在 **订阅充值** 页点「增购席位」,见[购买、账单与发票](https://platform.lyrouter.com/ai_gateway/docs/orders)。 - 组织有订阅时,「审批队列」标题旁显示「剩余席位 2 / 共 5 席」,满额时显示「席位已满(共 5 席),请先增购席位」。 ## 工作空间授权 普通成员能进入哪些工作空间,来自以下三种授权: | 来源 | 谁获得 | 角色 | | --- | --- | --- | | 组织共享 | 工作空间「访问范围」为「组织共享」时,组织的全部有效成员 | 该空间的「共享成员角色」:新设置的共享为编辑者,较早设为查看者的保持不变 | | 部门共享 | 「访问范围」为「指定部门」时,所选部门的成员;勾选「同时包含所选部门的子部门」时含子部门。属于其中任一部门即可,不要求是主部门 | 同上 | | 单独授权 | 邀请或审批时选择的空间,以及在「成员」页签点「编辑」后添加的空间 | 邀请和审批时不选角色,一律为编辑者;「编辑」时可选编辑者或管理员,已有的查看者保持不变 | - **单独授权优先**:成员有单独授权时,按单独授权的角色生效,即使它比共享角色低;移除单独授权后,成员跟随空间的共享角色。 - **访问范围由账号管理员设置**:新建或编辑工作空间时设置「访问范围」和「共享成员角色」。新建的工作空间默认「组织共享」和「编辑者」;「仅自己/指定成员」的空间只有账号管理员和单独授权的成员能进入。 - **查看生效权限**:「成员」页签的「授权空间」列显示每个空间的生效角色,悬停可以看到授权来源。 - **需要账号管理员实名**:编辑或移除成员要求账号管理员已完成个人实名认证,未完成时提示「当前操作需要 Owner 完成个人实名认证」,点「去认证」完成即可。 (截图:新建工作空间时设置访问范围和共享成员角色,图示为按部门共享并包含子部门。) (截图:成员页签显示姓名、归属部门、授权空间与组织角色,账号管理员所在行没有操作按钮。) ## 移除成员 在「成员」页签点「删除」并确认「确定从组织移除此成员?」后: - 该成员立即失去组织内所有工作空间的访问,部门归属和单独授权一并清除。 - 该成员创建的 API Key 随之失效,调用返回 401 `invalid api key`。已产生的用量和日志保留,用量分析中标注「已移出」;需要继续调用的应用请换用其他成员创建的 Key。 - 账号管理员不能被移除,所在行没有操作按钮。 只收回某个工作空间的单独授权时:成员仍有组织或部门共享授权的,照常进入该空间,Key 不受影响;不再有任何授权的,成员在该空间创建的 API Key 会被停用。 ## 常见问题 ### 成员在「工作空间」中找不到某个空间,应该检查什么? **答:** 请账号管理员在「成员」页签查看该成员的「授权空间」。没有这个空间时,检查空间的「访问范围」:「仅自己/指定成员」需要单独授权;「指定部门」要求成员属于所选部门(或在勾选了子部门时属于其子部门)。也可以直接点「编辑」,为该成员添加单独授权。 ### 用量应该按谁的 Key 统计? **答:** 调用的用量和日志都记在 API Key 的创建人名下,不区分实际是谁在使用这把 Key。需要按人统计时,请每位成员用自己的账号创建 Key,不要由账号管理员统一创建后分发,见[用量归因与分析](https://platform.lyrouter.com/ai_gateway/docs/analytics)。 --- # 模型授权 来源: https://platform.lyrouter.com/ai_gateway/docs/authorization 一把 API Key 能调用哪些模型由两层设置决定:Key 所属工作空间在 **模型广场** 中开通的模型是基线;安全围栏的「模型访问控制」策略再按部门、组织成员或 API Key 收窄,只能减少、不能增加。模型没有在工作空间开通时,调用返回 403 `model_not_available`;被模型策略拦下时返回 403 `guardrail_model`。 ## 两层授权 | 层 | 在哪里设置 | 谁来设置 | 作用 | | --- | --- | --- | --- | | 模型广场开通 | 工作空间的 **模型广场**:模型卡片上的开关,或模型详情页中每个服务商的开关 | 当前账号管理员、该工作空间的管理员(个人版为账户本人) | 决定工作空间内所有 API Key 能调用哪些模型、经由哪些服务商 | | 模型访问控制策略 | **安全围栏** 的「模型访问控制」 | 当前账号管理员,团队版起可用 | 对部门、组织成员或 API Key 进一步收窄 | - 没有任何模型策略时,工作空间内的所有 Key 都能调用模型广场中已开通的模型。 - 模型策略不能放开模型广场没开通的模型:即使允许名单里写了它,调用仍返回 `model_not_available`。 - 开通、停用和策略的修改保存后几秒内同步到网关,不需要更换 API Key。 - 安全围栏页面只对账号管理员显示,普通成员遇到权限问题时,请把模型 ID、API Key 名称和报错原文发给账号管理员核对。 ## 在模型广场开通模型 模型广场分三个区:「专属可用模型」是本工作空间已经开通、可以直接调用的模型;「可启用」是有可用来源但尚未开通的模型;「需接入」是还没有任何可用来源的模型,需要先[接入 BYOK](https://platform.lyrouter.com/ai_gateway/docs/byok)。 - **按模型开关**:卡片上的开关作用于整个模型,打开时开通它所有可开通的来源,关闭时停用全部已开通的来源。 - **按服务商开关**:只想开通或停用某一个服务商时,打开模型详情页的「服务商与价格」,在对应服务商那一行操作。 - **停用最后一个来源**:会先弹出「确认停用最后一个服务来源」,确认后本工作空间的 API Key 不能再调用这个模型。 - **作用范围**:开通和停用只影响当前工作空间,不改变其他工作空间。 (截图:模型广场的「专属可用模型」列出本工作空间已开通的模型,管理员可用卡片右上角的开关开通或停用。) ## 成员申请开通 工作空间角色为查看者或编辑者的成员看不到开关,可以在模型广场或模型详情页向账号管理员提出申请: | 按钮 | 出现位置 | | --- | --- | | 「申请开通」 | 模型在本工作空间没有可用来源时,出现在模型卡片或详情页顶部 | | 「申请开通该服务商」 | 详情页中某个服务商的状态为「已禁用」或「成员访问受限」时,出现在该服务商那一行 | - 点击后向当前账号管理员发送一条站内通知,按钮变为「已通知管理员」。同一成员 24 小时内对同一模型或服务商重复申请,不会再发新通知,页面提示「管理员已收到该通知」。 - 申请只发通知,不创建审批流程,也不改变任何权限。账号管理员或工作空间管理员需要在模型广场开通模型或服务商;限制来自模型策略时,由账号管理员在安全围栏中调整。 - 详情页的状态「成员访问受限」表示工作空间已经开通了这个服务商,限制来自模型访问控制策略,需要调整的是安全围栏而不是模型广场。 ## 用模型访问控制策略收窄范围 当前账号管理员在 **安全围栏** 打开「模型访问控制」页签,点「新建模型访问控制策略」,按三步完成: 1. **生效对象**:选择「部门」「组织成员」或「API Key」。这类策略不能挂在整个工作空间上,要限制全空间请直接在模型广场停用。 2. **策略规则**:在「名单模式」中选「允许名单」(只允许名单内的模型)或「拒绝名单」(禁止名单内的模型);在「允许调用的模型」或「禁止调用的模型」中选择具体模型,或在「模型通配符」中每行写一个 `*` 通配,例如 `qwen-*`、`deepseek/*`。执行动作固定为「阻断」。 3. **生效时间**:选择立即生效或定时生效,以及是否设置失效时间。 (截图:安全围栏按策略类型分页签;在「模型访问控制」页签查看各策略的生效对象、执行动作与状态。) ### 多条策略如何叠加 | 情况 | 结果 | | --- | --- | | 任意一条适用的拒绝名单命中 | 拒绝 | | 同一对象上有多条允许名单 | 合并,模型出现在其中任意一条即可 | | 不同对象上都有允许名单(例如部门一条、Key 一条) | 模型必须同时出现在每一个对象的允许名单里 | 所以 Key 上的允许名单不能放宽部门或成员的限制。生效对象的匹配方式:「部门」覆盖创建人主部门恰好是该部门的 Key,不含子部门;「组织成员」覆盖该成员创建的全部 Key;「API Key」只覆盖所选的 Key。 ## 调用时的结果 | 情况 | 结果 | | --- | --- | | 模型已开通,没有策略限制 | 正常调用 | | 模型未在工作空间开通 | 403 `Model is not available in the model plaza`,`error.code` 为 `model_not_available`。工作空间设置了默认模型时,对话类请求改由默认模型回答,见[通道选择与路由策略](https://platform.lyrouter.com/ai_gateway/docs/routing) | | 模型被模型策略禁止 | 403 `Request blocked by guardrail policy`,`error.code` 为 `guardrail_model`,不会再尝试备用模型 | - **按实际模型检查**:通过[虚拟模型](https://platform.lyrouter.com/ai_gateway/docs/presets)或 `lyrouter/auto` 调用时,网关按最终选中的模型 ID 检查策略。在模型策略里填写 `@vmodel/...` 或 `lyrouter/auto` 不起作用。 - **`GET /v1/models` 按 Key 列出**:返回工作空间已开通、且这把 Key 的模型策略允许的模型 ID,所以同一工作空间的不同 Key 可能得到不同的列表。`@vmodel/<名称>` 和 `lyrouter/auto` 总会列出,调用时再按实际模型检查。 - **日志中的标记**:在[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)的「状态说明」列,模型策略拦截显示为「模型访问被拒绝」。各类 403 的处理方法见[401 / 403:鉴权与权限](https://platform.lyrouter.com/ai_gateway/docs/auth-errors)。 ## 验证授权 用目标成员自己创建的 Key 调用 `GET /v1/models`,确认列表符合预期;再分别调用一个允许的模型和一个被禁止的模型,确认前者成功、后者返回 403 `guardrail_model`。环境变量的设置见[完成第一次模型调用](https://platform.lyrouter.com/ai_gateway/docs/quickstart): ```bash curl "$LYROUTER_BASE_URL/v1/models" \ -H "Authorization: Bearer $LYROUTER_API_KEY" ``` ## 常见问题 ### 模型在模型广场能看到,为什么 Key 调用返回 403? **答:** 先看 `error.code`。`model_not_available` 表示 Key 所属工作空间没有开通这个模型或服务商:确认模型在「专属可用模型」中,并确认 Key 属于这个工作空间。`guardrail_model` 表示模型策略禁止了这把 Key,请账号管理员在安全围栏的「模型访问控制」中检查对 Key、创建人及其主部门生效的策略。 ### 修改客户端里的模型名称能绕过限制吗? **答:** 不能。网关只认模型 ID,策略也按实际选中的模型检查。请把 `model` 写成模型广场卡片上复制的模型 ID,不要使用展示名称。 ### 成员申请开通后多久能用? **答:** 申请只是通知账号管理员。在模型广场开通模型或服务商、或调整模型策略并保存后,几秒内生效,成员无需更换 API Key,重新调用即可。 --- # 安全围栏与语义审计 来源: https://platform.lyrouter.com/ai_gateway/docs/guardrails 安全围栏是工作空间级的调用策略:网关按策略检查每次调用的配额、模型、客户端和请求内容,命中后告警、掩码、剥离、阻断或封禁,并在 **安全事件** 页留下记录。配额管理、模型访问控制、客户端访问控制从团队版起可用;敏感信息检测、提示词注入检测、意图安全检测需要企业版。策略和事件都由当前账号管理员在工作空间的 **安全围栏**、**安全事件** 页管理,普通成员看不到这两个页面。 ## 策略类型与版本 | 策略类型 | 检查什么 | 可选动作 | 拦截时的 `error.code` | 最低版本 | | --- | --- | --- | --- | --- | | 配额管理 | 统计周期内的信用点或 Token 用量,可另设 RPM、TPM | 阻断、告警 | 返回 429,见[预算、配额与限流](https://platform.lyrouter.com/ai_gateway/docs/quota) | 团队版 | | 模型访问控制 | 实际调用的模型 | 阻断 | `guardrail_model` | 团队版 | | 客户端访问控制 | 来源 IP、请求声明的工具名、`User-Agent` | 阻断、告警 | `guardrail_client` | 团队版 | | 敏感信息检测 | 请求或回答中的个人信息、凭证和敏感关键词 | 请求侧:阻断、告警、掩码;响应侧:阻断、告警 | `guardrail_sensitive` | 企业版 | | 提示词注入检测 | 用户输入中试图改写模型指令的内容 | 阻断、告警、剥离 | `guardrail_injection` | 企业版 | | 意图安全检测 | 请求意图是否属于高风险类型 | 封禁、阻断、告警 | `guardrail_context` | 企业版 | - **版本按订阅判断**:没有有效订阅的组织按个人版处理。个人版能看到两个菜单,但页面显示「当前版本不支持使用此功能」;个人账户不能直接订阅,需要先创建团队或企业组织,再在 **订阅充值** 页开通。 - **降级后存量策略继续生效**:当前版本不包含某类策略时(例如从企业版降到团队版),已创建的这类策略仍会在网关上拦截或掩码请求。页面会提示这一点,你可以停用或删除它们,但不能新建或修改。 - **事件保留期**:安全事件默认在团队版保留 30 天、企业版保留 180 天,超过保留期后无法在列表或详情中查到。 (截图:当前订阅版本不包含安全事件时,页面显示「当前版本不支持使用此功能」和升级入口。) ## 新建策略 在 **安全围栏** 切到对应类型的页签,点右上角的新建按钮(例如「新建配额管理策略」),按三步完成: 1. **生效对象**:「对象类型」选「工作空间」「部门」「组织成员」或「API Key」,并选择具体对象。模型访问控制不能选「工作空间」。 2. **策略规则**:填写「策略名称」(至少 2 个字符)和该类型的规则,再选「执行动作」。策略类型由所在页签决定,保存后不能更改。 3. **生效时间**:选「立即生效」或「定时生效」,以及「永久有效」或「指定失效时间」。最后点「保存草稿」(不生效)、「保存并启用」或「保存并设置定时生效」。 只有状态为「已启用」且处在生效时间内的策略才会执行。列表中可以随时停用、启用、编辑或删除策略。 | 生效对象 | 覆盖哪些调用 | | --- | --- | | 工作空间 | 本工作空间的全部调用 | | 部门 | 创建人的主部门恰好是所选部门的 API Key,不含子部门 | | 组织成员 | 所选成员创建的全部 API Key | | API Key | 所选的 API Key | 同一次调用适用多条策略时,所有策略同时执行,不是只取最具体的一条。例如工作空间级和某个 API Key 上的敏感信息策略都会检查;工作空间配额和成员配额是两个独立上限,任一触顶都会拒绝。 (截图:编辑策略的第一步「生效对象」:选择对象类型和具体部门,配额策略还要选择配额模式。) ## 各类策略的规则 **配额管理** 与 **模型访问控制** 分别见[预算、配额与限流](https://platform.lyrouter.com/ai_gateway/docs/quota)和[模型授权](https://platform.lyrouter.com/ai_gateway/docs/authorization)。 ### 客户端访问控制 每条策略选一种「控制对象」,再选「允许名单」或「拒绝名单」: | 控制对象 | 匹配什么 | 写法 | | --- | --- | --- | | IP / CIDR | 网关识别到的请求来源 IP | IPv4、IPv6 或网段,例如 `10.0.0.0/8` | | 工具 / function | 请求体 `tools`(或 `functions`)中声明的函数名 | 支持 `*` 通配;请求没有声明工具时不检查 | | 客户端 / SDK | 请求头 `User-Agent` | 支持 `*` 通配,整串匹配,区分大小写,例如 `company-agent/*` | 工具名使用允许名单时,请求声明的每一个工具都必须在名单内;使用拒绝名单时,任意一个工具命中即违规。 ### 敏感信息检测 - **检测类别**:身份证号、手机号、银行卡号、护照号、电子邮箱、家庭住址、车牌号、统一社会信用代码、内部凭证,以及按关键词识别的财务数据、健康数据、商业秘密。新建时默认勾选身份证号、手机号、银行卡号和内部凭证。身份证号、银行卡号和统一社会信用代码会校验校验位。 - **自定义规则**:「自定义信息类别与脱敏规则」中每条填写类别名称、正则表达式和可选的脱敏风格,最多 50 条。 - **检测方向**:「请求」「响应」或「请求与响应」。响应侧只做规则检测,动作只能是阻断或告警。 - **检测引擎**:「规则」或「混合」。「混合」还会用语义模型识别套取敏感数据的意图;语义命中没有可定位的文字,动作为掩码时会改为阻断。 - **检测范围**:默认「仅用户输入」,只检查用户消息;「整段对话(含助手回复与工具返回)」检查得更全,误报也明显更多,建议先用「告警」观察。 - **脱敏风格**:「整体替换」(默认,替换为 `[REDACTED]`)、「保留部分位」(如手机号 `138****5678`)、「哈希化」(替换为 `[SHA256:…]`,同一个值结果相同)。财务数据、健康数据、商业秘密匹配的是关键词而不是具体数值,不能选掩码,否则保存失败。 ### 提示词注入检测 - **检测类别**:直接指令覆盖、直接注入、系统提示词泄露、角色扮演越狱、分隔符与格式逃逸、编码混淆、多语言绕过、载荷拆分、间接注入、对抗性后缀、越权指令、工具劫持。 - **检测引擎**:「规则」「语义」或「混合」。 - **灵敏度**:「低」「中」「高」,越高越严格:「高」拦截最多,误报也最多;「低」只拦截把握最大的请求。新建时默认「高」。 - **剥离**:把命中的片段替换为 `[REMOVED]` 后继续转发;只有语义命中、没有可定位片段时改为阻断。注入检测只检查请求,不检查回答。 ### 意图安全检测 - **高风险意图类型**:敏感数据泄露、破坏性操作、欺诈、系统越权、恶意代码植入。 - **置信度阈值**:0.5~1,默认 0.9,风险概率达到或超过阈值才算命中。 - **封禁**:动作选「封禁」时还要填「自动解封时间(小时)」,范围 1~8760,默认 24。 - 保存前必须勾选「开启并同意用于跨会话安全分析」。 **适用接口**:敏感信息、提示词注入和意图安全检测只作用于 `/v1/chat/completions`、`/v1/messages` 和 `/v1/responses`。向量、图像、音频、视频和重排序接口只执行封禁、模型访问控制和客户端访问控制检查。语义检测服务暂时不可用时,语义部分不会拦截请求,规则检测照常执行。 ## 调用方看到什么 | 执行动作 | 网关行为 | 调用方看到 | | --- | --- | --- | | 告警 | 放行请求,记录安全事件并发送通知 | 正常响应 | | 掩码 | 把命中内容替换后再转发给模型 | 正常响应,模型收到的是掩码后的内容 | | 剥离 | 把命中的注入片段替换为 `[REMOVED]` 后转发 | 正常响应 | | 阻断(请求侧) | 不调用模型 | 403 `Request blocked by guardrail policy`,`error.code` 为 `guardrail_<类型>` | | 阻断(响应侧,非流式) | 丢弃模型的回答 | 403 `Response blocked by guardrail policy`,`error.code` 为 `guardrail_sensitive`。上游已经生成回答,这次调用照常计费 | | 阻断(响应侧,流式) | 响应已经开始输出,无法再返回 403,改为掩码 | 回答照常输出,命中内容被掩码 | | 封禁 | 拒绝本次请求,并封禁这把 API Key | 本次 403 `Request blocked by guardrail policy`(`guardrail_context`);之后 403 `Subject is blocked by an active security ban`(`guardrail_subject_banned`) | - 报错原文不包含策略名称和命中内容,同样的请求重试会得到同样的结果。各报错的处理方法见[401 / 403:鉴权与权限](https://platform.lyrouter.com/ai_gateway/docs/auth-errors)。 - 开启响应侧检测后,流式回答每段末尾约 64 字节会稍晚发出,用于识别被拆在两段之间的号码。 - 封禁在这条安全事件入库后建立,作用于这把 Key 在本工作空间的全部请求,期间每次被拒绝都会记一条「主体处于封禁状态」事件。到达「自动解封时间(小时)」后自动解除,也可以提前手动解除,见下文。 ## 查看和处置安全事件 **安全事件** 页顶部的「今日事件」「今日阻断」「待处置」「当前封禁」可以一键筛选;列表支持按事件、请求、链路或主体搜索,并按事件类型、严重级别、处置状态和时间筛选,「导出」按当前筛选条件下载。 打开一条事件,详情包括: | 区块 | 看什么 | | --- | --- | | 基本信息 | 发生时间、事件类型、触发策略、触发主体、执行动作、严重级别、处置状态、模型、客户端。「触发主体」显示 API Key 名称和创建人,创建人是 Key 的创建者,不一定是实际调用者 | | 触发时间线 | 「请求到达」→「围栏命中」(请求侧或响应侧,规则命中、语义命中及分数,或配额触顶)→「执行动作」。实际动作与配置不同时会写明原因,例如「响应已开始流式输出,阻断无法执行」「语义命中无字符位置,掩码降级为阻断」 | | 匹配详情 | 命中规则、触发阈值、置信度、检测器和请求 ID | | 取证原文 · 已脱敏 | 敏感信息和注入检测在请求侧命中时,显示命中位置附近的原文,敏感值已脱敏,查看行为会写入审计;配额、模型、客户端类事件不采集请求内容 | | 处置时间线 | 每次处置的动作、状态、备注、操作人和时间 | 点「查看关联访问日志」可以直接打开这次请求的[日志](https://platform.lyrouter.com/ai_gateway/docs/logs)详情。 **处置**:在「处置备注」中写明结论后,点「确认事件」(变为「已确认」)、「标记误报」(「误报」)或「完成处置」(「已解决」)。封禁类事件还有「解除主体封禁」,执行后状态变为「已解决」,几秒内撤销这把 Key 在本工作空间的封禁。在列表中勾选多条事件可以批量处置,单次最多 500 条,超出部分需要再执行一次。处置只改变事件状态,不修改策略;误报较多时请回到安全围栏调整策略。 ## 常见问题 ### 同一个问题为什么只生成了一条事件? **答:** 为避免列表被刷屏,敏感信息和提示词注入检测在 5 分钟内对同一策略、同一 Key、同一类别的命中合并为一条事件;配额触顶按统计周期合并。合并只影响事件记录,每次请求的拦截或掩码照常执行,每个被拦截的请求在[日志](https://platform.lyrouter.com/ai_gateway/docs/logs)中都有记录。 ### 成员报告请求被拦截,账号管理员怎么找到对应事件? **答:** 请成员提供调用时间、API Key 名称和报错中的 `error.code`,账号管理员在安全事件中按时间范围和事件类型筛选。能在日志中找到这次请求时,把日志详情顶部的 Request ID 粘贴到安全事件的搜索框,即可定位到对应事件。 --- # 日志内容与数据处理 来源: https://platform.lyrouter.com/ai_gateway/docs/privacy 模型调用的内容经过 LYRouter 网关转发给选中的上游服务商。日志默认只记录元数据,例如模型、服务商、状态码、Token、费用和耗时;只有工作空间开启「保存请求响应全文」后,才会保存经过平台脱敏的提示词、回答和报文正文。本章说明日志保存哪些内容、如何开关全文日志、上游服务商会收到什么,以及谁能查看正文和导出日志。 ## 日志保存哪些内容 | 内容 | 全文日志关闭 | 全文日志开启 | | --- | --- | --- | | 元数据:时间、API Key、API 路径、模型、服务商、状态码与状态说明、Token、费用、耗时、客户端、采样参数、请求中定义的工具名称、路由追踪、安全审查命中记录 | 保存 | 保存 | | 四段报文的请求头和响应头(凭据类请求头除外) | 保存 | 保存 | | 提示词、对话、回答和思考过程 | 不保存 | 保存(脱敏后) | | 模型返回的工具调用(函数名与参数) | 保存 | 保存 | | 四段报文的报文体 | 不保存 | 保存(脱敏后) | | 失败请求的上游错误响应、返回给客户端的错误响应 | 保存(脱敏后,每段最多 64 KB) | 保存(脱敏后) | - 开启后每段正文最多保存 1 MB,超出部分截断。 - `Authorization`、`x-api-key`、`api-key`、`Cookie`、`Proxy-Authorization` 等凭据类请求头在任何情况下都不保存。 - 安全围栏命中时,[安全事件](https://platform.lyrouter.com/ai_gateway/docs/guardrails)会保存触发位置附近的一小段脱敏文本作为证据,这与全文日志开关无关。 ## 开启或关闭全文日志 全文日志按工作空间设置,默认关闭。当前账号管理员和工作空间管理员可以修改;其他成员的 **日志存储设置** 按钮不可用,提示「仅管理员可修改全文日志设置。」 1. 在工作空间的 **日志分析** 页点击 **日志存储设置**,打开「日志详情存储策略」。 2. 打开「保存请求响应全文」开关,逐项勾选五项信息处理告知: - 「我知悉请求和响应内容会在平台脱敏后保存。」 - 「我知悉内容的存储位置,并确认其处于配置的数据边界内。」 - 「我知悉内容保留期限及删除流程。」 - 「我知悉可访问内容的工作空间角色范围。」 - 「我同意内容仅用于此处说明的调试、分析和安全取证。」 3. 点击 **保存**。没有全部勾选时,提示「请先确认全部信息处理告知事项。」 (截图:在日志详情存储策略中开启保存请求响应全文,并确认五项信息处理告知。) - **当前状态**:工具栏的「全文日志」标签显示「已开启」或「已关闭」。显示「未获取到」时无法打开设置,稍后刷新页面再试。 - **只对新请求生效**:开启之前已经发生的调用不会补存正文,这些日志的详情显示「本条日志未记录正文」。 - **关闭后**:新的请求不再保存正文,已保存的内容仍按现有保留策略处理,保留期限见[数据保留、导出与删除](https://platform.lyrouter.com/ai_gateway/docs/retention)。 - **操作记录**:每次开启或关闭都会记录操作人、时间和勾选的告知事项。 ## 平台脱敏 全文日志保存的正文和失败请求的错误响应,在保存前都会经过平台脱敏,有正文的日志详情标注「正文已按平台策略脱敏」。脱敏按固定规则识别: - `Bearer` 令牌、以 `sk-` 开头的密钥,以及名为 `api_key`、`token`、`secret`、`password` 等字段的值; - 手机号、身份证号、银行卡号等较长的数字串,只保留首尾几位; - IP 地址替换为 `[ip]`,邮箱地址替换为 `[email]`; - 图片等 base64 内容只保存长度和校验摘要,不保存原始数据。 规则无法覆盖所有敏感信息,例如姓名和地址不会被识别。处理高度敏感的数据时,请保持全文日志关闭。 ## 上游服务商会收到什么 - **完成调用所需的内容**:消息、系统提示词、参数、工具定义,以及图片、音频等输入。网关可能为适配服务商转换协议或参数,日志「原始报文」的「② 上游请求」就是实际发给服务商的内容。 - **网关的凭证**:网关使用平台凭证或你的 BYOK 凭证调用服务商,你的 LYRouter API Key 不会转发给上游。 - **日志脱敏不改变发往上游的内容**。需要在发出前遮盖敏感信息时,在[安全围栏](https://platform.lyrouter.com/ai_gateway/docs/guardrails)中配置「敏感信息检测」策略,并选择「掩码」动作。 各服务商是否将提示词用于模型训练,在 **模型广场** 打开模型详情,在「服务商与价格」中查看服务商名称旁的盾牌图标,鼠标停留时显示: | 提示 | 含义 | | --- | --- | | 「该服务商不会将提示词用于模型训练。」 | 服务商声明不用于训练 | | 「请注意:该服务商可能将提示词用于模型训练。」 | 服务商可能用于训练 | | 「该服务商尚未披露是否将提示词用于模型训练。」 | 没有可用的声明,不代表不会训练 | 平台对个人信息的处理规则见[隐私政策](https://platform.lyrouter.com/ai_gateway/legal/privacy-policy)。 ## 谁能查看正文和导出日志 | 操作 | 当前账号管理员、工作空间管理员 | 普通成员 | | --- | --- | --- | | 查看日志 | 工作空间内所有 API Key 的日志 | 只有自己创建的 API Key 产生的日志 | | 「对话」和「原始报文」四段报文 | 可以 | 可以(仅自己的 API Key) | | 「路由追踪」、按每次尝试分组的上游报文 | 可以 | 不显示 | | 导出日志 | 可以 | 不可以 | | 修改全文日志设置 | 可以 | 不可以 | 导出文件包含已保存的提示词、对话、模型响应和报文体,因此下载前需要验证绑定手机号并确认妥善保管,完整步骤见[数据保留、导出与删除](https://platform.lyrouter.com/ai_gateway/docs/retention#加密导出)。 (截图:日志导出按时间范围和格式生成加密文件,需要设置文件密码。) ## 常见问题 ### 开启全文日志后,能看到之前请求的正文吗? **答:** 不能。全文日志只对开启之后的新请求生效,之前的日志只有元数据。 ### 没有开启全文日志,为什么失败的请求能看到响应内容? **答:** 失败请求的上游错误响应和返回给客户端的错误响应会单独保存(每段最多 64 KB,已脱敏),用于排查问题。提示词和成功请求的回答不会保存。 ### 普通成员能看到其他人的对话吗? **答:** 不能。普通成员只能查看自己创建的 API Key 产生的日志。当前账号管理员和工作空间管理员可以查看工作空间内所有 API Key 的日志正文,开启全文日志前请在团队内明确这一点。 --- # 数据保留、导出与删除 来源: https://platform.lyrouter.com/ai_gateway/docs/retention 日志正文(对话、原始报文、路由候选与尝试记录)可以查看多少天,由账户的订阅决定;超过留存期后,日志只保留元数据。日志记录本身最多保存 180 天,之后自动删除。需要长期留存时,由当前账号管理员或工作空间管理员在留存期内按时间范围加密导出,导出文件保留 24 小时。 ## 查看留存期 在工作空间的 **日志分析** 页点击 **日志存储设置**,「日志详情存储策略」顶部显示当前账户的「滚动容量:N 条详情」和「详情留存:N 天」。这两个数值来自账户的订阅,各套餐的「日志详情条数」和「日志留存」显示在 **订阅充值** 页的套餐卡片上,见[计费规则与信用点](https://platform.lyrouter.com/ai_gateway/docs/billing)。 (截图:日志详情存储策略显示当前的滚动容量和详情留存天数。) | 内容 | 可以查看多久 | | --- | --- | | 元数据:时间、API Key、模型、服务商、状态码、Token、费用、耗时等 | 180 天,之后整条日志自动删除 | | 正文:「对话」「原始报文」、路由追踪中的候选和上游调用尝试、安全审查命中记录 | 订阅的「详情留存」天数内 | | 导出文件 | 创建导出任务后 24 小时 | - **超过留存期**:日志仍在列表中,元数据可以查看;详情标注「详情已超过留存期」,并提示「该请求的元数据仍可查看,但内容详情已超过当前版本的 N 天留存期。」 - **按当前订阅计算**:留存期按查看时账户的订阅计算,订阅变化后,可以查看正文的时间范围随之变化。 - **没有保存正文的日志**:工作空间没有开启全文日志时,日志本来就只有元数据,详情显示「本条日志未记录正文」,见[日志内容与数据处理](https://platform.lyrouter.com/ai_gateway/docs/privacy)。 - **滚动容量与超容**:「滚动容量」是订阅包含的日志详情条数,按账户计算,账户内所有开启全文日志的工作空间共用,只统计开启之后的新请求;超出容量的较早正文约每天清理一次。运营为套餐设置了超容单价时,弹窗中才会出现「超容后付费保留」开关:开启后超出容量的正文不再清理,按弹窗显示的单价从实付额度扣费。这个开关作用于整个账户,在任一工作空间修改都会影响同一账户的所有工作空间;修改后点击 **保存**。目前各套餐默认没有超容单价,不显示这个开关。 ## 加密导出 当前账号管理员和工作空间管理员可以把日志导出为加密文件,其他成员的 **导出** 按钮不可用。「最近导出任务」只列出你自己在当前工作空间创建的任务,也只有创建人可以下载。 1. 在 **日志分析** 页设置好搜索词和筛选条件,导出会沿用它们(时间范围除外)。 2. 点击 **导出**,打开「日志导出」。 3. 「导出格式」选择 CSV 或 JSON,默认 JSON。 4. 填写「导出时间范围」:列表已选时间范围时默认沿用,否则需要手动填写开始和结束时间。修改导出时间不影响列表筛选。 5. 设置「文件密码」,用于打开下载后的加密文件。请保存好密码,遗忘后只能重新导出。 6. 点击 **创建导出任务**。任务在后台排队生成,关闭窗口后继续处理。每个账号同一时间只能有一个处于「排队中」或「生成中」的任务,否则提示「已有导出任务正在处理或队列繁忙,请稍后重试」。 7. 任务状态变为「可下载」后,点击 **下载**,在「下载日志」中点击 **发送验证码**,输入发到绑定手机号的 6 位短信验证码,勾选「我已了解并会妥善保管敏感数据」,再点击 **验证并下载**。 8. 用创建任务时设置的密码打开下载的 ZIP 文件。 | 项目 | 限制 | | --- | --- | | 时间范围 | 单次最多 31 天;结束时间晚于当前时间时按当前时间截止 | | 条数 | 单次最多 50,000 条,超出时任务标注「已达上限」 | | 文件密码 | 6~128 个字符 | | 文件格式 | AES-256 加密的 ZIP,内含 `ai-logs.csv` 或 `ai-logs.json`;系统自带的解压工具可能无法打开,可使用 7-Zip 等支持 AES 加密的工具 | | 文件保留 | 创建任务后 24 小时,「剩余保留时间」显示倒计时,到期后文件删除、任务不再显示 | 导出内容包括元数据,以及已保存的提示词、对话、模型响应和四段报文体,不包括请求头和响应头。超过留存期或没有保存正文的日志只导出元数据,`content_state` 字段分别为 `expired` 和 `not_stored`,有正文时为 `stored`。 (截图:在日志导出中选择格式和时间范围,并设置文件密码。) ## 删除 - **导出文件**:创建 24 小时后从存储中删除,下载地址随之失效。 - **日志正文**:超过留存期后不再显示;关闭全文日志后,新请求不再保存正文。 - **日志记录**:保存 180 天后自动删除。 - **API Key**:删除 API Key 后,它已经产生的日志仍按上述期限保留。 控制台不提供手动删除单条日志的功能。需要删除个人信息或账户数据时,按[隐私政策](https://platform.lyrouter.com/ai_gateway/legal/privacy-policy)中的方式联系平台。 ## 常见问题 ### 导出能恢复没有保存或已过期的正文吗? **答:** 不能。导出只包含导出时仍能查看的内容;没有开启全文日志时的请求,以及超过留存期的日志,只有元数据。需要长期留存正文时,请在留存期内定期导出。 ### 弹窗提示「日志导出尚未启用,请联系管理员配置对象存储。」怎么办? **答:** 当前部署没有配置导出文件的存储,无法创建导出任务。请联系平台管理员处理。 ### 提示「单次最多导出 31 天,请调整导出时间范围。此修改不会影响列表。」怎么办? **答:** 缩短「导出时间范围」,分多次导出。同一时间只能有一个任务在排队或生成,前一个任务变为「可下载」后再创建下一个。 ### 下载时提示「请先在账号设置中绑定可用手机号」怎么办? **答:** 下载验证码发送到创建任务的账号所绑定的手机号。请先在账号设置中绑定可用的手机号,再回到「最近导出任务」点击 **下载**。导出任务只有创建人可以下载,其他管理员需要自己创建任务。 --- # 通过日志定位调用问题 来源: https://platform.lyrouter.com/ai_gateway/docs/logs 每次经过 LYRouter 网关的模型调用,都会在工作空间的 **日志分析** 页留下一条日志。按时间、API Key、模型和状态码找到这次请求,打开详情就能看到实际调用的模型和服务商、失败来自网关还是上游、各阶段耗时、Token 和费用。日志在调用结束后几秒内可以查到;联系支持时,请附上日志详情顶部的 Request ID。 ## 找到这次请求 在工作空间左侧菜单打开 **日志分析**,列表只显示当前工作空间的调用。当前账号管理员和工作空间管理员能看到工作空间内所有 API Key 的日志;普通成员只能看到自己创建的 API Key 产生的日志,一条都没有时列表显示「暂无你可查看的日志」。API Key 删除后,它产生的日志仍然保留,「API Key」列标注「已删除」。 - **搜索框**:输入后自动生效,不区分大小写,同时匹配模型、API Key 名称、创建人、Request ID、Trace ID 和 API 路径。搜索框不匹配错误信息,查找失败的调用请用「状态码」筛选。 - **添加筛选**:「时间范围」「服务商」「请求意图」「是否流式」「状态码」选中即生效;「模型」「客户端」「API Key」「会话 ID」「请求关键字」「响应关键字」输入后按回车或点击 **应用筛选**。「请求关键字」「响应关键字」在提示词和回答正文中搜索,只能搜到开启全文日志期间保存的内容。组织账户还可以按「创建人」「部门」筛选。所有条件同时生效,可在列表上方逐个移除,或点击 **清空全部**。 - **自定义列**:默认显示时间、API Key、API 路径、模型(请求)、服务商、总 Token、状态和状态说明,组织账户还显示创建人。「模型(实际)」「费用」「首 Token」「总延迟」「会话」等列在 **自定义列** 中打开。 - **时间**:「时间」是请求结束的时间。排查运行很久的请求时,用它减去「总延迟」,得到请求到达网关的大致时间。 (截图:在日志分析中按时间、API Key、模型和状态码查找请求。) ## 判断失败来自网关还是上游 列表的「状态」是返回给客户端的 HTTP 状态码,「状态说明」给出来源和原因。鼠标停在「状态说明」上,可以看到最终状态码、来源、原因和上游状态码。 | 「状态说明」 | 含义 | 下一步 | | --- | --- | --- | | 「网关」+ 具体原因,如「余额不足」「安全围栏已拦截请求」「网关限流规则已拒绝请求」「模型不可用」 | 网关在调用上游之前拒绝了请求 | 按原因查看[401 / 403:鉴权与权限](https://platform.lyrouter.com/ai_gateway/docs/auth-errors)、[429:限流与配额](https://platform.lyrouter.com/ai_gateway/docs/rate-errors)或[模型不可用](https://platform.lyrouter.com/ai_gateway/docs/unavailable) | | 「网关」+「连接上游失败,未收到响应」「上游请求超时」「上游请求或响应读取失败」 | 网关已发起调用,但连接上游失败、等待超时或读取中断 | 见[超时与流式中断](https://platform.lyrouter.com/ai_gateway/docs/stream-errors) | | 「上游」+「服务商返回“…”」 | 上游服务商返回了错误状态码,网关回退完所有候选后原样转发 | 在详情「原始报文」的「上游响应」中查看服务商的报错原文 | | 「未知」+「历史记录未保存状态来源」 | 较早的日志没有记录来源 | 结合「原始报文」判断 | ## 日志详情里看什么 点击日志行,右侧打开「日志详情」。顶部是「Request ID」和「状态码」,下面是 API 路径、时间、API Key、客户端、模型(请求)、模型(实际)、服务商、Token 总量、吞吐和费用。基本信息下方有三个页签: | 页签 | 内容 | | --- | --- | | 「概览」 | 「路由追踪」「安全审查」「各阶段耗时」「Token 消耗」 | | 「对话」 | 请求参数、系统提示词、历史消息(默认折叠)、工具调用和回答(思考过程默认折叠);失败的请求显示「错误响应」 | | 「原始报文」 | ① 客户端请求、② 上游请求、③ 上游响应、④ 客户端响应,每段包含请求头或响应头和报文体,可以 **复制** | - **路由追踪**:实际命中的服务商和模型、使用的 BYOK、每次上游调用尝试和换下一个候选的原因,见[查看实际路由](https://platform.lyrouter.com/ai_gateway/docs/route-log)。 - **安全审查**:「配额管理」「模型访问控制」「客户端访问控制」在这次请求上的命中记录、「风险检测」结果和意图分类,见[安全围栏与语义审计](https://platform.lyrouter.com/ai_gateway/docs/guardrails)。 - **各阶段耗时**:分为 ① 鉴权、② 选路、③ 选 Key、④ 上游调用,最后一行是「总耗时」;某个阶段没有记录时显示 `—`。上游调用重试过时,④ 旁边显示「· N 次尝试,最长 X」,耗时是各次尝试之和。阶段数据没有采集到时,①~③ 显示 `—` 并额外显示「首 Token(TTFT)」一行;完全读不到阶段数据时,只显示「总耗时」「上游耗时」「首 Token(TTFT)」三项。④ 占总耗时的大部分,说明时间主要花在上游服务商。 - **原始报文**:`Authorization`、`x-api-key`、`api-key`、`Cookie` 等凭据类请求头不会出现,上游服务商的真实地址也会隐去。 (截图:日志详情的概览包含路由追踪、安全审查、各阶段耗时和 Token 消耗。) 「对话」和「原始报文」中的正文只在工作空间开启全文日志后保存,没有保存时详情标注「本条日志未记录正文」。失败的请求例外:即使没有开启全文日志,也会保存上游返回的错误响应和网关返回给客户端的错误响应,便于排查。开关和保存范围见[日志内容与数据处理](https://platform.lyrouter.com/ai_gateway/docs/privacy);超过留存期的正文不再显示,见[数据保留、导出与删除](https://platform.lyrouter.com/ai_gateway/docs/retention)。 (截图:原始报文按客户端请求、上游请求、上游响应和客户端响应四段展示。) ## Token 与费用怎么读 日志把一次调用的 Token 分成四项,互不重叠,相加就是这次调用的全部 Token: | 名称 | 含义 | | --- | --- | | 「输入(缓存未命中)」 | 没有命中上游提示词缓存的输入 Token | | 「输入(缓存命中)」 | 命中上游提示词缓存的输入 Token | | 「输出」 | 模型生成的 Token | | 「显式缓存创建」 | 通过 `cache_control` 显式写入上游缓存的 Token | - 详情「Token 消耗」列出四项的数量和占比,「总计」是四项之和。 - 列表的「总 Token」和详情的「Token 总量」是上游上报的输入加输出,不含「显式缓存创建」,所以可能小于「总计」。 - 「费用」是这次调用按调用时实际扣除的 Credits 折算的人民币金额(¥),没有费用记录时显示「未计算」。账户实际扣了多少 Credits,以 **订阅充值** 页「消费明细」为准;按时间、模型、API Key 汇总的用量见[用量归因与分析](https://platform.lyrouter.com/ai_gateway/docs/analytics),计费方式见[计费规则与信用点](https://platform.lyrouter.com/ai_gateway/docs/billing)。 ## 普通成员与管理员的差异 | 能力 | 当前账号管理员、工作空间管理员 | 普通成员(仅自己创建的 API Key) | | --- | --- | --- | | 对话、原始报文、费用、各阶段耗时、会话 | 可以查看 | 可以查看 | | 「状态说明」中上游返回的状态码 | 显示「服务商返回“…”」 | 显示「服务商返回,未记录更具体原因」,上游报错原文在「原始报文」的「上游响应」中查看 | | 「路由追踪」 | 可以查看 | 不显示 | | 「安全审查」 | 完整命中记录和风险检测明细 | 只显示部分命中类别 | | 导出日志、修改全文日志设置 | 可以 | 不可以,**导出** 按钮提示「仅工作空间管理员或所有者可导出日志。」 | 加密导出的步骤和限制见[数据保留、导出与删除](https://platform.lyrouter.com/ai_gateway/docs/retention#加密导出)。 (截图:当前账号管理员和工作空间管理员可以按当前筛选创建加密导出任务。) ## 常见问题 ### 刚发出的请求在日志里找不到,怎么办? **答:** 日志在调用结束后异步写入,稍等几秒后点击 **刷新**,或打开「自动刷新 · 15s」。仍然找不到时,逐项排查:列表上方是否还有筛选条件(点击 **清空全部**);普通成员是否用了别人创建的 API Key;请求是否没有带有效的 API Key(401 `missing credentials` 或 `invalid api key`,这类请求无法归属到任何工作空间);请求是否是 `GET /v1/models`(获取模型列表不记日志);请求是否被错误率熔断(429 `api_key_circuit_open`)或永久封禁(403 `api_key_permanently_banned`)拒绝,这两类请求也不写入日志。 ### 请求成功了,但日志显示的模型或服务商和预期不同? **答:** 看「模型(实际)」和「服务商」。请求的模型全部失败或在本工作空间未开通时,网关会改用工作空间的默认模型;通过虚拟模型或 `lyrouter/auto` 调用时,实际模型由它们决定。每次尝试和换通道的原因在「路由追踪」中,见[查看实际路由](https://platform.lyrouter.com/ai_gateway/docs/route-log)和[失败重试与备用模型](https://platform.lyrouter.com/ai_gateway/docs/fallback)。 ### 怎样查看同一段对话的所有请求? **答:** 在 **自定义列** 中打开「会话」列,同一会话的请求用同色标签标出,点击标签即按该会话筛选。鼠标停在标签上可以看到会话 ID 和来源:「声明(客户端 x-session-id)」表示由客户端提供;「推断(网关派生)」表示由网关推断,标签末尾带 `≈`。 ### 图像、视频生成任务的日志怎么看? **答:** 列表中只出现创建任务的那次请求,「任务类型」列显示「异步」,任务结算前「费用」显示「结算中」。打开详情后在顶部切换「本次请求」和「整个任务」:「本次请求」是提交任务的那次 HTTP 请求,本身不产生费用;「整个任务」显示任务 ID、任务费用、生成耗时、轮询次数和生成结果。接口用法见[多模态能力](https://platform.lyrouter.com/ai_gateway/docs/multimodal)和[异步任务](https://platform.lyrouter.com/ai_gateway/docs/async)。 ### 提交调用问题时需要提供哪些信息? **答:** 网关的响应中不包含请求 ID,请先在日志中找到这次请求,复制详情顶部的 Request ID,再附上调用时间(精确到分钟并注明时区)、接口路径、模型、API Key 的名称和完整报错原文。不要发送 API Key 明文或完整的鉴权请求头。 --- # 401 / 403:鉴权与权限 来源: https://platform.lyrouter.com/ai_gateway/docs/auth-errors 401 表示网关没有认出请求中的 API Key;403 表示 Key 有效,但这次请求被拒绝。先读响应体中的 `error.message` 和 `error.code`,再按下表找到对应原因。通过 `/v1/messages` 调用时,错误会转换为 Anthropic 格式,不再带 `error.code`,请以 `message` 为准。 ## 401:API Key 没有被认出 | 报错原文(`error.message`) | 原因 | 处理 | | --- | --- | --- | | `missing credentials` | 请求没有携带 API Key | 加上 `Authorization: Bearer `;Anthropic 风格的客户端也可以使用 `x-api-key` | | `invalid authorization scheme, expected 'Bearer'` | `Authorization` 头不是 `Bearer ` 格式。`Bearer` 区分大小写,`bearer sk-...`、直接写密钥、`Basic ...` 都会被拒绝;只写 `Bearer` 而没有密钥也会返回这个错误 | 按 `Bearer ` 格式填写 | | `invalid api key` | 网关找不到这个 Key:复制不完整或带了空格、换行;Key 已删除、停用或过期;所属工作空间或创建人已停用;Key 刚创建,尚未同步到网关(通常几秒) | 重新复制完整的 Key;明文已丢失时删除旧 Key 并新建,见[创建工作空间与 API Key](https://platform.lyrouter.com/ai_gateway/docs/api-keys) | | `api key verification unavailable` | 平台的密钥校验服务暂时不可用,与 Key 是否正确无关 | 稍后重试;持续出现时查看[服务状态](https://platform.lyrouter.com/ai_gateway/docs/status) | (截图:鉴权失败时在日志详情核对状态、请求标识与错误来源;图示为无效密钥演示。) - 请使用 LYRouter API Key,不要使用服务商的 API Key 或控制台的登录会话。 - 请求同时带 `Authorization` 和 `x-api-key` 时,网关只读取 `Authorization`。 - 通过环境变量配置 Key 的工具(如 Claude Code、Codex),修改后需要新开终端,或重新加载 Shell 配置。 ## 403:请求被拒绝 | 报错原文(`error.message`) | `error.code` | 原因与处理 | | --- | --- | --- | | `api key expired` | — | Key 已超过有效期。新建一个 Key 替换它;过期一段时间后,同一个 Key 会改为返回 401 `invalid api key` | | `your IP address is not allowed` | — | Key 开启了 IP 白名单,请求的来源 IP 不在名单中。网关按到达时的出口 IP 判断,在公司网络、代理或云服务器上调用时,出口 IP 可能与本机看到的不同 | | `ip access control misconfigured` | — | Key 的 IP 白名单为空或包含无效的 IP / CIDR,网关拒绝所有请求。请 Key 创建者或账号管理员修正白名单 | | `api key workspace is unavailable` | — | 网关暂时读不到 Key 所属工作空间的配置,属于平台侧临时问题,稍后重试 | | `Model is not available in the model plaza` | `model_not_available` | Key 所属工作空间没有开通该模型,或在图像、视频、语音接口上使用了虚拟模型或 `lyrouter/auto`,见[模型不可用](https://platform.lyrouter.com/ai_gateway/docs/unavailable) | | `Request blocked by guardrail policy` | `guardrail_*` | 请求命中安全围栏的阻断策略,见下文 | | `Response blocked by guardrail policy` | `guardrail_sensitive` | 非流式请求的回答命中敏感信息策略。上游已生成回答,这次调用照常计费 | | `Subject is blocked by an active security ban` | `guardrail_subject_banned` | Key 被安全围栏封禁,期间所有请求都会被拒绝。到达策略设置的自动解封时间后解除,或由账号管理员在安全事件中提前解除 | | `该 API Key 已被永久封禁,无法恢复,请删除后创建新的 API Key。` | `api_key_permanently_banned` | Key 第 5 次触发错误率熔断后被永久封禁,不能解除。刚封禁时,后续请求由熔断检查返回 `该 API Key 因多次高错误率请求已被永久封禁,无法恢复,请删除后创建新的 API Key。`;封禁同步到网关后改为返回本行原文,两者含义相同。先修复持续报错的程序,再新建 Key,见[429:限流与配额](https://platform.lyrouter.com/ai_gateway/docs/rate-errors) | ### 安全围栏拦截 `Request blocked by guardrail policy` 的原文不包含策略名称或命中内容,请按 `error.code` 判断命中的策略类型: | `error.code` | 策略类型 | | --- | --- | | `guardrail_client` | 客户端访问控制:按来源 IP、工具名或 User-Agent 限制调用 | | `guardrail_context` | 意图安全检测:请求意图被判定有风险 | | `guardrail_sensitive` | 敏感信息检测:请求包含个人信息、凭证或敏感关键词 | | `guardrail_injection` | 提示词注入检测:请求疑似提示词注入 | | `guardrail_model` | 模型访问控制:所选模型不在允许范围内 | 同样的请求重试会得到同样的结果。调用方可以调整请求内容或换用允许的模型;需要查看命中详情或调整策略时,请账号管理员查看[安全围栏与语义审计](https://platform.lyrouter.com/ai_gateway/docs/guardrails)。模型策略按实际选中的模型检查,对[虚拟模型](https://platform.lyrouter.com/ai_gateway/docs/presets)同样生效。 ## 判断错误来自网关还是上游 [请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)列表的「状态说明」列会标明来源是「网关」还是「上游」,以及具体原因。上游返回 401 或 403,通常是上游凭证被拒绝:使用 BYOK 时,请账号管理员在服务商处确认凭证有效、额度充足,并在 [BYOK](https://platform.lyrouter.com/ai_gateway/docs/byok) 中重新测试连接。上游只返回状态码、没有响应体时,网关会补上 `error.code`(如 `upstream_unauthorized`、`upstream_forbidden`),并带 `"generated_by": "ai-gateway"` 标明这段内容由网关生成。 ## 常见问题 ### 模型在控制台能看到,为什么 API Key 调用返回 403? **答:** Key 只能调用它所属工作空间中已开通的模型。在模型目录中看得到,不代表该工作空间已开通,也不代表部门、成员或 Key 的模型策略允许调用。先在该工作空间的模型广场确认模型已开通,再请账号管理员检查安全围栏中的模型策略,详见[模型授权](https://platform.lyrouter.com/ai_gateway/docs/authorization)。修改客户端里的模型展示名不能绕过权限。 ### 提交鉴权问题时,需要提供哪些信息? **答:** 响应中不包含请求 ID。请记录调用时间、端点、模型、API Key 的名称和报错原文;如果能在日志中找到这次请求,再附上日志详情顶部的 Request ID。401 请求无法归属到任何 Key,不会出现在日志中。不要提供 API Key 明文、完整的 `Authorization` 头或敏感的输入输出。 --- # 429:限流与配额 来源: https://platform.lyrouter.com/ai_gateway/docs/rate-errors 429 有三种来源,按 `error.message` 区分:配额或预算已用完、API Key 因错误率过高被临时熔断、模型的所有上游凭证都已达到限额。三者的处理方式不同,单靠重试解决不了配额用完的问题。 ## 先判断是哪一类 | 报错原文(`error.message`) | `error.code` | 原因 | 处理 | | --- | --- | --- | --- | | `rate limit exceeded on <对象> <指标>/<窗口>` | — | 安全围栏的配额策略或 Key 的预算已达上限 | 等到重置时间后再调用,或请管理员调高额度 | | `API Key 因最近 60 秒错误率过高已临时熔断,请在 N 秒后重试。` | `api_key_circuit_open` | 这个 Key 最近的请求大量失败,被网关临时熔断 | 先修复失败原因,再按 `Retry-After` 等待 | | `all upstream credentials for this model are rate limited` | `upstream_quota_exhausted` | 能服务这个模型的所有通道或凭证都达到了各自的限额 | 稍后重试,或换用其他模型 | 此外,上游服务商自己返回的 429 会在网关回退完所有候选后原样转发,日志「状态说明」列的来源显示为「上游」。 (截图:429 示例展示网关侧拒绝,先读具体错误再核对相应限额。) ## 配额或预算用完 报错原文的三段表示哪一条限额被用完,例如 `rate limit exceeded on apikey total_tokens/day` 表示这个 Key 当天的 Token 用量已达上限: | 位置 | 可能的值 | | --- | --- | | 对象 | `apikey`(API Key)、`member`(成员)、`dept`(部门)、`ws`(工作空间) | | 指标 | `requests`(请求数)、`total_tokens`、`prompt_tokens`、`completion_tokens`(Token 数)、`credits`(Credits) | | 窗口 | `minute`、`minutes`(N 分钟)、`day`、`month`、`total`(累计,不会重置) | - 错误体还带 `limit`(上限)、`used`(已用)和 `reset_at`(重置时间)。`reset_at` 比窗口实际结束晚 1~2 分钟,在它之后重试不会被提前拒绝。 - 时间窗口按北京时间对齐,`day` 在每天 0 点重置;`total` 窗口不会重置,只能由管理员调高上限。 - 用量在请求完成后才计入,所以越过上限的那次请求会正常完成,下一次才被拒绝。 - 这类 429 不带 `Retry-After` 头。 **查看剩余额度**:控制台概览页的「我的配额」卡片显示适用于你的配额、剩余量和重置时间。配置了配额时,对话、向量等经过网关选路和配额检查的调用(成功的响应和被配额拦下的 429 都算)都带 `x-aigw-quota-<指标>-limit`、`x-aigw-quota-<指标>-remaining` 和 `x-aigw-quota-<指标>-reset` 响应头,指标为 `credits`、`tokens`、`requests` 等,程序可以据此提前降速。 **调高额度**:Key 的预算由 Key 创建者在 API Key 设置中调整;成员、部门和工作空间的配额由账号管理员在安全围栏中调整,见[预算、配额与限流](https://platform.lyrouter.com/ai_gateway/docs/quota)。 ## 错误率熔断 同一个 Key 在最近 60 秒内至少有 100 次请求、且其中 90% 以上失败(HTTP 状态码 ≥ 400)时,网关会临时熔断这个 Key: - 响应头 `Retry-After` 给出需要等待的秒数,错误体中的 `retry_after`、`blocked_until` 与之一致,到时自动恢复。 - 熔断时长逐次加长:第 1 次 30 秒、第 2 次 2 分钟、第 3 次 10 分钟、第 4 次 12 小时,**第 5 次触发即永久封禁**:此后的请求返回 403 `api_key_permanently_banned`。报错原文起初是 `该 API Key 因多次高错误率请求已被永久封禁,无法恢复,请删除后创建新的 API Key。`,封禁同步到网关后变为 `该 API Key 已被永久封禁,无法恢复,请删除后创建新的 API Key。`,两者含义相同。次数在 Key 的整个生命周期内累计,不会清零。 - 网关自己返回的 402、403、429 也计入失败。一个在余额不足或被限流后仍然不停重试的程序,很快就会把 Key 熔断。 - 被熔断的请求不写入日志。 先对照[401 / 403](https://platform.lyrouter.com/ai_gateway/docs/auth-errors)、[模型不可用](https://platform.lyrouter.com/ai_gateway/docs/unavailable)等章节找出持续失败的原因并修复,再等待 `Retry-After` 后重试。 ## 上游限额 `upstream_quota_exhausted` 表示该模型所有可用的通道或凭证都已达到各自的限额,网关在排序时就把它们移出了候选。稍后重试,或换用其他模型。如果该模型只走你的 BYOK 凭证,请账号管理员检查这些凭证在服务商处的额度和限额设置,或接入更多凭证,见 [BYOK](https://platform.lyrouter.com/ai_gateway/docs/byok)。 ## 常见问题 ### 429 可以自动重试吗? **答:** 可以,但要按类型处理。熔断按 `Retry-After` 等待;配额用完要等到 `reset_at` 之后,提前重试只会继续失败并计入熔断;上游限额使用有上限的指数退避加随机抖动。不要对 429 做无间隔的自动重试。 ### 减少并发后仍然返回 429,怎么办? **答:** 并发只影响频率类限制。如果报错原文中的指标是 Token 或 Credits,说明额度已经用完,减少并发无法解决,需要等待重置或调高额度。如果是 `upstream_quota_exhausted`,说明上游凭证的限额已满,可以换用其他模型。 ### 提交限流问题时,需要提供哪些信息? **答:** 响应中不包含请求 ID。请记录调用时间、模型、API Key 的名称和完整的报错原文(含 `limit`、`used`、`reset_at`);如果能在[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)中找到这次请求,再附上日志详情顶部的 Request ID。被熔断的请求不会写入日志。 --- # 模型不可用 来源: https://platform.lyrouter.com/ai_gateway/docs/unavailable 模型名写错、模型没有开通、没有可用的通道或凭证、余额不足,以及计费或配置暂时不可用,都会表现为模型调不通。请按响应中的报错原文在下表找到原因。工作空间在[智能路由](https://platform.lyrouter.com/ai_gateway/docs/routing)中设置了默认模型时,很多对话请求会改由默认模型回答,而不会收到这些错误;可以在日志的「模型(实际)」中确认。 ## 按报错原文查找 | 状态码 | 报错原文(`error.message`) | `error.code` | 原因与处理 | | --- | --- | --- | --- | | 400 | `you must provide a model parameter` | `missing_model` | 请求没写 `model`,工作空间也没有设置默认模型。在请求中写上模型 ID | | 400 | `invalid type for 'model': expected a string` | `invalid_model` | `model` 不是字符串。改成字符串形式的模型 ID | | 400 | `This model does not support the <接口> API` | `unsupported_model_api` | 模型不支持当前接口,例如用对话模型调用图像生成接口。换用支持该接口的模型 | | 400 | `This model accepts text input only` | `unsupported_model_input` | 给只接受文本的模型发送了图片、音频或文件。换用支持该输入的模型 | | 402 | `insufficient credit balance` | `insufficient_credit_balance` 等 | 账户 Credits 余额不足,见下文「余额与订阅」 | | 402 | `subscription expired; renew to continue` | — | 账户订阅已到期,见下文「余额与订阅」 | | 403 | `Model is not available in the model plaza` | `model_not_available` | 工作空间没有开通该模型;或在图像、视频、语音接口上使用了虚拟模型或 `lyrouter/auto`。在模型广场开通模型,或改写具体的模型 ID | | 503 | `all routed candidates exhausted` | `no_route_candidate` | 找不到可以服务这次请求的模型或通道。常见原因是 `@vmodel/<名称>` 写错或已停用,或者模型没有可用的通道或凭证 | | 503 | `No configured credential can serve this model` | `no_route_candidate` | 模型的通道在本工作空间没有可用凭证:平台通道没有开通,或 BYOK 凭证都不可用 | | 503 | `Platform supplier cost snapshot is unavailable` | `supplier_cost_snapshot_not_ready` | 服务这个模型的通道还没有配置好价格,网关无法计费。换用其他模型,并把模型 ID 告知支持人员 | | 503 | `billing balance is temporarily unavailable` | `billing_maintenance` 等 | 网关暂时无法确认账户余额,这不是余额不足。持续出现时联系支持 | | 503 | `Workspace model projection is unavailable` | `workspace_model_projection_unavailable` | 网关暂时读不到工作空间的模型配置,属于平台侧问题,稍后重试 | BYOK 通道的价格未就绪时,报错原文为 `BYOK supplier cost snapshot is unavailable`。返回 500 或 504、且响应体是 HTML 页面时,说明连接上游失败或等待上游超时,见[超时与流式中断](https://platform.lyrouter.com/ai_gateway/docs/stream-errors)。上游服务商自己返回的错误会原样转发,日志「状态说明」列的来源显示为「上游」。 (截图:检查模型是否启用、来源是否有效,以及当前身份是否可用。) ## 余额与订阅 | `error.code` | 含义 | 处理 | | --- | --- | --- | | `insufficient_credit_balance` | 账户余额已用完;使用 BYOK 且需要支付平台服务费时,余额不足以支付服务费 | 在 **订阅充值** 页面充值 | | `balance_missing` | 账户还没有余额记录,通常是从未充值 | 充值;已充值仍出现时联系支持 | | `billing_entity_missing` | 网关找不到 Key 对应的计费账户 | 平台侧数据问题,联系支持 | - 余额检查发生在调用之前:余额大于 0 就可以发起调用,一次调用可能把余额扣成负数,之后的调用才会被拒绝。余额不足时,网关不会改用其他计费方式或其他通道。 - `subscription expired; renew to continue` 表示订阅已到期且已过宽限期,该账户下所有工作空间的调用都会被拒绝,续费后恢复。没有订阅的账户不会收到这个错误。 - 充值和续费由账户管理员操作,见[计费规则与信用点](https://platform.lyrouter.com/ai_gateway/docs/billing)和[购买、账单与发票](https://platform.lyrouter.com/ai_gateway/docs/orders)。 ## 常见问题 ### 提示模型不存在或不可用,怎样核对模型名? **答:** 使用系统模型 ID,不要使用展示名称,也不要自己拼服务商前缀。用同一个 API Key 调用 [`GET /v1/models`](https://platform.lyrouter.com/ai_gateway/docs/models),列表中是 Key 所属工作空间已开通、且安全围栏模型策略允许这个 Key 调用的模型 ID,以及已启用的 `@vmodel/<名称>` 和 `lyrouter/auto`。模型不在列表中,说明它没有开通或被策略禁止。虚拟模型和 `lyrouter/auto` 总会列出,实际选中的模型被策略禁止时,调用仍会返回 403。模型 ID 区分大小写。 ### 模型已开通,为什么仍然返回 503? **答:** 开通模型不等于有可用的凭证。请账号管理员在模型广场确认至少有一个服务来源处于有效状态;使用 BYOK 时,在 [BYOK](https://platform.lyrouter.com/ai_gateway/docs/byok) 中检查凭证状态、模型映射,并重新测试连接。返回 `supplier_cost_snapshot_not_ready` 时是平台价格未就绪,需要联系支持。 ### 配置了「仅用此 BYOK」,为什么没有回退到其他来源? **答:** 这项设置限定该模型只使用指定通道的 BYOK 凭证,凭证全部失败后请求即结束,不会尝试平台凭证、其他通道或默认模型。请账号管理员检查该通道的凭证和映射,或在不需要独占时改为「优先使用此 Channel」,详见[失败重试与备用模型](https://platform.lyrouter.com/ai_gateway/docs/fallback)。 ### 更换模型后仍然失败,接下来检查什么? **答:** 确认替代模型支持原请求的接口、输入类型和工具调用,再按报错原文对照上表。记录调用时间、模型、API Key 名称和报错原文,在[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)中找到这次请求,查看「状态说明」和日志详情顶部的 Request ID。 --- # 超时与流式中断 来源: https://platform.lyrouter.com/ai_gateway/docs/stream-errors 网关等待上游时有 6 分钟的空闲超时。连接上游失败或等待超时,网关会先换下一个通道,全部失败后返回 500 或 504,响应体是 HTML 页面而不是 JSON。流式请求一旦开始输出就不再换通道,中途出错时网关在流末尾补发一个错误事件后结束连接。客户端应把没有收到结束标记的流当作失败处理,并自行决定重试和去重。 ## 504 / 500:响应体是 HTML 页面 | 状态码 | 原因 | 日志「状态说明」 | | --- | --- | --- | | 504 | 等待上游响应超时,或连接上游超时 | 「网关」+「上游请求超时」 | | 500 | 连接上游失败(例如连接被拒绝),或读取上游响应时出错 | 「网关」+「连接上游失败,未收到响应」或「上游请求或响应读取失败」 | - 这两种响应没有 JSON 错误体,返回的是一个 HTML 错误页,部分 SDK 会报「无法解析响应」一类的错误。请按 HTTP 状态码处理,不要依赖 `error.message`。 - 返回之前,网关已经按[失败重试与备用模型](https://platform.lyrouter.com/ai_gateway/docs/fallback)的规则尝试过其他通道,所有候选都失败后才返回最后一次的结果。 - 「状态说明」的来源显示「网关」,因为是网关终止了这次请求,但原因在网关与上游之间的连接。持续出现时,查看[服务状态](https://platform.lyrouter.com/ai_gateway/docs/status)或换用其他模型。 ## 上游超时怎么计算 网关调用上游时的读超时为 360 秒(6 分钟): - **非流式请求**:上游 6 分钟内没有返回响应即超时。生成很长的内容时,请改用 `stream: true`。 - **流式请求**:按相邻两段数据之间的间隔计算,只要上游持续有输出就不会超时;开始输出之前同样最多等待 6 分钟。 - **换通道后重新计时**:一个通道超时后,网关改用下一个通道并重新等待,所以一次请求的总耗时可能超过 6 分钟。 ## 流式输出开始后出错 流式请求的响应头和第一段内容一旦发出,网关就不能再换通道。此时上游中断或超时,网关在流的末尾补发一个错误事件,然后结束连接: **Chat Completions**: ```text data: {"error": {"message": "upstream timed out after the response had started", "type": "api_error", "code": "stream_interrupted"}} ``` **Anthropic Messages**(`/v1/messages`): ```text event: error data: {"type": "error", "error": {"type": "api_error", "message": "upstream timed out after the response had started"}} ``` **Responses**(`/v1/responses`):补一个 `response.failed` 事件,`response.error.code` 为 `server_error`。 ```text event: response.failed data: {"type": "response.failed", "sequence_number": 42, "response": {"id": "resp_...", "object": "response", "status": "failed", "error": {"code": "server_error", "message": "upstream timed out after the response had started"}}} ``` - 超时时 `message` 为 `upstream timed out after the response had started`;连接或读取失败时为 `upstream failed after the response had started`。 - 上游服务商自己在流中发出的错误事件(例如 Anthropic 的 `overloaded_error`)会按你调用的协议转给你。 - OpenAI 和 Anthropic 的官方 SDK 收到对应格式的错误事件会抛出 API 错误。 - 在日志中,这类请求的「状态」是 200(响应头已经发出),「状态说明」显示「网关」+「上游请求超时」或「上游请求或响应读取失败」。 ## 没有结束标记就当作失败 出现错误事件后,流中不会再有结束标记。请以协议规定的结束标记判断输出是否完整,没有收到就把这次调用视为失败: | 接口 | 正常结束的标记 | | --- | --- | | Chat Completions | `data: [DONE]` | | Anthropic Messages | `message_stop` 事件 | | Responses | `response.completed` 事件 | 上游直接断开连接、没有发出任何错误事件时,流也会在没有结束标记的情况下结束,同样按失败处理。各协议的事件结构见[流式响应](https://platform.lyrouter.com/ai_gateway/docs/streaming)。 ## 客户端与代理设置 - **客户端超时**:设得比 6 分钟长,避免客户端先断开;流式请求优先设置读取间隔超时,而不是整次请求的总超时。 - **按完整事件解析**:SSE 事件以空行分隔,一个网络数据块可能只包含半个事件,也可能包含多个事件,不要把每个数据块当作一段完整 JSON。 - **自建代理**:如果应用和 LYRouter 之间还有 Nginx 等反向代理,请关闭响应缓冲(Nginx 中设置 `proxy_buffering off`),并把代理的读超时设得比 6 分钟长,否则流式内容会被攒成一大块才到达,或被代理提前断开。 ## 重试与去重 - **流式中断**:收到 `stream_interrupted`、`response.failed`,或没有收到结束标记时,不要把已经收到的部分输出当作完整结果。重新调用会重新生成,内容可能不同,也可能再次触发工具调用;已经执行过的工具操作需要由应用去重,例如为每个操作携带业务上的幂等标识。 - **504 / 500**:网关已经在内部换过通道,客户端使用有上限的指数退避重试即可,不要无间隔地连续重试。 - **持续失败**:同一个 API Key 在 60 秒内大量请求失败会被临时熔断,返回 429 `api_key_circuit_open`,见[429:限流与配额](https://platform.lyrouter.com/ai_gateway/docs/rate-errors)。 ## 用日志定位 在[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)中找到这次请求,打开详情: - **各阶段耗时**:「④ 上游调用」占「总耗时」的大部分,说明时间花在上游;旁边显示「· N 次尝试,最长 X」时,说明换过通道,每次尝试都可能等待了接近 6 分钟。 - **首 Token**:日志列表的「首 Token」列(在 **自定义列** 中打开)显示上游开始输出前等待了多久。 - **路由追踪**:「上游调用尝试」中每次尝试的状态显示「超时」「连接失败」等,见[查看实际路由](https://platform.lyrouter.com/ai_gateway/docs/route-log)。 (截图:在日志详情的各阶段耗时中比较总耗时、上游耗时和首 Token 时间。) ## 常见问题 ### 客户端报超时,日志里这次请求却是 200? **答:** 通常是客户端或中间的代理先断开了连接,网关仍然完成了这次调用。用日志的「总延迟」和客户端的超时设置比较;日志的「时间」是请求结束的时间,减去「总延迟」就是请求到达网关的时间。把客户端超时调到 6 分钟以上,或改用流式请求。 ### 流式响应很久没有第一段内容? **答:** 先看日志的「首 Token」。首 Token 很长说明上游迟迟没有开始输出,可以稍后重试或换用其他模型;首 Token 正常但客户端迟迟收不到内容,检查中间代理是否缓冲了响应。 ### 流式响应解析 JSON 失败,应该检查什么? **答:** 确认解析器按完整 SSE 事件读取,并能处理 `data: [DONE]` 这类不是 JSON 的行。如果请求在输出开始前就失败,返回的是普通的错误响应而不是事件流:网关拒绝的请求通常是 JSON 错误体,500、504 是 HTML 页面,请先检查状态码和 `Content-Type`。 ### 提交超时问题时需要提供哪些信息? **答:** 网关的响应中不包含请求 ID。请在日志中找到这次请求,附上日志详情顶部的 Request ID、调用时间、模型、是否流式、客户端的超时设置,以及客户端收到的报错原文或最后收到的几个事件。 --- # 费用异常与缓存未命中 来源: https://platform.lyrouter.com/ai_gateway/docs/cache-errors 费用与预估不符,最常见的原因是把缓存命中的输入按输入单价重复计算、长上下文请求落入了更贵的档位、思考过程产生了大量输出,或者提示词缓存没有命中。排查时先在[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)详情的「Token 消耗」中看清四项 Token,再对照下面的问题逐项检查。估算方法见[调用费用与缓存计费](https://platform.lyrouter.com/ai_gateway/docs/estimate),提高命中率的做法见[降低成本与优化缓存](https://platform.lyrouter.com/ai_gateway/docs/cost-practice)。 ## 先看四项 Token 在 **日志分析** 中打开这次调用,详情「Token 消耗」列出「输入(缓存未命中)」「输入(缓存命中)」「输出」「显式缓存创建」四项,占比的分母是四项之和。这次调用的缓存命中率按下式计算: ```text 缓存命中率 = 输入(缓存命中) ÷(输入(缓存未命中)+ 输入(缓存命中)) ``` (截图:在 Token 消耗中分别核对缓存未命中输入、缓存命中输入、输出和显式缓存创建。) ## 费用异常 ### 按输入 Token 自己算出来的费用,为什么和日志不一致? **答:** 通常是输入里包含了缓存命中部分。OpenAI 兼容响应的 `usage.prompt_tokens` 已经包含缓存命中(命中数量通常在 `prompt_tokens_details.cached_tokens` 中),直接用它乘输入单价会高估;Anthropic 协议响应的 `input_tokens` 不含缓存读取和缓存写入,它们分别在 `cache_read_input_tokens` 和 `cache_creation_input_tokens` 中。由 Claude 等 Anthropic 协议上游服务的 `/v1/chat/completions` 调用,响应的 `prompt_tokens` 同样不含缓存命中。核对时以日志的四项为准,按[调用费用与缓存计费](https://platform.lyrouter.com/ai_gateway/docs/estimate)中的公式分别计价。 ### 缓存命中率很高,为什么仍按长上下文的价格计费? **答:** 按 Token 长度分档的模型,用本次全部输入 Token 判断档位,缓存命中的部分也计入长度。一个几十万 Token 的长会话即使大部分命中缓存,也会落在长上下文档,命中部分按该档的「输入(缓存命中)」单价、未命中部分按该档的「输入」单价计费。控制会话长度或定期开启新会话,可以让请求回到较低的档位。 ### 输出 Token 比回答的长度多很多,是什么原因? **答:** 思考(推理)过程也计入「输出」。工作空间开启全文日志时,可以在日志详情「对话」页签中看到思考内容及其 Token 数。不需要深度思考的任务,可以在请求中降低思考强度或关闭思考(参数因模型而异),并用 `max_tokens` 限制输出上限。 ### 没有写 `cache_control`,为什么出现了「显式缓存创建」? **答:** 「显式缓存创建」只在 Anthropic 协议的上游出现,来源有两种:Claude Code 等客户端会自动在请求中标记缓存断点;较早创建、开启了「Anthropic 提示词缓存」的虚拟模型,会在请求没有自带标记时为系统提示词加上标记。写入缓存按「显式缓存创建」单价计费,同一前缀在随后几分钟内被重复使用时,会按「输入(缓存命中)」单价计费,总体通常更省。 ### 日志「费用」显示「未计算」,是没有扣费吗? **答:** 通常是。「未计算」表示这条日志记录的扣费金额为 0 或没有记录,最常见于调用失败;个别情况下是这次调用的价格没能算出。要确认是否扣除了 Credits,按 Request ID 到 **订阅充值** 的「消费明细」中查找:查不到即没有扣费。日志列表的「费用」显示「结算中」时,是异步任务还没有结束,任务完成后显示整个任务的费用。显示「无权限查看」时,是当前账号不能查看这条日志的费用。 ### 日志费用、消费明细和用量分析的金额为什么对不上? **答:** 三处的口径不同: | 位置 | 显示什么 | 单位 | | --- | --- | --- | | 日志「费用」 | 单次调用实际扣除的 Credits 折算的金额;BYOK 调用是平台服务费 | 人民币 | | **订阅充值** 的「消费明细」 | 按请求列出实际扣除的 Credits,只列有扣费的请求 | Credits | | **用量分析** 的「费用」视角 | 平台请求按客户实付金额统计;BYOK 请求按服务商成本统计,BYOK 订阅费用单独列为未分摊 | 人民币 | 按 Request ID 可以把日志与消费明细逐条对应。比较汇总金额时,确认时间范围、工作空间和 API Key 相同;刚完成的调用可能需要几分钟才出现在用量分析和消费明细中。BYOK 请求在用量分析中显示的是你付给服务商的费用,不是平台服务费,所以与日志不同。 ### 同样的用量,不同时间的费用为什么不同? **答:** 检查价格表是否为「分时计价」:不同星期和时段的系数不同,节假日调休按星期几计算。另外,每次调用按当时生效的价格计费,调价后的新调用使用新价格,历史日志的金额保持不变。 ### 较早的 Claude 日志,「输入(缓存未命中)」为什么偏小或为 0? **答:** 较早的 Anthropic 协议日志记录的输入 Token 不含缓存命中部分,控制台再减去命中量后,「输入(缓存未命中)」会偏小甚至为 0,「总 Token」也不含缓存命中。新产生的日志已按全部输入记录,不受影响。比较这类日志时,以「输入(缓存命中)」和「输出」为准。 ## 缓存未命中 ### 相似的请求为什么没有命中缓存? **答:** 提示词缓存在上游服务商侧按字节前缀匹配:从请求开头起任何一个字节不同,之后的内容都不会命中,即使后面几十万 Token 完全一样。常见原因有:系统提示词开头带时间戳、请求 ID 或随机值;会话中途增删或调整了工具定义;历史消息被重新拼装或改写;请求换到了另一个通道或模型。缓存只在同一服务商的同一模型内复用,换模型或换服务商都要重新建立。 ### 命中率一直精确为 0,怎么排查? **答:** 说明前缀从第一个字节就不同。开启全文日志后,在日志详情的「原始报文」中比较相邻两次请求的「上游请求」开头。使用 Claude Code 时,部分版本会在系统提示词最开头写入一行带 `cch=` 的标记,且每个请求的值都不同,导致命中率为 0;升级 Claude Code 到最新版本即可。判断标准是这个值在相邻请求之间是否变化,而不是有没有这一行。 ### 每个会话的前一两次调用为什么没有命中? **答:** 第一次调用要先把前缀写入上游缓存,之后的调用才能读到;部分上游写入后需要短暂延迟才可读取,紧接着发出的第二次调用(例如工具结果回传)也可能未命中。之后的调用命中率稳定上升属于正常情况。 ### 同一个会话的命中率忽高忽低,是什么原因? **答:** 先确认前缀是否在不同位置被改动,再确认请求是否落到了同一个通道。工作空间的「多渠道选路策略」为「最低价」或「负载均衡」时,同一个 API Key 对同一模型的调用会保持在同一通道 30 分钟,每次调用续期;通道返回 429、408、5xx 或连接失败时会改绑到其他通道,新通道需要重新建立缓存。「最低延迟」「最高吞吐」不做会话保持,每次按当时的指标选择通道。同一会话请始终使用同一个 API Key 和同一个模型 ID,详见[通道选择与路由策略](https://platform.lyrouter.com/ai_gateway/docs/routing)。 ### 「显式缓存创建」始终为 0,`cache_control` 没有生效吗? **答:** 只有由 Anthropic 协议上游服务的调用才会使用 `cache_control`;上游是 OpenAI 兼容协议时,网关会删除这些标记,改由上游的隐式缓存工作。如果确实由 Anthropic 协议上游服务,检查被标记的前缀是否达到模型的最小可缓存长度,以及标记是否打在文本块上——通过 `/v1/messages` 调用时,打在图片块或 `tool_result` 块本身上的标记不会转发给上游。 ### 隔了一段时间后第一次调用没有命中,是缓存过期了吗? **答:** 不一定。缓存保留多长时间由上游服务商决定,通常为几分钟;有的上游有多个后端,请求没有落到保存缓存的后端时也会未命中。判断是否过期,请看之后连续几次调用的命中情况,不要只看一次。 ## 提交问题时提供的信息 请记录调用时间、模型、API Key 名称,以及日志详情顶部的 Request ID,附上「Token 消耗」四项的数值和日志「费用」。涉及消费明细的问题,再附上对应的「请求 ID」和「消费 Credits」。 (截图:将请求记录与消费明细按时间、模型和 API Key 对齐核对。) --- # 研发团队工具管理 来源: https://platform.lyrouter.com/ai_gateway/docs/dev-team 为研发团队接入 Claude Code、Codex 等编程工具时,推荐的做法是:按项目或环境划分工作空间,每位成员或每个应用使用自己创建的 API Key,工具里统一填写虚拟模型名。这样预算、权限、日志和用量都能按人、按应用分开统计,更换模型时也不必逐台修改工具配置。 ## 按项目或环境划分工作空间 工作空间是隔离调用配置的单位,一把 API Key 只属于一个工作空间: | 范围 | 内容 | | --- | --- | | 每个工作空间独立 | API Key、模型广场中开通的模型、BYOK、智能路由、虚拟模型、安全围栏策略、全文日志设置、日志与用量 | | 整个组织共用 | Credits 余额、订阅,以及成员和部门 | 团队和企业的当前账号管理员在 **工作空间** 页面点击 **新建工作空间** 创建,例如为「编程助手-测试」和「编程助手-生产」各建一个,数量上限由订阅档位决定。个人版只有一个默认工作空间。 (截图:「工作空间」页列出可进入的空间,卡片显示你的角色和共享标签;账号管理员可新建工作空间。) 用「访问范围」决定谁自动获得权限:「组织共享」给组织全部有效成员,「指定部门」给所选部门的成员,「仅自己/指定成员」只给账号管理员和单独授权的成员。前两种范围的成员获得「共享成员角色」,新设置的共享一律为「编辑者」;较早设成「查看者」的共享保持不变,直到修改访问范围。成员同时有单独授权和共享授权时,单独授权优先生效。工作空间内的角色决定能做什么: | 角色 | 与工具接入相关的能力 | | --- | --- | | 查看者 | 查看空间内已授权的资源,不能创建 API Key | | 编辑者 | 创建、编辑自己的 API Key | | 管理员 | 另外可以开通或停用模型、查看全部成员的日志并导出 | 生产空间建议用「仅自己/指定成员」,只给负责人单独授予「管理员」;成员与授权的管理见[组织、成员与角色](https://platform.lyrouter.com/ai_gateway/docs/organization)。 ## 每人或每个应用一把 Key 工作空间角色为「编辑者」及以上的成员,在 **API 密钥** 页面点击 **创建 API 密钥** 创建,完整密钥只显示一次。控制台创建的 Key 都是「仅自己使用」:只有创建人和当前账号管理员能看到、编辑、禁用或删除它,用量也记在创建人名下。因此请让每位成员用自己的账号创建 Key,不要由账号管理员统一创建后分发,否则所有用量都会算在账号管理员名下。早期创建的共享 Key(「指定成员」或「当前空间全部成员」)对相应成员仍然可见,新建时已不再提供这两个选项。 创建时按三步设置: | 步骤 | 设置 | 效果 | | --- | --- | --- | | 基本信息 | 「名称」和「到期时间」:「永不过期」或「指定到期时间」,精确到秒,只选日期时默认当天 23:59:59 | 过期后返回 403 `api key expired` | | 预算限额 | 「费用预算(元)」和「Token 预算(百万 Token)」,各有「每月」「总计」两项,留空表示不限 | 用完后返回 429 `rate limit exceeded on apikey ...` | | 访问控制 | 「启用 IP 白名单」,填写 IPv4 地址或 CIDR 网段 | 其他来源返回 403 `your IP address is not allowed` | 为 CI 等固定出口的应用开启 IP 白名单,并为临时成员设置到期时间。这些报错的处理见[401 / 403:鉴权与权限](https://platform.lyrouter.com/ai_gateway/docs/auth-errors)和[429:限流与配额](https://platform.lyrouter.com/ai_gateway/docs/rate-errors)。轮换 Key 时先创建新 Key、更新工具配置并确认调用正常,再禁用和删除旧 Key。 ## 用「使用密钥」生成工具配置 生成密钥后,在「请妥善保存密钥」窗口复制密钥,勾选「我已复制并安全保存此密钥」,再点击 **我已保存,查看配置示例**,「使用 API 密钥」窗口会给出已填好这把密钥的配置。之后也可以在列表操作列点击 **使用密钥** 打开,此时示例中的密钥显示为 `YOUR_API_KEY`,需要换成你保存的完整密钥。 | 页签 | 内容 | 接入地址 | | --- | --- | --- | | cURL | 对话请求和列出可用模型 | `https://api.lyrouter.com/v1` | | API | Python、Node.js 的 OpenAI SDK,以及 Anthropic SDK | OpenAI SDK 用 `/v1`;Anthropic SDK 用根地址 `https://api.lyrouter.com` | | TRAE、WorkBuddy | 在工具中填写的服务商、地址、密钥和模型 | `https://api.lyrouter.com/v1` | | CC Switch | 「供应商名称」、地址、Auth Token 和默认模型 | 根地址 | | Claude Code | macOS / Linux、Windows CMD、PowerShell 的环境变量,以及 `~/.claude/settings.json` | 根地址 | | OpenCode | `opencode.json` 配置和环境变量两种写法 | `opencode.json` 用 `/v1`;环境变量写法用根地址 | 窗口顶部的「示例模型」只列出这把 Key 可以调用的模型。Anthropic 协议的工具会自己拼接 `/v1/messages`,地址填根地址,多写 `/v1` 会返回 404。Codex、ChatGPT 等其他工具见[工具兼容性与接入总览](https://platform.lyrouter.com/ai_gateway/docs/tools)。 ## 在工具中统一使用虚拟模型名 请当前账号管理员在 **虚拟模型** 页面为团队创建虚拟模型,例如 `team-coding`,大家在工具中把模型填为 `@vmodel/team-coding`。之后更换模型只需修改虚拟模型的「默认模型」,保存后对所有成员的新请求生效。 - 编程工具依赖工具调用和流式输出,「备用模型」也要支持这些能力。 - 虚拟模型的推理参数按 Chat Completions 的字段名合并。给 Codex 这类使用 Responses 的工具使用时,建议只设置 `temperature`、`top_p` 这类通用参数。 - 虚拟模型属于一个工作空间,该工作空间的任何有效 API Key 都可以调用,配置方法见[虚拟模型](https://platform.lyrouter.com/ai_gateway/docs/presets)。 ## 设置团队额度 API Key 的预算只约束单把 Key。需要按成员、部门或整个工作空间控制用量时,账号管理员在 **安全围栏** 中新建「配额管理」策略;限制成员或 Key 能调用的模型,使用「模型访问控制」策略。安全围栏从团队版起可用,见[预算、配额与限流](https://platform.lyrouter.com/ai_gateway/docs/quota)和[模型授权](https://platform.lyrouter.com/ai_gateway/docs/authorization)。成员可以在控制台概览页的「我的配额」查看剩余额度。 (截图:在安全围栏的配额策略中为部门设置每月信用点额度、清零日、预警阈值和执行动作。) ## 按人和应用追踪用量 - **日志分析**:成员看到自己创建的 Key 的调用;工作空间管理员和账号管理员看到全部调用。团队和企业的日志有「创建人」列,「部门」列可在 **自定义列** 中打开,也可以按 API Key、创建人和部门筛选。 - **用量分析**:「按 API Key」页签比较各 Key 的用量;账号管理员还能看到「按部门」「按用户」。其他成员(包括工作空间管理员)只看到自己创建的 Key 的用量。 - **共享 Key 的归属**:日志中的「创建人」是 Key 的创建人,不是实际发起调用的人。用量分析的「按用户」「按部门」把共享 Key 的用量单列为「共享应用 · 未归属」,需要按人统计时请使用个人 Key。 对账与审计方法见[预算归因与调用审计](https://platform.lyrouter.com/ai_gateway/docs/audit-practice)。 --- # 应用接入多个供应商 来源: https://platform.lyrouter.com/ai_gateway/docs/multi-provider 应用只需写一个模型 ID,网关就会在提供该模型的多个通道之间选择和回退,平台提供的服务商通道和你通过 BYOK 接入的通道都算在内。需要在一个模型失败后改用另一个模型时,使用虚拟模型的备用模型或工作空间默认模型。不同通道可能使用不同的上游协议,对同一请求的处理也会不同,所以上线前要逐个通道验证。 ## 一个模型 ID,多个通道 模型广场中的一个模型可以有多个来源: - **平台来源**:平台提供的服务商通道,「接入来源」中显示为「三方服务」。一个模型可能由多家服务商提供,平台新上架的来源默认开通。 - **BYOK 来源**:当前账号管理员在 **自带密钥(BYOK)** 中用你自己在服务商处的 API Key 接入的通道,配置生效后默认开通。接入和映射方法见[BYOK 接入与测试连接](https://platform.lyrouter.com/ai_gateway/docs/byok)和[模型映射与来源配置](https://platform.lyrouter.com/ai_gateway/docs/mapping)。 只有已开通的来源参与调用。在模型详情的「服务商与价格」中,每个来源单独显示状态、开关和价格;同一服务商同时有平台来源和 BYOK 来源时,分别标为「平台价」和「BYOK 参考价」。来源的开通、停用见[如何选择模型](https://platform.lyrouter.com/ai_gateway/docs/choose)。 (截图:模型广场左侧的「接入来源」可分别筛出「三方服务」和「BYOK」来源;「专属可用模型」是当前工作空间已开通的模型。) ## 网关如何在通道之间选择 直接调用模型 ID 时,网关按以下设置给该模型的通道排序: | 设置 | 位置 | 作用 | | --- | --- | --- | | 仅用此 BYOK | BYOK 的「使用配置」 | 该模型只使用这个通道的 BYOK 凭证,失败后不再使用平台凭证、其他通道或默认模型 | | 优先使用此 Channel | BYOK 的「使用配置」 | 把这个通道排在最前,失败后照常回退 | | 多渠道选路策略 | **智能路由** | 其余通道按「最低价」「负载均衡」「最高吞吐」「最低延迟」排序,新建工作空间默认「最低价」 | | Channel 排序策略 | **虚拟模型** | 通过虚拟模型调用时,代替多渠道选路策略 | - 一个通道下先尝试你的 BYOK 凭证(按 BYOK 中设置的顺序),再尝试平台凭证(该通道的平台来源已开通时)。 - 「最低价」和「负载均衡」会把同一 API Key 对同一模型的调用保持在同一个通道上(保持期 30 分钟,每次调用续期),以提高上游提示词缓存的命中率。 - 请求中没有可以指定通道的参数。需要让一部分调用使用不同的排序时,为它们创建虚拟模型并设置「Channel 排序策略」。 各选项的排序方式见[通道选择与路由策略](https://platform.lyrouter.com/ai_gateway/docs/routing)。 (截图:智能路由中设置多渠道选路策略和默认模型,修改后自动保存。) ## 失败后的回退 - **同一模型内**:上游返回非 2xx、连接失败或等待超时时,网关在开始向客户端输出内容之前,自动换下一个凭证或通道。 - **跨模型**:[虚拟模型](https://platform.lyrouter.com/ai_gateway/docs/presets)按「默认模型 → 备用模型(按填写顺序)→ 工作空间默认模型」的顺序尝试;直接调用模型 ID 时,全部通道失败后由工作空间默认模型接手(已在智能路由中设置时)。 - **不会回退的情况**:流式输出已经开始、通道开启了「仅用此 BYOK」、网关拒绝了请求(如余额不足 402、安全围栏拦截 403、模型不支持当前接口或输入 400)。图像、视频和语音接口只在同一模型的通道之间回退。 完整规则见[失败重试与备用模型](https://platform.lyrouter.com/ai_gateway/docs/fallback)。 ## 上线前的兼容性检查 同一个请求落到不同通道时,结果可能不同。建议在测试工作空间中,于模型详情里只保留一个来源开启,逐个通道运行同一组真实任务,并核对下表: | 检查项 | 原因 | | --- | --- | | 结构化输出 | 发往 Anthropic 协议通道时,`response_format`、`seed`、`n`、`logprobs` 等字段会在转换中被去掉 | | Responses 接口 | `/v1/responses` 请求原样转发,只有提供 Responses 接口的通道能处理,Anthropic 协议通道没有该接口 | | 工具调用与流式 | 核对 `tool_calls` 的参数结构,以及流式输出是否以 `data: [DONE]`(或 `message_stop`)正常结束 | | 推理参数 | `reasoning_effort`、`enable_thinking`、`thinking_budget` 分属不同服务商,网关不相互换算 | | 提示词缓存 | 各通道的缓存命中率不同;Anthropic 的 `cache_control` 标记只在发往 Anthropic 协议通道时保留 | | 价格与限额 | 每个来源单独计价;BYOK 凭证还受服务商自身的额度和限流约束 | 协议转换的完整规则见[模型能力与兼容性](https://platform.lyrouter.com/ai_gateway/docs/capabilities),缓存优化见[降低成本与优化缓存](https://platform.lyrouter.com/ai_gateway/docs/cost-practice)。 ## 验证实际路由 调用后在[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)中打开记录,查看「模型(实际)」和「服务商」。当前账号管理员和工作空间管理员还能在「路由追踪」中看到「路由策略」「全部候选」和「上游调用尝试」,后者记录每次实际尝试的状态码和换下一个候选的原因,见[查看实际路由](https://platform.lyrouter.com/ai_gateway/docs/route-log)。 ### 配置了 BYOK,为什么请求仍走平台通道? **答:** 在「最低价」等策略下,平台通道可能排在你的 BYOK 通道前面。需要优先使用 BYOK 时,请账号管理员在该 BYOK 的「使用配置」中打开「优先使用此 Channel」;需要只用 BYOK 时打开「仅用此 BYOK」,开启后该通道的平台来源在模型广场中显示为「仅允许 BYOK」。 ### 同一模型的回答质量或速度时好时坏,怎么排查? **答:** 在日志中按模型筛选,对比不同请求的「服务商」、首 Token 和总延迟,确认是否落在不同通道。找到表现不佳的来源后,可以在模型详情中停用它,或调整多渠道选路策略。 --- # 降低成本与优化缓存 来源: https://platform.lyrouter.com/ai_gateway/docs/cost-practice Agent、编程助手这类应用每一轮都会重新发送系统提示词、工具定义和全部历史,输入 Token 往往占费用的大头,所以提示词缓存命中率基本决定了 Token 费用。降低成本的主要做法是让请求前缀保持稳定、让同一会话留在同一个通道上,再减少不必要的输出和上下文。每项调整后,用日志和用量分析中的缓存命中率与费用验证效果。 ## 先找到钱花在哪 在 **用量分析** 中把「统计视角」切到「费用」,按模型、API Key 查看费用占比;「总览」的「缓存命中率」和「按模型」表格的「缓存命中率」列显示命中情况。费用集中、命中率又低的模型,是最值得优化的对象。具体请求的四项 Token 在[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)详情中查看,费用计算方法见[调用费用与缓存计费](https://platform.lyrouter.com/ai_gateway/docs/estimate)。 (截图:在用量分析中切换统计视角,对比各模型的用量、费用和缓存命中率。) 设缓存命中率为 `h`,模型的缓存读取单价与输入单价之比为 `r`,输入费用约为全部未命中时的 `(1 − h) + h × r` 倍。`r` 越小,提高命中率省得越多。 ## 让请求前缀保持稳定 上游按字节前缀匹配缓存,从第一个不同的字节开始,之后的内容全部按未命中计费。把越稳定的内容放得越靠前,从前到后依次是: 1. **固定的角色与规则**:最稳定,放在最前。 2. **工具定义**:会话内不变,顺序固定。 3. **示例与项目级上下文**:同一项目内不变。 4. **环境信息、日期等**:容易变化,尽量靠后。 5. **对话历史**:只追加,不改写。 6. **本轮新消息**。 - **前缀里不放变化的值**:请求 ID、trace ID、精确到秒的时间戳、随机数不要写进系统提示词开头;必须带时放到最后一条消息里,日期精确到天即可。 - **会话中途不改工具**:增删或调整工具会改变工具定义之后的全部内容。需要临时限制工具时,在提示词或调用逻辑中约束;按需加入的工具放在工具列表最后。 - **历史只追加、原样回放**:不要每轮重新拼装或格式化历史消息;工具调用参数按模型上一轮返回的原样回传。 - **不必担心 JSON 键顺序**:网关发往上游前会把请求体中 JSON 对象的键按固定顺序排列,包括工具调用参数里的 JSON(参数中含 15 位以上连续数字时保持原样,以免改写数字)。消息、工具和内容块的先后顺序不会调整,需要由客户端保持稳定。 ## 让同一会话留在同一个通道 缓存保存在具体的服务商通道上,换通道就要重新建立。工作空间的「多渠道选路策略」为「最低价」(新建工作空间的默认值)或「负载均衡」时,网关会把同一个 API Key 对同一模型的调用保持在同一个通道上: - 保持期为 30 分钟,每次调用续期;通道返回 429、408、5xx 或连接失败时改绑到其他通道,因请求本身格式错误而换通道时不改绑。 - 「最低价」只为新会话或保持过期后的调用选择当前预估最便宜的通道,价格排序变化不会把进行中的会话挪走。 - 「最低延迟」「最高吞吐」不做会话保持;虚拟模型的「Channel 排序策略」为按价格优先或负载均衡时同样会保持。 - `lyrouter/auto` 按每次请求的内容选择模型,同一会话可能换到不同模型,长会话请固定一个模型 ID。 调用方只需让同一个会话或 Agent 始终使用同一个 API Key 和同一个模型,不需要额外参数。如果客户端会发送 `X-Session-Id` 请求头,网关会原样转发;请为每个会话固定一个值,不要每个请求更换。设置方法见[通道选择与路由策略](https://platform.lyrouter.com/ai_gateway/docs/routing)。 ## 使用显式缓存(cache_control) 隐式缓存由上游自动完成,不需要任何参数。显式缓存在请求中用 `cache_control` 标出断点,只在实际服务这次调用的上游使用 Anthropic 协议时生效: | 调用接口 | 实际服务的上游协议 | `cache_control` 的处理 | | --- | --- | --- | | `/v1/messages` | Anthropic | 保留 `system`、消息文本块和工具定义上的标记 | | `/v1/chat/completions` | Anthropic | 保留消息文本部分和工具定义上的标记 | | 任意接口 | OpenAI 兼容 | 全部删除,只有隐式缓存 | - 通过 `/v1/messages` 调用时,打在图片块或 `tool_result` 块本身上的标记不会转发,请把断点打在文本块上。 - `system` 有多个文本块时会合并成一个,只保留最后一个标记。 - 标记中写 `"ttl": "1h"` 时,网关会把 `anthropic-beta` 请求头设为 1 小时缓存所需的值;客户端自带的 `anthropic-beta` 会被覆盖。 - Anthropic 每个请求最多 4 个断点,前缀短于模型的最小可缓存长度时不会缓存。 下例把一段固定的长系统提示词标记为缓存断点(`MODEL_ID` 换成由 Anthropic 协议上游服务的模型,例如 Claude 系列;环境变量的设置见[完成第一次模型调用](https://platform.lyrouter.com/ai_gateway/docs/quickstart)): ```bash curl "$LYROUTER_BASE_URL/v1/messages" \ -H "x-api-key: $LYROUTER_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -H "Content-Type: application/json" \ -d '{ "model": "MODEL_ID", "max_tokens": 1024, "system": [{"type": "text", "text": "你是合同审阅助手。以下是审阅规则……(每次相同的长文本)", "cache_control": {"type": "ephemeral"}}], "messages": [{"role": "user", "content": "请检查第 3 条的违约责任是否对等。"}] }' ``` 第一次调用在日志中出现「显式缓存创建」,说明标记已被上游接受;之后几分钟内发送相同前缀的请求,这部分记为「输入(缓存命中)」。 ## 客户端注意事项 - **Claude Code**:命中率精确为 0 时先升级 Claude Code。部分版本会在系统提示词开头写入一行每个请求都变化的 `cch=` 标记,使前缀从第一个字节起就不同。会话中途调整可用工具也会让工具定义之后的内容全部未命中。接入方法见[Claude Code](https://platform.lyrouter.com/ai_gateway/docs/claude-code)。 - **自研应用**:确认 SDK 或框架没有在每次请求中自动插入时间戳、请求 ID,也没有每轮重新排序工具或消息。 ## 减少不必要的用量 - **控制输出**:用 `max_tokens` 限制输出长度;不需要深度思考的任务降低思考强度或关闭思考,思考过程计入「输出」。 - **控制上下文**:清理与任务无关的历史;超长会话可能落入更贵的长上下文档,定期总结后开启新会话。 - **选择模型与来源**:在相同任务和时间范围内比较不同模型与来源的费用和效果,见[如何选择模型](https://platform.lyrouter.com/ai_gateway/docs/choose)与[平台模型与 BYOK 如何选择](https://platform.lyrouter.com/ai_gateway/docs/byok-choice)。按 Credits 设置预算与配额见[预算、配额与限流](https://platform.lyrouter.com/ai_gateway/docs/quota)。 ## 验证效果 调整后,在日志详情的「Token 消耗」中观察连续调用的「输入(缓存命中)」是否逐轮增加,再在 **用量分析** 中按相同时间长度比较调整前后的缓存命中率和费用。自己计算命中率时按 Token 加权:Σ 输入(缓存命中)÷ Σ(输入(缓存未命中)+ 输入(缓存命中)),不要对每次调用的命中率取平均。命中率仍然偏低时,按[费用异常与缓存未命中](https://platform.lyrouter.com/ai_gateway/docs/cache-errors)逐项排查。 (截图:在日志详情中观察缓存命中输入随调用轮次的变化,验证优化效果。) --- # 预算归因与调用审计 来源: https://platform.lyrouter.com/ai_gateway/docs/audit-practice LYRouter 以 API Key 为归属单位:每次调用都记在 Key 所属的工作空间、Key 的创建人和创建人的主部门名下。要让费用落到具体的人或应用,就让每位成员、每个应用使用自己创建的 Key。对账时,用日志分析、用量分析和消费明细三处数据交叉核对;审计材料按角色控制正文的查看和导出,对外提供前先脱敏。 ## 调用记在谁名下 | 维度 | 怎么确定 | 注意 | | --- | --- | --- | | 工作空间 | API Key 所属的工作空间 | 一把 Key 只属于一个工作空间 | | API Key | 发起调用的 Key | Key 删除后,历史日志和消费记录仍保留,并标注「已删除」 | | 创建人 | Key 的创建人 | 不是实际发起调用的人。多人共用一把 Key 时,日志和消费明细都只显示创建人 | | 部门 | 创建人在本组织中的主部门 | 按查看时的当前主部门显示:成员调整主部门后,历史记录也随之显示新部门;成员离开组织后显示其最后的主部门 | - 用量分析的「按用户」「按部门」只统计「仅自己使用」的 Key;共享给成员或全工作空间的旧 Key 单列为「共享应用 · 未归属」,不计入任何人或部门。 - 不要由账号管理员统一创建 Key 再分发给成员,否则这些用量都会记在账号管理员名下。成员创建 Key 的方法见[研发团队工具管理](https://platform.lyrouter.com/ai_gateway/docs/dev-team)。 - 部门统计依赖主部门。请当前账号管理员在组织管理中为成员设置主部门,见[组织、成员与角色](https://platform.lyrouter.com/ai_gateway/docs/organization);创建人没有主部门时,消费明细显示「未归属部门」。 ## 三处数据各看什么 | 位置 | 谁能查看 | 内容 | 金额 | | --- | --- | --- | --- | | 工作空间的 **日志分析** | 账号管理员和工作空间管理员看全部调用;其他成员只看自己创建的 Key | 逐条请求:时间、API Key、创建人、部门、模型、服务商、Token、状态 | 「费用」列,默认隐藏,可在 **自定义列** 中打开 | | 工作空间的 **用量分析** | 账号管理员看全部,并有「按部门」「按用户」;其他成员只看自己创建的 Key | 按时间、模型、API Key 等汇总的请求数、成功率、Token 和费用 | 人民币:平台请求按实付金额,BYOK 按服务商成本 | | **订阅充值** 的「消费明细」 | 仅当前账号管理员 | 组织下全部工作空间已结算的扣费:请求时间、API Key、工作空间、创建人、部门、模型、消费 Credits、请求 ID | Credits | (截图:「消费明细」按请求列出已结算的 Credits,以及对应的 API Key、工作空间、创建人、部门和模型。) ## 对账方法 1. **固定时间范围**:三处选择同一段时间。「消费明细」单次最多查询 90 天,只显示已结算的部分,最近几分钟的调用可能还没有出现;页面提示「消费归因仍在同步,当前分项合计可能暂时与结算总额不一致」时,稍后刷新再核对。 2. **注意单位**:「消费明细」以 Credits 计,只包含从账户 Credits 中实际扣除的金额;用量分析的费用以人民币计,并包含 BYOK 调用付给服务商的成本。两者不能直接相减,Credits 与人民币的换算见[计费规则与信用点](https://platform.lyrouter.com/ai_gateway/docs/billing)。 3. **从汇总下钻到请求**:在用量分析中找到异常的 Key 或模型,记下时间段;到日志分析按 API Key、模型和时间筛选,打开具体请求。需要自定义维度时,用用量分析的「自定义统计」查询并点击 **导出 CSV**。 4. **从扣费记录找日志**:「消费明细」的「请求 ID」就是日志详情顶部的 Request ID。复制它,进入对应工作空间,在[日志](https://platform.lyrouter.com/ai_gateway/docs/logs)的搜索框中即可找到这次请求。 5. **区分失败请求**:日志记录失败的请求,消费明细只包含产生扣费的请求。核对差异时,在日志中按状态码筛选失败请求,见[通过日志定位调用问题](https://platform.lyrouter.com/ai_gateway/docs/logs)。 ## 正文与权限 日志的元数据(时间、模型、Token、状态等)始终记录。提示词和回答正文只在工作空间开启全文日志后保存:工作空间管理员在日志分析工具栏点击 **日志存储设置**,打开「保存请求响应全文」,勾选全部信息处理告知事项后保存。开启只对之后的新请求生效,正文按平台策略脱敏后保存。留存期限见[数据保留、导出与删除](https://platform.lyrouter.com/ai_gateway/docs/retention)。 | 角色 | 可查看的日志 | 正文与原始报文 | 路由追踪、安全详情、导出 | | --- | --- | --- | --- | | 当前账号管理员、工作空间管理员 | 工作空间内全部 Key | 可以 | 可以 | | Key 的创建人 | 自己创建的 Key | 可以 | 不可以 | 日志中保存的请求头会去掉 `Authorization`、`x-api-key`、`api-key`、`Cookie` 等鉴权信息。成员可以看到自己 Key 的正文,涉及敏感业务时,请让不同人员各自创建 Key,并按需关闭全文日志,见[日志内容与数据处理](https://platform.lyrouter.com/ai_gateway/docs/privacy)。 ## 导出审计材料 工作空间管理员或账号管理员在日志分析工具栏点击 **导出**,在「日志导出」窗口创建任务: - 「导出格式」可选 CSV 或 JSON;「导出时间范围」最多 31 天,并沿用列表当前的筛选条件。 - 设置「文件密码」(至少 6 个字符),文件为密码加密的 ZIP,单次最多 50,000 条,保留 24 小时。关闭窗口后任务继续处理。 - 下载时需要通过绑定手机号的短信验证,并确认文件包含敏感数据。导出会一并包含已留存的提示词、对话和模型响应。 (截图:「日志导出」设置导出格式、时间范围和文件密码,并列出最近的导出任务。) 对外提供审计材料时,只保留必要字段:用 Key 名称和密钥前缀标识 Key,删除提示词与回答中的个人信息和业务数据;不要附 API Key 明文、BYOK 凭证或完整的鉴权头。文件密码与文件分开传递。 ## 常见问题 ### 日志里的「创建人」能证明是谁发起的调用吗? **答:** 「创建人」只说明这把 Key 由谁创建。只有每把 Key 只由一个人或一个应用使用时,它才能对应到实际调用方。需要按人审计时,请每位成员用自己的账号创建 Key,并停用多人共用的 Key。 ### 成员调整部门后,历史费用归到哪个部门? **答:** 部门按创建人当前的主部门显示,历史记录也会归到新部门。需要保留调整前的部门归属时,在调整前用用量分析的「自定义统计」按部门查询并 **导出 CSV** 留档。 --- # 服务状态 来源: https://platform.lyrouter.com/ai_gateway/docs/status [服务状态](https://platform.lyrouter.com/ai_gateway/status)页公开展示网关对各模型上游线路的主动探测结果,包括每条线路的状态、首字延迟、吞吐、成功率和最近 24 小时的逐小时记录。点击顶栏 **服务状态** 即可打开,无需登录。它反映的是平台线路本身是否可用;某个 API Key 的权限、余额、配额,以及你的 BYOK 凭证都不在探测范围内。线路正常但请求失败时,请按响应中的报错原文排查。 ## 页面内容 - **总览**:页面顶部显示「全部线路运行正常」或「部分线路性能下降」,以及线路总数和各状态的数量;还没有探测数据时显示「暂无监测数据」。 - **新鲜度**:「最近一次探测:」后显示最近一轮探测的时间,后面说明本页多久同步一次结果、探测任务多久执行一轮。探测周期由平台调整,以页面上的说明为准;页面会自动刷新,也可以点击 **刷新**。 - **模型卡片**:每张卡片的标题是模型 ID,右侧的「N/M 条线路正常」统计该模型的线路。卡片中每一行是一条上游线路,以服务商名称标识,依次显示状态、首字延迟、吞吐、成功率、24 小时格子条和更新时间;把鼠标悬停在更新时间上可以查看具体的探测时间。 (截图:服务状态页按模型列出各服务商线路的状态、首字延迟、吞吐、成功率和 24 小时格子条。) ## 线路状态 把鼠标悬停在状态标签上可以查看判定依据: | 状态 | 颜色 | 含义 | | --- | --- | --- | | 正常 | 绿色 | 最近一次探测中链路可达、鉴权通过、生成正常,延迟与成功率处于该线路自身的常态区间 | | 性能下降 | 黄色 | 线路仍可用,但相较自身基线明显变差:首字延迟的短期均值超过长期均值约 1.8 倍、成功率低于 98%,或解码吞吐低于基线(也可能来自上游限流) | | 网络不可达 | 红色 | DNS 解析、TCP 连接或 TLS 握手失败,请求没有到达上游 | | 服务不可用 | 红色 | 链路可达,但调用没有成功:上游返回错误、超时或空响应 | | 鉴权失败 | 红色 | 上游拒绝了平台的凭据(HTTP 401/403),通常是密钥失效、账户欠费或权限变更 | | 暂无数据 | 灰色 | 近期缺少有效探测样本,例如探测刚启动、该模型不在探测范围内,或连续多轮没有取得数据 | 首字延迟、吞吐和成功率都来自探测请求,用于和该线路自己的历史基线比较,不用于在服务商之间横向比较。 ## 24 小时格子条 格子条按你所在时区的自然小时排列,共 24 格,最右边一格是当前小时(轴上标为「现在」)。每格的颜色取该小时内最差的探测结果: | 颜色 | 图例 | 含义 | | --- | --- | --- | | 绿色 | 正常 | 该小时探测正常 | | 黄色 | 性能下降 | 首字延迟或解码吞吐相较自身基线明显变差 | | 橙色 | 服务不可用 | 链路可达,但上游返回错误、超时或空响应 | | 红色 | 网络/鉴权异常 | 网络不可达,或上游拒绝了平台的凭据 | | 灰色 | 无数据 | 该小时没有有效探测样本 | 把鼠标悬停在格子上,可以看到该小时的时段、状态、成功率、首字延迟、吞吐、「探测轮次」,有错误时还显示「错误类别」。几种特殊情况: - **进行中**:当前小时还没有产出探测样本,格子以斜纹显示。刚过整点时通常如此,不表示线路故障。 - **「生成阶段」显示「未执行」**:该小时的探测没有进行到生成阶段(网络不可达或上游拒绝了凭据),所以没有延迟和吞吐数据。 - **灰色但有探测轮次**:该小时探测过,但没有产出判定,通常是网关没有取得该线路的可用凭据,不表示上游故障。 ## 探测范围 - 网关定期直接向每条平台线路发送一次最小的流式生成请求,先检查连通性,再检查生成是否成功。探测不经过工作空间的路由设置。 - 只探测对话模型;图像、视频、语音等模型不在页面上。你通过 BYOK 接入的通道也不在探测范围内。 - 实际调用时,网关根据每次请求的结果在通道之间回退:某个通道失败后改用同一模型的其他通道,见[失败重试与备用模型](https://platform.lyrouter.com/ai_gateway/docs/fallback)。 ## 状态正常但请求失败 按以下顺序排查: 1. **读报错原文**:401、403 见[401 / 403:鉴权与权限](https://platform.lyrouter.com/ai_gateway/docs/auth-errors),429 见[429:限流与配额](https://platform.lyrouter.com/ai_gateway/docs/rate-errors),模型调不通或 402、503 见[模型不可用](https://platform.lyrouter.com/ai_gateway/docs/unavailable),504 或流式中断见[超时与流式中断](https://platform.lyrouter.com/ai_gateway/docs/stream-errors)。 2. **查日志**:在[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)中找到这次请求,「状态说明」列标明错误来自「网关」还是「上游」;在详情中查看「模型(实际)」和「服务商」,再到状态页找对应模型和服务商的那一行比较。 3. **确认是否使用 BYOK**:请求走的是 BYOK 通道时,状态页不覆盖它。请账号管理员在 [BYOK](https://platform.lyrouter.com/ai_gateway/docs/byok) 中重新测试连接,并到服务商处确认额度。 4. **对比请求特征**:探测使用很短的请求。长上下文、大量工具定义或长时间的流式输出更容易触发上游超时和限流,请对照日志中的耗时和上游响应排查。 ## 常见问题 ### 某条线路显示异常,我的调用会受影响吗? **答:** 网关会在该线路失败后改用同一模型的其他通道。模型只有这一条线路时,调用可能失败,可以改用其他模型,或通过[虚拟模型](https://platform.lyrouter.com/ai_gateway/docs/presets)的备用模型自动兜底。 ### 报告服务问题时,需要提供哪些信息? **答:** 提供调用时间、模型 ID、API Key 名称、完整的报错原文,以及日志详情顶部的 Request ID;如果状态页同时有异常,附上对应的模型和服务商名称。响应中不包含请求 ID,请从日志详情中复制。不要提供 API Key 明文或完整的鉴权头。 --- # API 文档 来源: https://platform.lyrouter.com/ai_gateway/docs/api-overview LYRouter 网关的完整接口参考。所有接口都在 `https://api.lyrouter.com` 上开放,用同一个 API Key 鉴权:对话、向量、图像接口兼容 OpenAI 格式,`/v1/messages` 兼容 Anthropic 格式,视频生成是异步任务。 ## 概述 API 文档分为两组: - **AI 模型接口**:按能力分类,每个接口一页,依次给出请求方法与路径、鉴权、请求头、请求体、请求示例、响应和常见错误。 - **通用说明**:所有接口共用的约定,包括接入地址与鉴权、模型命名、流式响应、工具调用、异步任务、网关扩展的请求头与响应头、错误码和协议兼容性,以及如何把本文档交给 AI 工具。 ## AI 模型接口 | 分类 | 接口 | 说明 | | --- | --- | --- | | 聊天(Chat) | [Chat Completions 格式](https://platform.lyrouter.com/ai_gateway/docs/chat-completions)、[Responses 格式](https://platform.lyrouter.com/ai_gateway/docs/responses-api)、[Anthropic 格式](https://platform.lyrouter.com/ai_gateway/docs/anthropic-messages) | 三种对话协议,OpenAI SDK、Codex、Claude Code 等工具分别使用 | | 嵌入(Embeddings) | [创建向量](https://platform.lyrouter.com/ai_gateway/docs/embeddings) | 把文本转换为向量 | | 重排(Rerank) | [文档重排](https://platform.lyrouter.com/ai_gateway/docs/rerank) | 按与查询的相关性给文档排序 | | 图像(Images) | [图像生成](https://platform.lyrouter.com/ai_gateway/docs/images-generations)、[图像编辑](https://platform.lyrouter.com/ai_gateway/docs/images-edits) | 同步返回图片 | | 模型(Models) | [列出模型](https://platform.lyrouter.com/ai_gateway/docs/models) | 当前 API Key 可调用的模型 | | 视频(Videos) | [Seedance 视频生成](https://platform.lyrouter.com/ai_gateway/docs/video-seedance)、[MiniMax H3 视频生成](https://platform.lyrouter.com/ai_gateway/docs/video-minimax) | 异步任务:提交、查询、下载 | ## 通用说明 | 文档 | 内容 | | --- | --- | | [接入地址与鉴权](https://platform.lyrouter.com/ai_gateway/docs/call-gateway) | Base URL、API Key 的两种写法、SDK 配置 | | [模型命名与查询](https://platform.lyrouter.com/ai_gateway/docs/model-names) | 模型 ID、虚拟模型、Auto 的写法与查询 | | [流式响应](https://platform.lyrouter.com/ai_gateway/docs/streaming) | 三种对话接口的 SSE 格式与结束标记 | | [工具调用](https://platform.lyrouter.com/ai_gateway/docs/tool-call) | 函数定义、调用与结果回传,各协议的对应关系 | | [异步任务](https://platform.lyrouter.com/ai_gateway/docs/async) | 视频任务的状态、轮询、下载与计费 | | [网关扩展请求头与响应头](https://platform.lyrouter.com/ai_gateway/docs/gateway-headers) | 网关约定的请求头、响应头 | | [错误码与请求标识](https://platform.lyrouter.com/ai_gateway/docs/errors) | 全部报错原文与处理方法 | | [协议兼容性与限制](https://platform.lyrouter.com/ai_gateway/docs/compatibility) | 跨协议转换时参数的保留与丢弃 | | [在 AI 工具中使用本文档](https://platform.lyrouter.com/ai_gateway/docs/ai-tools) | 每页的 Markdown 版本、llms.txt、OpenAPI 规格与文档 MCP 服务 | ## 接入地址 | 协议 | Base URL | 示例路径 | | --- | --- | --- | | OpenAI 兼容(SDK 的 `base_url`) | `https://api.lyrouter.com/v1` | `/chat/completions` | | Anthropic(SDK 的 `base_url`、`ANTHROPIC_BASE_URL`) | `https://api.lyrouter.com` | `/v1/messages` | 鉴权方式在所有接口上相同: ```text Authorization: Bearer ``` 也可以改用 `x-api-key: `,两者同时存在时只读 `Authorization`。详见[接入地址与鉴权](https://platform.lyrouter.com/ai_gateway/docs/call-gateway)。 ## 全部接口 | 分类 | 方法 | 路径 | 用途 | 文档 | | --- | --- | --- | --- | --- | | 聊天 | POST | `/v1/chat/completions` | 对话补全 | [Chat Completions 格式](https://platform.lyrouter.com/ai_gateway/docs/chat-completions) | | 聊天 | POST | `/v1/responses` | 对话(Responses 格式),Codex 等工具使用 | [Responses 格式](https://platform.lyrouter.com/ai_gateway/docs/responses-api) | | 聊天 | POST | `/v1/messages` | 对话(Anthropic 格式),Claude Code 等工具使用 | [Anthropic 格式](https://platform.lyrouter.com/ai_gateway/docs/anthropic-messages) | | 嵌入 | POST | `/v1/embeddings` | 文本向量 | [创建向量](https://platform.lyrouter.com/ai_gateway/docs/embeddings) | | 重排 | POST | `/v1/rerank` | 文档重排,服务商的 rerank 格式原样转发 | [文档重排](https://platform.lyrouter.com/ai_gateway/docs/rerank) | | 图像 | POST | `/v1/images/generations` | 图像生成 | [图像生成](https://platform.lyrouter.com/ai_gateway/docs/images-generations) | | 图像 | POST | `/v1/images/edits` | 图像编辑,`multipart/form-data` 或 JSON | [图像编辑](https://platform.lyrouter.com/ai_gateway/docs/images-edits) | | 模型 | GET | `/v1/models` | 列出当前 API Key 可调用的模型 | [列出模型](https://platform.lyrouter.com/ai_gateway/docs/models) | | 视频 | POST | `/v1/videos` | 提交视频生成任务 | [Seedance](https://platform.lyrouter.com/ai_gateway/docs/video-seedance)、[MiniMax H3](https://platform.lyrouter.com/ai_gateway/docs/video-minimax) | | 视频 | GET | `/v1/videos/{id}` | 查询任务状态 | [异步任务](https://platform.lyrouter.com/ai_gateway/docs/async) | | 视频 | GET | `/v1/videos/{id}/content` | 下载产物(302 跳转到产物地址) | [异步任务](https://platform.lyrouter.com/ai_gateway/docs/async) | | 视频 | DELETE | `/v1/videos/{id}` | 对已结束的任务返回 `deleted: true`;进行中的任务不能取消 | [异步任务](https://platform.lyrouter.com/ai_gateway/docs/async) | | 视频 | POST | `/v1/videos/regenerations` | 视频升清,仅 MiniMax H3 支持 | [MiniMax H3 视频生成](https://platform.lyrouter.com/ai_gateway/docs/video-minimax) | | 视频 | POST | `/v1/videos/context` | 上下文增强,产出增强后的提示词,仅 MiniMax H3 支持 | [MiniMax H3 视频生成](https://platform.lyrouter.com/ai_gateway/docs/video-minimax) | - 路径前缀也可以写成其他版本号或省略,例如 `/v4/chat/completions`、`/chat/completions` 与 `/v1/chat/completions` 相同,方便要求固定前缀的工具接入。 - 表外的 OpenAI 接口,例如 `/v1/completions`、`/v1/files`、`/v1/batches`、`/v1/moderations`,网关没有开放,请求返回 404。 - 接入地址、SDK 的 Base URL 写法见[接入地址与鉴权](https://platform.lyrouter.com/ai_gateway/docs/call-gateway),网关约定的请求头、响应头见[网关扩展请求头与响应头](https://platform.lyrouter.com/ai_gateway/docs/gateway-headers)。 - 表中对话、向量、重排、模型接口的机器可读规格见 [lyrouter-openapi.yaml](https://platform.lyrouter.com/ai_gateway/api-spec/lyrouter-openapi.yaml)(OpenAPI 3.1),图像、视频接口见 [multimodal-openapi.yaml](https://platform.lyrouter.com/ai_gateway/api-spec/multimodal-openapi.yaml),用法见[在 AI 工具中使用本文档](https://platform.lyrouter.com/ai_gateway/docs/ai-tools#openapi-规格)。 ## 能力对照 | 接口 | 虚拟模型 `@vmodel/` | Auto `lyrouter/auto` | 流式 | 执行方式 | 全部失败后改用默认模型 | | --- | --- | --- | --- | --- | --- | | `/v1/chat/completions` | 支持 | 支持 | 支持 | 同步 | 是 | | `/v1/responses` | 支持 | 支持 | 支持 | 同步 | 是 | | `/v1/messages` | 支持 | 支持 | 支持 | 同步 | 是 | | `/v1/embeddings`、`/v1/rerank` | 支持,模型列表须为对应的向量或重排模型 | 不要使用:目前网关不拒绝,但拿不到可用结果,见[创建向量](https://platform.lyrouter.com/ai_gateway/docs/embeddings#网关行为) | 不支持 | 同步 | 是,但默认模型通常是对话模型,结果多为报错 | | `/v1/images/*` | 不支持(403) | 不支持(403) | 取决于模型 | 同步 | 否 | | `/v1/videos` 及其子接口 | 不支持(403) | 不支持(403) | 不支持 | 异步任务 | 否 | - **虚拟模型与 Auto**:在不支持的接口上返回 403 `Model is not available in the model plaza`,请改写具体的模型 ID。详见[虚拟模型](https://platform.lyrouter.com/ai_gateway/docs/presets)和[Auto 智能路由](https://platform.lyrouter.com/ai_gateway/docs/auto)。 - **流式**:对话三个接口用 `stream: true` 开启,格式与结束标记见[流式响应](https://platform.lyrouter.com/ai_gateway/docs/streaming)。 - **异步任务**:视频接口提交后立即返回任务 ID,之后查询状态、下载产物,完整流程见[异步任务](https://platform.lyrouter.com/ai_gateway/docs/async)。图像接口是同步返回,但单次可能需要几分钟,客户端超时请按分钟设置。 - **失败回退**:同一模型有多个通道时,所有接口都会在通道之间依次尝试;改用其他模型只发生在对话、向量和重排接口上,见[失败重试与备用模型](https://platform.lyrouter.com/ai_gateway/docs/fallback)。 --- # Chat Completions 格式 来源: https://platform.lyrouter.com/ai_gateway/docs/chat-completions 根据对话历史生成模型回答,支持流式和非流式响应、图片输入和工具调用。兼容 OpenAI Chat Completions API:OpenAI 官方 SDK 和大多数兼容 OpenAI 的应用把 Base URL 改成 `https://api.lyrouter.com/v1` 即可使用。同一个模型可能由 OpenAI 兼容或 Anthropic 协议的通道服务,网关会自动转换请求和响应,本页同时说明转换时哪些参数会变化。 `POST /v1/chat/completions` ## 鉴权 在请求头中携带 API Key: ```text Authorization: Bearer ``` `Bearer` 区分大小写。也可以改用 `x-api-key: `,两者同时存在时只读 `Authorization`。API Key 在工作空间的 **API 密钥** 页面创建,只用于 LYRouter 鉴权,不会转发给上游服务商。完整说明见[接入地址与鉴权](https://platform.lyrouter.com/ai_gateway/docs/call-gateway)。 ## 请求头 | 请求头 | 必填 | 说明 | | --- | --- | --- | | `Content-Type` | 否 | 建议携带 `application/json`。不带时网关按 JSON 解析请求体;写成其他值(如 `application/x-www-form-urlencoded`)时返回 400 | ## 请求体 | 参数 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | `model` | string | 否 | 模型 ID,例如模型广场中复制的系统模型标识;也可以写虚拟模型 `@vmodel/<名称>` 或 `lyrouter/auto`。不写、写成 `""` 或 `null` 时使用工作空间的默认模型,没有默认模型时返回 400。见[模型命名与查询](https://platform.lyrouter.com/ai_gateway/docs/model-names) | | `messages` | array | 是 | 对话消息,结构见下文 | | `stream` | boolean | 否 | `true` 时以 SSE 流式返回,默认 `false` | | `stream_options` | object | 否 | 流式时网关总是设为 `{"include_usage": true}`,最后一个 chunk 带 `usage`,你传的值会被覆盖 | | `max_tokens` | integer | 否 | 本次最多生成的 Token 数。Anthropic 协议通道要求必填,请求中没有 `max_tokens` 和 `max_completion_tokens` 时网关补 4096 | | `max_completion_tokens` | integer | 否 | OpenAI 新版的输出上限字段,透传给 OpenAI 兼容通道;发往 Anthropic 协议通道时在没有 `max_tokens` 的情况下作为 `max_tokens` 使用 | | `temperature` | number | 否 | 采样温度,取值范围以模型为准(Anthropic 协议通道为 0~1),网关不做换算 | | `top_p` | number | 否 | 核采样 | | `stop` | string \| array | 否 | 停止序列;发往 Anthropic 协议通道时转换为 `stop_sequences` | | `tools` | array | 否 | 可调用的函数列表,见[工具调用](https://platform.lyrouter.com/ai_gateway/docs/tool-call) | | `tool_choice` | string \| object | 否 | `"auto"`、`"none"`、`"required"` 或 `{"type":"function","function":{"name":"..."}}`,各协议的对应关系见[工具调用](https://platform.lyrouter.com/ai_gateway/docs/tool-call) | | `parallel_tool_calls` | boolean | 否 | 是否允许一次返回多个工具调用;发往 Anthropic 协议通道时会被去掉 | | `response_format` | object | 否 | `{"type":"json_object"}` 或 `{"type":"json_schema",...}`;只对 OpenAI 兼容通道生效,发往 Anthropic 协议通道时会被去掉 | | `reasoning_effort` | string | 否 | 推理强度,网关按服务商处理,见下文「推理参数」 | | `enable_thinking` / `thinking_budget` | boolean / integer | 否 | 思考开关与思考预算,网关按服务商处理,见下文「推理参数」 | | `seed` | integer | 否 | 随机种子;透传给 OpenAI 兼容通道,是否生效取决于模型;发往 Anthropic 协议通道时会被去掉 | | `user` | string | 否 | 终端用户标识,透传给上游,是否生效取决于模型 | | `frequency_penalty` / `presence_penalty` / `logprobs` / `n` | — | 否 | 透传给 OpenAI 兼容通道,是否生效取决于模型;发往 Anthropic 协议通道时会被去掉 | 表中没有列出的其他参数,网关原样转发给 OpenAI 兼容通道,是否生效取决于模型。 ### messages 的结构 每条消息包含 `role` 和 `content`: | `role` | 用途 | 说明 | | --- | --- | --- | | `system` | 系统提示词 | 放在最前面。发往 Anthropic 协议通道时,所有 `system` 和 `developer` 消息合并为 Anthropic 的 `system`,`content` 请写成字符串 | | `developer` | 新版 OpenAI 的系统提示词 | 透传给 OpenAI 兼容通道,是否支持取决于模型;Anthropic 协议通道按 `system` 处理 | | `user` | 用户输入 | `content` 可以是字符串或内容块数组 | | `assistant` | 模型之前的回答 | 多轮对话时原样放回;包含工具调用时带 `tool_calls` | | `tool` | 工具执行结果 | 必须带 `tool_call_id`,对应上一条 assistant 消息中的调用 ID | `content` 有两种写法。纯文本直接写字符串;需要图片时写成内容块数组: ```json { "role": "user", "content": [ { "type": "text", "text": "这张图里有什么?" }, { "type": "image_url", "image_url": { "url": "https://example.com/cat.jpg" } } ] } ``` - `image_url.url` 可以是公网可访问的 `https://` 地址,也可以是 `data:image/png;base64,<数据>` 形式的 Base64 数据。 - 模型必须支持图像输入,只接受文本的模型返回 400 `This model accepts text input only`。在模型广场用「输入模态」筛选可用模型,详见[多模态能力](https://platform.lyrouter.com/ai_gateway/docs/multimodal)。 - Anthropic 协议通道只转换文本块和图片块;`input_audio`、`file` 等其他内容块只对 OpenAI 兼容通道有效。 ### 推理参数 三个推理参数分属不同服务商的写法,网关按实际服务这次请求的服务商保留或去掉,不会把其中一个换算成另一个(发往 Anthropic 协议通道时转换成 `thinking`,见表中说明): | 实际服务的上游 | `reasoning_effort` | `enable_thinking` | `thinking_budget` | | --- | --- | --- | --- | | OpenAI 官方接口 | 转发 | 去掉 | 去掉 | | 阿里云百炼(DashScope 兼容接口) | 去掉 | 转发 | 转发 | | DeepSeek 官方接口 | 去掉 | 去掉 | 去掉(是否思考由所选模型决定) | | Anthropic 协议通道 | 去掉 | `true` 且没有预算时转为 `thinking: {"type": "adaptive"}`,`false` 时不开启思考 | 大于 0 时转为 `thinking: {"type": "enabled", "budget_tokens": N}` | | 其他 OpenAI 兼容服务商 | 原样转发 | 原样转发 | 原样转发 | - 实际服务的服务商在[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)详情的「服务商」中查看。同一模型有多个来源时,请对每个来源验证推理参数是否生效。 - Anthropic 协议通道开启思考时,上游要求 `max_tokens` 大于 `budget_tokens`,网关不调整这些参数,不满足时由上游返回 400。 - 强制工具调用(`tool_choice` 为 `"required"` 或指定函数)且没有写 `enable_thinking` / `thinking_budget` 时,阿里云百炼通道会被自动加上 `enable_thinking: false`,因为这类上游在思考模式下不接受强制工具调用。 - OpenAI Python SDK 没有定义 `enable_thinking`、`thinking_budget`,请放在 `extra_body` 中传递,例如 `extra_body={"enable_thinking": False}`;Node.js SDK 直接写在请求参数里即可。 ## 请求示例 **请求示例** cURL: ```bash curl https://api.lyrouter.com/v1/chat/completions \ -H "Authorization: Bearer $LYROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "MODEL_ID", "messages": [ {"role": "system", "content": "你是一个简洁的助手。"}, {"role": "user", "content": "用一句话介绍 LYRouter。"} ], "temperature": 0.7, "max_tokens": 512 }' ``` Python: ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["LYROUTER_API_KEY"], base_url="https://api.lyrouter.com/v1", ) completion = client.chat.completions.create( model="MODEL_ID", messages=[ {"role": "system", "content": "你是一个简洁的助手。"}, {"role": "user", "content": "用一句话介绍 LYRouter。"}, ], temperature=0.7, max_tokens=512, ) print(completion.choices[0].message.content) print(completion.usage) ``` Node.js: ```js import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.LYROUTER_API_KEY, baseURL: "https://api.lyrouter.com/v1", }); const completion = await client.chat.completions.create({ model: "MODEL_ID", messages: [ { role: "system", content: "你是一个简洁的助手。" }, { role: "user", content: "用一句话介绍 LYRouter。" }, ], temperature: 0.7, max_tokens: 512, }); console.log(completion.choices[0].message.content); console.log(completion.usage); ``` ## 响应 非流式请求返回一个 `chat.completion` 对象;出错时返回 `error` 对象。下面的 200 是 OpenAI 兼容通道的典型响应,400 是没有写 `model` 且工作空间没有默认模型,429 是 API Key 当天的 Token 配额已用完(见[429:限流与配额](https://platform.lyrouter.com/ai_gateway/docs/rate-errors))。 **响应示例** 200: ```json { "id": "chatcmpl-9f1c2a7e4b", "object": "chat.completion", "created": 1791950400, "model": "MODEL_ID", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "LYRouter 是可信模型服务与 Token 治理平台,用一个 API Key 统一调用多家模型服务商。" }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 1250, "completion_tokens": 32, "total_tokens": 1282, "prompt_tokens_details": { "cached_tokens": 1024 }, "completion_tokens_details": { "reasoning_tokens": 0 } } } ``` 400: ```json { "error": { "message": "you must provide a model parameter", "type": "invalid_request_error", "code": "missing_model" } } ``` 429: ```json { "error": { "message": "rate limit exceeded on apikey total_tokens/day", "type": "rate_limit_error", "subject": "apikey", "metric": "total_tokens", "window": "day", "limit": 1000000, "used": 1000523, "reset_at": "2026-10-14T16:01:00Z" } } ``` | 字段 | 说明 | | --- | --- | | `id` | 上游生成的响应 ID,不是 LYRouter 的 Request ID。网关不在响应中返回 Request ID,排查时在日志详情顶部复制 | | `model` | 上游返回的模型名,可能与请求中的模型 ID 写法不同;实际使用的模型以日志的「模型(实际)」为准 | | `choices[0].message.content` | 回答正文;只返回工具调用时可能为 `null` 或空字符串 | | `choices[0].message.tool_calls` | 模型请求调用的工具,见[工具调用](https://platform.lyrouter.com/ai_gateway/docs/tool-call) | | `choices[0].message.reasoning_content` | 部分模型返回的思考过程;由 Anthropic 协议通道服务且开启思考时同样出现在这里 | | `choices[0].message.reasoning_blocks` | LYRouter 扩展字段,只在 Anthropic 协议通道开启思考时出现,保存带签名的原始思考块。多轮工具调用时把 assistant 消息原样放回,网关才能把思考块交还上游 | | `choices[0].finish_reason` | `stop`(正常结束)、`length`(达到输出上限)、`tool_calls`(等待工具结果)、`content_filter`(被上游过滤)等。Anthropic 协议通道的 `end_turn`、`stop_sequence` 映射为 `stop`,`max_tokens` 映射为 `length`,`tool_use` 映射为 `tool_calls` | | `usage` | 本次的 Token 用量,由上游上报,见下表 | ### usage 与日志中的四项 Token `usage` 的字段取决于实际服务的上游。它与[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)「Token 消耗」四项的对应关系如下: | 日志中的名称 | OpenAI 兼容通道 | Anthropic 协议通道 | | --- | --- | --- | | 「输入(缓存命中)」 | `prompt_tokens_details.cached_tokens`(DeepSeek 等上游为 `prompt_cache_hit_tokens`) | `cache_read_input_tokens` | | 「输入(缓存未命中)」 | `prompt_tokens` 减去缓存命中 | `prompt_tokens` | | 「输出」 | `completion_tokens`,包含思考 Token(`completion_tokens_details.reasoning_tokens`) | `completion_tokens` | | 「显式缓存创建」 | 不出现 | `cache_creation_input_tokens` | 由 Anthropic 协议通道服务时,响应中的 `usage` 是这样的,`prompt_tokens` **不包含**缓存命中和缓存写入: ```json "usage": { "prompt_tokens": 226, "completion_tokens": 32, "total_tokens": 258, "cache_read_input_tokens": 1024, "cache_creation_input_tokens": 0 } ``` 自己按 `usage` 估算费用时,先确认是哪种上游,再按四项分别计价,方法见[调用费用与缓存计费](https://platform.lyrouter.com/ai_gateway/docs/estimate)。核对时以日志为准。 ## 流式响应 设置 `"stream": true` 后,响应的 `Content-Type` 为 `text/event-stream`,每个事件是一行 `data: ` 加一个空行: ```text data: {"id":"chatcmpl-9f1c2a7e4b","object":"chat.completion.chunk","created":1791950400,"model":"MODEL_ID","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]} data: {"id":"chatcmpl-9f1c2a7e4b","object":"chat.completion.chunk","created":1791950400,"model":"MODEL_ID","choices":[{"index":0,"delta":{"content":"LYRouter 是"},"finish_reason":null}]} data: {"id":"chatcmpl-9f1c2a7e4b","object":"chat.completion.chunk","created":1791950400,"model":"MODEL_ID","choices":[{"index":0,"delta":{"content":"可信模型服务与 Token 治理平台。"},"finish_reason":null}]} data: {"id":"chatcmpl-9f1c2a7e4b","object":"chat.completion.chunk","created":1791950400,"model":"MODEL_ID","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]} data: {"id":"chatcmpl-9f1c2a7e4b","object":"chat.completion.chunk","created":1791950400,"model":"MODEL_ID","choices":[],"usage":{"prompt_tokens":1250,"completion_tokens":32,"total_tokens":1282,"prompt_tokens_details":{"cached_tokens":1024}}} data: [DONE] ``` - 正文在 `choices[0].delta.content` 中逐段到达,思考过程在 `delta.reasoning_content`(个别上游为 `delta.reasoning`)。 - 网关总会开启 `include_usage`,所以结束前有一个 `choices` 为空数组、带 `usage` 的 chunk。读取 `choices[0]` 之前先判断数组非空。 - `data: [DONE]` 是正常结束的标记。没有收到它就断开,或收到了 `"code": "stream_interrupted"` 的错误事件,说明输出不完整,见[超时与流式中断](https://platform.lyrouter.com/ai_gateway/docs/stream-errors)。 - 由 Anthropic 协议通道服务时,chunk 由网关转换生成,带 `usage` 的 chunk 只有 `prompt_tokens`、`completion_tokens`、`total_tokens` 三个字段,缓存数量请在日志中查看。 **流式示例** cURL: ```bash curl -N https://api.lyrouter.com/v1/chat/completions \ -H "Authorization: Bearer $LYROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"MODEL_ID","stream":true,"messages":[{"role":"user","content":"写两行关于秋天的诗"}]}' ``` Python: ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["LYROUTER_API_KEY"], base_url="https://api.lyrouter.com/v1", ) stream = client.chat.completions.create( model="MODEL_ID", messages=[{"role": "user", "content": "写两行关于秋天的诗"}], stream=True, ) for chunk in stream: if chunk.choices and chunk.choices[0].delta.content: print(chunk.choices[0].delta.content, end="", flush=True) if chunk.usage: print("\n", chunk.usage) ``` Node.js: ```js import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.LYROUTER_API_KEY, baseURL: "https://api.lyrouter.com/v1", }); const stream = await client.chat.completions.create({ model: "MODEL_ID", messages: [{ role: "user", content: "写两行关于秋天的诗" }], stream: true, }); for await (const chunk of stream) { const text = chunk.choices[0]?.delta?.content; if (text) process.stdout.write(text); if (chunk.usage) console.log("\n", chunk.usage); } ``` 三种对话接口的事件格式对比和客户端实现要点见[流式响应](https://platform.lyrouter.com/ai_gateway/docs/streaming)。 ## 网关行为 与直接调用上游相比,经 LYRouter 调用有以下差别: - **选择通道与回退**:网关按工作空间的路由策略为模型选择通道,失败时换下一个通道,最后可能改用工作空间的默认模型,见[失败重试与备用模型](https://platform.lyrouter.com/ai_gateway/docs/fallback)和[通道选择与路由策略](https://platform.lyrouter.com/ai_gateway/docs/routing)。流式输出开始后不再换通道。 - **协议转换**:通道是 Anthropic 协议时,网关把请求转换成 Anthropic Messages 格式,响应再转换回 Chat Completions 格式。`response_format`、`seed`、`n`、`logprobs`、`top_logprobs`、`frequency_penalty`、`presence_penalty`、`logit_bias`、`parallel_tool_calls`、`reasoning_effort` 会被去掉,`metadata` 只保留 `user_id`;这些去掉不会写进响应头。对比见[模型能力与兼容性](https://platform.lyrouter.com/ai_gateway/docs/capabilities)。 - **推理参数**:按上文「推理参数」的表格保留、去掉或转换。 - **提示词缓存标记**:`cache_control` 只在 Anthropic 协议通道上生效,保留文本内容块和工具定义上的标记,`"ttl": "1h"` 时网关把 `anthropic-beta` 请求头设为 1 小时缓存所需的值(覆盖客户端自带的值);发往 OpenAI 兼容通道时全部删除,由上游的隐式缓存工作。 - **历史消息中的扩展字段**:发往 OpenAI 兼容通道前,网关删除消息上的 `reasoning_content`、`reasoning_blocks` 和 `cache_control`。 - **固定 JSON 键序**:网关把发往上游的请求体中所有 JSON 对象的键按固定顺序重新排列,包括工具调用参数字符串里的 JSON,使相同内容每次产生相同的字节,提高上游前缀缓存的命中率,见[降低成本与优化缓存](https://platform.lyrouter.com/ai_gateway/docs/cost-practice)。 - **数字精度**:网关会解析并重新编码请求体,数字最多保留 14 位有效数字。超过的长整数(如 19 位 ID)会变成科学计数法,请以字符串传递。 - **用量**:流式请求总会返回 `usage`;`usage` 的字段随上游变化,见上文对照表。 ## 常见错误 错误响应为 `{"error":{"message":"...","type":"...","code":"..."}}`,`code` 只有部分错误才有。 | 状态码 | `error.message` | `error.code` | 原因与处理 | | --- | --- | --- | --- | | 400 | `you must provide a model parameter` | `missing_model` | 没有写 `model`,工作空间也没有默认模型。写上模型 ID。请求体不是合法的 JSON 对象时,部分版本也返回这个错误,见下一行 | | 400 | `request body must be a JSON object` | `invalid_json` | 请求体不是合法的 JSON 对象,例如 JSON 被截断或顶层是数组。部分版本返回的是 400 `you must provide a model parameter`(`missing_model`)。工作空间设置了默认模型时,返回的是 `{"message":"could not get parse JSON request body: <解析错误>"}`,外层没有 `error` | | 400 | `This model accepts text input only` | `unsupported_model_input` | 给只接受文本的模型发了图片等非文本内容,换用支持图像输入的模型 | | 400 | `This model does not support the chat_completions API` | `unsupported_model_api` | 模型不支持对话接口,例如图像生成模型 | | 403 | `Model is not available in the model plaza` | `model_not_available` | 工作空间没有开通这个模型,请管理员在模型广场开通,或换用已开通的模型 | | 503 | `all routed candidates exhausted` | `no_route_candidate` | 找不到可服务这次请求的通道,常见于 `@vmodel/<名称>` 写错或模型没有可用来源,见[模型不可用](https://platform.lyrouter.com/ai_gateway/docs/unavailable) | - 401 / 403 鉴权问题见[401 / 403:鉴权与权限](https://platform.lyrouter.com/ai_gateway/docs/auth-errors),429 见[429:限流与配额](https://platform.lyrouter.com/ai_gateway/docs/rate-errors)。 - 500 / 504 是连接上游失败或等待上游超时,响应体是 HTML 页面而不是 JSON,见[超时与流式中断](https://platform.lyrouter.com/ai_gateway/docs/stream-errors)。 - 网关自己生成的部分 400 是一行纯文本而不是 JSON,例如 `Content-Type` 不是 `application/json` 时的 `unsupported content-type: …`。这类响应的响应头目前仍是 `Content-Type: application/json`,解析错误体前请先判断正文是否为 JSON。 - 上游服务商返回的错误会原样转发,状态码和报错原文由上游决定。完整列表见[错误码与请求标识](https://platform.lyrouter.com/ai_gateway/docs/errors)。 --- # Responses 格式 来源: https://platform.lyrouter.com/ai_gateway/docs/responses-api 创建一个模型响应:用 `input` 传入文本或一组输入项,返回带 `id` 的响应对象,输出放在 `output` 数组里,按项区分消息、函数调用和推理内容,支持流式。兼容 OpenAI Responses API:OpenAI SDK 的 `client.responses` 和使用 Responses 协议的客户端(例如 [Codex](https://platform.lyrouter.com/ai_gateway/docs/codex) CLI)把 Base URL 设为 `https://api.lyrouter.com/v1` 即可使用,与 Chat Completions 相同。网关按 Responses 协议转发请求、不做协议转换,所选模型和服务它的通道都必须支持 Responses。 `POST /v1/responses` ## 鉴权 在请求头中携带 API Key: ```text Authorization: Bearer ``` `Bearer` 区分大小写。也可以改用 `x-api-key: `,两者同时存在时只读 `Authorization`。API Key 在工作空间的 **API 密钥** 页面创建,只用于 LYRouter 鉴权,不会转发给上游服务商。完整说明见[接入地址与鉴权](https://platform.lyrouter.com/ai_gateway/docs/call-gateway)。 ## 请求头 | 请求头 | 必填 | 说明 | | --- | --- | --- | | `Content-Type` | 否 | 建议携带 `application/json`。不带时网关按 JSON 解析请求体;写成其他值(如 `application/x-www-form-urlencoded`)时返回 400 | ## 请求体 | 参数 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | `model` | string | 否 | 模型 ID,也可以写 `@vmodel/<名称>`([虚拟模型](https://platform.lyrouter.com/ai_gateway/docs/presets))或 `lyrouter/auto`([Auto 智能路由](https://platform.lyrouter.com/ai_gateway/docs/auto))。省略、为 `""` 或 `null` 时使用工作空间的默认模型,没有默认模型时返回 400 | | `input` | string / array | 是 | 字符串等同于一条用户消息;数组按顺序放入消息项和其他输入项,见下文「input 数组中的项」 | | `instructions` | string | 否 | 系统级指令。使用虚拟模型时,虚拟模型的系统提示词追加在这段指令之后 | | `stream` | boolean | 否 | `true` 时以 SSE 事件流返回,见下文「流式响应」 | | `tools` | array | 否 | 函数工具写作 `{"type": "function", "name", "description", "parameters", "strict"}`,字段平铺,不像 Chat 那样包在 `function` 里。内置工具(如 `web_search`)原样转发,是否可用取决于上游 | | `tool_choice` | string / object | 否 | `auto`、`none`、`required`,或 `{"type": "function", "name": "..."}` | | `parallel_tool_calls` | boolean | 否 | 是否允许一次返回多个函数调用 | | `max_output_tokens` | integer | 否 | 输出上限,包含推理 Token。请使用这个字段;Chat 的 `max_tokens` 会原样转发,是否生效由上游决定 | | `reasoning` | object | 否 | 例如 `{"effort": "low", "summary": "auto"}`。透传给上游,是否生效取决于模型 | | `text.format` | object | 否 | 输出格式:`{"type": "text"}`、`{"type": "json_object"}`,或 `{"type": "json_schema", "name": "...", "schema": {...}, "strict": true}`。效果取决于上游:例如有的上游在 `json_object` 时仍把 JSON 包在 Markdown 的 json 代码块里返回,在 `json_schema` 时不按 schema 输出(响应回显的 `text.format` 中字段名为 `schema_`)。依赖结构化输出前请先用所选模型验证,解析前去掉代码块标记 | | `temperature`、`top_p` | number | 否 | 透传给上游,推理模型通常不支持 | | `store` | boolean | 否 | 是否让上游保存这次响应。网关原样转发,不填时按上游默认(OpenAI 默认为 `true`) | | `previous_response_id` | string | 否 | 接续上一轮响应,由上游拼接上下文,见下文「多轮对话与函数调用」 | | `include` | array | 否 | 附加返回内容,例如 `["reasoning.encrypted_content"]`。透传 | | `metadata` | object | 否 | 透传 | ### input 数组中的项 | 项 | 写法 | 用途 | | --- | --- | --- | | 消息 | `{"role": "user", "content": "..."}`。`role` 可为 `user`、`assistant`、`system`、`developer`;`content` 可以是字符串,也可以是 `input_text`、`input_image` 等内容部分的数组 | 传入对话内容。图片输入需要模型支持,见[多模态能力](https://platform.lyrouter.com/ai_gateway/docs/multimodal) | | 函数调用结果 | `{"type": "function_call_output", "call_id": "...", "output": "..."}` | 把工具执行结果交回模型 | | 上一轮的输出项 | 上一次响应 `output` 中的 `message`、`function_call`、`reasoning` 项,原样放回 | 不使用 `previous_response_id` 时,由客户端自己携带历史 | ## 请求示例 **请求示例** cURL: ```bash curl https://api.lyrouter.com/v1/responses \ -H "Authorization: Bearer $LYROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "MODEL_ID", "instructions": "你是一个简洁的助手。", "input": "用一句话解释什么是 API 网关。", "max_output_tokens": 1024 }' ``` Python: ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["LYROUTER_API_KEY"], base_url="https://api.lyrouter.com/v1", ) response = client.responses.create( model="MODEL_ID", instructions="你是一个简洁的助手。", input="用一句话解释什么是 API 网关。", max_output_tokens=1024, ) print(response.output_text) print(response.usage) ``` Node.js: ```js import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.LYROUTER_API_KEY, baseURL: "https://api.lyrouter.com/v1", }); const response = await client.responses.create({ model: "MODEL_ID", instructions: "你是一个简洁的助手。", input: "用一句话解释什么是 API 网关。", max_output_tokens: 1024, }); console.log(response.output_text); console.log(response.usage); ``` 将 `MODEL_ID` 替换为工作空间中已开通、且支持 Responses 的模型 ID。`output_text` 是 SDK 提供的便捷属性,会把所有 `output_text` 内容拼接起来;原始 JSON 中没有这个字段,直接解析 HTTP 响应时请遍历 `output`。Python 示例需要 openai Python SDK 1.66 或更高版本,旧版本没有 `client.responses`,会报 `AttributeError: 'OpenAI' object has no attribute 'responses'`。 ## 响应 非流式请求返回一个 `response` 对象;出错时返回 `error` 对象。下面的 200 是带推理摘要的典型响应,400 是所选模型不支持 Responses,403 是工作空间没有开通这个模型。 **响应示例** 200: ```json { "id": "resp_68ee1b9a52c48190a71c3e7d6a0b2f5e", "object": "response", "created_at": 1760427600, "status": "completed", "error": null, "incomplete_details": null, "model": "gpt-5.5", "instructions": "你是一个简洁的助手。", "output": [ { "id": "rs_68ee1b9ab1d08190b3a2c5e7f9013d4a", "type": "reasoning", "summary": [ { "type": "summary_text", "text": "用户要一句话定义,直接给出结论。" } ] }, { "id": "msg_68ee1b9b0e7c8190b9f2d4a6c8e01a37", "type": "message", "status": "completed", "role": "assistant", "content": [ { "type": "output_text", "text": "API 网关是位于客户端与后端服务之间的统一入口,负责鉴权、路由、限流和监控。", "annotations": [] } ] } ], "max_output_tokens": 1024, "previous_response_id": null, "reasoning": { "effort": "low", "summary": "auto" }, "store": true, "text": { "format": { "type": "text" } }, "tool_choice": "auto", "tools": [], "usage": { "input_tokens": 1830, "input_tokens_details": { "cached_tokens": 1536 }, "output_tokens": 196, "output_tokens_details": { "reasoning_tokens": 128 }, "total_tokens": 2026 }, "metadata": {} } ``` 400: ```json { "error": { "message": "This model does not support the responses API", "type": "invalid_request_error", "code": "unsupported_model_api" } } ``` 403: ```json { "error": { "message": "Model is not available in the model plaza", "type": "access_denied", "code": "model_not_available" } } ``` | 字段 | 说明 | | --- | --- | | `id` | 响应 ID,由上游生成,常见为 `resp_` 开头(也有上游返回 `resp-` 开头的 ID),不是 LYRouter 的 Request ID。用于 `previous_response_id` | | `status` | `completed`;输出达到 `max_output_tokens` 时为 `incomplete`,原因在 `incomplete_details.reason`;还可能是 `failed`、`cancelled`,后台执行时有 `queued`、`in_progress` | | `model` | 上游返回的实际模型名,可能与请求中的模型 ID 不同。对应日志的「模型(实际)」 | | `output` | 输出项数组,按 `type` 分别处理:`message` 的 `content` 里是 `output_text`;`function_call` 是函数调用;`reasoning` 是推理摘要或加密的推理内容。不能按 Chat 的 `choices[0].message` 解析 | | `usage` | 本次 Token 用量,网关原样返回上游的值,见下表 | ### usage 与日志中的四项 Token `usage` 与[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)「Token 消耗」四项的对应关系: | `usage` 字段 | 含义 | 日志中的对应项 | | --- | --- | --- | | `input_tokens` | 全部输入,**包含**缓存命中的部分 | 「输入(缓存未命中)」+「输入(缓存命中)」 | | `input_tokens_details.cached_tokens` | 命中上游提示词缓存的输入 | 「输入(缓存命中)」 | | `output_tokens` | 全部输出,**包含**推理 Token | 「输出」 | | `output_tokens_details.reasoning_tokens` | 输出中用于推理的部分 | 包含在「输出」中 | 上例中「输入(缓存未命中)」为 1830 − 1536 = 294,「输入(缓存命中)」为 1536,「输出」为 196;Responses 上游不产生「显式缓存创建」。计费方法见[调用费用与缓存计费](https://platform.lyrouter.com/ai_gateway/docs/estimate)。 ## 流式响应 设置 `"stream": true` 后,响应是 `text/event-stream`。每个事件由 `event:` 行和 `data:` 行组成,`data` 中的 `type` 与事件名相同,`sequence_number` 递增。实际的流中每个事件前还有一行 `id:`,`event:`、`data:` 的冒号后也可能没有空格(如 `data:{...}`),按 SSE 规范两种写法都合法,自己写解析器时要兼容。以下片段省略了 `id:` 行和 `response` 对象中的部分字段: ```text event: response.created data: {"type":"response.created","sequence_number":0,"response":{"id":"resp_68ee1b9a52c48190a71c3e7d6a0b2f5e","object":"response","status":"queued","output":[],"usage":null}} event: response.output_item.added data: {"type":"response.output_item.added","sequence_number":2,"output_index":0,"item":{"id":"msg_68ee1b9b0e7c8190b9f2d4a6c8e01a37","type":"message","status":"in_progress","role":"assistant","content":[]}} event: response.output_text.delta data: {"type":"response.output_text.delta","sequence_number":4,"item_id":"msg_68ee1b9b0e7c8190b9f2d4a6c8e01a37","output_index":0,"content_index":0,"delta":"API 网关是"} event: response.output_text.done data: {"type":"response.output_text.done","sequence_number":9,"item_id":"msg_68ee1b9b0e7c8190b9f2d4a6c8e01a37","output_index":0,"content_index":0,"text":"API 网关是位于客户端与后端服务之间的统一入口,负责鉴权、路由、限流和监控。"} event: response.completed data: {"type":"response.completed","sequence_number":12,"response":{"id":"resp_68ee1b9a52c48190a71c3e7d6a0b2f5e","object":"response","status":"completed","usage":{"input_tokens":1830,"input_tokens_details":{"cached_tokens":1536},"output_tokens":196,"output_tokens_details":{"reasoning_tokens":128},"total_tokens":2026}}} ``` | 事件 | 含义 | | --- | --- | | `response.created`、`response.in_progress` | 响应已创建、正在生成。`response.created` 中的 `status` 可能是 `queued` | | `response.output_item.added` / `.done` | 一个输出项(消息、函数调用、推理)开始 / 结束 | | `response.content_part.added` / `.done` | 消息中的一个内容块开始 / 结束 | | `response.output_text.delta` / `.done` | 文本增量 / 完整文本 | | `response.reasoning_text.delta` / `.done` | 推理文本增量 / 完整推理文本,推理模型会返回 | | `response.function_call_arguments.delta` / `.done` | 函数调用参数增量 / 完整参数 | | `response.completed` | 正常结束,`response.usage` 是本次用量 | | `response.incomplete`、`response.failed` | 输出被截断或生成失败,同样携带完整的 `response` 对象 | - Responses 流**没有** `data: [DONE]`,以 `response.completed`(或 `response.incomplete`、`response.failed`)作为结束。网关不会给 Responses 请求加 `stream_options`,用量只在结束事件里。 - 输出开始后上游中断时,网关在流末尾补一个 `response.failed` 事件后结束:`response.status` 为 `failed`,`response.error.code` 为 `server_error`,`response.id` 是这条流的响应 ID,不再有 `response.completed`。没有收到结束事件就按失败处理,见[超时与流式中断](https://platform.lyrouter.com/ai_gateway/docs/stream-errors)。 **流式示例** cURL: ```bash curl -N https://api.lyrouter.com/v1/responses \ -H "Authorization: Bearer $LYROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"MODEL_ID","input":"写一首两行的小诗","stream":true}' ``` Python: ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["LYROUTER_API_KEY"], base_url="https://api.lyrouter.com/v1", ) stream = client.responses.create( model="MODEL_ID", input="写一首两行的小诗", stream=True, ) for event in stream: if event.type == "response.output_text.delta": print(event.delta, end="", flush=True) elif event.type == "response.completed": print("\n", event.response.usage) ``` Node.js: ```js import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.LYROUTER_API_KEY, baseURL: "https://api.lyrouter.com/v1", }); const stream = await client.responses.create({ model: "MODEL_ID", input: "写一首两行的小诗", stream: true, }); for await (const event of stream) { if (event.type === "response.output_text.delta") { process.stdout.write(event.delta); } else if (event.type === "response.completed") { console.log("\n", event.response.usage); } } ``` 各协议流式格式的对比见[流式响应](https://platform.lyrouter.com/ai_gateway/docs/streaming)。 ## 多轮对话与函数调用 多轮对话有两种写法: - **`previous_response_id`**:把上一轮响应的 `id` 填进下一次请求,只发送新的输入,由上游保存并拼接上下文。需要上游支持,且上一轮没有设置 `store: false`。 - **自带历史**:每次在 `input` 中带上完整历史,把上一轮 `output` 中的项原样追加进去,再加新的输入。这种写法不依赖上游保存的状态,模型有多个通道或凭证时更稳妥。不需要上游保存时可以设置 `store: false`;此时要回传推理项,请同时设置 `"include": ["reasoning.encrypted_content"]`。 网关用 `previous_response_id` 把同一条接续链的请求归为一个会话,可以在[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)的「会话」列中查看。网关**不会**把接续请求固定到创建上一轮响应的那个上游:模型有多个通道或凭证时,接续请求可能落到没有保存这条响应的上游,由上游返回找不到响应的错误。 函数调用的完整流程如下。第一次请求声明工具: ```json { "model": "MODEL_ID", "input": "上海现在天气怎么样?", "tools": [ { "type": "function", "name": "get_weather", "description": "查询城市的实时天气", "parameters": { "type": "object", "properties": { "city": { "type": "string" } }, "required": ["city"], "additionalProperties": false }, "strict": true } ] } ``` 模型决定调用工具时,`output` 中出现 `function_call` 项,`arguments` 是 JSON 字符串: ```json { "id": "fc_68ee1c20a3f88190c2d4e6f8a0b1c3d5", "type": "function_call", "status": "completed", "call_id": "call_k3Jw9Xq2mZ7tVb1R", "name": "get_weather", "arguments": "{\"city\":\"上海\"}" } ``` 在客户端执行工具,再把结果以 `function_call_output` 交回,`call_id` 必须与调用一致。下面用自带历史的写法,同时带上原来的 `tools`: ```json { "model": "MODEL_ID", "input": [ { "role": "user", "content": "上海现在天气怎么样?" }, { "type": "function_call", "call_id": "call_k3Jw9Xq2mZ7tVb1R", "name": "get_weather", "arguments": "{\"city\":\"上海\"}" }, { "type": "function_call_output", "call_id": "call_k3Jw9Xq2mZ7tVb1R", "output": "{\"temp_c\":22,\"condition\":\"多云\"}" } ], "tools": ["……与第一次请求相同……"] } ``` 示例中 `tools` 的值为省略写法,实际请求要放入完整的工具定义。与 Chat Completions 的写法对比见[工具调用](https://platform.lyrouter.com/ai_gateway/docs/tool-call)。 ## 网关行为 - **不做协议转换**:网关按 Responses 协议把请求转发到上游的 `/responses`,不会把它转换成 Chat Completions 或 Anthropic Messages,所以模型和服务它的通道都必须原生支持 Responses。模型声明了支持的接口、且其中没有 Responses 时,网关直接返回 400 `This model does not support the responses API`(`unsupported_model_api`);没有声明的模型会照常转发,由上游返回错误。 - **请求基本原样转发**:网关只做以下改动:把 `model` 换成所选通道的实际模型名;使用虚拟模型时合并参数和系统提示词;把 `input` 中以 `at_` 开头的项 ID 改为以 `msg_` 开头,以兼容要求 `msg_` 前缀的上游;重新排列请求 JSON 中对象的键顺序(数组顺序不变),让相同前缀稳定命中上游缓存。`store`、`previous_response_id`、`background`、`include` 和内置工具都原样转发。 - **虚拟模型**:虚拟模型的系统提示词在 `instructions` 为空时直接填入,已有内容时空一行后追加;参数按 Chat Completions 的字段名合并,`max_tokens` 不会换成 `max_output_tokens`,见[虚拟模型](https://platform.lyrouter.com/ai_gateway/docs/presets#系统提示词何时注入)。 - **用量**:`usage` 原样返回上游的值,网关不补全、不改写。 - **失败回退**:开始输出之前上游返回错误或连接失败时,网关按[失败重试与备用模型](https://platform.lyrouter.com/ai_gateway/docs/fallback)换通道,必要时改用备用模型和工作空间默认模型。接手的模型同样要支持 Responses,否则返回上面的 `unsupported_model_api`。流式输出开始后不再换通道。 - **Codex CLI**:在 Codex 中配置 `wire_api = "responses"` 就是调用本接口,模型和通道还需要支持函数工具。配置方法见 [Codex](https://platform.lyrouter.com/ai_gateway/docs/codex)。 - 配置了配额时,响应带 `x-aigw-quota-*` 响应头,见[网关扩展请求头与响应头](https://platform.lyrouter.com/ai_gateway/docs/gateway-headers)。 ## 常见错误 网关返回的错误为 `{"error":{"message":"...","type":"...","code":"..."}}`,`code` 只有部分错误才有。上游原样透传的错误可能是其他形状,例如 `previous_response_id` 指向的响应不存在时,返回的是 400 `{"request_id":"...","code":"InvalidParameter","message":"..."}`,外层没有 `error`,解析时请兼容。 | 状态码 | `error.message` | `error.code` | 原因与处理 | | --- | --- | --- | --- | | 400 | `This model does not support the responses API` | `unsupported_model_api` | 模型不支持 Responses。改用支持的模型,或改用 [Chat Completions](https://platform.lyrouter.com/ai_gateway/docs/chat-completions);Codex 中出现时同样换模型 | | 400 | `you must provide a model parameter` | `missing_model` | 请求没写 `model`,工作空间也没有默认模型。写上模型 ID | | 403 | `Model is not available in the model plaza` | `model_not_available` | 工作空间没有开通该模型,见[模型不可用](https://platform.lyrouter.com/ai_gateway/docs/unavailable) | | 503 | `all routed candidates exhausted` | `no_route_candidate` | 找不到可服务这次请求的通道,例如 `@vmodel/<名称>` 写错、这个虚拟模型不存在。核对名称,见[模型不可用](https://platform.lyrouter.com/ai_gateway/docs/unavailable) | | 上游状态码 | 上游原文 | 上游原样 | 例如 `previous_response_id` 指向的响应在当前上游不存在。在日志「状态说明」中来源显示为「上游」 | - 401、403 鉴权问题见[401 / 403:鉴权与权限](https://platform.lyrouter.com/ai_gateway/docs/auth-errors),429 见[429:限流与配额](https://platform.lyrouter.com/ai_gateway/docs/rate-errors)。 - 500 / 504 是连接上游失败或等待上游超时,响应体是 HTML 页面而不是 JSON,见[超时与流式中断](https://platform.lyrouter.com/ai_gateway/docs/stream-errors)。 - 完整列表见[错误码与请求标识](https://platform.lyrouter.com/ai_gateway/docs/errors)。网关的响应中不包含请求 ID,排查时请在[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)中按 API Key 和时间找到这次请求,从日志详情顶部复制 Request ID。 --- # Anthropic 格式 来源: https://platform.lyrouter.com/ai_gateway/docs/anthropic-messages 根据对话历史生成模型回答,支持流式、图片输入和工具调用。兼容 Anthropic Messages API:系统提示词放在 `system`,对话放在由内容块组成的 `messages`,响应的 `content` 也是内容块数组;Anthropic 官方 SDK 和 [Claude Code](https://platform.lyrouter.com/ai_gateway/docs/claude-code) 等 Anthropic 协议客户端,把 Base URL 设为网关根地址 `https://api.lyrouter.com` 即可接入。网关会在 Messages 与上游协议之间转换,所以这个接口除了 Claude 系列,也能调用平台上的其他对话模型。 `POST /v1/messages` ## 鉴权 在请求头中携带 API Key,以下两种写法任选其一: ```text x-api-key: Authorization: Bearer ``` 两者同时存在时只读取 `Authorization`,`Bearer` 区分大小写。Anthropic SDK 的 `api_key` 参数发送 `x-api-key`,`auth_token` 参数发送 `Authorization: Bearer`;Claude Code 的 `ANTHROPIC_AUTH_TOKEN` 用的是后者。API Key 在工作空间的 **API 密钥** 页面创建,只用于 LYRouter 鉴权,不会转发给上游服务商。完整说明见[接入地址与鉴权](https://platform.lyrouter.com/ai_gateway/docs/call-gateway)。 Anthropic SDK 和 Claude Code 会自己拼接 `/v1/messages`,Base URL 不要再带 `/v1`,否则请求路径变成 `/v1/v1/messages`,返回 404。 ## 请求头 | 请求头 | 必填 | 说明 | | --- | --- | --- | | `Content-Type` | 否 | 建议携带 `application/json`。不带时网关按 JSON 解析请求体;写成其他值(如 `application/x-www-form-urlencoded`)时返回 400 | | `x-api-key` 或 `Authorization` | 是 | LYRouter API Key,写法见上文「鉴权」。只用于网关鉴权,不会转发给上游 | | `anthropic-version` | 否 | 网关不校验。调用 Anthropic 上游时版本由通道决定,通常为 `2023-06-01` | | `anthropic-beta` | 否 | 原样转发给上游。请求中带有 `"ttl": "1h"` 的缓存标记、且发往 Anthropic 上游时,网关把它设为 `extended-cache-ttl-2025-04-11`,替换请求中原有的值 | | `x-gateway-passthrough` | 否 | LYRouter 扩展请求头,写 `require` 表示请求体必须原样发给 Anthropic 上游,做不到就返回 400。公共网关目前没有开启原生直通,不需要时不要发送,见[网关扩展请求头与响应头](https://platform.lyrouter.com/ai_gateway/docs/gateway-headers#x-gateway-passthrough) | ## 请求体 | 参数 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | `model` | string | 否 | 模型 ID,也可以写 `@vmodel/<名称>`([虚拟模型](https://platform.lyrouter.com/ai_gateway/docs/presets))或 `lyrouter/auto`([智能路由](https://platform.lyrouter.com/ai_gateway/docs/auto))。省略、为 `""` 或 `null` 时使用工作空间的默认模型,没有默认模型时返回 400。Anthropic SDK 要求必须填写 | | `max_tokens` | integer | 是 | 输出上限。省略时网关不报错:发往 Anthropic 上游时补为 4096,发往 OpenAI 兼容上游时不发送,由上游默认值决定。思考是否计入这个上限由上游决定,例如阿里云百炼不计入:qwen3.7-plus 设为 16 时,`output_tokens` 为 100,`stop_reason` 为 `end_turn` | | `messages` | array | 是 | 每项为 `{"role": "user" 或 "assistant", "content": 字符串或内容块数组}`,见下文「内容块」 | | `system` | string / array | 否 | 系统提示词。可以是字符串,也可以是 `text` 块数组(块上可带 `cache_control`);多个块会合并成一段,块之间空一行 | | `stream` | boolean | 否 | `true` 时以 SSE 事件流返回,见下文「流式响应」 | | `temperature`、`top_p`、`top_k` | number | 否 | 原样发给上游,是否生效取决于模型 | | `stop_sequences` | array | 否 | 停止序列。发往 OpenAI 兼容上游时转为 `stop` | | `tools` | array | 否 | 自定义工具 `{"name", "description", "input_schema"}`,可带 `cache_control`,见下文「工具调用」 | | `tool_choice` | object | 否 | `{"type": "auto"}`、`{"type": "any"}` 或 `{"type": "tool", "name": "..."}`。`{"type": "none"}` 和 `disable_parallel_tool_use` 不会发给上游;不希望模型调用工具时,请不要传 `tools` | | `thinking` | object | 否 | `{"type": "enabled", "budget_tokens": 2048}`、`{"type": "adaptive"}` 或 `{"type": "disabled"}`,转换规则见下文「网关行为」 | | `metadata` | object | 否 | 只有 `user_id` 会发给 Anthropic 上游;OpenAI 兼容上游不发送 | | `service_tier` | string | 否 | 原样发给上游 | | `context_management`、`output_config` | object | 否 | 只发给 Anthropic 上游 | 表中未列出的其他字段不会转发给上游。 ### 内容块 | 块类型 | 出现位置 | 说明 | | --- | --- | --- | | `text` | `system`、`user`、`assistant` | 文本,可带 `cache_control` | | `image` | `user`、`tool_result` 内 | `source` 为 `{"type": "base64", "media_type", "data"}` 或 `{"type": "url", "url"}`。发往 OpenAI 兼容上游时转为 `image_url`,需要模型支持图片输入,见[多模态](https://platform.lyrouter.com/ai_gateway/docs/multimodal) | | `tool_use` | `assistant` | 模型发起的工具调用:`id`、`name`、`input` | | `tool_result` | `user` | 工具执行结果:`tool_use_id` 与 `content`(字符串,或 `text` / `image` 块) | | `thinking`、`redacted_thinking` | `assistant` 历史 | 上一轮返回的思考块,回传时保留 `signature` | 其他类型的块(如 `document`)不会转发给上游。 ### 提示词缓存 在 `system` 块、消息中的 `text` 块或工具定义上加 `"cache_control": {"type": "ephemeral"}`(1 小时缓存写 `{"type": "ephemeral", "ttl": "1h"}`),标记可缓存前缀的结束位置: | 标记位置 | 发往 Anthropic 协议上游 | 发往 OpenAI 兼容上游 | | --- | --- | --- | | `system` 块 | 保留;多个块合并后,以最后一个带标记的块为准 | 删除 | | 消息中的 `text` 块 | 保留 | 删除 | | `tools` 中的工具定义 | 保留 | 删除 | | `image` 块、`tool_result` 块 | 不转发 | 删除 | 写入缓存的部分记为「显式缓存创建」,之后命中的部分记为「输入(缓存命中)」。OpenAI 兼容上游只有上游自动进行的缓存,不产生「显式缓存创建」。标记方法和命中率优化见[降低成本与优化缓存](https://platform.lyrouter.com/ai_gateway/docs/cost-practice)。 ## 请求示例 先安装 SDK:`pip install anthropic` 或 `npm install @anthropic-ai/sdk`。 **请求示例** cURL: ```bash curl https://api.lyrouter.com/v1/messages \ -H "x-api-key: $LYROUTER_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -H "Content-Type: application/json" \ -d '{ "model": "MODEL_ID", "max_tokens": 1024, "system": "你是一个简洁的助手。", "messages": [ { "role": "user", "content": "用一句话解释什么是 API 网关。" } ] }' ``` Python: ```python import os import anthropic client = anthropic.Anthropic( api_key=os.environ["LYROUTER_API_KEY"], base_url="https://api.lyrouter.com", ) message = client.messages.create( model="MODEL_ID", max_tokens=1024, system="你是一个简洁的助手。", messages=[{"role": "user", "content": "用一句话解释什么是 API 网关。"}], ) print(message.content[0].text) # content 可能为空,见下文「响应」 print(message.usage) ``` Node.js: ```js import Anthropic from "@anthropic-ai/sdk"; const client = new Anthropic({ apiKey: process.env.LYROUTER_API_KEY, baseURL: "https://api.lyrouter.com", }); const message = await client.messages.create({ model: "MODEL_ID", max_tokens: 1024, system: "你是一个简洁的助手。", messages: [{ role: "user", content: "用一句话解释什么是 API 网关。" }], }); console.log(message.content[0].text); console.log(message.usage); ``` 将 `MODEL_ID` 替换为工作空间中已开通的模型 ID。改用 `Authorization: Bearer` 时,cURL 把 `x-api-key` 头换成 `-H "Authorization: Bearer $LYROUTER_API_KEY"`;SDK 把 `api_key` / `apiKey` 换成 `auth_token` / `authToken`。 ## 响应 非流式请求返回一个 `message` 对象;出错时返回 Anthropic 格式的错误对象。下面的 200 是 Anthropic 协议上游的典型响应,400 是没有写 `model` 且工作空间没有默认模型,401 是 API Key 无效,429 是 API Key 当天的 Token 配额已用完(见[429:限流与配额](https://platform.lyrouter.com/ai_gateway/docs/rate-errors))。 **响应示例** 200: ```json { "id": "msg_01HCDu5LRGeP2o7s2xGmxyZa", "type": "message", "role": "assistant", "model": "claude-sonnet-4-5-20250929", "content": [ { "type": "text", "text": "API 网关是位于客户端与后端服务之间的统一入口,负责鉴权、路由、限流和监控。" } ], "stop_reason": "end_turn", "usage": { "input_tokens": 294, "output_tokens": 46, "cache_read_input_tokens": 1536, "cache_creation_input_tokens": 212 } } ``` 400: ```json { "type": "error", "error": { "type": "invalid_request_error", "message": "you must provide a model parameter" } } ``` 401: ```json { "type": "error", "error": { "type": "authentication_error", "message": "invalid api key" } } ``` 429: ```json { "type": "error", "error": { "type": "rate_limit_error", "message": "rate limit exceeded on apikey total_tokens/day" } } ``` | 字段 | 说明 | | --- | --- | | `id` | 沿用上游返回的标识。Anthropic 上游以 `msg_` 开头,其他上游的格式不同,不要依赖它的前缀 | | `model` | 上游返回的实际模型名,可能与请求中的模型 ID 不同。对应日志的「模型(实际)」 | | `content` | 非流式响应只包含 `text` 和 `tool_use` 块;需要拿到思考内容时,请使用流式。例外见表下说明 | | `stop_reason` | `end_turn`、`max_tokens` 或 `tool_use`,按上游的结束原因换算。上游的其他结束原因(如 `stop_sequence`、`refusal`)都返回为 `end_turn`。用 `{"type": "tool"}` 指定工具时目前可能是 `end_turn`,见下文「工具调用」 | | `stop_sequence` | 目前响应中没有这个字段,流式的 `message_start`、`message_delta` 中也没有。用官方 SDK 读取时,Python 为 `None`,Node.js 为 `undefined` | | `usage` | 本次 Token 用量,见下表 | - **`content` 可能是 `{}`**:上游只输出了思考、并且在思考阶段就被 `max_tokens` 截断时,非流式响应的 `content` 目前是空对象 `{}`,而不是空数组 `[]`(glm-5.3、kimi-k2.7-code、deepseek-v4 上都出现过)。请把 `max_tokens` 留足,解析时把不是数组的 `content` 当作没有内容处理。 - **`` 标签**:部分模型(如 minimax-m3)把思考过程以 `…` 写在 `text` 块里,非流式和流式都是如此。网关不会剥离,需要时请自行去掉。 ### usage 与日志中的四项 Token `usage` 与日志「Token 消耗」四项一一对应,四个字段互不重叠: | `usage` 字段 | 含义 | 日志中的对应项 | | --- | --- | --- | | `input_tokens` | 没有命中缓存的输入,**不含**缓存读取和缓存写入 | 「输入(缓存未命中)」 | | `cache_read_input_tokens` | 命中提示词缓存的输入 | 「输入(缓存命中)」 | | `cache_creation_input_tokens` | 本次写入缓存的输入,只在 Anthropic 协议上游出现 | 「显式缓存创建」 | | `output_tokens` | 输出,包含思考内容 | 「输出」 | 两个缓存字段为 0 时不返回。上游是 OpenAI 兼容协议时,网关从上游的 `prompt_tokens` 中减去缓存命中量得到 `input_tokens`,口径与 Anthropic 一致,本次全部输入是 `input_tokens + cache_read_input_tokens + cache_creation_input_tokens`。计费方法见[调用费用与缓存计费](https://platform.lyrouter.com/ai_gateway/docs/estimate)。 ## 工具调用 请求中声明工具: ```json { "model": "MODEL_ID", "max_tokens": 1024, "tools": [ { "name": "get_weather", "description": "查询城市的实时天气", "input_schema": { "type": "object", "properties": { "city": { "type": "string" } }, "required": ["city"] } } ], "messages": [{ "role": "user", "content": "上海现在天气怎么样?" }] } ``` 模型决定调用工具时,`content` 中出现 `tool_use` 块,`stop_reason` 一般为 `tool_use`: ```json { "type": "tool_use", "id": "toolu_01A09q90qw90lq917835lq9", "name": "get_weather", "input": { "city": "上海" } } ``` 判断是否需要执行工具,请看 `content` 中有没有 `tool_use` 块,不要只看 `stop_reason`:目前 `tool_choice` 为 `{"type": "tool", "name": "..."}` 时,响应带有 `tool_use` 块,`stop_reason` 却是 `end_turn`;`any`、`auto` 时为 `tool_use`。 执行工具后,把助手这一轮原样放回 `messages`,再用一条 `user` 消息回传 `tool_result`,`tool_use_id` 与调用的 `id` 一致: ```json { "model": "MODEL_ID", "max_tokens": 1024, "tools": ["……与第一次请求相同……"], "messages": [ { "role": "user", "content": "上海现在天气怎么样?" }, { "role": "assistant", "content": [ { "type": "tool_use", "id": "toolu_01A09q90qw90lq917835lq9", "name": "get_weather", "input": { "city": "上海" } } ] }, { "role": "user", "content": [ { "type": "tool_result", "tool_use_id": "toolu_01A09q90qw90lq917835lq9", "content": "{\"temp_c\":22,\"condition\":\"多云\"}" } ] } ] } ``` 示例中 `tools` 的值为省略写法,实际请求要放入完整的工具定义。使用时注意: - 只使用带 `input_schema` 的自定义工具。Anthropic 服务端工具(如 `web_search`)会被当作普通自定义工具发出,不会在服务端执行。 - 包含 `tool_result` 的 `user` 消息里,与它并列的 `text`、`image` 块不会转发。需要补充说明时,放进 `tool_result` 的 `content`,或放在下一条 `user` 消息中。 - `tool_result` 的 `is_error` 不会转发;执行失败时请在 `content` 中写明错误信息。 与 Chat Completions 的写法对比见[工具调用](https://platform.lyrouter.com/ai_gateway/docs/tool-call)。 ## 流式响应 设置 `"stream": true` 后,响应是 `text/event-stream`,每个事件由 `event:` 行和 `data:` 行组成: ```text event: message_start data: {"type":"message_start","message":{"id":"msg_01HCDu5LRGeP2o7s2xGmxyZa","type":"message","role":"assistant","model":"claude-sonnet-4-5-20250929","content":[],"usage":{"input_tokens":294,"output_tokens":0}}} event: content_block_start data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}} event: content_block_delta data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"API 网关是"}} event: content_block_stop data: {"type":"content_block_stop","index":0} event: message_delta data: {"type":"message_delta","delta":{"stop_reason":"end_turn"},"usage":{"input_tokens":294,"output_tokens":46,"cache_read_input_tokens":1536,"cache_creation_input_tokens":212}} event: message_stop data: {"type":"message_stop"} ``` - **事件顺序**:`message_start` → 每个内容块的 `content_block_start`、`content_block_delta`、`content_block_stop` → `message_delta` → `message_stop`。正常结束的标记是 `message_stop`。 - **增量类型**:文本为 `text_delta`;工具调用参数为 `input_json_delta`(`partial_json` 拼接后才是完整 JSON);思考内容为 `thinking_delta`,Anthropic 上游的思考块在 `content_block_stop` 之前还有一条完整的 `signature_delta`。OpenAI 兼容上游返回的思考内容同样以 `thinking` 块输出,但没有签名。 - **用量**:完整的 `usage` 在 `message_delta` 中,包括缓存字段。`message_start` 的 `usage` 只有 `input_tokens` 和为 0 的 `output_tokens`,上游是 OpenAI 兼容协议时 `input_tokens` 也为 0,请以 `message_delta` 为准。 - **中途出错**:输出开始后上游中断时,网关补发 `event: error`,数据为 `{"type": "error", "error": {"type": "api_error", "message": "upstream timed out after the response had started"}}`,之后不再有 `message_stop`。上游自己发出的错误事件(如 `overloaded_error`)按同样格式转给客户端。没有收到 `message_stop` 就按失败处理,见[超时与流式中断](https://platform.lyrouter.com/ai_gateway/docs/stream-errors)。 **流式示例** cURL: ```bash curl -N https://api.lyrouter.com/v1/messages \ -H "x-api-key: $LYROUTER_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -H "Content-Type: application/json" \ -d '{"model":"MODEL_ID","max_tokens":1024,"stream":true,"messages":[{"role":"user","content":"写一首两行的小诗"}]}' ``` Python: ```python import os import anthropic client = anthropic.Anthropic( api_key=os.environ["LYROUTER_API_KEY"], base_url="https://api.lyrouter.com", ) with client.messages.stream( model="MODEL_ID", max_tokens=1024, messages=[{"role": "user", "content": "写一首两行的小诗"}], ) as stream: for text in stream.text_stream: print(text, end="", flush=True) print("\n", stream.get_final_message().usage) ``` Node.js: ```js import Anthropic from "@anthropic-ai/sdk"; const client = new Anthropic({ apiKey: process.env.LYROUTER_API_KEY, baseURL: "https://api.lyrouter.com", }); const stream = client.messages.stream({ model: "MODEL_ID", max_tokens: 1024, messages: [{ role: "user", content: "写一首两行的小诗" }], }); stream.on("text", (text) => process.stdout.write(text)); const final = await stream.finalMessage(); console.log("\n", final.usage); ``` 各协议流式格式的对比见[流式响应](https://platform.lyrouter.com/ai_gateway/docs/streaming)。 ## 网关行为 网关内部统一用 OpenAI Chat Completions 格式处理对话请求。`/v1/messages` 的请求先转换为内部格式,再按选中通道的协议发出:Anthropic 协议的通道还原成 Messages 请求,OpenAI 兼容的通道转换为 Chat Completions 请求;响应和流式事件再转换回 Messages 格式。上游是 Anthropic 时也经过这一转换,请求和响应不会逐字节原样转发。 | 请求内容 | 发往 Anthropic 协议上游 | 发往 OpenAI 兼容上游 | | --- | --- | --- | | `system` | 合并为一段文本 | 转为 `system` 消息 | | `text`、`image` 块 | 保留 | 转为 `content` 中的 `text`、`image_url` | | `tool_use`、`tool_result` | 保留 | 转为 `tool_calls` 和 `tool` 消息 | | `tools`、`tool_choice` | 保留(`none` 除外) | 转为函数工具;`any` 转为 `required`,指定工具转为指定函数 | | `thinking` 参数 | `enabled` 保留预算,`adaptive` 保留,`disabled` 不发送 | 转为 `enable_thinking`、`thinking_budget`,已知不支持的上游会删除 | | 历史中的思考块 | 带签名的原样回传;历史里有没有签名的思考块时,这一轮删除全部思考块并关闭思考 | 删除 | | `max_tokens` | 保留,省略时补为 4096 | 保留,省略时不发送 | | `stop_sequences` | 保留 | 转为 `stop` | | `metadata` | 只保留 `user_id` | 删除 | | `context_management`、`output_config` | 保留 | 删除 | | `cache_control` | 见上文「提示词缓存」 | 删除 | - **思考块与切换模型**:同一会话中途从 OpenAI 兼容上游的模型换到 Anthropic 上游时,历史中的思考块没有签名,这一轮会关闭思考后再发送,避免上游拒绝请求。 - **模型名**:`model` 换成所选通道的实际模型名,响应中的 `model` 是上游返回的名称。 - **虚拟模型**:请求没有 `system` 时,网关填入虚拟模型的系统提示词;已有 `system` 时不注入,见[虚拟模型](https://platform.lyrouter.com/ai_gateway/docs/presets#系统提示词何时注入)。 - **键顺序**:发往上游的请求 JSON 中,对象的键会被重新排列(数组顺序不变),让相同前缀稳定命中上游缓存。 - **失败回退**:开始输出之前上游返回错误或连接失败时,网关按[失败重试与备用模型](https://platform.lyrouter.com/ai_gateway/docs/fallback)换通道,必要时改用备用模型和工作空间默认模型。流式输出开始后不再换通道。 - **响应头**:上游的 `Retry-After` 会转发给客户端。响应带 `anthropic-ratelimit-*` 头:上游返回了这组头时原样转发,否则在配置了配额时按网关配额生成;`x-aigw-quota-*` 见[网关扩展请求头与响应头](https://platform.lyrouter.com/ai_gateway/docs/gateway-headers)。 ## 常见错误 `/v1/messages` 上的错误一律转换为 Anthropic 格式。`message` 保持原文,不再带 `error.code`,`error.type` 按状态码确定: ```json { "type": "error", "error": { "type": "permission_error", "message": "Model is not available in the model plaza" } } ``` | HTTP 状态码 | `error.type` | | --- | --- | | 400、402、422 | `invalid_request_error` | | 401 | `authentication_error` | | 403 | `permission_error` | | 404 | `not_found_error` | | 413 | `request_too_large` | | 429 | `rate_limit_error` | | 503、529 | `overloaded_error` | | 其他 5xx | `api_error` | | 状态码 | `error.message` | 原因与处理 | | --- | --- | --- | | 401 | `missing credentials` / `invalid api key` | 没有携带 API Key,或 Key 无效、已删除、已过期。检查 `x-api-key` 或 `Authorization`,见[401 / 403:鉴权与权限](https://platform.lyrouter.com/ai_gateway/docs/auth-errors) | | 400 | `you must provide a model parameter` | 请求没写 `model`,工作空间也没有设置默认模型 | | 400 | `tool_choice 'required' is incompatible with thinking enabled` | `tool_choice` 为 `any` 或指定工具时,上游在思考模式下拒绝强制调用。改用 `{"type": "auto"}`,或用 `thinking: {"type": "disabled"}` 关闭思考。kimi-k2.7-code 上关闭思考不起作用,仍返回这个错误,请改用 `auto`;阿里云百炼的 qwen 模型上关闭有效 | | 403 | `Model is not available in the model plaza` | 工作空间没有开通该模型。Claude Code 的后台任务常用官方模型名发起请求,按 [Claude Code](https://platform.lyrouter.com/ai_gateway/docs/claude-code) 补齐模型配置 | | 402 | `insufficient credit balance` | 账户 Credits 余额不足,见[模型不可用](https://platform.lyrouter.com/ai_gateway/docs/unavailable) | | 429 | `rate limit exceeded on <对象> <指标>/<窗口>` | 配额或预算已用完。Anthropic SDK 会自动重试 429,但配额用完时重试无效,见[429:限流与配额](https://platform.lyrouter.com/ai_gateway/docs/rate-errors) | | 503 | `No configured credential can serve this model` | 模型在本工作空间没有可用的通道或凭证,见[模型不可用](https://platform.lyrouter.com/ai_gateway/docs/unavailable) | | 503 | `all routed candidates exhausted` | 找不到可服务这次请求的通道,例如 `@vmodel/<名称>` 写错、这个虚拟模型不存在。`error.type` 为 `overloaded_error`,Anthropic SDK 会自动重试,但名称写错时重试无效。核对名称,见[模型不可用](https://platform.lyrouter.com/ai_gateway/docs/unavailable) | 完整列表见[错误码与请求标识](https://platform.lyrouter.com/ai_gateway/docs/errors)。需要区分同一状态码下的具体原因时,以 `message` 为准,或在[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)中查看这次请求的「状态说明」。网关的响应中不包含请求 ID,排查时请在日志详情顶部复制 Request ID。 --- # 创建向量 来源: https://platform.lyrouter.com/ai_gateway/docs/embeddings 把一段或多段文本转换成向量,适合检索增强(RAG)、语义搜索和去重;需要按与查询的相关度给文档排序时,用[文档重排](https://platform.lyrouter.com/ai_gateway/docs/rerank)。接口采用 OpenAI Embeddings API 的格式,OpenAI SDK 的 `client.embeddings.create()` 把 Base URL 设为 `https://api.lyrouter.com/v1` 即可使用;请求和响应都是 JSON,不支持流式。网关只把 `model` 换成服务商的真实模型名,其余字段原样转发,所以参数和响应格式以模型所属服务商为准。 `POST /v1/embeddings` ## 鉴权 在请求头中携带 API Key: ```text Authorization: Bearer ``` `Bearer` 区分大小写。也可以改用 `x-api-key: `,两者同时存在时只读 `Authorization`。API Key 在工作空间的 **API 密钥** 页面创建,只用于 LYRouter 鉴权,不会转发给上游服务商。完整说明见[接入地址与鉴权](https://platform.lyrouter.com/ai_gateway/docs/call-gateway),环境变量 `LYROUTER_API_KEY` 的设置见[完成第一次模型调用](https://platform.lyrouter.com/ai_gateway/docs/quickstart)。 ## 请求头 | 请求头 | 必填 | 说明 | | --- | --- | --- | | `Content-Type` | 是 | `application/json`,其他类型返回 400 | ## 请求体 | 参数 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | `model` | string | 是 | 向量模型 ID,获取方法见下文「选择模型」。请始终写明:不写时使用工作空间的默认模型,而默认模型通常是对话模型,落到它上面会返回 400 `unsupported_model_api` 或上游的错误,见下文「网关行为」 | | `input` | string \| array | 是 | 一段文本,或文本数组(一次生成多条向量)。单次条数、单条长度上限由服务商决定 | | `encoding_format` | string | 否 | `float`(数字数组)或 `base64`。透传给上游,是否支持取决于模型 | | `dimensions` | integer | 否 | 输出向量的维度。透传给上游,是否生效取决于模型 | | `user` | string | 否 | 终端用户标识。透传给上游,是否生效取决于模型 | 表中没有列出的字段原样转发给上游,是否生效取决于模型。 ### 选择模型 可用的向量模型以工作空间的模型广场为准:在模型广场搜索 `embedding` 等关键词,复制模型 ID 替换示例中的 `MODEL_ID`。 也可以用 [`GET /v1/models`](https://platform.lyrouter.com/ai_gateway/docs/models) 筛选。返回的每个模型带 `api_types` 字段,含 `embeddings` 的可调用本接口: ```bash curl -s https://api.lyrouter.com/v1/models \ -H "Authorization: Bearer $LYROUTER_API_KEY" \ | jq -r '.data[] | select((.api_types // []) | index("embeddings")) | .id' ``` 模型没有声明 `api_types` 时不会出现在筛选结果里,可以在模型广场确认。字段说明见[列出模型](https://platform.lyrouter.com/ai_gateway/docs/models),筛选重排模型的方法见[文档重排](https://platform.lyrouter.com/ai_gateway/docs/rerank)。 ## 请求示例 **请求示例** cURL: ```bash curl https://api.lyrouter.com/v1/embeddings \ -H "Authorization: Bearer $LYROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "MODEL_ID", "input": ["LYRouter 是可信模型服务与 Token 治理平台", "用一个 API Key 调用多家模型"], "encoding_format": "float" }' ``` Python: ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["LYROUTER_API_KEY"], base_url="https://api.lyrouter.com/v1", ) result = client.embeddings.create( model="MODEL_ID", input=["LYRouter 是可信模型服务与 Token 治理平台", "用一个 API Key 调用多家模型"], encoding_format="float", ) for item in result.data: print(item.index, len(item.embedding)) print(result.usage) ``` Node.js: ```js import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.LYROUTER_API_KEY, baseURL: "https://api.lyrouter.com/v1", }); const result = await client.embeddings.create({ model: "MODEL_ID", input: ["LYRouter 是可信模型服务与 Token 治理平台", "用一个 API Key 调用多家模型"], encoding_format: "float", }); for (const item of result.data) { console.log(item.index, item.embedding.length); } console.log(result.usage); ``` OpenAI 官方 SDK 在没有指定 `encoding_format` 时会请求 `base64` 并在本地解码。如果上游不支持 `base64` 而报错,像上例一样显式传 `encoding_format="float"`。 ## 响应 成功时返回一个 `list` 对象,`data` 中每条输入对应一个向量;出错时返回 `error` 对象。下面的 200 是 OpenAI 兼容服务商的典型响应(向量已截短),400 是请求落到了不支持向量接口的模型(多为默认模型,见下文「网关行为」),403 是模型没有在本工作空间开通且工作空间没有设置默认模型。 **响应示例** 200: ```json { "object": "list", "data": [ { "object": "embedding", "index": 0, "embedding": [0.0123, -0.0456, 0.0789] }, { "object": "embedding", "index": 1, "embedding": [-0.0211, 0.0334, 0.0102] } ], "model": "MODEL_ID", "usage": { "prompt_tokens": 19, "total_tokens": 19 } } ``` 400: ```json { "error": { "message": "This model does not support the embeddings API", "type": "invalid_request_error", "code": "unsupported_model_api" } } ``` 403: ```json { "error": { "message": "Model is not available in the model plaza", "type": "access_denied", "code": "model_not_available" } } ``` | 字段 | 说明 | | --- | --- | | `data[].index` | 对应 `input` 数组中的位置,按它对齐,不要依赖返回顺序 | | `data[].embedding` | 向量。`encoding_format` 为 `base64` 时是 Base64 字符串 | | `model` | 上游返回的模型名,可能与请求中的模型 ID 写法不同;实际使用的模型以日志的「模型(实际)」为准 | | `usage.prompt_tokens` | 本次输入的 Token 数,即计费数量。在[日志](https://platform.lyrouter.com/ai_gateway/docs/logs)中记为「输入(缓存未命中)」,「输出」「输入(缓存命中)」「显式缓存创建」均为 0 | | `usage.total_tokens` | 与 `prompt_tokens` 相同 | ### 计费 按输入 Token 数计费,取自响应的 `usage.prompt_tokens`。单价以模型广场为准,每次调用的实际费用在[日志](https://platform.lyrouter.com/ai_gateway/docs/logs)中查看。费用估算方法见[调用费用与缓存计费](https://platform.lyrouter.com/ai_gateway/docs/estimate)。 ## 网关行为 - **请求原样转发**:网关只把 `model` 换成通道的真实模型名,其余字段原样转发(通过虚拟模型调用时见下文)。网关会重新编码 JSON:对象的键按固定顺序排列,数字最多保留 14 位有效数字。 - **通道回退**:同一模型有多个通道时,按工作空间的[路由策略](https://platform.lyrouter.com/ai_gateway/docs/routing)依次尝试,前一个通道失败就换下一个。 - **默认模型兜底**:工作空间在智能路由中设置了默认模型时,下面三种情况会落到默认模型上。默认模型通常是对话模型,此时得到的是报错,而不是你预期的结果(默认模型声明了 `api_types` 时,网关返回 400 `This model does not support the embeddings API`;没有声明时,请求会转发给上游,由上游报错,见下文「常见错误」): - 请求没写 `model`; - `model` 写错,或该模型没有在本工作空间开通; - 该模型的所有通道都失败了。这时上游的真实报错被默认模型的报错取代,请到日志详情的「上游调用尝试」查看前面每次尝试的原因。 - **虚拟模型与 Auto**:[虚拟模型](https://platform.lyrouter.com/ai_gateway/docs/presets)可以用于本接口,前提是它的模型列表全部是向量模型;虚拟模型的系统提示词不会注入,但设置的推理参数会按字段名合并进请求体,因此给向量接口使用的虚拟模型不要设置推理参数。[`lyrouter/auto`](https://platform.lyrouter.com/ai_gateway/docs/auto) 的候选是对话模型,不要用于本接口。目前网关不会拒绝这类请求:请求会挂起约 2 分钟,之后返回 HTTP 200,响应体是上游的原生错误(如 `{"vectors":null,"base_resp":{"status_code":2013,...}}`)而不是向量列表,只看状态码的程序会误以为成功;使用 HTTP/2 时连接还可能中途断开。 - **安全围栏**:[安全围栏](https://platform.lyrouter.com/ai_gateway/docs/guardrails)的封禁、模型访问控制和客户端访问控制照常生效;敏感信息、提示词注入和意图安全检测不作用于本接口。 ## 常见错误 错误响应为 `{"error":{"message":"...","type":"...","code":"..."}}`,`code` 只有部分错误才有。 | 状态码 | `error.message` | `error.code` | 原因与处理 | | --- | --- | --- | --- | | 400 | `This model does not support the embeddings API` | `unsupported_model_api` | 所用模型声明了 `api_types` 且不支持向量接口,多为请求落到了默认模型,见上文「默认模型兜底」。写上正确的向量模型 ID | | 400 | `you must provide a model parameter` | `missing_model` | 没写 `model`,工作空间也没有默认模型 | | 400 | `unsupported content-type: <类型>, only application/json is supported` | — | `Content-Type` 不是 JSON。响应体是一行纯文本,但响应头 `Content-Type` 目前是 `application/json`,解析前先判断正文是否为 JSON | | 403 | `Model is not available in the model plaza` | `model_not_available` | 模型没有在本工作空间开通,且没有设置默认模型。请管理员在模型广场开通,或换用已开通的模型 | | 503 | `all routed candidates exhausted` | `no_route_candidate` | 找不到可服务这次请求的通道,见[模型不可用](https://platform.lyrouter.com/ai_gateway/docs/unavailable) | - 输入超长、条数超限等由上游服务商返回,状态码和报错原文由上游决定。 - 用没有声明 `api_types` 的对话模型(见[列出模型](https://platform.lyrouter.com/ai_gateway/docs/models))调用本接口时,不会收到 400 `unsupported_model_api`:请求会转发给上游,由上游报错,可能要等待较长时间。例如某对话模型约 60 秒后返回上游的 404 ``Unsupported model `<模型>` for OpenAI compatibility mode.``,`error.code` 为 `model_not_supported`。 - 网关先解析模型,再检查 `Content-Type`:没写 `model` 或模型没有开通时,先返回模型相关的错误(400 `missing_model`、403 `model_not_available`);模型有效时才返回 400 `unsupported content-type: …`。 - 401 / 403 鉴权问题见[401 / 403:鉴权与权限](https://platform.lyrouter.com/ai_gateway/docs/auth-errors),429 见[429:限流与配额](https://platform.lyrouter.com/ai_gateway/docs/rate-errors)。完整列表见[错误码与请求标识](https://platform.lyrouter.com/ai_gateway/docs/errors)。 --- # 文档重排 来源: https://platform.lyrouter.com/ai_gateway/docs/rerank 按与查询的相关度给一组文档打分并排序,适合在检索增强(RAG)、语义搜索中对召回结果做精排;把文本转换成向量用[创建向量](https://platform.lyrouter.com/ai_gateway/docs/embeddings)。OpenAI 没有重排接口,LYRouter 把请求体原样发到通道的 `/rerank` 地址,只替换 `model`,所以字段名、取值和响应格式以模型所属服务商的 rerank 文档为准。请求和响应都是 JSON,不支持流式;OpenAI SDK 没有重排方法,请直接发 HTTP 请求。 `POST /v1/rerank` ## 鉴权 在请求头中携带 API Key: ```text Authorization: Bearer ``` `Bearer` 区分大小写。也可以改用 `x-api-key: `,两者同时存在时只读 `Authorization`。API Key 在工作空间的 **API 密钥** 页面创建,只用于 LYRouter 鉴权,不会转发给上游服务商。完整说明见[接入地址与鉴权](https://platform.lyrouter.com/ai_gateway/docs/call-gateway),环境变量 `LYROUTER_API_KEY` 的设置见[完成第一次模型调用](https://platform.lyrouter.com/ai_gateway/docs/quickstart)。 ## 请求头 | 请求头 | 必填 | 说明 | | --- | --- | --- | | `Content-Type` | 是 | `application/json`,其他类型返回 400 | ## 请求体 下表是 Jina、Cohere 等常见重排接口通用的字段,具体字段名和取值以模型所属服务商的 rerank 文档为准。 | 参数 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | `model` | string | 是 | 重排模型 ID,获取方法见下文「选择模型」。请始终写明:不写时使用工作空间的默认模型,而默认模型通常是对话模型,落到它上面会返回 400 `unsupported_model_api` 或上游的错误,见下文「网关行为」 | | `query` | string | 是 | 查询文本 | | `documents` | array | 是 | 待排序的文档,通常是字符串数组。条数和长度上限由服务商决定 | | `top_n` | integer | 否 | 只返回相关度最高的前 N 条。透传给上游,是否生效取决于模型 | | `return_documents` | boolean | 否 | 结果中是否带回文档原文。透传给上游,是否生效取决于模型 | 其他字段原样转发给上游,是否生效取决于模型。 ### 选择模型 可用的重排模型以工作空间的模型广场为准:在模型广场搜索 `rerank` 等关键词,复制模型 ID 替换示例中的 `MODEL_ID`。 也可以用 [`GET /v1/models`](https://platform.lyrouter.com/ai_gateway/docs/models) 筛选。返回的每个模型带 `api_types` 字段,含 `rerank` 的可调用本接口: ```bash curl -s https://api.lyrouter.com/v1/models \ -H "Authorization: Bearer $LYROUTER_API_KEY" \ | jq -r '.data[] | select((.api_types // []) | index("rerank")) | .id' ``` 模型没有声明 `api_types` 时不会出现在筛选结果里,可以在模型广场确认。字段说明见[列出模型](https://platform.lyrouter.com/ai_gateway/docs/models),筛选向量模型的方法见[创建向量](https://platform.lyrouter.com/ai_gateway/docs/embeddings)。 ## 请求示例 Python 示例使用 `httpx`,安装 `openai` 时已一并安装。 **请求示例** cURL: ```bash curl https://api.lyrouter.com/v1/rerank \ -H "Authorization: Bearer $LYROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "MODEL_ID", "query": "如何查看一次调用实际使用的模型?", "documents": [ "日志详情的「模型(实际)」显示最终回答的模型。", "API Key 在工作空间的 API 密钥页面创建。", "智能路由页面可以设置默认模型。" ], "top_n": 2, "return_documents": true }' ``` Python: ```python import os import httpx resp = httpx.post( "https://api.lyrouter.com/v1/rerank", headers={"Authorization": f"Bearer {os.environ['LYROUTER_API_KEY']}"}, json={ "model": "MODEL_ID", "query": "如何查看一次调用实际使用的模型?", "documents": [ "日志详情的「模型(实际)」显示最终回答的模型。", "API Key 在工作空间的 API 密钥页面创建。", "智能路由页面可以设置默认模型。", ], "top_n": 2, "return_documents": True, }, timeout=60, ) resp.raise_for_status() for item in resp.json()["results"]: print(item["index"], item["relevance_score"]) ``` Node.js: ```js const resp = await fetch("https://api.lyrouter.com/v1/rerank", { method: "POST", headers: { Authorization: `Bearer ${process.env.LYROUTER_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ model: "MODEL_ID", query: "如何查看一次调用实际使用的模型?", documents: [ "日志详情的「模型(实际)」显示最终回答的模型。", "API Key 在工作空间的 API 密钥页面创建。", "智能路由页面可以设置默认模型。", ], top_n: 2, return_documents: true, }), }); if (!resp.ok) throw new Error(await resp.text()); const { results } = await resp.json(); for (const item of results) console.log(item.index, item.relevance_score); ``` ## 响应 成功时的响应由服务商返回,网关不改写;出错时返回 `error` 对象。下面的 200 是常见形态,400 是请求落到了不支持重排接口的模型(多为默认模型,见下文「网关行为」),403 是模型没有在本工作空间开通且工作空间没有设置默认模型。 **响应示例** 200: ```json { "model": "MODEL_ID", "results": [ { "index": 0, "relevance_score": 0.92, "document": { "text": "日志详情的「模型(实际)」显示最终回答的模型。" } }, { "index": 2, "relevance_score": 0.31, "document": { "text": "智能路由页面可以设置默认模型。" } } ], "usage": { "total_tokens": 86 } } ``` 400: ```json { "error": { "message": "This model does not support the rerank API", "type": "invalid_request_error", "code": "unsupported_model_api" } } ``` 403: ```json { "error": { "message": "Model is not available in the model plaza", "type": "access_denied", "code": "model_not_available" } } ``` | 字段 | 说明 | | --- | --- | | `results[].index` | 文档在请求 `documents` 中的位置 | | `results[].relevance_score` | 相关度分数,按它从高到低排列。分数范围由模型决定,不同模型之间不可直接比较 | | `results[].document` | 设置了 `return_documents` 且模型支持时返回原文 | | `usage` | 用量,字段由服务商决定;有的服务商放在 `meta` 等其他位置 | ### 计费 按模型广场列出的计费项计费,用量取自上游响应的 `usage`;按次计价的模型读取其中的 `search_units`。单价以模型广场为准,每次调用的实际费用在[日志](https://platform.lyrouter.com/ai_gateway/docs/logs)中查看。费用估算方法见[调用费用与缓存计费](https://platform.lyrouter.com/ai_gateway/docs/estimate)。 ## 网关行为 - **请求原样转发**:网关只把 `model` 换成通道的真实模型名,其余字段原样转发(通过虚拟模型调用时见下文)。网关会重新编码 JSON:对象的键按固定顺序排列,数字最多保留 14 位有效数字。 - **通道回退**:同一模型有多个通道时,按工作空间的[路由策略](https://platform.lyrouter.com/ai_gateway/docs/routing)依次尝试,前一个通道失败就换下一个。 - **默认模型兜底**:工作空间在智能路由中设置了默认模型时,下面三种情况会落到默认模型上。默认模型通常是对话模型,此时得到的是报错,而不是你预期的结果(默认模型声明了 `api_types` 时,网关返回 400 `This model does not support the rerank API`;没有声明时,请求会转发给上游,由上游报错): - 请求没写 `model`; - `model` 写错,或该模型没有在本工作空间开通; - 该模型的所有通道都失败了。这时上游的真实报错被默认模型的报错取代,请到日志详情的「上游调用尝试」查看前面每次尝试的原因。 - **虚拟模型与 Auto**:[虚拟模型](https://platform.lyrouter.com/ai_gateway/docs/presets)可以用于本接口,前提是它的模型列表全部是重排模型;虚拟模型的系统提示词不会注入,但设置的推理参数会按字段名合并进请求体,因此给重排接口使用的虚拟模型不要设置推理参数。[`lyrouter/auto`](https://platform.lyrouter.com/ai_gateway/docs/auto) 的候选是对话模型,不要用于本接口。 - **安全围栏**:[安全围栏](https://platform.lyrouter.com/ai_gateway/docs/guardrails)的封禁、模型访问控制和客户端访问控制照常生效;敏感信息、提示词注入和意图安全检测不作用于本接口。 ## 常见错误 错误响应为 `{"error":{"message":"...","type":"...","code":"..."}}`,`code` 只有部分错误才有。 | 状态码 | `error.message` | `error.code` | 原因与处理 | | --- | --- | --- | --- | | 400 | `This model does not support the rerank API` | `unsupported_model_api` | 所用模型声明了 `api_types` 且不支持重排接口,多为请求落到了默认模型,见上文「默认模型兜底」。写上正确的重排模型 ID | | 400 | `you must provide a model parameter` | `missing_model` | 没写 `model`,工作空间也没有默认模型 | | 400 | `unsupported content-type: <类型>, only application/json is supported` | — | `Content-Type` 不是 JSON。响应体是一行纯文本,但响应头 `Content-Type` 目前是 `application/json`,解析前先判断正文是否为 JSON | | 403 | `Model is not available in the model plaza` | `model_not_available` | 模型没有在本工作空间开通,且没有设置默认模型。请管理员在模型广场开通,或换用已开通的模型 | | 503 | `all routed candidates exhausted` | `no_route_candidate` | 找不到可服务这次请求的通道,见[模型不可用](https://platform.lyrouter.com/ai_gateway/docs/unavailable) | - 文档条数、长度超限等由上游服务商返回,状态码和报错原文由上游决定。 - 用没有声明 `api_types` 的模型(见[列出模型](https://platform.lyrouter.com/ai_gateway/docs/models))调用本接口时,网关不返回 400 `unsupported_model_api`,而是把请求转发给上游,由上游报错。 - 网关先解析模型,再检查 `Content-Type`:没写 `model` 或模型没有开通时,先返回模型相关的错误(400 `missing_model`、403 `model_not_available`);模型有效时才返回 400 `unsupported content-type: …`。 - 401 / 403 鉴权问题见[401 / 403:鉴权与权限](https://platform.lyrouter.com/ai_gateway/docs/auth-errors),429 见[429:限流与配额](https://platform.lyrouter.com/ai_gateway/docs/rate-errors)。完整列表见[错误码与请求标识](https://platform.lyrouter.com/ai_gateway/docs/errors)。 --- # 图像生成 来源: https://platform.lyrouter.com/ai_gateway/docs/images-generations 根据文本提示词生成图片,也可以附带参考图做图生图。兼容 OpenAI Images API 的 `images.generate`:OpenAI 官方 SDK 把 Base URL 改成 `https://api.lyrouter.com/v1` 即可调用,图片在同一个响应里返回,不需要轮询。目前可用 Seedream 5.0、GPT-Image、Gemini Image 三个系列,参数写法和返回形式因系列而异,见下文各模型小节。 `POST /v1/images/generations` ## 鉴权 在请求头中携带 API Key: ```text Authorization: Bearer ``` `Bearer` 区分大小写。也可以改用 `x-api-key: `,两者同时存在时只读 `Authorization`。API Key 在工作空间的 **API 密钥** 页面创建,只用于 LYRouter 鉴权,不会转发给上游服务商。完整说明见[接入地址与鉴权](https://platform.lyrouter.com/ai_gateway/docs/call-gateway)。 ## 请求头 | 请求头 | 必填 | 说明 | | --- | --- | --- | | `Content-Type` | 是 | `application/json` | | `X-Gateway-Strict-Parameters` | 否 | 设为 `true`(只认小写)时,请求中有会被网关丢弃的参数就直接返回 400 `unsupported_parameters`,不调用上游、不计费。哪些参数会被丢弃见下文「各模型的处理方式」 | ## 请求体 各模型共用的参数如下,每个参数在各系列上是否生效见后面的模型小节。 | 参数 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | `model` | string | 是 | 图像模型 ID,例如 `bytedance/doubao-seedream-5.0-lite`。只能写具体的模型 ID:虚拟模型 `@vmodel/<名称>` 和 `lyrouter/auto` 在图像接口上返回 403。可用模型在模型广场查看,或调用[列出模型](https://platform.lyrouter.com/ai_gateway/docs/models) | | `prompt` | string | 是 | 提示词。Seedream pro 做图层拆分时可以省略 | | `size` | string | 否 | 输出尺寸,写成宽高(如 `2048x2048`)或档位名(如 `2K`)。可用写法和取值范围因模型而异,见各模型小节 | | `n` | integer | 否 | 生成张数。GPT-Image 原样转发给上游,最大 10。Seedream 目前不能用它一次生成多张:`n` 会转发给上游,但只出 1 张,不报错,也不列进 `X-Gateway-Unsupported-Parameters`,需要多张请发多次请求。Gemini 会丢弃 | | `quality` | string | 见说明 | 生成质量,GPT-Image 系列使用,取值逐模型不同,`gpt-image-2` 必填;Gemini 会丢弃 | | `response_format` | string | 否 | `url` 或 `b64_json`,只对 Seedream 生效(默认 `url`)。GPT-Image、Gemini 固定返回 `b64_json`,网关丢弃这个参数 | | `image` | string \| array | 否 | 参考图,用于图生图。Seedream 接受公网 URL 或 `data:image/<格式>;base64,<数据>`;Gemini 也接受,写法见[图像编辑](https://platform.lyrouter.com/ai_gateway/docs/images-edits) | | `user` | string | 否 | 终端用户标识。Seedream、GPT-Image 原样转发;Gemini 会丢弃 | 表中没有的其他参数:Seedream、GPT-Image 原样转发给上游,是否生效取决于模型;Gemini 一律丢弃。 ### 各模型的处理方式 网关按模型决定怎样处理请求体,这决定了哪些参数能生效: | 模型系列 | 模型 ID | 处理方式 | 网关丢弃的参数 | 返回的图片 | | --- | --- | --- | --- | --- | | Seedream 5.0 | `bytedance/doubao-seedream-5.0-pro`
`bytedance/doubao-seedream-5.0-lite` | 透传 | 无 | `url`(默认)或 `b64_json` | | GPT-Image | `openai/gpt-image-2`
`openai/gpt-image-2.5-flare`
`openai/gpt-image-2.5-sunburst` | 透传 | `response_format`;2.5 两个模型另丢弃 `stream`、`stream_options` | `b64_json` | | Gemini Image | `google/gemini-3-pro-image`
`google/gemini-3.1-flash-image` | 契约转换 | 除 `model`、`prompt`、`size`、`image` 外的全部参数;`size` 无法匹配时也会丢弃 | `b64_json` | - **透传**:请求体原样发给上游,只改写模型名,服务商支持的其他参数也可以传。参数不被上游接受时,返回的是上游自己的错误。 - **契约转换**:网关把参数翻译成服务商的格式,翻译不了的参数丢弃。 - 被丢弃的参数列在响应头 `X-Gateway-Unsupported-Parameters` 中,请求照常执行;带 `X-Gateway-Strict-Parameters: true` 时改为返回 400。透传给上游的参数不受这个请求头影响。 模型的能力对比和使用场景见[多模态能力](https://platform.lyrouter.com/ai_gateway/docs/multimodal)。模型以模型广场为准,下文按系列列出各自的参数与限制。 ### Seedream 5.0(pro / lite) 火山方舟的 Seedream 模型,透传,默认返回图片 URL,单次生成约 20 秒。 | 参数 | 类型 | 说明 | | --- | --- | --- | | `size` | string | 默认 `2K`。推荐写档位名,宽高比在 `prompt` 里用文字描述:pro 为 `1K`、`1.5K`、`2K`,lite 为 `2K`、`3K`、`4K`。也可以写 `宽x高`:pro 要求总像素在 [921600, 4624220] 之间,lite 要求不少于 3686400(最小正方形是 `1920x1920`,常见的 `1024x1024` 会被拒绝),宽高比都要在 [1/16, 16] 之间。两种写法不能混用 | | `response_format` | string | `url`(默认)或 `b64_json` | | `image` | string \| array | 参考图,公网 URL 或 `data:image/<格式>;base64,<数据>`(`<格式>` 须小写),建议不超过 10 张,限制见下表 | | `output_format` | string | `png` 或 `jpeg`。图层拆分时只控制底图格式,图层固定为 PNG | | `background` | string | `opaque`(默认)或 `transparent`。只用于图生图,且只能输入 1 张带透明通道的图 | | `watermark` | boolean | `true` 时在右下角加「AI生成」水印。不传时默认加水印,不需要时传 `false` | | `layer_decomposition` | boolean | 仅 pro,默认 `false`。`true` 时把 1 张输入图拆成 1 张底图和最多 16 个带透明通道的 PNG 图层,`image` 必填且只能 1 张,`size` 只能写档位名(默认 `auto`) | | `optimize_prompt_options.mode` | string | 仅 pro。`standard`(默认)或 `fast`(更快、质量略低) | 参考图的限制: | 限制 | 生图 | 图层拆分 | | --- | --- | --- | | 格式 | jpeg、png、webp、bmp、tiff、gif、heic、heif | png、jpeg | | 总像素(宽 × 高) | [196, 36000000] | [262144, 36000000] | | 宽、高 | 不小于 14 px | — | | 宽高比(宽/高) | [1/16, 16] | [1/16, 16] | | 单张大小 | ≤ 30 MB | ≤ 30 MB | | 张数 | 建议不超过 10 张;超过时服务商目前不拒绝,但输出可能异常 | 仅 1 张 | - pro 支持交互编辑:在 `prompt` 里用 `x y` 或 `x1 y1 x2 y2`(坐标归一化到 0~999)指定要改的位置。 - 图层拆分的响应在 `data[]` 中同时返回底图和图层,带 `z_index`、`bounding_box`、`name`、`description` 等字段;每次请求预占 17 张的限流额度,完成后按实际张数返还。各档位对应的像素、坐标换算和还原方法见[多模态能力](https://platform.lyrouter.com/ai_gateway/docs/multimodal#seedream-5-0-pro-lite-火山方舟)。 - 火山方舟的其他参数也可以直接写在请求体里。用 OpenAI Python SDK 时放进 `extra_body`,例如 `extra_body={"watermark": False}`。 **计费**:按张计。pro 按分辨率分档:1K 与 1.5K(≤ 261 万像素)一档、2K 一档,图层拆分另有两档(同样按 1K/1.5K 与 2K 分),按实际产出的张数(底图 + 各图层)计;pro 的参考图单独计一项,每次请求的第 1 张参考图不收费,超出部分按张计(数的是输入的参考图,不是出图张数)。lite 不分档。`1.5K` 与 `1K` 同价且出图更好,没有特殊要求时优先用 `1.5K`。 ```bash curl https://api.lyrouter.com/v1/images/generations \ -H "Authorization: Bearer $LYROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "bytedance/doubao-seedream-5.0-lite", "prompt": "一只戴墨镜的柴犬坐在冲浪板上,黄昏海面,电影感,横幅构图", "size": "2K", "watermark": false }' ``` ### GPT-Image(2 / 2.5-flare / 2.5-sunburst) 透传,参数与 OpenAI 图像 API 一致,固定返回 `b64_json`。 | 参数 | 类型 | 说明 | | --- | --- | --- | | `quality` | string | 取值逐模型不同,见下表。建议所有 GPT-Image 模型都显式传入 | | `size` | string | 只接受 `宽x高`,不接受档位名(传 `4K` 返回 `Invalid size '4K'. Expected WIDTHxHEIGHT, for example '1824x1024'.`);须满足下文四条硬约束,否则返回 400 | | `n` | integer | 生成张数,最大 10 | | `background` | string | `transparent`、`opaque` 或 `auto` | | `output_format` | string | 输出格式。`gpt-image-2` 只接受 `png`、`jpeg`,传 `webp` 返回 400 `Invalid value: 'webp'. Supported values are: 'png' and 'jpeg'.`;2.5 系列接受 `png`、`jpeg`、`webp` | | `moderation` | string | `auto` 或 `low` | | `user` | string | 终端用户标识 | | `response_format` | — | 网关丢弃并在响应头中列出:这个系列固定返回 `b64_json`,上游对该参数时而接受、时而报错 | | `stream`、`stream_options` | — | 2.5 系列由网关丢弃(上游开启流式会使请求失败);`gpt-image-2` 也不要传 `stream` | `quality` 的取值: | 模型 | 取值 | 默认 | | --- | --- | --- | | `gpt-image-2` | `low`、`medium`、`high`、`auto` | 无,必填:不传会间歇性返回 400(`INVALID_REQUEST_BODY`);`auto` 实测等同 `low` | | `gpt-image-2.5-flare`、`gpt-image-2.5-sunburst` | `low`、`medium`、`high`、`xhigh`、`max`、`auto` | `low`(`auto` 实测等同 `low`) | `xhigh`、`max` 两档是否可用由上游账号能力决定,可能被拒;收到 `Invalid value: 'xhigh'` 时改用 `high`。 `size` 的四条硬约束,由服务商校验,任一不满足返回 400: | 约束 | 服务商报错原文 | 示例 | | --- | --- | --- | | 宽和高都能被 16 整除 | `Invalid size '<宽>x<高>'. Width and height must both be divisible by 16.` | `1008x1008` 可用;`1254x1254`、`1312x1199` 被拒 | | 最长边不超过 3840 | `Invalid size '<宽>x<高>'. The longest edge must be less than or equal to 3840.` | `3840x2160` 可用;`4096x4096`、`1024x4096` 被拒 | | 总像素不少于约 100 万 | `Invalid size '<宽>x<高>'. Requested resolution is below the current minimum pixel budget.` | `1008x1008`(约 102 万)可用;`512x1024`(约 52 万)被拒 | | 总像素不超过约 830 万 | `Invalid size '<宽>x<高>'. Requested resolution exceeds the current pixel budget.` | `3840x2160`(约 829 万)可用;`3840x2176`(约 836 万)被拒 | - **耗时**:一次生成实测约 20~60 秒,偶有更长(最长一次约 83 秒);参数错误导致的上游 400 实测在 2 秒内返回。客户端超时请按分钟设置,不低于 300 秒。 **计费**:按 Token 计,输入文本、输入图片、输出分别计价,上游在 `usage.input_tokens_details` 中分开上报文字与图片 Token,所以同样长度的提示词,带图与不带图费用不同。缓存命中另有一项单价;2.5 系列的 `usage` 不含缓存字段,不产生这一项。 输出 Token 主要由 `quality` 决定:`1024x1024` 时 2.5 系列 `low` 输出 196 Token、`max` 输出 7024 Token,最高档约为最低档的 36 倍。同名档位在两代模型上不是同一个量:2.5 系列的 `high` 与 `gpt-image-2` 的 `medium` 输出 Token 相同,跨模型比较请比 Token,不要比档位名。另外,GPT-Image 不是像素越多越贵(只适用于 GPT-Image):输出 Token 不随像素增加,例如 `1024x1536`(约 157 万像素)的输出 Token 比 `1024x1024`(约 105 万像素)还少。 ### Gemini Image(3 Pro / 3.1 Flash) 契约转换:网关把请求翻译成 Gemini 原生的 `generateContent` 格式,只使用下表中生效的参数,其余参数丢弃并在响应头中列出。固定返回 `b64_json`,不能返回 URL。单次生成实测 20~250 秒(`gemini-3-pro-image`),偶有超过 300 秒仍未返回。 | 参数 | 是否生效 | 说明 | | --- | --- | --- | | `prompt` | 生效 | 必填,不写或为空返回 400 `prompt is required for this model` | | `size` | 生效 | 写法见下表 | | `image` | 生效 | 参考图,写法见[图像编辑](https://platform.lyrouter.com/ai_gateway/docs/images-edits) | | `n` | 丢弃 | 需要多张图请发多次请求 | | `quality` | 丢弃 | Gemini 没有对应参数 | | `response_format` | 丢弃 | 只能返回 `b64_json` | | `user` 及其他参数 | 丢弃 | — | `size` 的写法决定了比例和分辨率: | 写法 | 网关的处理 | 效果 | | --- | --- | --- | | 档位名:`1K`、`2K`、`4K` | 原样作为分辨率档位 | 控制分辨率,宽高比由上游默认 | | `宽x高`,如 `1376x768` | 匹配最接近的支持比例(误差 2% 以内),再按长边向上取分辨率档位 | 同时控制比例和分辨率 | | 宽高比超出 2% 误差,如 `1000x700` | 整个 `size`(比例和档位)都不下发,`size` 计入丢弃参数 | 返回 200、照常出图并计费,但比例和分辨率都是上游默认值,唯一的信号是响应头 `X-Gateway-Unsupported-Parameters: size`;严格模式下返回 400 | | 比例字符串,如 `16:9` | 当作档位名原样传给上游 | 上游不认识,返回 400(`upstream_rejected`)。要 16:9 请写该比例的宽高,如 `1376x768` | `512` 档在生产环境被服务商拒绝(两个模型都是),不要使用。 支持的宽高比:`1:1`、`2:3`、`3:2`、`3:4`、`4:3`、`4:5`、`5:4`、`9:16`、`16:9`、`21:9`、`1:4`、`4:1`、`1:8`、`8:1`。写宽高时按长边向上取档,超过 4K 的按 4K;长边不超过 704 时网关会映射到 `512` 档,同样可能被拒绝,请让长边大于 704。同一档位在两个模型上的输出 Token 不同: | 长边 | 档位 | `gemini-3-pro-image` 输出 Token | `gemini-3.1-flash-image` 输出 Token | | --- | --- | --- | --- | | ≤ 1376 | `1K` | 1120 | 1120 | | ≤ 2816 | `2K` | 1120(2K 档不生效,与 1K 相同) | 1680 | | 更大(封顶) | `4K` | 2000 | 2520 | 出图尺寸由服务商按比例档和分辨率档决定,不等于请求的宽高,例如 `gemini-3-pro-image` 请求 `4096x2304` 实际出图 `5504x3072`;请以返回图片的实际宽高为准。 例如 `1024x1024` 映射为 1:1 + `1K`,`2048x2048` 映射为 1:1 + `2K`。要 16:9 + 4K 请写 `4096x2304`,不要照抄 `5632x3072`:它的比例是 1.833,偏离 16:9 超过 2%,整个 `size` 会被丢弃。生产环境建议带 `X-Gateway-Strict-Parameters: true`,让这种请求改为返回 400。 **计费**:按 Token 计,输入、输出、思考三项分别计价;带参考图时,输入图片并入「输入」。思考 Token 只在上游返回时出现(`gemini-3-pro-image`),位于 `usage.output_tokens_details.reasoning_tokens`,`usage.total_tokens` 包含它。思考 Token 每次不同,由模型自行决定:生产实测 115~316 个、中位约 220,约占单次费用的 1.5%,预算时可按每次约 220 个估算。 ```json { "data": [{ "b64_json": "iVBORw0KGgoAAAANSUhEUgAA…" }], "usage": { "input_tokens": 7, "output_tokens": 1120, "total_tokens": 1339, "output_tokens_details": { "reasoning_tokens": 212 } } } ``` ## 请求示例 下面以 `openai/gpt-image-2` 为例,把返回的 Base64 图片保存为文件。换成 Seedream 时,图片默认以 URL 返回,读取 `data[0].url` 并及时下载。 **请求示例** cURL: ```bash curl https://api.lyrouter.com/v1/images/generations \ --max-time 300 \ -H "Authorization: Bearer $LYROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "openai/gpt-image-2", "prompt": "一只戴墨镜的柴犬坐在冲浪板上,黄昏海面,电影感", "size": "1024x1024", "quality": "medium" }' ``` Python: ```python import base64 import os from openai import OpenAI client = OpenAI( api_key=os.environ["LYROUTER_API_KEY"], base_url="https://api.lyrouter.com/v1", timeout=300, ) result = client.images.generate( model="openai/gpt-image-2", prompt="一只戴墨镜的柴犬坐在冲浪板上,黄昏海面,电影感", size="1024x1024", quality="medium", ) with open("shiba.png", "wb") as f: f.write(base64.b64decode(result.data[0].b64_json)) print(result.usage) ``` Node.js: ```js import { writeFileSync } from "node:fs"; import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.LYROUTER_API_KEY, baseURL: "https://api.lyrouter.com/v1", timeout: 300_000, }); const result = await client.images.generate({ model: "openai/gpt-image-2", prompt: "一只戴墨镜的柴犬坐在冲浪板上,黄昏海面,电影感", size: "1024x1024", quality: "medium", }); writeFileSync("shiba.png", Buffer.from(result.data[0].b64_json, "base64")); console.log(result.usage); ``` ## 响应 成功时返回 OpenAI Images 格式的对象,图片在顶层 `data` 数组中;出错时返回 `error` 对象。下面的 200 分别是 Seedream(返回 URL)和 GPT-Image(返回 Base64),400 是开启严格模式时给 Gemini 传了它不支持的参数,403 是模型未开通,或使用了虚拟模型、Auto。 **响应示例** 200(url): ```json { "model": "doubao-seedream-5-0-260128", "created": 1789454321, "data": [ { "url": "https://ark-acg-cn-beijing.tos-cn-beijing.volces.com/…", "size": "1920x1920" } ], "usage": { "generated_images": 1, "output_tokens": 14400, "total_tokens": 14400 } } ``` 200(b64_json): ```json { "created": 1791950400, "data": [ { "b64_json": "iVBORw0KGgoAAAANSUhEUgAA…" } ], "size": "1024x1024", "quality": "medium", "output_format": "png", "background": "opaque", "usage": { "input_tokens": 29, "input_tokens_details": { "text_tokens": 29, "image_tokens": 0 }, "output_tokens": 1756, "total_tokens": 1785 } } ``` 400: ```json { "error": { "message": "unsupported parameters for this model: n,quality", "type": "invalid_request_error", "code": "unsupported_parameters" } } ``` 403: ```json { "error": { "message": "Model is not available in the model plaza", "type": "access_denied", "code": "model_not_available" } } ``` | 字段 | 说明 | | --- | --- | | `created` | Unix 时间戳(秒)。Gemini 不返回这个字段 | | `model` | 服务商侧的模型名(Seedream 返回),例如 `doubao-seedream-5-0-260128`,与请求中的模型 ID 不同 | | `data` | 产物数组,只生成一张时也是数组 | | `data[].url` | 图片下载地址,Seedream 默认返回。这是服务商签发的临时地址,约 24 小时后失效,请及时下载保存 | | `data[].b64_json` | Base64 编码的图片。GPT-Image、Gemini 固定返回;Seedream 在 `response_format` 为 `b64_json` 时返回 | | `data[].size` | 实际生成的尺寸(Seedream 返回) | | `data[].output_format` | 图片格式(Seedream pro 返回) | | `size`、`quality`、`output_format`、`background` | 本次实际使用的生成参数(GPT-Image 返回) | | `usage` | 计量信息,字段随模型变化,见下表 | ### usage 的字段 | 模型系列 | `usage` 中的字段 | 计量方式 | | --- | --- | --- | | Seedream | `generated_images`(生成张数)、`output_tokens`、`total_tokens`;pro 带参考图时另有 `input_images`(输入的参考图张数) | 按张 | | GPT-Image | `input_tokens`、`input_tokens_details.text_tokens` / `image_tokens`、`output_tokens`、`total_tokens` | 按 Token | | Gemini | `input_tokens`、`output_tokens`、`total_tokens`,有思考 Token 时另有 `output_tokens_details.reasoning_tokens` | 按 Token | 不要假设某个字段一定存在,读取前先判断。各模型的计费方式见上文模型小节,单价以控制台模型广场为准,每次调用的实际扣费在[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)中查看。 ### 响应头 | 响应头 | 说明 | | --- | --- | | `X-Gateway-Unsupported-Parameters` | 网关丢弃了参数时出现,值为逗号分隔的参数名,例如 `n,quality`。请求照常执行,列出的参数没有生效 | 配置了配额时,响应还会带 `x-aigw-quota-*` 系列响应头,见[网关扩展请求头与响应头](https://platform.lyrouter.com/ai_gateway/docs/gateway-headers)。 这样读取被丢弃的参数(Python、Node.js 沿用上文示例中的 `client`): **读取被丢弃的参数** cURL: ```bash curl -sS -D - -o result.json https://api.lyrouter.com/v1/images/generations \ --max-time 300 \ -H "Authorization: Bearer $LYROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"google/gemini-3.1-flash-image","prompt":"一片绿色的叶子,扁平风格","size":"1376x768","n":2}' # 响应头中出现:X-Gateway-Unsupported-Parameters: n ``` Python: ```python raw = client.images.with_raw_response.generate( model="google/gemini-3.1-flash-image", prompt="一片绿色的叶子,扁平风格", size="1376x768", n=2, ) print(raw.headers.get("X-Gateway-Unsupported-Parameters")) # n result = raw.parse() ``` Node.js: ```js const { data: result, response } = await client.images .generate({ model: "google/gemini-3.1-flash-image", prompt: "一片绿色的叶子,扁平风格", size: "1376x768", n: 2, }) .withResponse(); console.log(response.headers.get("X-Gateway-Unsupported-Parameters")); // n ``` ## 网关行为 与直接调用上游相比,经 LYRouter 调用有以下差别: - **只用指定的模型**:图像接口不会改用其他模型。同一模型有多个通道时,失败后依次尝试其他通道;虚拟模型、Auto 智能路由和工作空间默认模型的回退都不用于图像接口,见[失败重试与备用模型](https://platform.lyrouter.com/ai_gateway/docs/fallback)。 - **丢弃参数与严格模式**:网关只丢弃上文「各模型的处理方式」中列出的参数,并在响应头 `X-Gateway-Unsupported-Parameters` 中列出。生产环境建议检查这个响应头,或者带上 `X-Gateway-Strict-Parameters: true`,让请求在出现会被丢弃的参数时直接返回 400、不调用上游、不计费。用 SDK 时通过 `extra_headers={"X-Gateway-Strict-Parameters": "true"}`(Python)或请求选项 `{ headers: { "X-Gateway-Strict-Parameters": "true" } }`(Node.js)传入。透传给上游的参数不受这个请求头影响,参数是否被接受由上游判断。 - **上游在成功响应里声明错误**:Gemini 的上游拒绝请求时可能返回 HTTP 200 而没有图片。网关把它改写成错误响应,状态码取上游声明的错误:上游拒绝时 `error.code` 为 `upstream_rejected`,`error.message` 是上游原文;没有产出图片时为 `upstream_no_artifact`,并带 `upstream_finish_reason`(如 `NO_IMAGE`、`SAFETY`)。`upstream_status` 保留上游原本的 200。这类错误不换通道重试,请按提示修改提示词或参数: ```json { "error": { "message": "upstream produced no image (finishReason: NO_IMAGE)", "type": "invalid_request_error", "code": "upstream_no_artifact", "upstream_status": 200, "upstream_finish_reason": "NO_IMAGE", "generated_by": "ai-gateway" } } ``` - **上游错误原样返回**:透传模型的参数错误由上游返回,格式和错误码以上游为准,例如 Seedream 返回 `{"error":{"code":"InvalidParameter","message":"..."}}`。上游返回错误状态却没有响应体时,网关补一个错误体,带 `upstream_status` 和 `generated_by: "ai-gateway"`;上游提供了请求 ID 时还带 `upstream_request_id`,向服务商报障时提供它。 - **日志中不保存图片**:请求和响应中的 Base64 图片在日志里替换成 `[base64 <字节数>B #]` 摘要,日志详情里看不到图片不代表请求失败,图片在响应体里。返回 URL 的模型,URL 保留在日志中。 - **超时**:图像接口同步返回,Seedream 约 20 秒,GPT-Image 系列实测约 20~60 秒,Gemini 实测 20~250 秒、偶有超过 300 秒。客户端超时请按分钟设置,不低于 300 秒,不要沿用文本接口的 30 秒;客户端超时后不要立即重复提交,先在[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)中确认上一次请求的结果。 ## 常见错误 网关返回的错误为 `{"error":{"message":"...","type":"...","code":"..."}}`;透传模型的参数错误由上游返回,格式以上游为准。 | 状态码 | `error.message` | `error.code` | 原因与处理 | | --- | --- | --- | --- | | 400 | `you must provide a model parameter` | `missing_model` | 没有写 `model`,工作空间也没有默认模型。图像接口请总是写明模型 ID | | 400 | `unsupported parameters for this model: <参数名>` | `unsupported_parameters` | 带了 `X-Gateway-Strict-Parameters: true`,且请求中有会被丢弃的参数。删掉列出的参数,或换用支持它们的模型 | | 400 | `prompt is required for this model` | `invalid_parameter` | 调用 Gemini 时没有写 `prompt` 或为空 | | 400 | 上游原文,例如 `Request contains an invalid argument.` | `upstream_rejected` | Gemini 的上游拒绝了请求,例如 `size` 写成了 `16:9`。按原文修改参数 | | 400 | `upstream produced no image (finishReason: <原因>)` | `upstream_no_artifact` | Gemini 没有产出图片,按 `upstream_finish_reason` 修改提示词或内容后重试 | | 400 | ``The parameter `size` specified in the request is not valid: image size must be at least 3686400 pixels`` | `InvalidParameter` | Seedream lite 的尺寸低于下限。改用 `2K` 档位或更大的宽高,如 `1920x1920` | | 400 | `Invalid size '<宽>x<高>'. Width and height must both be divisible by 16.` | — | GPT-Image 的宽或高不是 16 的倍数,由上游返回 | | 400 | `Invalid size '<宽>x<高>'. The longest edge must be less than or equal to 3840.`、`Invalid size '<宽>x<高>'. Requested resolution is below the current minimum pixel budget.`、`Invalid size '<宽>x<高>'. Requested resolution exceeds the current pixel budget.` | — | GPT-Image 的 `size` 最长边超过 3840,或总像素不在约 100 万到约 830 万之间,由上游返回。按上文 `size` 的四条硬约束调整 | | 400 | `Invalid size '4K'. Expected WIDTHxHEIGHT, for example '1824x1024'.` | — | 给 GPT-Image 传了档位名。改写成 `宽x高` | | 400 | `Invalid value: 'xhigh'` | — | 上游账号不支持 `xhigh` / `max` 这两档 `quality`(是否可用由上游账号能力决定)。改用 `high` | | 400 | 上游原文 | `INVALID_REQUEST_BODY` | GPT-Image 请求体不合法,先检查是否传了 `quality`:`gpt-image-2` 不传会间歇性返回 400 | | 400 | `This model does not support the images API` | `unsupported_model_api` | 模型声明的接口类型([列出模型](https://platform.lyrouter.com/ai_gateway/docs/models)中的 `api_types`)不含图像接口,例如用对话模型调用本接口。没有声明 `api_types` 的对话模型不会触发这条,请求会转发给上游,可能返回 404 `upstream_not_found`,或返回没有图片的 200(如 `{"data":{"content":null}}`)。图像接口请只用图像模型 | | 403 | `Model is not available in the model plaza` | `model_not_available` | 工作空间没有开通这个模型,或者写了 `@vmodel/<名称>`、`lyrouter/auto`。请管理员在模型广场开通,或改写已开通的具体模型 ID | - 401 / 403 鉴权问题见[401 / 403:鉴权与权限](https://platform.lyrouter.com/ai_gateway/docs/auth-errors),429 见[429:限流与配额](https://platform.lyrouter.com/ai_gateway/docs/rate-errors)。 - 500 / 504 是连接上游失败或等待上游超时,响应体是 HTML 页面而不是 JSON,见[超时与流式中断](https://platform.lyrouter.com/ai_gateway/docs/stream-errors)。 - 完整列表见[错误码与请求标识](https://platform.lyrouter.com/ai_gateway/docs/errors)。 --- # 图像编辑 来源: https://platform.lyrouter.com/ai_gateway/docs/images-edits 按提示词修改输入的图片,或以一张、多张图片为参考生成新图。兼容 OpenAI Images API 的 `images.edit`,请求体有两种写法:`multipart/form-data` 上传图片文件(OpenAI 官方 SDK 的写法),或 JSON 把图片以 Base64 放在请求体里(LYRouter 的扩展)。支持编辑的是 GPT-Image 和 Gemini Image 两个系列,两种写法都可用;Seedream 不支持本接口,它的图生图请用[图像生成](https://platform.lyrouter.com/ai_gateway/docs/images-generations)的 `image` 参数。 `POST /v1/images/edits` ## 鉴权 在请求头中携带 API Key: ```text Authorization: Bearer ``` `Bearer` 区分大小写。也可以改用 `x-api-key: `,两者同时存在时只读 `Authorization`。API Key 在工作空间的 **API 密钥** 页面创建,只用于 LYRouter 鉴权,不会转发给上游服务商。完整说明见[接入地址与鉴权](https://platform.lyrouter.com/ai_gateway/docs/call-gateway)。 ## 请求头 | 请求头 | 必填 | 说明 | | --- | --- | --- | | `Content-Type` | 是 | `multipart/form-data; boundary=...` 或 `application/json`。multipart 的 boundary 由 curl `-F` 或 SDK 自动生成,自己拼请求时不要只写 `multipart/form-data` | | `X-Gateway-Strict-Parameters` | 否 | 设为 `true`(只认小写)时,请求中有会被网关丢弃的参数就直接返回 400 `unsupported_parameters`,不调用上游、不计费。编辑接口上只有 Gemini 会丢弃参数,GPT-Image 的参数全部原样转发,不受这个请求头影响 | ## 请求体 两种写法的字段名相同,GPT-Image 和 Gemini 都支持,按调用方便选择即可。 ### multipart/form-data | 字段 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | `model` | string | 是 | 模型 ID,例如 `openai/gpt-image-2`。只能写具体的模型 ID:虚拟模型 `@vmodel/<名称>` 和 `lyrouter/auto` 返回 403 | | `image` | file | 是 | 待编辑的图片文件。Gemini 上重复多个 `image` 字段即传入多张图,按出现顺序使用 | | `prompt` | string | 是 | 编辑指令 | | `mask` | file | 否 | 遮罩图,GPT-Image 使用;Gemini 会丢弃 | | `quality` | string | 见说明 | GPT-Image 使用,`gpt-image-2` 必填;Gemini 会丢弃 | | `n` | integer | 否 | 生成张数,GPT-Image 使用(最大 10);Gemini 会丢弃 | | `size` | string | 否 | 输出尺寸,写法见各模型小节 | - GPT-Image:网关只改写 `model` 字段,文件和其他字段一个字节都不动,原样发给上游。 - Gemini:网关解析表单,把文件转成 Base64(格式取自文件段的 `Content-Type`,没有时按文件头识别),再按 JSON 写法转换。所有文件合计不能超过 30 MB,超过返回 400。 ### JSON OpenAI 官方的 `/images/edits` 只收 multipart,JSON 写法是 LYRouter 的扩展,图片以 Base64 放在 `image` 中。 | 参数 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | `model` | string | 是 | 模型 ID,同上 | | `prompt` | string | 是 | 编辑指令,不能为空 | | `image` | string \| array | 是 | 一张或多张输入图,写成 `data:image/png;base64,<数据>`,多张时传数组。Gemini 也接受不带前缀的 Base64,见下文 | | `quality`、`n`、`size` 等 | — | 否 | 与 multipart 写法相同,见各模型小节 | ### 各模型的处理方式 | 模型系列 | 模型 ID | 处理方式 | 网关丢弃的参数 | | --- | --- | --- | --- | | GPT-Image | `openai/gpt-image-2`
`openai/gpt-image-2.5-flare`
`openai/gpt-image-2.5-sunburst` | 透传 | 无,全部原样转发 | | Gemini Image | `google/gemini-3-pro-image`
`google/gemini-3.1-flash-image` | 契约转换 | 除 `model`、`prompt`、`image`、`size` 外的全部参数;`size` 无法匹配时也会丢弃 | 被丢弃的参数列在响应头 `X-Gateway-Unsupported-Parameters` 中,请求照常执行;带 `X-Gateway-Strict-Parameters: true` 时改为返回 400。模型的能力对比和使用场景见[多模态能力](https://platform.lyrouter.com/ai_gateway/docs/multimodal)。 ### GPT-Image(2 / 2.5-flare / 2.5-sunburst) 透传:请求体原样发给上游,只改写模型名,参数与 OpenAI 图像 API 一致,固定返回 `b64_json`。 | 参数 | 类型 | 说明 | | --- | --- | --- | | `quality` | string | 取值逐模型不同:`gpt-image-2` 为 `low`、`medium`、`high`、`auto`(`auto` 实测等同 `low`),必填,不传会间歇性返回 400(`INVALID_REQUEST_BODY`);2.5 系列为 `low`、`medium`、`high`、`xhigh`、`max`、`auto`,默认 `low`,`xhigh`、`max` 可能被上游拒绝(收到 `Invalid value: 'xhigh'` 时改用 `high`)。详见[图像生成](https://platform.lyrouter.com/ai_gateway/docs/images-generations#gpt-image-2-2-5-flare-2-5-sunburst) | | `size` | string | 只接受 `宽x高`,不接受档位名;须满足四条硬约束:宽高都能被 16 整除、最长边不超过 3840、总像素在约 100 万到约 830 万之间,见[图像生成](https://platform.lyrouter.com/ai_gateway/docs/images-generations#gpt-image-2-2-5-flare-2-5-sunburst)。不传时输出尺寸由上游决定:实测 `gpt-image-2` 输入 1024×1024 的图时输出 `1254x1254`(不能被 16 整除,在生成接口主动请求这个尺寸会被拒),`gpt-image-2.5-flare` 输入 1536×1024 的图时输出 `1024x1024`。需要固定尺寸时请显式传 `size` | | `mask` | file | 遮罩图,multipart 写法上传 | | `n`、`background`、`output_format`、`moderation`、`user` | — | 与[图像生成](https://platform.lyrouter.com/ai_gateway/docs/images-generations#gpt-image-2-2-5-flare-2-5-sunburst)相同 | | `response_format`、`stream` | — | 不要传。编辑接口上网关不丢弃它们:`response_format` 原样转发给上游,这个系列固定返回 `b64_json`;`stream` 为 `true` 时网关目前会自行补上 `stream_options`,上游返回 400 `Unknown parameter: 'stream_options'.` | - **耗时**:两种写法在网关侧的开销相同(约 0.1 秒),耗时几乎全在上游,单次从 20 秒到 4 分钟以上不等,同样的请求两次耗时也可能差好几倍。客户端超时请设为不低于 300 秒。 - **图片校验**:上游会校验图片本身,过小或损坏的图片会被拒绝(例如返回 `Invalid image file or mode`),请换一张正常的图片重试。 **计费**:与图像生成相同,按 Token 计,输入文本、输入图片、输出分别计价。编辑比生成多一项输入图片的费用:图片按 32×32 像素一块折算成 Token,记在 `usage.input_tokens_details.image_tokens`:长边不足 1024 时先放大到长边的 2 倍(最多 1024),像素超过约 152 万时先等比缩小,再按 `ceil(宽/32) × ceil(高/32)` 计。实测 1024×1024 的图为 1024 Token,8×8 的图为 1 Token。`mask` 也按同样的规则计入 `image_tokens`:实测 1024×1024 的原图加同尺寸的 mask,`image_tokens` 为 2048。同样的 `quality` 和 `size` 下,编辑与生成的输出 Token 相同;输出 Token 随 `quality` 的量级差异见[图像生成](https://platform.lyrouter.com/ai_gateway/docs/images-generations#gpt-image-2-2-5-flare-2-5-sunburst)。 ### Gemini Image(3 Pro / 3.1 Flash) 契约转换:网关把请求翻译成 Gemini 原生的 `generateContent` 格式,只使用下表中生效的参数,其余参数丢弃并在响应头中列出。固定返回 `b64_json`。 | 参数 | 是否生效 | 说明 | | --- | --- | --- | | `prompt` | 生效 | 必填,不写或为空返回 400 `prompt is required for this model` | | `image` | 生效 | 一张或多张。JSON 写法中,带 `data:<格式>;base64,` 前缀时使用其中声明的格式;不带前缀时按 PNG、JPEG、WEBP、GIF 的文件头识别;都无法识别时返回 400 并指明第几张图。不接受图片 URL | | `size` | 生效 | 与图像生成相同:档位名(`1K`、`2K`、`4K`)控制分辨率,`512` 档在生产环境被服务商拒绝,不要使用;`宽x高` 匹配宽高比并按长边取档,比例偏差超过 2% 时整个 `size` 被丢弃、请求仍返回 200 并计费。各档输出 Token 两个模型不同,见[图像生成](https://platform.lyrouter.com/ai_gateway/docs/images-generations#gemini-image-3-pro-3-1-flash) | | `n`、`quality`、`mask`、`response_format`、`user` 等 | 丢弃 | — | - multipart 写法中,所有文件合计不超过 30 MB。OpenAI 官方 SDK 的 `images.edit()` 总是以 multipart 发送,可以直接用来调用 Gemini。 **计费**:按 Token 计,输入、输出、思考三项分别计价,输入图片并入「输入」(`usage.input_tokens`),每张输入图按固定 Token 数计,与图片尺寸无关:生产实测 `gemini-3-pro-image` 每张 560,`gemini-3.1-flash-image` 每张 1120,两者相差一倍。思考 Token 的说明见[图像生成](https://platform.lyrouter.com/ai_gateway/docs/images-generations#gemini-image-3-pro-3-1-flash)。 ## 请求示例 ### multipart/form-data 以 `openai/gpt-image-2` 为例,上传 `cat.png` 并把结果保存为文件。Python 示例需要较新版本的 openai SDK:实测 1.58.1 的 `images.edit()` 不接受 `quality`,会报 `TypeError: edit() got an unexpected keyword argument 'quality'`。 **请求示例(multipart)** cURL: ```bash curl https://api.lyrouter.com/v1/images/edits \ --max-time 300 \ -H "Authorization: Bearer $LYROUTER_API_KEY" \ -F model=openai/gpt-image-2 \ -F quality=medium \ -F image=@cat.png \ -F prompt="把背景换成雪山" ``` Python: ```python import base64 import os from openai import OpenAI client = OpenAI( api_key=os.environ["LYROUTER_API_KEY"], base_url="https://api.lyrouter.com/v1", timeout=300, ) with open("cat.png", "rb") as image: result = client.images.edit( model="openai/gpt-image-2", image=image, prompt="把背景换成雪山", quality="medium", ) with open("cat-snow.png", "wb") as f: f.write(base64.b64decode(result.data[0].b64_json)) print(result.usage) ``` Node.js: ```js import { createReadStream, writeFileSync } from "node:fs"; import OpenAI, { toFile } from "openai"; const client = new OpenAI({ apiKey: process.env.LYROUTER_API_KEY, baseURL: "https://api.lyrouter.com/v1", timeout: 300_000, }); const result = await client.images.edit({ model: "openai/gpt-image-2", // 用 toFile 指明图片类型:直接传 createReadStream 时文件段的类型是 application/octet-stream,上游返回 400 image: await toFile(createReadStream("cat.png"), "cat.png", { type: "image/png" }), prompt: "把背景换成雪山", quality: "medium", }); writeFileSync("cat-snow.png", Buffer.from(result.data[0].b64_json, "base64")); console.log(result.usage); ``` ### JSON 以 `google/gemini-3-pro-image` 为例,把图片转成 Base64 放进请求体: **请求示例(JSON)** cURL: ```bash printf '{"model":"google/gemini-3-pro-image","prompt":"把背景换成雪山","image":"data:image/png;base64,%s"}' \ "$(base64 < cat.png | tr -d '\n')" > body.json curl https://api.lyrouter.com/v1/images/edits \ --max-time 300 \ -H "Authorization: Bearer $LYROUTER_API_KEY" \ -H "Content-Type: application/json" \ --data-binary @body.json ``` Python: ```python import base64 import os import httpx with open("cat.png", "rb") as f: b64 = base64.b64encode(f.read()).decode() resp = httpx.post( "https://api.lyrouter.com/v1/images/edits", headers={"Authorization": f"Bearer {os.environ['LYROUTER_API_KEY']}"}, json={ "model": "google/gemini-3-pro-image", "prompt": "把背景换成雪山", "image": f"data:image/png;base64,{b64}", # 多张图时传数组 }, timeout=300, ) resp.raise_for_status() with open("cat-snow.png", "wb") as f: f.write(base64.b64decode(resp.json()["data"][0]["b64_json"])) ``` Node.js: ```js import { readFileSync, writeFileSync } from "node:fs"; const b64 = readFileSync("cat.png").toString("base64"); const resp = await fetch("https://api.lyrouter.com/v1/images/edits", { method: "POST", headers: { Authorization: `Bearer ${process.env.LYROUTER_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ model: "google/gemini-3-pro-image", prompt: "把背景换成雪山", image: `data:image/png;base64,${b64}`, // 多张图时传数组 }), signal: AbortSignal.timeout(300_000), }); const result = await resp.json(); if (!resp.ok) throw new Error(JSON.stringify(result.error)); writeFileSync("cat-snow.png", Buffer.from(result.data[0].b64_json, "base64")); ``` ## 响应 响应格式与[图像生成](https://platform.lyrouter.com/ai_gateway/docs/images-generations)相同:成功时图片在顶层 `data` 数组中,以 `b64_json` 返回;出错时返回 `error` 对象。下面的 200 是 GPT-Image 的编辑结果(上文 multipart 示例,未传 `size`),400 是开启严格模式时给 Gemini 传了它不支持的 `quality`,403 是模型未开通,或使用了虚拟模型、Auto。 **响应示例** 200: ```json { "created": 1791950400, "data": [ { "b64_json": "iVBORw0KGgoAAAANSUhEUgAA…" } ], "size": "1254x1254", "quality": "medium", "output_format": "png", "background": "opaque", "usage": { "input_tokens": 1036, "input_tokens_details": { "text_tokens": 12, "image_tokens": 1024 }, "output_tokens": 2058, "total_tokens": 3094 } } ``` 400: ```json { "error": { "message": "unsupported parameters for this model: quality", "type": "invalid_request_error", "code": "unsupported_parameters" } } ``` 403: ```json { "error": { "message": "Model is not available in the model plaza", "type": "access_denied", "code": "model_not_available" } } ``` | 字段 | 说明 | | --- | --- | | `created` | Unix 时间戳(秒)。Gemini 不返回这个字段 | | `data` | 产物数组,只生成一张时也是数组 | | `data[].b64_json` | Base64 编码的图片 | | `size`、`quality`、`output_format`、`background` | 本次实际使用的生成参数(GPT-Image 返回) | | `usage` | 计量信息。GPT-Image 在 `input_tokens_details` 中分开报文字与图片 Token;Gemini 的输入图片计入 `input_tokens`,有思考 Token 时另有 `output_tokens_details.reasoning_tokens`。各字段见[图像生成](https://platform.lyrouter.com/ai_gateway/docs/images-generations) | 单价以控制台模型广场为准,每次调用的实际扣费在[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)中查看。 ### 响应头 | 响应头 | 说明 | | --- | --- | | `X-Gateway-Unsupported-Parameters` | 网关丢弃了参数时出现(只会发生在 Gemini 上),值为逗号分隔的参数名,例如 `n,quality`。请求照常执行,列出的参数没有生效 | 配置了配额时,响应还会带 `x-aigw-quota-*` 系列响应头,见[网关扩展请求头与响应头](https://platform.lyrouter.com/ai_gateway/docs/gateway-headers)。 ## 网关行为 与直接调用上游相比,经 LYRouter 调用有以下差别: - **两种请求体**:GPT-Image 的 multipart 请求只改写 `model` 字段,文件原样转发;JSON 请求原样转发。Gemini 的两种写法都先归一成同一组字段,再翻译成 Gemini 的格式,因此行为完全相同。 - **只用指定的模型**:图像接口不会改用其他模型。同一模型有多个通道时,失败后依次尝试其他通道;虚拟模型、Auto 智能路由和工作空间默认模型的回退都不用于图像接口,见[失败重试与备用模型](https://platform.lyrouter.com/ai_gateway/docs/fallback)。 - **丢弃参数与严格模式**:只有 Gemini 会丢弃参数,并在响应头 `X-Gateway-Unsupported-Parameters` 中列出;带 `X-Gateway-Strict-Parameters: true` 时改为直接返回 400、不调用上游、不计费。GPT-Image 的参数全部原样转发,是否被接受由上游判断。 - **上游在成功响应里声明错误**:Gemini 的上游拒绝请求时可能返回 HTTP 200 而没有图片。网关把它改写成错误响应:上游拒绝时 `error.code` 为 `upstream_rejected`,`error.message` 是上游原文;没有产出图片时为 `upstream_no_artifact`,并带 `upstream_finish_reason`(如 `NO_IMAGE`、`SAFETY`)。`upstream_status` 保留上游原本的 200。这类错误不换通道重试,请按提示修改提示词或图片。 - **上游错误原样返回**:GPT-Image 的参数和图片错误由上游返回,格式和错误码以上游为准。上游返回错误状态却没有响应体时,网关补一个错误体,带 `upstream_status` 和 `generated_by: "ai-gateway"`;上游提供了请求 ID 时还带 `upstream_request_id`,向服务商报障时提供它。 - **日志中不保存图片**:请求和响应中的 Base64 图片在日志里替换成 `[base64 <字节数>B #]` 摘要,日志详情里看不到图片不代表请求失败,图片在响应体里。 - **超时**:编辑同样是同步返回,GPT-Image 系列常需数分钟。客户端超时请设为不低于 300 秒;客户端超时后不要立即重复提交,先在[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)中确认上一次请求的结果。 ## 常见错误 网关返回的错误为 `{"error":{"message":"...","type":"...","code":"..."}}`;GPT-Image 的参数错误由上游返回,格式以上游为准。 | 状态码 | `error.message` | `error.code` | 原因与处理 | | --- | --- | --- | --- | | 400 | `unsupported parameters for this model: <参数名>` | `unsupported_parameters` | 带了 `X-Gateway-Strict-Parameters: true`,且给 Gemini 传了它不支持的参数。删掉列出的参数 | | 400 | `prompt is required for this model` | `invalid_parameter` | 调用 Gemini 时没有写 `prompt` 或为空 | | 400 | ``image[<序号>]: cannot determine the image MIME type; send a data URI such as `data:image/png;base64,` `` | `invalid_parameter` | Gemini 认不出第几张图的格式,例如传了图片 URL。改写成 data URI | | 400 | `inline file parts exceed the limit of 31457280 bytes` | `invalid_parameter` | 调用 Gemini 时 multipart 中的文件合计超过 30 MB。压缩图片后重试 | | 400 | `you must provide a model parameter` | `missing_model` | 没有写 `model`(multipart 写法缺少 `model` 字段同样如此),工作空间也没有默认模型。图像接口请总是写明模型 ID | | 400 | `This model does not support the images_edits operation` | `unsupported_model_operation` | 所选模型不支持图像编辑。换用 GPT-Image 或 Gemini;Seedream 的图生图请用[图像生成](https://platform.lyrouter.com/ai_gateway/docs/images-generations) | | 400 | `This model does not support the images API` | `unsupported_model_api` | 模型声明的接口类型([列出模型](https://platform.lyrouter.com/ai_gateway/docs/models)中的 `api_types`)不含图像接口,例如用对话模型调用本接口。没有声明 `api_types` 的对话模型不会触发这条,请求会转发给上游,可能返回 404 `upstream_not_found` 等上游错误。图像接口请只用图像模型 | | 400 | 上游原文,例如 `Request contains an invalid argument.` | `upstream_rejected` | Gemini 的上游拒绝了请求,按原文修改参数或图片 | | 400 | `upstream produced no image (finishReason: <原因>)` | `upstream_no_artifact` | Gemini 没有产出图片,按 `upstream_finish_reason` 修改提示词或图片后重试 | | 400 | 上游原文,例如 `Invalid size '<宽>x<高>'. Width and height must both be divisible by 16.`、`Invalid size '<宽>x<高>'. Requested resolution is below the current minimum pixel budget.` | — | GPT-Image 的 `size` 不满足四条硬约束之一,按[图像生成](https://platform.lyrouter.com/ai_gateway/docs/images-generations#gpt-image-2-2-5-flare-2-5-sunburst)中的约束表调整 | | 400 | 上游原文 | `INVALID_REQUEST_BODY` | GPT-Image 请求体不合法,先检查是否传了 `quality`:`gpt-image-2` 不传会间歇性返回 400 | | 403 | `Model is not available in the model plaza` | `model_not_available` | 工作空间没有开通这个模型,或者写了 `@vmodel/<名称>`、`lyrouter/auto`。请管理员在模型广场开通,或改写已开通的具体模型 ID | - 401 / 403 鉴权问题见[401 / 403:鉴权与权限](https://platform.lyrouter.com/ai_gateway/docs/auth-errors),429 见[429:限流与配额](https://platform.lyrouter.com/ai_gateway/docs/rate-errors)。 - 500 / 504 是连接上游失败或等待上游超时,响应体是 HTML 页面而不是 JSON,见[超时与流式中断](https://platform.lyrouter.com/ai_gateway/docs/stream-errors)。 - 完整列表见[错误码与请求标识](https://platform.lyrouter.com/ai_gateway/docs/errors)。 --- # 列出模型 来源: https://platform.lyrouter.com/ai_gateway/docs/models 返回当前 API Key 可以写进 `model` 的全部名称:Key 所属工作空间已开通、且安全围栏模型策略允许这个 Key 调用的模型,外加已启用的虚拟模型(`@vmodel/<名称>`)和 `lyrouter/auto`。响应是 OpenAI 的模型列表格式,适合客户端填充模型选择器,或在启动时检查配置的模型是否可用。这个接口由网关直接应答,不调用上游、不计费,也不写入日志列表。 `GET /v1/models` ## 鉴权 在请求头中携带 API Key: ```text Authorization: Bearer ``` `Bearer` 区分大小写。也可以改用 `x-api-key: `,两者同时存在时只读 `Authorization`。API Key 在工作空间的 **API 密钥** 页面创建,列表按这个 Key 所属的工作空间和适用的模型策略生成。完整说明见[接入地址与鉴权](https://platform.lyrouter.com/ai_gateway/docs/call-gateway)。 ## 请求头 | 请求头 | 必填 | 说明 | | --- | --- | --- | | `Authorization` 或 `x-api-key` | 是 | 二选一,见上文「鉴权」 | GET 请求没有请求体,不需要 `Content-Type`。 ## 查询参数 无。列表不分页,一次返回全部条目;请求中带的查询参数会被忽略。 ## 请求示例 **请求示例** cURL: ```bash curl https://api.lyrouter.com/v1/models \ -H "Authorization: Bearer $LYROUTER_API_KEY" ``` Python: ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["LYROUTER_API_KEY"], base_url="https://api.lyrouter.com/v1", ) for model in client.models.list(): print(model.id) ``` Node.js: ```js import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.LYROUTER_API_KEY, baseURL: "https://api.lyrouter.com/v1", }); for await (const model of client.models.list()) { console.log(model.id); } ``` ## 响应 成功时返回 `Content-Type: application/json` 的模型列表;出错时返回 `error` 对象。下面的 401 是请求没有带 API Key,503 是网关暂时读不到工作空间的模型配置。 **响应示例** 200: ```json { "object": "list", "data": [ { "id": "deepseek/deepseek-v4-flash", "object": "model", "created": 1791964800, "owned_by": "workspace", "display_name": "DeepSeek V4 Flash", "context_length": 131072, "max_output_tokens": 8192, "api_types": ["chat_completions", "responses"], "input_modalities": ["text"], "output_modalities": ["text"], "supported_params": ["temperature", "top_p", "max_tokens", "tools", "tool_choice", "response_format", "stream"] }, { "id": "google/gemini-3-pro-image", "object": "model", "created": 1791964800, "owned_by": "workspace", "display_name": "Gemini 3 Pro Image", "api_types": ["images"], "input_modalities": ["text", "image"], "output_modalities": ["image"] }, { "id": "lyrouter/auto", "object": "model", "created": 1791964800, "owned_by": "workspace" }, { "id": "@vmodel/support-bot", "object": "model", "created": 1791964800, "owned_by": "workspace" } ] } ``` 401: ```json { "error": { "message": "missing credentials", "type": "invalid_request_error" } } ``` 503: ```json { "error": { "message": "Workspace model projection is unavailable", "type": "service_unavailable", "code": "workspace_model_projection_unavailable" } } ``` 条目顺序固定:先是具体模型,按模型 ID 的字母顺序排列;然后是 `lyrouter/auto`;最后是虚拟模型,按名称排列。 | 字段 | 类型 | 说明 | | --- | --- | --- | | `object` | string | 固定为 `list` | | `data[].id` | string | 写进请求 `model` 的名称,原样使用 | | `data[].object` | string | 固定为 `model` | | `data[].created` | integer | 生成这次响应的 Unix 时间(秒),所有条目相同,不是模型的发布时间 | | `data[].owned_by` | string | 固定为 `workspace`,不表示模型厂商或服务商 | | `data[].display_name` | string | 模型在模型广场上的显示名称,适合在界面上展示;调用时仍使用 `id` | | `data[].context_length` | integer | 上下文长度(Token) | | `data[].max_output_tokens` | integer | 最大输出长度(Token) | | `data[].api_types` | string[] | 模型声明支持的接口,如 `chat_completions`、`responses`、`embeddings`、`rerank`、`images`、`videos`;也可能是更细的操作,如 `images_edits` | | `data[].input_modalities` / `output_modalities` | string[] | 输入、输出模态,如 `text`、`image` | | `data[].supported_params` | string[] | 模型声明支持的请求参数,仅供参考,网关不据此删减对话请求的参数 | - `display_name` 及其后的字段只出现在具体模型上,并且只在模型目录有这项信息时才返回;字段缺失或为空数组(如 `"api_types": []`)都表示「没有声明」,不是「不支持」。 - `lyrouter/auto` 和虚拟模型只有 `id`、`object`、`created`、`owned_by` 四个字段,它们实际调用的模型由路由时决定。 - 响应始终是 OpenAI 格式,没有 Anthropic Models 接口的 `has_more`、`first_id` 等字段;使用 Anthropic SDK 的应用请直接发 HTTP 请求读取 `data[].id`。 ### 列表包含哪些名称 | 类别 | 是否列出 | 条件 | | --- | --- | --- | | 模型广场「专属可用模型」中的模型 | 列出 | 按这个 Key 适用的安全围栏模型策略过滤:被策略禁止,或不在允许列表中的模型不列出 | | 「可启用」「需接入」中的模型 | 不列出 | 在本工作空间开通或通过 BYOK 接入后才会出现 | | 已启用的虚拟模型 | 列出,写作 `@vmodel/<名称>` | 不按模型策略过滤;已停用、已删除的虚拟模型不列出 | | `lyrouter/auto` | 总是列出 | 不按模型策略过滤,也不受 Auto 候选范围影响 | ### 与模型广场的关系 两者的范围相同,都是当前工作空间已开通的模型,区别在于展示对象: | | 模型广场 | `GET /v1/models` | | --- | --- | --- | | 看的人 | 登录控制台的成员 | 持有 API Key 的程序 | | 模型策略 | 受限的服务商显示「成员访问受限」 | 直接不列出受限模型 | | 粒度 | 每个模型下按服务商列出状态和价格 | 每个模型一条,不显示服务商 | | 虚拟模型、Auto | 不显示 | 列出 | | 显示名称 | 卡片标题 | `display_name` 字段 | 模型广场中某个模型可用、列表中却没有它时,通常是安全围栏的模型策略限制了这个 Key,请当前账号管理员查看[模型授权](https://platform.lyrouter.com/ai_gateway/docs/authorization)。公开的模型广场展示的是平台全部模型,与某个工作空间可调用的范围不同。 ## 常见用法 ### 填充客户端的模型选择器 用 `display_name` 展示、`id` 提交。只列对话模型时,保留 `api_types` 包含 `chat_completions`(使用 Responses 的客户端看 `responses`)的条目,没有 `api_types` 或 `api_types` 为空数组的条目和 `lyrouter/auto`、虚拟模型一起保留: ```python import os from openai import OpenAI client = OpenAI(api_key=os.environ["LYROUTER_API_KEY"], base_url="https://api.lyrouter.com/v1") def is_chat(model): extra = model.model_extra or {} api_types = extra.get("api_types") return not api_types or "chat_completions" in api_types options = [ {"value": m.id, "label": (m.model_extra or {}).get("display_name") or m.id} for m in client.models.list() if is_chat(m) ] ``` `display_name`、`api_types` 等不是 OpenAI 的标准字段,OpenAI Python SDK 把它们放在 `model_extra` 中;Node.js SDK 直接作为对象属性读取。 按 `api_types` 筛选向量模型、重排模型的命令见[创建向量](https://platform.lyrouter.com/ai_gateway/docs/embeddings)和[文档重排](https://platform.lyrouter.com/ai_gateway/docs/rerank)。 ### 启动时检查配置的模型 应用启动时请求一次列表,确认配置文件里的模型 ID 在 `data[].id` 中;不在时提示「模型未开通或无权调用」,比等到第一次调用才收到 403 更容易排查。列表可以缓存几分钟,不必每次调用前都请求。 ## 网关行为 - **由网关直接应答**:网关按工作空间的配置生成列表,不调用上游服务商、不计费;模型发现请求不写入日志列表。 - **列表不代表一定调得通**:网关生成列表时不检查服务商凭证当前是否可用,也不检查余额、预算和配额。列出的模型仍可能因凭证失效返回 503,或因余额不足返回 402,见[模型不可用](https://platform.lyrouter.com/ai_gateway/docs/unavailable)。 - **虚拟模型和 Auto 在调用时才检查**:它们实际选中的模型被模型策略禁止时,调用返回 403 `Request blocked by guardrail policy`。 - **接口能力要另行判断**:列表包含对话、向量、图像等各类模型。只给对话界面用时,按 `api_types` 或 `output_modalities` 筛选,见上文「常见用法」。 - **配置变化几秒后生效**:在模型广场开通或停用模型、启用或停用虚拟模型、修改模型策略后,几秒内反映到列表中。 ## 常见错误 错误响应为 `{"error":{"message":"...","type":"...","code":"..."}}`,`code` 只有部分错误才有。 | 状态码 | `error.message` | `error.code` | 原因与处理 | | --- | --- | --- | --- | | 401 | `missing credentials` | — | 没有带 API Key,见[401 / 403:鉴权与权限](https://platform.lyrouter.com/ai_gateway/docs/auth-errors) | | 401 | `invalid api key` | — | 网关找不到这个 Key:复制不完整,或 Key 已删除、停用、过期,见[401 / 403:鉴权与权限](https://platform.lyrouter.com/ai_gateway/docs/auth-errors) | | 402 | `subscription expired; renew to continue` | — | 账户订阅已到期且已过宽限期,请当前账号管理员续费 | | 403 | `api key expired` | — | Key 已过期 | | 403 | `your IP address is not allowed` | — | 请求的出口 IP 不在 Key 的 IP 白名单中 | | 503 | `Workspace model projection is unavailable` | `workspace_model_projection_unavailable` | 网关暂时读不到工作空间的模型配置,属于平台侧问题,稍后重试 | - 用了 GET 以外的方法,或路径拼错(如 `/v1/models/` 末尾多了 `/`)时返回 404,响应体是 `{"error_msg":"404 Route Not Found"}`,外层没有 `error`。 - 完整错误码见[错误码与请求标识](https://platform.lyrouter.com/ai_gateway/docs/errors)。 ## 常见问题 ### 列表里只有 `lyrouter/auto`,没有任何模型,怎么办? **答:** 工作空间还没有开通任何模型,或者安全围栏的模型策略禁止了这个 Key 调用全部模型。在工作空间的 **模型广场** 确认「专属可用模型」不为空,再请当前账号管理员检查模型策略,见[如何选择模型](https://platform.lyrouter.com/ai_gateway/docs/choose)和[模型授权](https://platform.lyrouter.com/ai_gateway/docs/authorization)。 ### 同一个模型由多个服务商提供,为什么列表里只有一条? **答:** 模型 ID 与服务商无关,一个模型只有一个 ID。调用时网关按[通道选择与路由策略](https://platform.lyrouter.com/ai_gateway/docs/routing)选择服务商,实际命中的服务商在请求日志的「服务商」中查看。 ### 列表里的 `id` 能直接用在图像、视频接口上吗? **答:** 具体模型的 `id` 可以,前提是 `api_types` 或 `output_modalities` 表明它支持该接口。`lyrouter/auto` 和 `@vmodel/<名称>` 用在图像、视频接口上返回 403 `Model is not available in the model plaza`:`lyrouter/auto` 只适合 Chat Completions、Anthropic Messages 和 Responses;虚拟模型除这三个接口外,也可以用于[创建向量](https://platform.lyrouter.com/ai_gateway/docs/embeddings)和[文档重排](https://platform.lyrouter.com/ai_gateway/docs/rerank),前提是它的模型列表全部是对应的向量或重排模型。 --- # Seedance 视频生成 来源: https://platform.lyrouter.com/ai_gateway/docs/video-seedance 用火山方舟的 Seedance 系列模型生成视频,支持文生视频、首帧 / 首尾帧生视频、参考图或参考视频生视频,以及视频编辑与延长。视频生成以异步任务的方式提供:提交后立即拿到任务 ID,轮询到完成后再下载视频。接口形状参照 OpenAI 的 Videos API,网关把统一的参数转换成火山方舟的格式;OpenAI 官方 SDK 的 `videos.create()` 可以直接提交任务,查询和下载建议用 HTTP 直接调用。任务生命周期的通用说明见[异步任务](https://platform.lyrouter.com/ai_gateway/docs/async)。 ## 支持的模型 | 模型 ID | 特点 | 时长与分辨率 | 计费口径 | | --- | --- | --- | --- | | `bytedance/doubao-seedance-2.5` | 能力最全:参考图最多 30 张,可输出 1080p(10bit)和 `mov`,支持用 `omni_reference_task_type` 声明任务类型 | 4~30 秒;480p、720p、1080p | 按输出 Token;按分辨率(480p / 720p 一档、1080p 一档)和有无视频输入分档 | | `bytedance/doubao-seedance-2.0-fast` | 2.0 系列,参考图最多 9 张,只输出 `mp4` | 4~15 秒;480p、720p | 按输出 Token;按有无视频输入分档 | | `bytedance/doubao-seedance-2.0-mini` | 与 2.0-fast 能力相同 | 4~15 秒;480p、720p | 按输出 Token;按有无视频输入分档 | 三个模型都支持文生视频、首帧 / 首尾帧生视频、图片参考、视频参考、视频编辑与延长、生成有声视频,输出宽高比可选 21:9、16:9、4:3、1:1、3:4、9:16 或自适应。模型需要在工作空间的模型广场开通后才能调用;具体单价以模型广场显示的为准。 ## 端点 | 方法 | 路径 | 用途 | | --- | --- | --- | | POST | `/v1/videos` | 提交视频生成任务,立即返回任务 ID | | GET | `/v1/videos/{id}` | 查询任务状态 | | GET | `/v1/videos/{id}/content` | 下载视频(302 跳转到视频地址) | | DELETE | `/v1/videos/{id}` | 删除已结束的任务;不能取消进行中的任务 | 完整地址为 `https://api.lyrouter.com` 加上表中的路径。 ## 鉴权 在请求头中携带 API Key: ```text Authorization: Bearer ``` `Bearer` 区分大小写。也可以改用 `x-api-key: `,两者同时存在时只读 `Authorization`。API Key 在工作空间的 **API 密钥** 页面创建,只用于 LYRouter 鉴权,不会转发给上游服务商。完整说明见[接入地址与鉴权](https://platform.lyrouter.com/ai_gateway/docs/call-gateway)。 同一工作空间内的任意 API Key 都能查询、下载该工作空间的任务;其他工作空间的 Key 查询时返回 404。 ## 请求头 | 请求头 | 必填 | 说明 | | --- | --- | --- | | `Content-Type` | 提交时必填 | `application/json`。`POST /v1/videos` 也接受 `multipart/form-data`,见下文「用表单提交」 | | `X-Gateway-Strict-Parameters` | 否 | 设为 `true` 时,请求中有会被丢弃的参数就直接返回 400,不提交任务、不计费,见[网关扩展请求头与响应头](https://platform.lyrouter.com/ai_gateway/docs/gateway-headers) | ## 提交任务 `POST /v1/videos` 提交一个视频生成任务。网关校验参数、转换成火山方舟的格式后提交给服务商,立即返回 `status` 为 `queued` 的任务对象,视频在后台生成。提交请求本身不产生费用。 ### 请求体 | 参数 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | `model` | string | 是 | 上表中的模型 ID。必须是具体的模型 ID:虚拟模型 `@vmodel/<名称>` 和 `lyrouter/auto` 返回 403,失败时也不会改用工作空间的默认模型 | | `prompt` | string | 是 | 提示词。用 `@图像1`、`@视频1` 指代参考素材;视频编辑、延长任务靠提示词表达意图,见下文「任务类型与限制」 | | `seconds` | integer | 否 | 视频时长(秒),必须是正整数。2.5 为 4~30,2.0 系列为 4~15;不写时用服务商的默认值。**视频编辑任务不要传** | | `size` | string | 否 | 分辨率,写成 `宽x高`(如 `1280x720`)或档位名(`480p`、`720p`、`1080p`),见下文「`size` 的两种写法」。`1080p` 仅 2.5 支持 | | `first_frame` | string | 否 | 首帧图片的 URL(首帧生视频),1 张。输出宽高比自动跟随首帧图片 | | `last_frame` | string | 否 | 尾帧图片的 URL,与 `first_frame` 一起使用(首尾帧生视频) | | `reference_image` | string \| string[] | 否 | 参考图的 URL,单张写字符串,多张写数组。2.5 最多 30 张,2.0 系列最多 9 张 | | `input_reference` | string | 否 | 参考**视频**的 URL,用于参考生视频、视频编辑和视频延长。只能传一个地址,写成数组返回 400 | | `generate_audio` | boolean | 否 | 是否生成有声视频,三个模型都支持。不传时默认开启,生成的视频带音轨 | | `watermark` | boolean | 否 | `true` 时在视频右下角加「AI生成」标识,默认不加 | | `output_format` | string | 否 | 输出格式:`mp4`(默认)或 `mov`。`mov` 仅 2.5 支持 | | `omni_reference_task_type` | string | 否 | 为 2.5 设计;2.0 系列传入目前不会报错,任务照常生成并计费。显式声明任务类型:`auto`(默认)、`reference`、`edit`、`extend`,见下文「任务类型与限制」 | - 表中没有的字段会被丢弃,响应头 `X-Gateway-Unsupported-Parameters` 列出它们的名字;带 `X-Gateway-Strict-Parameters: true` 时改为返回 400。火山方舟原生的 `duration`、`resolution`、`ratio`、`content` 也属于这一类,请改用 `seconds`、`size` 和上面的素材字段。 - 本接口不支持 `n`,每次请求生成一个视频。 - `reference_audio`(参考音频)是例外:目前不会转发给 Seedance,传了不报错,也不会出现在 `X-Gateway-Unsupported-Parameters` 中,参考音频被直接忽略;需要参考音频时请改用 [MiniMax H3 视频生成](https://platform.lyrouter.com/ai_gateway/docs/video-minimax)。`source_video` 只用于 MiniMax H3 的视频升清,传给 Seedance 返回 400 `source_video is not supported for this model`。 - 素材地址要能被服务商访问。大文件请用公网 URL,不要用 Base64,请求体总大小不超过 64 MB。 ### 用表单提交 `POST /v1/videos` 也接受 `multipart/form-data`,OpenAI 官方 SDK 的 `videos.create()` 就用这种格式。表单中网关读取 `model`、`prompt`、`seconds`、`size`、`input_reference`、`watermark`、`generate_audio`、`output_format`、`omni_reference_task_type` 这几个字段: - **`input_reference` 只能传 URL,传文件不会报错但会被忽略**:请填可公开访问的 `https://` 地址;目前上传文件时,任务按没有参考视频的方式生成,并照常计费。 - `watermark`、`generate_audio` 只接受字面量 `true` 或 `false`。 - `first_frame`、`last_frame`、`reference_image` 请用 JSON 请求体提交。目前表单里的这些字段会被换成占位值转发给服务商,例如带 `first_frame` 时服务商返回 400 `The parameter content[1].image_url specified in the request is not valid`,报错不指向真实原因。 ### 请求示例 示例从环境变量 `LYROUTER_API_KEY` 读取 API Key,设置方法见[完成第一次模型调用](https://platform.lyrouter.com/ai_gateway/docs/quickstart)。 **请求示例** cURL: ```bash curl https://api.lyrouter.com/v1/videos \ -H "Authorization: Bearer $LYROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "bytedance/doubao-seedance-2.0-mini", "prompt": "一只柯基在草地上奔跑,阳光穿过树叶", "size": "1280x720", "seconds": 5, "generate_audio": true }' ``` Python: ```python import os import httpx resp = httpx.post( "https://api.lyrouter.com/v1/videos", headers={"Authorization": f"Bearer {os.environ['LYROUTER_API_KEY']}"}, json={ "model": "bytedance/doubao-seedance-2.0-mini", "prompt": "一只柯基在草地上奔跑,阳光穿过树叶", "size": "1280x720", "seconds": 5, "generate_audio": True, }, timeout=60, ) resp.raise_for_status() dropped = resp.headers.get("X-Gateway-Unsupported-Parameters") if dropped: print("这些参数没有生效:", dropped) task = resp.json() print(task["id"], task["status"]) ``` Node.js: ```js const resp = await fetch("https://api.lyrouter.com/v1/videos", { method: "POST", headers: { Authorization: `Bearer ${process.env.LYROUTER_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ model: "bytedance/doubao-seedance-2.0-mini", prompt: "一只柯基在草地上奔跑,阳光穿过树叶", size: "1280x720", seconds: 5, generate_audio: true, }), }); if (!resp.ok) throw new Error(await resp.text()); const dropped = resp.headers.get("X-Gateway-Unsupported-Parameters"); if (dropped) console.log("这些参数没有生效:", dropped); const task = await resp.json(); console.log(task.id, task.status); ``` ### 响应 提交成功返回 HTTP 200 和任务对象,`status` 为 `queued`,字段含义见下文「查询任务」。提交响应里没有 `usage`,费用在任务完成时结算。下面的 400 是 `seconds` 不是正整数,403 是模型没有在本工作空间开通(或用了虚拟模型、`lyrouter/auto`),429 是服务商账户的并发任务已满。 **响应示例** 200: ```json { "id": "aigwt_volcengine_videos_MXgno8VlzuzZtJl0kq83jA", "object": "video", "model": "doubao-seedance-2-0-mini-260615", "status": "queued", "progress": 0, "created_at": 1791950400, "expires_at": 1792555200, "seconds": 5, "size": "1280x720" } ``` 400: ```json { "error": { "message": "seconds must be a positive whole number of seconds", "type": "invalid_request_error", "code": "invalid_parameter" } } ``` 403: ```json { "error": { "message": "Model is not available in the model plaza", "type": "access_denied", "code": "model_not_available" } } ``` 429: ```json { "error": { "message": "upstream concurrency full", "type": "rate_limit_error", "code": "upstream_concurrency_full" } } ``` - 保存好返回的 `id`。查询时网络出错或超时,用同一个 ID 继续查询,不要重新提交:重新提交会生成新任务并再次计费。 - 429 `upstream_concurrency_full` 的并发限制按服务商账户共享,换一个 API Key 也一样,请稍后重新提交。 ## 查询任务 `GET /v1/videos/{id}` 读取任务的当前状态。网关在后台替你向服务商轮询进度,这个接口只返回网关记录的状态,查得更频繁不会更早拿到结果。 ### 路径参数 | 参数 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | `id` | string | 是 | 提交时返回的任务 ID,以 `aigwt_` 开头。服务商自己的任务 ID 查不到,返回 404 | ### 请求示例 **请求示例** cURL: ```bash curl https://api.lyrouter.com/v1/videos/$TASK_ID \ -H "Authorization: Bearer $LYROUTER_API_KEY" ``` Python: ```python import os import httpx task_id = "aigwt_volcengine_videos_MXgno8VlzuzZtJl0kq83jA" resp = httpx.get( f"https://api.lyrouter.com/v1/videos/{task_id}", headers={"Authorization": f"Bearer {os.environ['LYROUTER_API_KEY']}"}, timeout=60, ) resp.raise_for_status() task = resp.json() print(task["status"], task.get("usage"), task.get("error")) ``` Node.js: ```js const taskId = "aigwt_volcengine_videos_MXgno8VlzuzZtJl0kq83jA"; const resp = await fetch(`https://api.lyrouter.com/v1/videos/${taskId}`, { headers: { Authorization: `Bearer ${process.env.LYROUTER_API_KEY}` }, }); if (!resp.ok) throw new Error(await resp.text()); const task = await resp.json(); console.log(task.status, task.usage, task.error); ``` ### 响应 任务存在时总是返回 HTTP 200,任务本身失败也一样,以 `status` 判断结果。任务 ID 不存在、已超过 7 天或属于其他工作空间时返回 404。 **响应示例** 200 进行中: ```json { "id": "aigwt_volcengine_videos_MXgno8VlzuzZtJl0kq83jA", "object": "video", "model": "doubao-seedance-2-0-mini-260615", "status": "in_progress", "progress": 0, "created_at": 1791950400, "expires_at": 1792555200, "seconds": 5, "size": "1280x720" } ``` 200 已完成: ```json { "id": "aigwt_volcengine_videos_MXgno8VlzuzZtJl0kq83jA", "object": "video", "model": "doubao-seedance-2-0-mini-260615", "status": "completed", "progress": 100, "created_at": 1791950400, "completed_at": 1791950538, "expires_at": 1792555200, "seconds": 5, "size": "1280x720", "usage": { "duration_seconds": 5, "completion_tokens": 108900 } } ``` 200 已失败: ```json { "id": "aigwt_volcengine_videos_Qw3hTz0bVn1sLk8pYc4dRe", "object": "video", "model": "doubao-seedance-2-0-mini-260615", "status": "failed", "progress": 0, "created_at": 1791950400, "completed_at": 1791950482, "expires_at": 1792555200, "seconds": 5, "error": { "code": "OutputVideoSensitiveContentDetected", "message": "The request failed because the output video may contain sensitive information.", "provider_request_id": "021791950538123abcdef", "retryable": false } } ``` 404: ```json { "error": { "message": "video task not found", "type": "invalid_request_error", "code": "not_found" } } ``` | `status` | 含义 | 你需要做的 | | --- | --- | --- | | `queued` | 已受理,尚未开始生成 | 继续轮询 | | `in_progress` | 服务商正在生成 | 继续轮询 | | `completed` | 已完成 | 调用 `/content` 下载视频 | | `failed` | 已失败 | 读取 `error`,不收费 | | 字段 | 说明 | | --- | --- | | `id` | 网关的任务 ID,格式为 `aigwt_<服务商>_<任务类型>_<随机串>`。它不是服务商的任务 ID,向服务商报障时请用 `error.provider_request_id` | | `object` | 固定为 `video` | | `model` | 实际调用的上游模型名,例如 `doubao-seedance-2-0-mini-260615`,与请求中的模型 ID 写法不同 | | `status` | `queued`、`in_progress`、`completed`、`failed` 之一 | | `progress` | 完成前为 `0`,完成后为 `100`,不表示中间进度,请以 `status` 判断 | | `created_at` / `completed_at` | 提交时间、结束时间(Unix 秒)。`completed_at` 只在任务结束后出现 | | `expires_at` | 任务记录的过期时间,提交后 7 天。过期后查询返回 404 | | `seconds` / `size` | 原样回显提交时的值 | | `error` | 仅 `failed` 时出现:`code`、`message`,以及有值时才出现的 `provider_request_id`(服务商的请求标识)和 `retryable` | | `usage` | 任务完成后出现:`duration_seconds` 为视频秒数,`completion_tokens` 为服务商上报的输出 Token 数,Seedance 按它计费 | 失败任务的 `error.code` 多为服务商的错误码,原样返回: | `error.code` | 含义与处理 | | --- | --- | | `InvalidParameter.TaskTypeConstraint` | 任务类型与参数冲突,例如视频编辑任务传了 `seconds`。对照下文「任务类型与限制」修改参数 | | `InvalidParameter.TaskTypeMismatch` | 用 `omni_reference_task_type` 声明的类型与模型的判定不一致。按任务类型表中的关键词写提示词,或改用 `auto` | | `OutputVideoSensitiveContentDetected` 等 | 内容审核未通过,修改提示词或素材后重新提交 | | `upstream_error` | 服务商报告失败,但没有给出可识别的错误码 | - `error.retryable` 为 `false` 表示原样重试不会成功,需要修改请求;为 `true` 表示可以重试;没有这个字段表示网关无法判断,请不要把缺失当成 `false`。完整的取值见[异步任务](https://platform.lyrouter.com/ai_gateway/docs/async)。 - **轮询间隔**:提交后约 10 秒开始查询,之后逐步放宽到每 30 秒一次。 - **等待上限**:提交 24 小时后仍未完成的任务不会再有结果,也不收费,可以停止轮询。这时查询结果可能仍显示 `queued` 或 `in_progress`,任务的实际状态请在控制台工作空间的 **多媒体生成** 页面按任务 ID 搜索查看(「状态」显示「已过期」)。 ## 下载视频 `GET /v1/videos/{id}/content` 任务变为 `completed` 后调用,返回 302,`Location` 响应头是服务商提供的带签名的视频地址。让客户端跟随跳转即可下载:cURL 加 `-L`,Python `httpx` 设 `follow_redirects=True`,Node.js 的 `fetch` 默认跟随。 ### 请求示例 **请求示例** cURL: ```bash # 下载到本地 curl -L https://api.lyrouter.com/v1/videos/$TASK_ID/content \ -H "Authorization: Bearer $LYROUTER_API_KEY" \ -o video.mp4 # 只取视频地址,不下载 curl -s -o /dev/null -w '%{redirect_url}\n' \ https://api.lyrouter.com/v1/videos/$TASK_ID/content \ -H "Authorization: Bearer $LYROUTER_API_KEY" ``` Python: ```python import os import httpx task_id = "aigwt_volcengine_videos_MXgno8VlzuzZtJl0kq83jA" with httpx.stream( "GET", f"https://api.lyrouter.com/v1/videos/{task_id}/content", headers={"Authorization": f"Bearer {os.environ['LYROUTER_API_KEY']}"}, follow_redirects=True, timeout=600, ) as video: video.raise_for_status() with open("video.mp4", "wb") as f: for chunk in video.iter_bytes(): f.write(chunk) ``` Node.js: ```js import { writeFile } from "node:fs/promises"; const taskId = "aigwt_volcengine_videos_MXgno8VlzuzZtJl0kq83jA"; const video = await fetch(`https://api.lyrouter.com/v1/videos/${taskId}/content`, { headers: { Authorization: `Bearer ${process.env.LYROUTER_API_KEY}` }, }); if (!video.ok) throw new Error(`download failed: ${video.status}`); await writeFile("video.mp4", Buffer.from(await video.arrayBuffer())); ``` ### 响应 **响应示例** 302: ```text 状态码:302 Location: <服务商提供的带签名的视频地址> ``` 409: ```json { "error": { "message": "video is not ready yet", "type": "invalid_request_error", "code": "not_ready" } } ``` 404: ```json { "error": { "message": "video task not found", "type": "invalid_request_error", "code": "not_found" } } ``` - 视频地址在任务完成时确定,之后每次调用都跳转到同一个地址。地址的有效期由服务商决定,通常为 24 小时,过期后无法通过网关重新获取,请拿到后立即下载或转存到自己的存储。 - 任务还没完成(或已失败)时返回 409。这类 4xx 也会计入 API Key 的错误率,频繁调用可能触发[熔断](https://platform.lyrouter.com/ai_gateway/docs/rate-errors),请先查询到 `completed` 再下载。 ## 删除任务 `DELETE /v1/videos/{id}` 对已结束(`completed` 或 `failed`)的任务返回 HTTP 200 和任务对象,并带 `"deleted": true`;任务记录不会因此删除,在 `expires_at` 之前仍可查询和下载。对进行中的任务调用返回 409 `cancel_not_supported`:服务商不提供取消接口,请等待任务结束。OpenAI 官方 SDK 的 `videos.delete()` 读取的就是这个 `deleted` 字段。 ## Seedance 特有参数与限制 ### `size` 的两种写法 | 写法 | 网关怎么处理 | | --- | --- | | `宽x高`(如 `1280x720`) | 取**短边**作为分辨率档(`1280x720` → `720p`);宽高比与服务商支持的某个比例相差在 2% 以内时取该比例,否则按约分后的比例原样发出,由服务商返回 400(如 `1000x480` 报 `the parameter ratio specified in the request is not valid ...`) | | 档位名(如 `720p`、`1080p`) | 原样送出,宽高比由服务商按提示词自适应 | - 首帧 / 首尾帧生视频时,输出宽高比跟随首帧图片。 - Seedance 2.5 的 1080p 采用 10bit 位深 + H.265/HEVC 编码,少数播放器不兼容;`mov` 采用 H.264 + yuv444p + PCM。建议用 VLC、mpv、ffplay 或 IINA 播放。 ### 任务类型与限制 Seedance 会根据输入素材和提示词**自动判断任务类型**,不同类型有不同的限制: | 任务类型 | 怎么触发 | 限制 | | --- | --- | --- | | 文生视频 | 只传 `prompt` | 无特殊限制 | | 首帧 / 首尾帧生视频 | 传 `first_frame`(+ `last_frame`) | 输出宽高比自动跟随首帧图片 | | 参考生视频 | 传 `reference_image` / `input_reference` | 无特殊限制 | | **视频编辑** | 传 `input_reference`,并在提示词中表达编辑意图 | **不要传 `seconds`**;输出宽高比与时长自动跟随源视频;源视频时长须为 4~30 秒 | | **视频延长** | 传 `input_reference`,并在提示词中表达延长意图 | 输出宽高比自动跟随源视频 | 视频编辑任务的时长固定跟随源视频,而网关的 `seconds` 只接受正整数,所以编辑任务请直接不传 `seconds`;传了会被服务商拒绝(`InvalidParameter.TaskTypeConstraint`)。 使用 Seedance 2.5 时,可以用 `omni_reference_task_type` 显式声明任务类型,把服务商的异步失败提前成提交时的同步报错: | 值 | 含义 | 提示词需包含的关键词 | | --- | --- | --- | | `auto`(默认) | 由模型判断 | — | | `reference` | 参考生视频 | — | | `edit` | 视频编辑 | 编辑视频 / 增加 / 加上 / 删除 / 去掉 / 修改 / 替换 / 改成 | | `extend` | 视频延长 | 向前延长 / 向后延长 / 延续 / 续写 | `edit`、`extend` 只适用于带参考素材的场景:用在文生视频(不带参考素材)上,提交时直接返回 400,错误码为 `InvalidParameter.TaskTypeConstraint`,报错信息包含 `This parameter is only supported in the multimodal reference scenario, and is not applicable to text-to-video generation or first-frame / first-last-frame generation`。 声明的类型与模型实际判定的不一致时,任务可能异步失败(`InvalidParameter.TaskTypeMismatch`)。 ### 输入素材限制(Seedance 2.5) | 素材 | 限制 | | --- | --- | | 图片 | jpeg、png、webp、bmp、tiff、gif、heic、heif;宽高 [300, 6000] px;宽高比 [0.4, 2.5];单张 ≤ 30 MB;首帧 1 张 / 首尾帧 2 张 / 参考图 1~30 张 | | 视频 | mp4、mov(H.264 或 H.265,音频 AAC / MP3 / PCM);分辨率 480p 或 720p;时长 [2, 30] 秒(编辑任务 [4, 30] 秒);宽高 [300, 6000] px;宽高比 [0.4, 2.5];单个 ≤ 200 MB;帧率 [24, 60] | | 请求体 | 总大小 ≤ 64 MB,大文件请用公网 URL,不要用 Base64 | Seedance **不接受含真人人脸的参考图和参考视频**,会被输入审核拦截。 服务商的联网搜索、返回尾帧等能力没有对应的网关参数,目前无法通过 LYRouter 使用。 ### 计费 Seedance 按服务商上报的**输出 Token** 计费(任务对象中的 `usage.completion_tokens`),分档维度是分辨率和有无视频输入: | 模型 | 分档 | | --- | --- | | `bytedance/doubao-seedance-2.5` | 480p / 720p 与 1080p 两档,每档再按有无视频输入分 | | `bytedance/doubao-seedance-2.0-fast` | 只按有无视频输入分两档 | | `bytedance/doubao-seedance-2.0-mini` | 只按有无视频输入分两档 | - **有视频输入时按另一档单价计费,单价更低,但总价更高**:传了 `input_reference` 的任务(参考视频、视频编辑、视频延长)计量的 Token 大约是不带参考视频时的两倍(见下文「等效秒」),单价的下降抵不过用量的增加。只传首帧 / 首尾帧的图生视频不算视频输入。 - Token 数 = 固定开销 + 每秒 Token × 等效秒,已经体现了分辨率与时长的差异(实测 480p 4 秒约 40,594 Token,8 秒约 80,770,720p 4 秒约 87,300),不再按时长分档。不带参考视频时,等效秒就是输出秒数。 - **带参考视频时,等效秒不等于输出时长**:输出不超过 6 秒时,等效秒 = 输出秒数 + 参考视频秒数;超过 6 秒时,等效秒 = 1.5 × 输出秒数 + 2,与参考视频时长无关。6 秒是拐点,例如参考视频 5 秒时,输出 5 秒按 10 秒计量,输出 10 秒按 17 秒计量。视频编辑、视频延长同样按这条规则计量(实测)。 - 价格在提交时锁定;任务变为 `completed` 时按实际上报的 Token 数结算;`failed` 的任务(包括超时)不收费。在日志中查看任务费用的方法见[异步任务](https://platform.lyrouter.com/ai_gateway/docs/async)。 ## 完整调用示例 提交一个首帧生视频任务,轮询到结束后下载。把 `first_frame` 换成你自己的公网图片地址。cURL 示例需要 `jq`,请保存为脚本文件后用 `bash` 运行(出错时用 `exit` 退出)。 **完整示例** cURL: ```bash BASE=https://api.lyrouter.com/v1 AUTH="Authorization: Bearer $LYROUTER_API_KEY" # 1. 提交任务;没拿到任务 ID 就打印响应并退出,不要继续轮询 RESP=$(curl -s "$BASE/videos" -H "$AUTH" -H "Content-Type: application/json" \ -d '{ "model": "bytedance/doubao-seedance-2.0-mini", "prompt": "镜头缓慢推近,小猫转头看向窗外", "first_frame": "https://example.com/cat.jpg", "size": "720p", "seconds": 5 }') TASK_ID=$(echo "$RESP" | jq -r '.id // empty') if [ -z "$TASK_ID" ]; then echo "提交失败:$RESP"; exit 1; fi echo "task: $TASK_ID" # 2. 轮询:从 10 秒开始,逐步放宽到 30 秒,直到结束;最多等 2 小时 DELAY=10 GIVE_UP_AT=$(( $(date +%s) + 2 * 3600 )) while true; do if [ "$(date +%s)" -gt "$GIVE_UP_AT" ]; then echo "$TASK_ID 仍在生成,可稍后用同一个 ID 继续查询"; exit 1 fi sleep $DELAY DELAY=$(( DELAY * 3 / 2 > 30 ? 30 : DELAY * 3 / 2 )) TASK=$(curl -s "$BASE/videos/$TASK_ID" -H "$AUTH") STATUS=$(echo "$TASK" | jq -r '.status') echo "status: $STATUS" case "$STATUS" in completed|failed) break ;; queued|in_progress|"") ;; # 空值多为网络抖动:保留任务 ID 继续查 *) echo "查询出错:$TASK"; exit 1 ;; esac done # 3. 完成则下载,失败则打印原因 if [ "$STATUS" = "completed" ]; then curl -sL "$BASE/videos/$TASK_ID/content" -H "$AUTH" -o video.mp4 else echo "$TASK" | jq '.error' fi ``` Python: ```python import os import time import httpx BASE = "https://api.lyrouter.com/v1" HEADERS = {"Authorization": f"Bearer {os.environ['LYROUTER_API_KEY']}"} with httpx.Client(headers=HEADERS, timeout=60) as client: # 1. 提交任务 resp = client.post(f"{BASE}/videos", json={ "model": "bytedance/doubao-seedance-2.0-mini", "prompt": "镜头缓慢推近,小猫转头看向窗外", "first_frame": "https://example.com/cat.jpg", "size": "720p", "seconds": 5, }) resp.raise_for_status() task = resp.json() task_id = task.get("id") if not task_id: raise RuntimeError(f"没有拿到任务 ID:{task}") print("task:", task_id) # 2. 轮询:从 10 秒开始,逐步放宽到 30 秒;最多等 2 小时 delay, give_up_at = 10, time.time() + 2 * 3600 while task["status"] in ("queued", "in_progress"): if time.time() > give_up_at: raise TimeoutError(f"{task_id} 仍在生成,可稍后用同一个 ID 继续查询") time.sleep(delay) delay = min(delay * 1.5, 30) try: resp = client.get(f"{BASE}/videos/{task_id}") resp.raise_for_status() except httpx.TransportError: continue # 网络抖动:保留任务 ID 继续查,不要重新提交 task = resp.json() if task["status"] == "failed": err = task.get("error", {}) raise RuntimeError(f"{err.get('code')}: {err.get('message')}") # 3. 下载:接口返回 302,跟随跳转即可 with client.stream("GET", f"{BASE}/videos/{task_id}/content", follow_redirects=True, timeout=600) as video: video.raise_for_status() with open("video.mp4", "wb") as f: for chunk in video.iter_bytes(): f.write(chunk) print("已保存 video.mp4,用量:", task.get("usage")) ``` Node.js: ```js import { writeFile } from "node:fs/promises"; const BASE = "https://api.lyrouter.com/v1"; const headers = { Authorization: `Bearer ${process.env.LYROUTER_API_KEY}` }; const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); // 1. 提交任务 const submit = await fetch(`${BASE}/videos`, { method: "POST", headers: { ...headers, "Content-Type": "application/json" }, body: JSON.stringify({ model: "bytedance/doubao-seedance-2.0-mini", prompt: "镜头缓慢推近,小猫转头看向窗外", first_frame: "https://example.com/cat.jpg", size: "720p", seconds: 5, }), }); if (!submit.ok) throw new Error(await submit.text()); let task = await submit.json(); if (!task.id) throw new Error(`没有拿到任务 ID:${JSON.stringify(task)}`); console.log("task:", task.id); // 2. 轮询:从 10 秒开始,逐步放宽到 30 秒 let delay = 10_000; while (task.status === "queued" || task.status === "in_progress") { await sleep(delay); delay = Math.min(delay * 1.5, 30_000); let resp; try { resp = await fetch(`${BASE}/videos/${task.id}`, { headers }); } catch { continue; // 网络抖动:保留任务 ID 继续查,不要重新提交 } if (!resp.ok) throw new Error(await resp.text()); task = await resp.json(); } if (task.status === "failed") { throw new Error(`${task.error?.code}: ${task.error?.message}`); } // 3. 下载:fetch 默认跟随 302 跳转 const video = await fetch(`${BASE}/videos/${task.id}/content`, { headers }); if (!video.ok) throw new Error(`download failed: ${video.status}`); await writeFile("video.mp4", Buffer.from(await video.arrayBuffer())); console.log("saved video.mp4", task.usage); ``` ## 常见错误 错误响应为 `{"error":{"message":"...","type":"...","code":"..."}}`。 | 状态码 | `error.message` | `error.code` | 原因与处理 | | --- | --- | --- | --- | | 400 | `seconds must be a positive whole number of seconds` | `invalid_parameter` | `seconds` 不是正整数,例如写成了 `0`、负数或小数 | | 400 | `input_reference must be a non-empty URL string` | `invalid_parameter` | `input_reference` 为空或写成了数组。Seedance 只收一个参考视频地址 | | 400 | `generate_audio must be a boolean` | `invalid_parameter` | JSON 中 `generate_audio`(或 `watermark`)不是布尔值 | | 400 | `source_video is not supported for this model` | `invalid_parameter` | `source_video` 只用于 MiniMax H3 的视频升清,从请求中删掉 | | 400 | `unsupported parameters for this model: <参数名>` | `unsupported_parameters` | 带了 `X-Gateway-Strict-Parameters: true`,且请求中有会被丢弃的参数。删掉列出的参数或改用网关的参数名 | | 403 | `Model is not available in the model plaza` | `model_not_available` | 模型没有在本工作空间开通,或使用了虚拟模型、`lyrouter/auto`。换用已开通的具体模型 ID | | 404 | `video task not found` | `not_found` | 任务 ID 不存在、已超过 7 天、属于其他工作空间,或传入的是服务商的任务 ID | | 409 | `video is not ready yet` | `not_ready` | 任务还没完成(或已失败)就调用了 `/content`。先查询到 `completed` | | 409 | `cancelling an in-flight video task is not supported: ...` | `cancel_not_supported` | 对进行中的任务调用了 `DELETE`。请等待任务结束 | | 429 | `upstream concurrency full` | `upstream_concurrency_full` | 服务商账户的并发任务已满,换 API Key 无效,稍后重新提交 | - 用表单提交时 `input_reference` 只能传 URL。目前上传文件**不会报错**,文件会被忽略,任务按没有参考视频的方式生成并照常计费;只有填了非 URL 的文本(如 `video.mp4`)时才返回 400 纯文本 `input_reference must be a URL; uploading a file is not supported by this gateway (pass a publicly reachable https:// URL instead)`。这类由网关返回的纯文本报错,响应头目前仍是 `Content-Type: application/json`,解析前请先判断正文是不是 JSON。 - 分辨率、时长、素材数量等超出模型范围时,由服务商拒绝,状态码和报错原文由服务商决定;任务提交后才发现的问题以失败任务的形式返回,见上文「查询任务」。完整列表见[错误码与请求标识](https://platform.lyrouter.com/ai_gateway/docs/errors)。 ## 常见问题 ### 视频编辑任务失败并返回 `InvalidParameter.TaskTypeConstraint`,怎么办? **答:** 视频编辑任务的时长固定跟随源视频,请从请求中删掉 `seconds` 再提交。其他任务类型的限制见上文「任务类型与限制」。 ### 任务失败并返回 `InvalidParameter.TaskTypeMismatch`,怎么办? **答:** 用 `omni_reference_task_type` 声明的任务类型与模型的判定不一致。按任务类型表中的关键词改写提示词(例如编辑任务写明「替换」「去掉」),或改用 `auto` 让模型自行判断。 ### 请求 1080p 或 `mov` 被服务商拒绝,为什么? **答:** 1080p 和 `mov` 只有 `bytedance/doubao-seedance-2.5` 支持,2.0 系列只能输出 480p、720p 的 `mp4`。换用 2.5,或把 `size` 改为 `720p` 并去掉 `output_format`。 ### 下载的 1080p 视频打不开,怎么办? **答:** Seedance 2.5 的 1080p 是 10bit H.265/HEVC 编码,部分播放器不支持。用 VLC、mpv、ffplay 或 IINA 播放,或者自行转码。 ### 可以用 OpenAI 官方 SDK 调用吗? **答:** 可以用 `client.videos.create()` 提交任务,SDK 以表单格式提交,网关会转换成服务商需要的格式。Python SDK 需要 `openai` 2.x:实测 1.58.1 没有 `client.videos`,2.48.0 可用。表单中只能传 URL 形式的 `input_reference`:Python SDK 直接写 `input_reference="https://…"` 会在本地抛出 `RuntimeError: Expected entry at input_reference to be bytes, an io.IOBase instance, PathLike or a tuple …`,请求不会发出,请改用 `extra_body={"input_reference": "https://…"}`;Node.js SDK 运行时接受字符串,但 TypeScript 类型不允许,需要绕过类型检查。`size` 的档位名(如 `720p`)同样不在 SDK 的类型声明里,TypeScript 中需要绕过类型检查;首帧、尾帧、参考图请用 HTTP 发送 JSON 请求体。查询和下载建议按本页的 HTTP 写法调用。 ### 视频地址过期了,还能重新下载吗? **答:** 不能。视频地址在任务完成时确定,再次调用 `/content` 拿到的仍是同一个地址,过期后需要重新提交任务。请在任务完成后立即下载或转存。 ### 查询结果一直是 `in_progress`,怎么办? **答:** 视频生成通常需要几分钟。提交 24 小时后仍未完成的任务不会再有结果,也不收费,可以停止轮询,并在控制台 **多媒体生成** 页面按任务 ID 查看任务状态。不要在等待期间重复提交同样的请求,每次提交都会生成新任务并单独计费。 --- # MiniMax H3 视频生成 来源: https://platform.lyrouter.com/ai_gateway/docs/video-minimax 用 MiniMax H3 系列模型生成视频,支持文生视频、首尾帧图生视频,以及用参考图、参考视频、参考音频做多模态参考生视频。除了普通的视频生成,`minimax/minimax-h3` 还提供两个只有它支持的接口:视频升清(`POST /v1/videos/regenerations`,把 768P 视频重新生成为 2K)和上下文增强(`POST /v1/videos/context`,产物是增强后的提示词文本)。三种任务都以异步任务的方式提供,用同一个查询接口跟踪进度。接口形状参照 OpenAI 的 Videos API,网关把统一的参数转换成 MiniMax 的格式。任务生命周期的通用说明见[异步任务](https://platform.lyrouter.com/ai_gateway/docs/async)。 ## 支持的模型 | 模型 ID | 特点 | 时长与分辨率 | 计费口径 | | --- | --- | --- | --- | | `minimax/minimax-h3` | 标准版:文生视频、首尾帧图生视频、多模态参考(参考图 / 视频 / 音频);支持视频升清和上下文增强 | 4~15 秒;480P、768P、2K | 视频按秒(输入 + 输出),按分辨率分档;升清单独一档;参考图单独计一项;上下文增强按输入、输出 Token 计 | | `minimax/minimax-h3-max` | **已被服务商下线,目前不可用,请改用 `minimax/minimax-h3`**。极速版:文生视频、首尾帧图生视频、多模态参考;不支持多张参考图,不支持升清和上下文增强 | 5~15 秒;480P、768P | 视频按秒,按 480P、768P 分档;参考图单独计一项 | > [!warning] > `minimax/minimax-h3-max` 已被服务商下线:目前调用它会返回 HTTP 200,但任务对象是空的、没有任务 ID,无法轮询,也不扣费。请改用 `minimax/minimax-h3`。 模型需要在工作空间的模型广场开通后才能调用;具体单价以模型广场显示的为准。 ## 端点 | 方法 | 路径 | 用途 | | --- | --- | --- | | POST | `/v1/videos` | 提交视频生成任务,立即返回任务 ID | | GET | `/v1/videos/{id}` | 查询任务状态,三种任务通用 | | GET | `/v1/videos/{id}/content` | 下载视频(302 跳转到视频地址) | | POST | `/v1/videos/regenerations` | 视频升清:把 H3 生成的 768P 视频重新生成为 2K,仅 `minimax/minimax-h3` | | POST | `/v1/videos/context` | 上下文增强:把多模态上下文整理成更丰富的提示词,产物是文本,仅 `minimax/minimax-h3` | | DELETE | `/v1/videos/{id}` | 删除已结束的任务;不能取消进行中的任务 | 完整地址为 `https://api.lyrouter.com` 加上表中的路径。三个提交接口用的是同一个模型名、同一套任务 ID,返回的任务都用 `GET /v1/videos/{id}` 查询。 ## 鉴权 在请求头中携带 API Key: ```text Authorization: Bearer ``` `Bearer` 区分大小写。也可以改用 `x-api-key: `,两者同时存在时只读 `Authorization`。API Key 在工作空间的 **API 密钥** 页面创建,只用于 LYRouter 鉴权,不会转发给上游服务商。完整说明见[接入地址与鉴权](https://platform.lyrouter.com/ai_gateway/docs/call-gateway)。 同一工作空间内的任意 API Key 都能查询、下载该工作空间的任务;其他工作空间的 Key 查询时返回 404。 ## 请求头 | 请求头 | 必填 | 说明 | | --- | --- | --- | | `Content-Type` | 提交时必填 | `application/json`。`POST /v1/videos` 也接受 `multipart/form-data`,见下文「用表单提交」;升清和上下文增强只接受 JSON | | `X-Gateway-Strict-Parameters` | 否 | 设为 `true` 时,请求中有会被丢弃的参数就直接返回 400,不提交任务、不计费,见[网关扩展请求头与响应头](https://platform.lyrouter.com/ai_gateway/docs/gateway-headers) | ## 提交任务 `POST /v1/videos` 提交一个视频生成任务。网关校验参数、转换成 MiniMax 的格式后提交给服务商,立即返回 `status` 为 `queued` 的任务对象,视频在后台生成。提交请求本身不产生费用。 ### 请求体 | 参数 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | `model` | string | 是 | `minimax/minimax-h3` 或 `minimax/minimax-h3-max`(已被服务商下线,目前不可用,请改用 `minimax/minimax-h3`)。必须是具体的模型 ID:虚拟模型 `@vmodel/<名称>` 和 `lyrouter/auto` 返回 403,失败时也不会改用工作空间的默认模型 | | `prompt` | string | 是 | 提示词 | | `seconds` | integer | 是 | 视频时长(秒),必须是正整数。H3 为 4~15,H3-Max 为 5~15(H3-Max 已被服务商下线,目前不可用)。MiniMax 要求提供时长,网关不补默认值 | | `size` | string | 是 | 分辨率:档位名(`480P`、`768P`、`2K`)或 `宽x高`(短边必须正好是 480 或 768),见下文「`size`:短边必须正好落在档位上」。H3-Max 不支持 `2K`(H3-Max 已被服务商下线,目前不可用)。MiniMax 要求提供分辨率 | | `first_frame` | string | 否 | 首帧图片的 URL(图生视频),1 张 | | `last_frame` | string | 否 | 尾帧图片的 URL,1 张 | | `reference_image` | string \| string[] | 否 | 参考图的 URL,单张写字符串,多张写数组,最多 9 张 | | `input_reference` | string \| string[] | 否 | 参考**视频**的 URL,最多 3 个 | | `reference_audio` | string \| string[] | 否 | 参考音频的 URL,最多 3 个 | | `watermark` | boolean | 否 | 是否给视频加水印 | - **图生视频与多模态参考互斥**:传了 `reference_image`、`input_reference` 或 `reference_audio`,就不能再传 `first_frame` / `last_frame`,反之亦然。这条由服务商校验。 - 以下参数在网关契约里存在(其他模型用得上),但 MiniMax 没有对应概念,传了返回 400 `<参数名> is not supported for this model`:`generate_audio`(有声由参考音频承载)、`output_format`(没有容器格式选项)、`omni_reference_task_type`(没有全模态任务类型)、`source_video`(只属于视频升清接口)。 - 表中没有的其他字段会被丢弃,响应头 `X-Gateway-Unsupported-Parameters` 列出它们的名字;带 `X-Gateway-Strict-Parameters: true` 时改为返回 400。MiniMax 原生的 `duration`、`resolution`、`ratio`、`content` 也属于这一类,请改用 `seconds`、`size` 和上面的素材字段。 - 本接口不支持 `n`,每次请求生成一个视频。 ### 用表单提交 `POST /v1/videos` 也接受 `multipart/form-data`,OpenAI 官方 SDK 的 `videos.create()` 就用这种格式。表单中网关读取 `model`、`prompt`、`seconds`、`size`、`input_reference`、`watermark` 等字段: - **`input_reference` 只能传 URL,传文件不会报错但会被忽略**:请填可公开访问的 `https://` 地址;目前上传文件时,任务按没有参考视频的方式生成,并照常计费。 - `watermark` 只接受字面量 `true` 或 `false`。 - `first_frame`、`last_frame`、`reference_image`、`reference_audio` 请用 JSON 请求体提交。目前表单里的这些字段会被换成占位值转发给服务商,例如带 `reference_audio` 时提交返回 200,任务随后失败,`error.message` 为 `content[1].audio_url: invalid param: audio url must be http(s):// or data:...;base64`(失败不收费)。 ### 请求示例 示例从环境变量 `LYROUTER_API_KEY` 读取 API Key,设置方法见[完成第一次模型调用](https://platform.lyrouter.com/ai_gateway/docs/quickstart)。 **请求示例** cURL: ```bash curl https://api.lyrouter.com/v1/videos \ -H "Authorization: Bearer $LYROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "minimax/minimax-h3", "prompt": "史诗级太空歌剧预告:女舰长独自站在观景窗前", "size": "768P", "seconds": 5 }' ``` Python: ```python import os import httpx resp = httpx.post( "https://api.lyrouter.com/v1/videos", headers={"Authorization": f"Bearer {os.environ['LYROUTER_API_KEY']}"}, json={ "model": "minimax/minimax-h3", "prompt": "史诗级太空歌剧预告:女舰长独自站在观景窗前", "size": "768P", "seconds": 5, }, timeout=60, ) resp.raise_for_status() dropped = resp.headers.get("X-Gateway-Unsupported-Parameters") if dropped: print("这些参数没有生效:", dropped) task = resp.json() print(task["id"], task["status"]) ``` Node.js: ```js const resp = await fetch("https://api.lyrouter.com/v1/videos", { method: "POST", headers: { Authorization: `Bearer ${process.env.LYROUTER_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ model: "minimax/minimax-h3", prompt: "史诗级太空歌剧预告:女舰长独自站在观景窗前", size: "768P", seconds: 5, }), }); if (!resp.ok) throw new Error(await resp.text()); const dropped = resp.headers.get("X-Gateway-Unsupported-Parameters"); if (dropped) console.log("这些参数没有生效:", dropped); const task = await resp.json(); console.log(task.id, task.status); ``` ### 响应 提交成功返回 HTTP 200 和任务对象,`status` 为 `queued`,字段含义见下文「查询任务」。提交响应里没有 `usage`,费用在任务完成时结算。下面的 400 是 `size` 写成了 `1280x720`(短边 720 不在 MiniMax 的档位里),403 是模型没有在本工作空间开通(或用了虚拟模型、`lyrouter/auto`),429 是服务商账户的并发任务已满。 **响应示例** 200: ```json { "id": "aigwt_minimax_videos_Qm3Tz8VbN1sLk0pYc4dReA", "object": "video", "model": "MiniMax-H3", "status": "queued", "progress": 0, "created_at": 1791950400, "expires_at": 1792555200, "seconds": 5, "size": "768P" } ``` 400: ```json { "error": { "message": "this model takes discrete resolution tiers, not arbitrary sizes: 1280x720 (short side 720). Use a size whose short side is 480 or 768, or pass the tier name directly as size (e.g. \"768P\", \"2K\")", "type": "invalid_request_error", "code": "invalid_parameter" } } ``` 403: ```json { "error": { "message": "Model is not available in the model plaza", "type": "access_denied", "code": "model_not_available" } } ``` 429: ```json { "error": { "message": "upstream concurrency full", "type": "rate_limit_error", "code": "upstream_concurrency_full" } } ``` - 保存好返回的 `id`。查询时网络出错或超时,用同一个 ID 继续查询,不要重新提交:重新提交会生成新任务并再次计费。 - 429 `upstream_concurrency_full` 的并发限制按服务商账户共享,换一个 API Key 也一样,请稍后重新提交。 ## 查询任务 `GET /v1/videos/{id}` 读取任务的当前状态,视频生成、视频升清、上下文增强三种任务都用这个接口。网关在后台替你向服务商轮询进度,这个接口只返回网关记录的状态,查得更频繁不会更早拿到结果。 ### 路径参数 | 参数 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | `id` | string | 是 | 提交时返回的任务 ID,以 `aigwt_` 开头。服务商自己的任务 ID 查不到,返回 404 | ### 请求示例 **请求示例** cURL: ```bash curl https://api.lyrouter.com/v1/videos/$TASK_ID \ -H "Authorization: Bearer $LYROUTER_API_KEY" ``` Python: ```python import os import httpx task_id = "aigwt_minimax_videos_Qm3Tz8VbN1sLk0pYc4dReA" resp = httpx.get( f"https://api.lyrouter.com/v1/videos/{task_id}", headers={"Authorization": f"Bearer {os.environ['LYROUTER_API_KEY']}"}, timeout=60, ) resp.raise_for_status() task = resp.json() print(task["status"], task.get("usage"), task.get("error")) ``` Node.js: ```js const taskId = "aigwt_minimax_videos_Qm3Tz8VbN1sLk0pYc4dReA"; const resp = await fetch(`https://api.lyrouter.com/v1/videos/${taskId}`, { headers: { Authorization: `Bearer ${process.env.LYROUTER_API_KEY}` }, }); if (!resp.ok) throw new Error(await resp.text()); const task = await resp.json(); console.log(task.status, task.usage, task.error); ``` ### 响应 任务存在时总是返回 HTTP 200,任务本身失败也一样,以 `status` 判断结果。任务 ID 不存在、已超过 7 天或属于其他工作空间时返回 404。 **响应示例** 200 已完成: ```json { "id": "aigwt_minimax_videos_Qm3Tz8VbN1sLk0pYc4dReA", "object": "video", "model": "MiniMax-H3", "status": "completed", "progress": 100, "created_at": 1791950400, "completed_at": 1791950507, "expires_at": 1792555200, "seconds": 5, "size": "768P", "usage": { "duration_seconds": 5 } } ``` 200 上下文增强: ```json { "id": "aigwt_minimax_videos-context_Zp8Rk2Vt5Lq9Wx3Ny6Bh1A", "object": "video", "model": "MiniMax-H3", "status": "completed", "progress": 100, "created_at": 1791950400, "completed_at": 1791950421, "expires_at": 1792555200, "seconds": 5, "output_text": "integrated_multimodal_description: [Shot 1] Cinematic, a medium shot featuring a slow push-in on ...", "usage": { "completion_tokens": 1820 } } ``` 200 已失败: ```json { "id": "aigwt_minimax_videos_Fj4Ns7Kd2Pw9Lm5Qx8Rt3Y", "object": "video", "model": "MiniMax-H3", "status": "failed", "progress": 0, "created_at": 1791950400, "completed_at": 1791950482, "expires_at": 1792555200, "seconds": 5, "size": "768P", "error": { "code": "upstream_error", "message": "upstream task failed" } } ``` 404: ```json { "error": { "message": "video task not found", "type": "invalid_request_error", "code": "not_found" } } ``` | `status` | 含义 | 你需要做的 | | --- | --- | --- | | `queued` | 已受理,尚未开始生成 | 继续轮询 | | `in_progress` | 服务商正在生成 | 继续轮询 | | `completed` | 已完成 | 视频任务调用 `/content` 下载;上下文增强任务读取 `output_text` | | `failed` | 已失败 | 读取 `error`,不收费 | | 字段 | 说明 | | --- | --- | | `id` | 网关的任务 ID,格式为 `aigwt_<服务商>_<任务类型>_<随机串>`,例如 `aigwt_minimax_videos_…`、`aigwt_minimax_videos-regenerations_…`、`aigwt_minimax_videos-context_…`。它不是服务商的任务 ID,向服务商报障时请用 `error.provider_request_id` | | `object` | 固定为 `video`,上下文增强任务也一样 | | `model` | 实际调用的上游模型名,例如 `MiniMax-H3` | | `status` | `queued`、`in_progress`、`completed`、`failed` 之一 | | `progress` | 完成前为 `0`,完成后为 `100`,不表示中间进度,请以 `status` 判断 | | `created_at` / `completed_at` | 提交时间、结束时间(Unix 秒)。`completed_at` 只在任务结束后出现 | | `expires_at` | 任务记录的过期时间,提交后 7 天。过期后查询返回 404 | | `seconds` / `size` | 原样回显提交时的值,没有提交的不出现 | | `output_text` | 仅上下文增强任务有,为增强后的提示词 | | `error` | 仅 `failed` 时出现:`code`、`message`,以及有值时才出现的 `provider_request_id`(服务商的请求标识)和 `retryable` | | `usage` | 任务完成后出现:视频生成和升清为 `duration_seconds`(计费秒数:视频生成含参考视频的秒数;升清只计源视频的秒数),上下文增强为 `completion_tokens`(输出 Token 数) | - 失败任务的 `error.code` 是服务商给出的错误码;服务商没有给出可识别的错误码时为 `upstream_error`。`error.retryable` 为 `false` 表示原样重试不会成功,`true` 表示可以重试,没有这个字段表示网关无法判断。完整的取值见[异步任务](https://platform.lyrouter.com/ai_gateway/docs/async)。 - **轮询间隔**:提交后约 10 秒开始查询,之后逐步放宽到每 30 秒一次。 - **等待上限**:提交 24 小时后仍未完成的任务不会再有结果,也不收费,可以停止轮询。这时查询结果可能仍显示 `queued` 或 `in_progress`,任务的实际状态请在控制台工作空间的 **多媒体生成** 页面按任务 ID 搜索查看(「状态」显示「已过期」)。 ## 下载视频 `GET /v1/videos/{id}/content` 视频生成或升清任务变为 `completed` 后调用,返回 302,`Location` 响应头是服务商提供的带签名的视频地址。让客户端跟随跳转即可下载:cURL 加 `-L`,Python `httpx` 设 `follow_redirects=True`,Node.js 的 `fetch` 默认跟随。上下文增强任务的结果是 `output_text` 中的文本,没有视频可下载,不要对它调用这个接口:目前对已完成的上下文增强任务调用会返回 HTTP 500,正文是 HTML 页面,不是 JSON 错误。 ### 请求示例 **请求示例** cURL: ```bash # 下载到本地 curl -L https://api.lyrouter.com/v1/videos/$TASK_ID/content \ -H "Authorization: Bearer $LYROUTER_API_KEY" \ -o video.mp4 # 只取视频地址,不下载 curl -s -o /dev/null -w '%{redirect_url}\n' \ https://api.lyrouter.com/v1/videos/$TASK_ID/content \ -H "Authorization: Bearer $LYROUTER_API_KEY" ``` Python: ```python import os import httpx task_id = "aigwt_minimax_videos_Qm3Tz8VbN1sLk0pYc4dReA" with httpx.stream( "GET", f"https://api.lyrouter.com/v1/videos/{task_id}/content", headers={"Authorization": f"Bearer {os.environ['LYROUTER_API_KEY']}"}, follow_redirects=True, timeout=600, ) as video: video.raise_for_status() with open("video.mp4", "wb") as f: for chunk in video.iter_bytes(): f.write(chunk) ``` Node.js: ```js import { writeFile } from "node:fs/promises"; const taskId = "aigwt_minimax_videos_Qm3Tz8VbN1sLk0pYc4dReA"; const video = await fetch(`https://api.lyrouter.com/v1/videos/${taskId}/content`, { headers: { Authorization: `Bearer ${process.env.LYROUTER_API_KEY}` }, }); if (!video.ok) throw new Error(`download failed: ${video.status}`); await writeFile("video.mp4", Buffer.from(await video.arrayBuffer())); ``` ### 响应 **响应示例** 302: ```text 状态码:302 Location: <服务商提供的带签名的视频地址> ``` 409: ```json { "error": { "message": "video is not ready yet", "type": "invalid_request_error", "code": "not_ready" } } ``` 404: ```json { "error": { "message": "video task not found", "type": "invalid_request_error", "code": "not_found" } } ``` - 视频地址在任务完成时确定,之后每次调用都跳转到同一个地址。地址的有效期由服务商决定,通常为 24 小时,过期后无法通过网关重新获取,请拿到后立即下载或转存到自己的存储。 - 任务还没完成(或已失败)时返回 409。这类 4xx 也会计入 API Key 的错误率,频繁调用可能触发[熔断](https://platform.lyrouter.com/ai_gateway/docs/rate-errors),请先查询到 `completed` 再下载。 ## 视频升清 `POST /v1/videos/regenerations` 把一条 **H3 生成的 768P 视频**重新生成为 2K,仅 `minimax/minimax-h3` 支持。它只适用于 H3 自己产出、符合 768P 规格的视频,不是通用的视频放大。提交后返回同样的任务对象,用 `GET /v1/videos/{id}` 查询,完成后用 `/content` 下载。只接受 JSON 请求体。 ### 请求体 | 参数 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | `model` | string | 是 | `minimax/minimax-h3` | | `prompt` | string | 是 | 生成那条 768P 视频时**实际送入模型的最终提示词**。当时用过上下文增强的,填增强**之后**的提示词 | | `source_video` | string | 是 | 要升清的 768P 视频的 URL | | `size` | string | 否 | 目标分辨率,默认 `2K` | | `first_frame` / `last_frame` / `reference_image` / `input_reference` / `reference_audio` | — | 否 | 生成源视频时用过的参考素材,按当时的输入原样附上,写法同「提交任务」 | | `watermark` | boolean | 否 | 是否给视频加水印 | - **不要传 `seconds`**:时长由源视频决定,传了返回 400 `seconds is not supported for video regeneration (the source video determines the duration)`。 - `generate_audio`、`output_format`、`omni_reference_task_type` 同样返回 400 `<参数名> is not supported for this model`。 - 源视频必须满足:含音轨、24 fps、宽和高都能被 32 整除、面积在 589,824~1,032,192 像素之间、总帧数 107~362(每档递增 17 帧,约 4~15 秒)。 - 服务商要求 `prompt` 和参考素材与生成源视频时完全一致。给的不是当时那一份时**不会报错**,只是拿不到预期的效果,网关也无法替你校验。 ### 请求示例 **请求示例** cURL: ```bash curl https://api.lyrouter.com/v1/videos/regenerations \ -H "Authorization: Bearer $LYROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "minimax/minimax-h3", "prompt": "生成那条 768P 视频时实际送入模型的最终提示词", "source_video": "https://example.com/h3-768p.mp4", "size": "2K" }' ``` Python: ```python import os import httpx resp = httpx.post( "https://api.lyrouter.com/v1/videos/regenerations", headers={"Authorization": f"Bearer {os.environ['LYROUTER_API_KEY']}"}, json={ "model": "minimax/minimax-h3", "prompt": "生成那条 768P 视频时实际送入模型的最终提示词", "source_video": "https://example.com/h3-768p.mp4", "size": "2K", }, timeout=60, ) resp.raise_for_status() print(resp.json()["id"]) ``` Node.js: ```js const resp = await fetch("https://api.lyrouter.com/v1/videos/regenerations", { method: "POST", headers: { Authorization: `Bearer ${process.env.LYROUTER_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ model: "minimax/minimax-h3", prompt: "生成那条 768P 视频时实际送入模型的最终提示词", source_video: "https://example.com/h3-768p.mp4", size: "2K", }), }); if (!resp.ok) throw new Error(await resp.text()); console.log((await resp.json()).id); ``` ### 响应 提交成功返回 HTTP 200 和任务对象,`id` 以 `aigwt_minimax_videos-regenerations_` 开头;完成后的 `usage.duration_seconds` 为计费秒数。下面的 400 是没有传 `source_video`。 **响应示例** 200: ```json { "id": "aigwt_minimax_videos-regenerations_Hk2Lp9WqR4tYv7Xz1Bc3Nd", "object": "video", "model": "MiniMax-H3", "status": "queued", "progress": 0, "created_at": 1791950400, "expires_at": 1792555200, "size": "2K" } ``` 400: ```json { "error": { "message": "source_video is required for video regeneration (the 768P video to upscale)", "type": "invalid_request_error", "code": "invalid_parameter" } } ``` ## 上下文增强 `POST /v1/videos/context` 把提示词和多模态上下文整理成一段结构化、语义更丰富的提示词,仅 `minimax/minimax-h3` 支持。**这个接口只返回文本,不生成视频。** 它同样是异步任务:提交后用 `GET /v1/videos/{id}` 查询,完成后增强后的提示词在任务对象的 `output_text` 中,没有 `/content` 可下载。典型用法是两步:先调本接口拿到 `output_text`,再把它作为 `prompt` 提交给 `POST /v1/videos`。只接受 JSON 请求体。 > [!warning] > 目前这个接口不会拒绝 Seedance 模型:传 Seedance 的模型 ID 会生成一条普通视频(没有 `output_text`),并按视频计费。请只用 `minimax/minimax-h3` 调用本接口。 ### 请求体 | 参数 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | `model` | string | 是 | `minimax/minimax-h3` | | `prompt` | string | 是 | 原始提示词 | | `seconds` | integer | 是 | 计划生成的视频时长(秒),4~15。不传时返回 400,正文是纯文本 `binding: expr_path=duration, cause=missing required parameter`(响应头目前仍是 `Content-Type: application/json`) | | `size` | string | 否 | 写法同「提交任务」。不传时网关按 `2K` 发给服务商 | | `first_frame` / `last_frame` / `reference_image` / `input_reference` / `reference_audio` | — | 否 | 多模态上下文,写法和限制同「提交任务」 | `generate_audio`、`output_format`、`omni_reference_task_type`、`source_video` 返回 400 `<参数名> is not supported for this model`。 ### 请求示例 **请求示例** cURL: ```bash curl https://api.lyrouter.com/v1/videos/context \ -H "Authorization: Bearer $LYROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "minimax/minimax-h3", "prompt": "一只猫在雨里走过霓虹街道", "seconds": 5 }' ``` Python: ```python import os import httpx resp = httpx.post( "https://api.lyrouter.com/v1/videos/context", headers={"Authorization": f"Bearer {os.environ['LYROUTER_API_KEY']}"}, json={ "model": "minimax/minimax-h3", "prompt": "一只猫在雨里走过霓虹街道", "seconds": 5, }, timeout=60, ) resp.raise_for_status() print(resp.json()["id"]) ``` Node.js: ```js const resp = await fetch("https://api.lyrouter.com/v1/videos/context", { method: "POST", headers: { Authorization: `Bearer ${process.env.LYROUTER_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ model: "minimax/minimax-h3", prompt: "一只猫在雨里走过霓虹街道", seconds: 5, }), }); if (!resp.ok) throw new Error(await resp.text()); console.log((await resp.json()).id); ``` ### 响应 提交成功返回 HTTP 200 和任务对象,`id` 以 `aigwt_minimax_videos-context_` 开头。完成后的结果见上文「查询任务」中的「200 上下文增强」:`output_text` 是增强后的提示词,`usage.completion_tokens` 是输出 Token 数。下面的 400 是用 `minimax/minimax-h3-max`(已下线)调用本接口时服务商返回的报错,网关原样透传,没有 `error.code`。 **响应示例** 200: ```json { "id": "aigwt_minimax_videos-context_Zp8Rk2Vt5Lq9Wx3Ny6Bh1A", "object": "video", "model": "MiniMax-H3", "status": "queued", "progress": 0, "created_at": 1791950400, "expires_at": 1792555200, "seconds": 5 } ``` 400: ```json { "type": "error", "error": { "type": "bad_request_error", "message": "invalid params, model MiniMax-H3-Max does not support resolution 2K, supported resolutions: 480P, 768P (2013)", "http_code": "400" }, "request_id": "<服务商的请求标识>" } ``` ## 删除任务 `DELETE /v1/videos/{id}` 对已结束(`completed` 或 `failed`)的任务返回 HTTP 200 和任务对象,并带 `"deleted": true`;任务记录不会因此删除,在 `expires_at` 之前仍可查询和下载。对进行中的任务调用返回 409 `cancel_not_supported`:服务商不提供取消接口,请等待任务结束。OpenAI 官方 SDK 的 `videos.delete()` 读取的就是这个 `deleted` 字段。 ## MiniMax 特有参数与限制 ### `size`:短边必须正好落在档位上 | 写法 | 网关怎么处理 | | --- | --- | | 档位名(`480P`、`768P`、`2K`) | 原样送出 | | `宽x高` | 取**短边**查档位表:短边必须**正好**是 `480` 或 `768`,否则网关直接返回 400 并列出合法写法;宽高比按就近匹配 | - `1280x720` 的短边是 720,不在档位里,会被拒绝;768P 横屏可以写 `1366x768`,竖屏写 `768x1366`。 - `2K` 没有固定的短边,只能写档位名 `"2K"`。 - 用 `宽x高` 时,宽高比也要落在 21:9、16:9、4:3、1:1、3:4、9:16 之一(允许 2% 误差),否则返回 400 `size implies an aspect ratio this model does not support: <取值>`。 - 档位决定的是分辨率档,产物的实际像素由服务商决定,以下载到的视频为准。实测:文生视频和多模态参考用 `480P` 或 `854x480` 时产物为 1038×576(短边 576,不是 480);`768P` 为 1344×768;首尾帧图生视频用 1:1 的图片 + `854x480` 时为 768×768;升清到 `2K` 为 2560×1440。 ### 三种输入场景与宽高比 | 场景 | 怎么传 | 宽高比 | | --- | --- | --- | | 文生视频 | 只传 `prompt` | 必须是明确的比例,不能自适应:网关按 `size` 推出比例;`size` 写的是档位名时按 16:9 生成 | | 图生视频 | `first_frame`(+ `last_frame`) | 由输入图片决定,`size` 只决定分辨率 | | 多模态参考生视频 | `reference_image` / `input_reference` / `reference_audio` | `size` 写 `宽x高` 时按它推出的比例,写档位名时自适应。**传参考视频时不能自适应**:`size` 请写成 `宽x高`(如 `854x480`、`1366x768`),写档位名时任务会失败 | ### 输入素材限制 | 素材 | 限制 | | --- | --- | | 图片 | JPG、JPEG、PNG、WEBP、HEIC、HEIF;宽高 [256, 5760] px;宽高比 [0.4, 2.5];≤ 30 MB;首帧 ≤ 1、尾帧 ≤ 1、参考图 ≤ 9 | | 视频 | MP4、MOV(视频 H.264 / H.265,音频 AAC / MP3);≤ 50 MB;≤ 3 个;单段 [2, 15] 秒且总时长 ≤ 15 秒;宽高 [256, 5760] px;宽高比 [0.4, 2.5];帧率 [23.976, 60] | | 音频 | WAV、MP3;≤ 15 MB;≤ 3 个;单段 [2, 15] 秒且总时长 ≤ 15 秒 | | 请求体 | 总大小 ≤ 64 MB,大文件请用公网 URL | 参考素材的尺寸和宽高比由服务商校验:不符合时服务商以错误码 2013 拒绝,并在报错中指出是哪一项(如 `content[N].image_url`),不收费。H3-Max 不支持多张参考图,服务商会拒绝并建议改用 H3(H3-Max 已被服务商下线,目前不可用)。 ### 计费 | 任务 | 计量 | 分档 | | --- | --- | --- | | 视频生成(`minimax-h3`) | 按秒 | 480P / 768P / 2K 三档 | | 视频生成(`minimax-h3-max`,已被服务商下线,目前不可用,请改用 `minimax-h3`) | 按秒 | 480P / 768P 两档 | | 视频升清(`/v1/videos/regenerations`) | 按秒 | 单独一档 | | 上下文增强(`/v1/videos/context`) | 按 Token | 输入、输出两项分开计 | - **计费秒数是输入 + 输出的总和**,即任务对象中的 `usage.duration_seconds`:传了参考视频时,参考视频的秒数同样计入(例如 4 秒参考视频 + 4 秒输出,`duration_seconds` 为 8)。参考音频不收费。视频升清不相加,`duration_seconds` 只计源视频的秒数(实测源视频 4 秒,计 4)。 - **参考图单独计一项**(两个模型的参考图单价不同):`minimax-h3` 的参考图前 5 张免费,超出部分按张计费。张数不在 `usage` 中,费用可在日志中查看。 - 上下文增强按输入、输出 Token 两项计费,任务对象的 `usage` 只列出 `completion_tokens`(输出),输入 Token 的费用同样计入。 - 价格在提交时锁定;任务变为 `completed` 时按服务商实际返回的计量结算;`failed` 的任务(包括超时)不收费。在日志中查看任务费用的方法见[异步任务](https://platform.lyrouter.com/ai_gateway/docs/async)。 ## 完整调用示例 先用上下文增强把提示词扩写,再用增强后的提示词生成 768P 视频,轮询到结束后下载。cURL 示例需要 `jq`,请保存为脚本文件后用 `bash` 运行(出错时用 `exit` 退出)。 **完整示例** cURL: ```bash BASE=https://api.lyrouter.com/v1 AUTH="Authorization: Bearer $LYROUTER_API_KEY" # 提交任务(请求体从标准输入读取),输出任务 ID;没拿到任务 ID 时打印响应并返回失败 submit() { local resp id resp=$(curl -s "$BASE/$1" -H "$AUTH" -H "Content-Type: application/json" -d @-) id=$(echo "$resp" | jq -r '.id // empty') if [ -z "$id" ]; then echo "提交失败:$resp" >&2; return 1; fi echo "task: $id" >&2 echo "$id" } # 轮询一个任务直到结束,输出最终的任务对象;查询出错或等待超过 2 小时时返回失败 wait_task() { local delay=10 give_up_at=$(( $(date +%s) + 2 * 3600 )) task status while [ "$(date +%s)" -le "$give_up_at" ]; do sleep $delay delay=$(( delay * 3 / 2 > 30 ? 30 : delay * 3 / 2 )) task=$(curl -s "$BASE/videos/$1" -H "$AUTH") status=$(echo "$task" | jq -r '.status') case "$status" in completed|failed) echo "$task"; return 0 ;; queued|in_progress|"") ;; # 空值多为网络抖动:保留任务 ID 继续查 *) echo "查询出错:$task" >&2; return 1 ;; esac done echo "$1 仍在处理,可稍后用同一个 ID 继续查询" >&2; return 1 } # 1. 上下文增强,拿到增强后的提示词;失败时打印原因并退出 CTX_ID=$(echo '{"model":"minimax/minimax-h3","prompt":"一只猫在雨里走过霓虹街道","seconds":5}' \ | submit videos/context) || exit 1 CTX=$(wait_task "$CTX_ID") || exit 1 PROMPT=$(echo "$CTX" | jq -r '.output_text // empty') if [ -z "$PROMPT" ]; then echo "$CTX" | jq '.error'; exit 1; fi # 2. 用增强后的提示词生成视频 VIDEO_ID=$(jq -n --arg p "$PROMPT" \ '{model:"minimax/minimax-h3",prompt:$p,size:"768P",seconds:5}' \ | submit videos) || exit 1 TASK=$(wait_task "$VIDEO_ID") || exit 1 # 3. 完成则下载,失败则打印原因 if [ "$(echo "$TASK" | jq -r '.status')" = "completed" ]; then curl -sL "$BASE/videos/$VIDEO_ID/content" -H "$AUTH" -o video.mp4 else echo "$TASK" | jq '.error' fi ``` Python: ```python import os import time import httpx BASE = "https://api.lyrouter.com/v1" HEADERS = {"Authorization": f"Bearer {os.environ['LYROUTER_API_KEY']}"} def wait_task(client: httpx.Client, task: dict, max_wait: int = 2 * 3600) -> dict: """从 10 秒开始轮询,逐步放宽到 30 秒,直到任务结束。""" if not task.get("id"): raise RuntimeError(f"没有拿到任务 ID:{task}") print("task:", task["id"]) delay, give_up_at = 10, time.time() + max_wait while task["status"] in ("queued", "in_progress"): if time.time() > give_up_at: raise TimeoutError(f"{task['id']} 仍在处理,可稍后用同一个 ID 继续查询") time.sleep(delay) delay = min(delay * 1.5, 30) try: resp = client.get(f"{BASE}/videos/{task['id']}") resp.raise_for_status() except httpx.TransportError: continue # 网络抖动:保留任务 ID 继续查,不要重新提交 task = resp.json() if task["status"] == "failed": err = task.get("error", {}) raise RuntimeError(f"{err.get('code')}: {err.get('message')}") return task with httpx.Client(headers=HEADERS, timeout=60) as client: # 1. 上下文增强,拿到增强后的提示词 resp = client.post(f"{BASE}/videos/context", json={ "model": "minimax/minimax-h3", "prompt": "一只猫在雨里走过霓虹街道", "seconds": 5, }) resp.raise_for_status() prompt = wait_task(client, resp.json())["output_text"] # 2. 用增强后的提示词生成视频 resp = client.post(f"{BASE}/videos", json={ "model": "minimax/minimax-h3", "prompt": prompt, "size": "768P", "seconds": 5, }) resp.raise_for_status() task = wait_task(client, resp.json()) # 3. 下载:接口返回 302,跟随跳转即可 with client.stream("GET", f"{BASE}/videos/{task['id']}/content", follow_redirects=True, timeout=600) as video: video.raise_for_status() with open("video.mp4", "wb") as f: for chunk in video.iter_bytes(): f.write(chunk) print("已保存 video.mp4,用量:", task.get("usage")) ``` Node.js: ```js import { writeFile } from "node:fs/promises"; const BASE = "https://api.lyrouter.com/v1"; const headers = { Authorization: `Bearer ${process.env.LYROUTER_API_KEY}` }; const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); async function submit(path, body) { const resp = await fetch(`${BASE}${path}`, { method: "POST", headers: { ...headers, "Content-Type": "application/json" }, body: JSON.stringify(body), }); if (!resp.ok) throw new Error(await resp.text()); return resp.json(); } // 从 10 秒开始轮询,逐步放宽到 30 秒,直到任务结束 async function waitTask(task) { if (!task.id) throw new Error(`没有拿到任务 ID:${JSON.stringify(task)}`); console.log("task:", task.id); let delay = 10_000; while (task.status === "queued" || task.status === "in_progress") { await sleep(delay); delay = Math.min(delay * 1.5, 30_000); let resp; try { resp = await fetch(`${BASE}/videos/${task.id}`, { headers }); } catch { continue; // 网络抖动:保留任务 ID 继续查,不要重新提交 } if (!resp.ok) throw new Error(await resp.text()); task = await resp.json(); } if (task.status === "failed") { throw new Error(`${task.error?.code}: ${task.error?.message}`); } return task; } // 1. 上下文增强,拿到增强后的提示词 const ctx = await waitTask(await submit("/videos/context", { model: "minimax/minimax-h3", prompt: "一只猫在雨里走过霓虹街道", seconds: 5, })); // 2. 用增强后的提示词生成视频 const task = await waitTask(await submit("/videos", { model: "minimax/minimax-h3", prompt: ctx.output_text, size: "768P", seconds: 5, })); // 3. 下载:fetch 默认跟随 302 跳转 const video = await fetch(`${BASE}/videos/${task.id}/content`, { headers }); if (!video.ok) throw new Error(`download failed: ${video.status}`); await writeFile("video.mp4", Buffer.from(await video.arrayBuffer())); console.log("saved video.mp4", task.usage); ``` ## 常见错误 错误响应为 `{"error":{"message":"...","type":"...","code":"..."}}`。 | 状态码 | `error.message` | `error.code` | 原因与处理 | | --- | --- | --- | --- | | 400 | `this model takes discrete resolution tiers, not arbitrary sizes: ...` | `invalid_parameter` | `size` 的短边不是 480 或 768。改写档位名(如 `768P`、`2K`)或短边正好为 480 / 768 的尺寸 | | 400 | `size implies an aspect ratio this model does not support: <取值>` | `invalid_parameter` | `size` 推出的宽高比不在支持的比例中 | | 400 | `seconds must be a positive whole number of seconds` | `invalid_parameter` | `seconds` 不是正整数 | | 400 | `<参数名> is not supported for this model` | `invalid_parameter` | 传了 MiniMax 不支持的 `generate_audio`、`output_format`、`omni_reference_task_type`,或在 `/v1/videos` 上传了 `source_video`。从请求中删掉 | | 400 | `seconds is not supported for video regeneration (the source video determines the duration)` | `invalid_parameter` | 视频升清不接受 `seconds`,删掉即可 | | 400 | `source_video is required for video regeneration (the 768P video to upscale)` | `invalid_parameter` | 视频升清缺少源视频 | | 400 | `This model does not support the videos_regenerations operation`(或 `videos_context`) | `unsupported_model_operation` | 所选模型不支持视频升清或上下文增强,改用 `minimax/minimax-h3`。目前并非所有不支持的模型都返回这条,见表下说明 | | 400 | `unsupported parameters for this model: <参数名>` | `unsupported_parameters` | 带了 `X-Gateway-Strict-Parameters: true`,且请求中有会被丢弃的参数 | | 403 | `Model is not available in the model plaza` | `model_not_available` | 模型没有在本工作空间开通,或使用了虚拟模型、`lyrouter/auto`。换用已开通的具体模型 ID | | 404 | `video task not found` | `not_found` | 任务 ID 不存在、已超过 7 天、属于其他工作空间,或传入的是服务商的任务 ID | | 409 | `video is not ready yet` | `not_ready` | 任务还没完成(或已失败)就调用了 `/content`。先查询到 `completed` | | 409 | `cancelling an in-flight video task is not supported: ...` | `cancel_not_supported` | 对进行中的任务调用了 `DELETE`。请等待任务结束 | | 429 | `upstream concurrency full` | `upstream_concurrency_full` | 服务商账户的并发任务已满,换 API Key 无效,稍后重新提交 | - 目前用其他模型调用视频升清或上下文增强,不一定返回 `unsupported_model_operation`:Seedance 2.5 调视频升清返回 400 `source_video is not supported for this model`(`invalid_parameter`);Seedance 模型调上下文增强会被受理,生成一条普通视频并照常计费;`minimax/minimax-h3-max`(已下线)调视频升清会被受理并建出任务,调上下文增强返回服务商透传的 400(`invalid params, model MiniMax-H3-Max does not support resolution 2K, …`,没有 `error.code`)。这两个接口请只用 `minimax/minimax-h3` 调用。 - 用表单提交时 `input_reference` 只能传 URL。目前上传文件**不会报错**,文件会被忽略,任务按没有参考视频的方式生成并照常计费;只有填了非 URL 的文本(如 `video.mp4`)时才返回 400 纯文本 `input_reference must be a URL; uploading a file is not supported by this gateway (pass a publicly reachable https:// URL instead)`。这类由网关返回的纯文本报错,响应头目前仍是 `Content-Type: application/json`,解析前请先判断正文是不是 JSON。 - 时长超出范围、图生视频与多模态参考混用、参考素材不合规等由服务商拒绝,状态码和报错原文由服务商决定;任务提交后才发现的问题以失败任务的形式返回,见上文「查询任务」。完整列表见[错误码与请求标识](https://platform.lyrouter.com/ai_gateway/docs/errors)。 ## 常见问题 ### 提示短边必须是 480 或 768,怎么办? **答:** MiniMax 的分辨率是离散档位,不是任意尺寸。直接写档位名(如 `"768P"`、`"2K"`),或使用短边正好为 480 / 768 的尺寸(如 `1366x768`)。`2K` 只能写档位名。 ### H3-Max 能做视频升清或上下文增强吗? **答:** 不能。这两个接口只支持 `minimax/minimax-h3`。目前用 H3-Max 调用时网关不会直接拒绝:调视频升清会被受理并建出任务;调上下文增强返回服务商透传的 400(`invalid params, model MiniMax-H3-Max does not support resolution 2K, …`,没有 `error.code`)。H3-Max 也不支持 2K 和 4 秒时长。另外,H3-Max 已被服务商下线,目前连普通视频生成也不可用(调用返回 HTTP 200,但任务对象为空、没有任务 ID),请改用 `minimax/minimax-h3`。 ### 升清后的视频效果不理想,怎么办? **答:** 确认三件事:源视频是 H3 生成的 768P 产物;`prompt` 是生成源视频时实际送入模型的最终提示词(用过上下文增强的,填增强之后的那份);参考素材与生成时一致。这些不一致时网关和服务商都不会报错,只是效果不达预期。 ### 上下文增强完成了,为什么下载不到视频? **答:** 上下文增强只产出文本,结果在任务对象的 `output_text` 中,没有视频可下载;目前对它调用 `/content` 会返回 HTTP 500。把 `output_text` 作为 `prompt` 提交给 `POST /v1/videos` 才会生成视频。 ### 传了参考视频,为什么计费秒数比视频时长多? **答:** MiniMax 的计费秒数是输入加输出:参考视频的秒数也计入 `usage.duration_seconds`。参考音频不收费,参考图前 5 张免费、超出部分按张计费。 ### 传了参考视频,任务失败并提示 `aspect ratio "adaptive" is not supported`,怎么办? **答:** 完整报错是 `h3submit: aspect ratio "adaptive" is not supported for task ref2va`。传参考视频(`input_reference`)时,MiniMax 要求明确的宽高比,而 `size` 写成档位名(如 `480P`)时网关发出的是自适应比例。把 `size` 改成 `宽x高`,短边为 480 或 768,例如 `854x480`、`1366x768`,再重新提交。这类失败不收费。 ### 视频地址过期了,还能重新下载吗? **答:** 不能。视频地址在任务完成时确定,再次调用 `/content` 拿到的仍是同一个地址,过期后需要重新提交任务。请在任务完成后立即下载或转存。 ### 查询结果一直是 `in_progress`,怎么办? **答:** 视频生成通常需要几分钟。提交 24 小时后仍未完成的任务不会再有结果,也不收费,可以停止轮询,并在控制台 **多媒体生成** 页面按任务 ID 查看任务状态。不要在等待期间重复提交同样的请求,每次提交都会生成新任务并单独计费。 --- # 接入地址与鉴权 来源: https://platform.lyrouter.com/ai_gateway/docs/call-gateway 所有调用都发往网关地址 `https://api.lyrouter.com`,用同一个 LYRouter API Key 鉴权。OpenAI SDK 的 Base URL 填 `https://api.lyrouter.com/v1`,Anthropic SDK 填根地址 `https://api.lyrouter.com`;密钥放在 `Authorization: Bearer ` 或 `x-api-key` 请求头中。请求体的 `model` 写系统模型 ID、`@vmodel/<名称>` 或 `lyrouter/auto`,省略时使用工作空间的默认模型。 ## 地址 | 协议 | SDK Base URL | 请求路径 | | --- | --- | --- | | Chat Completions | https://api.lyrouter.com/v1 | /v1/chat/completions | | Responses | https://api.lyrouter.com/v1 | /v1/responses | | Anthropic Messages | https://api.lyrouter.com | /v1/messages | - **SDK 只填 Base URL**:OpenAI SDK 会在 `/v1` 后拼接 `/chat/completions`、`/responses`、`/models` 等路径,Anthropic SDK 会在根地址后拼接 `/v1/messages`。cURL 和自己发 HTTP 请求时写完整 URL,例如 `https://api.lyrouter.com/v1/chat/completions`。 - **不要重复 `/v1`**:Anthropic SDK 的 Base URL 写成 `https://api.lyrouter.com/v1` 时,实际请求 `/v1/v1/messages`,返回 404。OpenAI SDK 的 Base URL 写到 `/v1/chat/completions` 也会拼出错误路径。 - **版本前缀**:除 `/v1` 外,网关也接受不带版本前缀(如 `/chat/completions`)或其他版本号前缀(如部分智谱客户端使用的 `/v4/chat/completions`)的同名路径,按同一接口处理。新接入的应用请统一使用 `/v1`。 - **控制台地址不是网关地址**:浏览器中打开的控制台页面(`/ai_gateway/...`)不能用作 Base URL。自部署时,把本页的 `https://api.lyrouter.com` 换成你的网关地址。 ## 鉴权 在当前工作空间的 **API 密钥** 页面创建 API Key,见[创建工作空间与 API Key](https://platform.lyrouter.com/ai_gateway/docs/api-keys)。网关按 API Key 识别工作空间,并在调用上游时换成平台或 BYOK 的服务商凭证;你的 API Key 不会转发给上游。服务商的 API Key 和控制台登录会话都不能用来调用网关。 | 请求头 | 写法 | 适用 | | --- | --- | --- | | `Authorization` | `Bearer `,`Bearer` 区分大小写,后面有一个空格 | 所有接口;OpenAI SDK 的 `api_key` / `apiKey`、Anthropic SDK 的 `auth_token` / `authToken` 使用这种写法 | | `x-api-key` | 直接写 ``,不加前缀 | 所有接口;Anthropic SDK 的 `api_key` / `apiKey` 使用这种写法 | - **只读一个**:同时带两个请求头时,网关只读 `Authorization`。`Authorization` 格式错误时直接返回 401,不会改读 `x-api-key`。 - **只放在请求头**:不要把密钥写进 URL 查询参数或请求体。 - **生效时间**:新建、停用或修改 Key 后几秒内同步到网关。 ### API Key 自身的限制 创建或编辑 Key 时可以设置以下限制,触发后网关在调用上游前拒绝请求: | 设置(API 密钥编辑页) | 触发后的响应 | 说明 | | --- | --- | --- | | 「基本信息」中的「到期时间」 | 403 `api key expired` | 到期后过一段时间改为 401 `invalid api key`;新建 Key 替换 | | 「预算限额」中的「费用预算(元)」「Token 预算(百万 Token)」 | 429 `rate limit exceeded on apikey <指标>/<窗口>` | 「每月」每月 1 日重置,「总计」不重置,见[预算、配额与限流](https://platform.lyrouter.com/ai_gateway/docs/quota) | | 「访问控制」中的「启用 IP 白名单」 | 403 `your IP address is not allowed` | 网关按请求到达时的出口 IP 判断;白名单为空或含无效条目时返回 403 `ip access control misconfigured` | 此外,Key 还受工作空间的安全围栏策略约束(模型策略、配额、客户端访问控制),见[安全围栏与语义审计](https://platform.lyrouter.com/ai_gateway/docs/guardrails)。各报错的处理见[401 / 403:鉴权与权限](https://platform.lyrouter.com/ai_gateway/docs/auth-errors)和[429:限流与配额](https://platform.lyrouter.com/ai_gateway/docs/rate-errors)。 ## OpenAI SDK Chat Completions、Responses、Models、Embeddings 等 OpenAI 兼容接口共用同一个客户端,Base URL 写到 `/v1`: **请求示例** cURL: ```bash curl https://api.lyrouter.com/v1/chat/completions \ -H "Authorization: Bearer $LYROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "MODEL_ID", "messages": [{"role": "user", "content": "用一句话介绍你自己"}] }' ``` Python: ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["LYROUTER_API_KEY"], base_url="https://api.lyrouter.com/v1", ) completion = client.chat.completions.create( model="MODEL_ID", messages=[{"role": "user", "content": "用一句话介绍你自己"}], ) print(completion.choices[0].message.content) # 同一个客户端调用 Responses response = client.responses.create(model="MODEL_ID", input="用一句话介绍你自己") print(response.output_text) ``` Node.js: ```js import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.LYROUTER_API_KEY, baseURL: "https://api.lyrouter.com/v1", }); const completion = await client.chat.completions.create({ model: "MODEL_ID", messages: [{ role: "user", content: "用一句话介绍你自己" }], }); console.log(completion.choices[0].message.content); // 同一个客户端调用 Responses const response = await client.responses.create({ model: "MODEL_ID", input: "用一句话介绍你自己" }); console.log(response.output_text); ``` `MODEL_ID` 换成模型广场中复制的模型 ID,`LYROUTER_API_KEY` 环境变量的设置见[完成第一次模型调用](https://platform.lyrouter.com/ai_gateway/docs/quickstart)。Responses 要求模型和服务它的通道支持 Responses 接口,见[Responses](https://platform.lyrouter.com/ai_gateway/docs/responses-api)。Python 示例中的 `client.responses` 需要 openai Python SDK 1.66 或更高版本,旧版本会报 `AttributeError: 'OpenAI' object has no attribute 'responses'`。 ## Anthropic SDK Anthropic SDK 的 Base URL 写根地址,不带 `/v1`。`/v1/messages` 不要求模型来自 Anthropic,任何对话模型都可以通过它调用: **请求示例** cURL: ```bash curl https://api.lyrouter.com/v1/messages \ -H "x-api-key: $LYROUTER_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -H "Content-Type: application/json" \ -d '{ "model": "MODEL_ID", "max_tokens": 1024, "messages": [{"role": "user", "content": "用一句话介绍你自己"}] }' ``` Python: ```python import os from anthropic import Anthropic client = Anthropic( api_key=os.environ["LYROUTER_API_KEY"], base_url="https://api.lyrouter.com", ) message = client.messages.create( model="MODEL_ID", max_tokens=1024, messages=[{"role": "user", "content": "用一句话介绍你自己"}], ) print(message.content[0].text) ``` Node.js: ```js import Anthropic from "@anthropic-ai/sdk"; const client = new Anthropic({ apiKey: process.env.LYROUTER_API_KEY, baseURL: "https://api.lyrouter.com", }); const message = await client.messages.create({ model: "MODEL_ID", max_tokens: 1024, messages: [{ role: "user", content: "用一句话介绍你自己" }], }); console.log(message.content[0].text); ``` 请求、响应和流式事件的细节见[Anthropic Messages](https://platform.lyrouter.com/ai_gateway/docs/anthropic-messages)。 ### 只改环境变量接入已有代码 两种 SDK 都会读取环境变量。已有代码没有显式传入地址和密钥时,设置下表中的变量即可改走网关: | SDK | 地址变量 | 密钥变量 | | --- | --- | --- | | OpenAI(Python / Node.js) | `OPENAI_BASE_URL=https://api.lyrouter.com/v1` | `OPENAI_API_KEY=` | | Anthropic(Python / Node.js) | `ANTHROPIC_BASE_URL=https://api.lyrouter.com` | `ANTHROPIC_API_KEY=`(以 `x-api-key` 发送)或 `ANTHROPIC_AUTH_TOKEN=`(以 `Authorization: Bearer` 发送) | 代码中的模型名也要换成 LYRouter 的模型 ID。Claude Code、Codex 等编程工具的配置见[工具兼容性与接入总览](https://platform.lyrouter.com/ai_gateway/docs/tools)。 ## `model` 字段 | 写法 | 含义 | 可用接口 | | --- | --- | --- | | 系统模型 ID,如 `deepseek/deepseek-v4-flash` | 调用这个模型,网关按[通道选择与路由策略](https://platform.lyrouter.com/ai_gateway/docs/routing)选择服务商通道 | 所有带 `model` 的接口 | | `@vmodel/<名称>`(旧写法 `@preset/<名称>` 等价) | 调用已启用的[虚拟模型](https://platform.lyrouter.com/ai_gateway/docs/presets),按其主模型、备用模型和参数执行 | Chat Completions、Anthropic Messages、Responses;模型列表全部是向量或重排模型时也可用于[创建向量](https://platform.lyrouter.com/ai_gateway/docs/embeddings)和[文档重排](https://platform.lyrouter.com/ai_gateway/docs/rerank) | | `lyrouter/auto` | 按任务难度在已开通的模型中挑选,见[Auto 智能路由](https://platform.lyrouter.com/ai_gateway/docs/auto) | Chat Completions、Anthropic Messages、Responses | | 省略,或写成 `""`、`null` | 使用工作空间在 **智能路由** 中设置的默认模型 | 带 `model` 的接口 | - 模型 ID 区分大小写,必须与模型广场或 [`GET /v1/models`](https://platform.lyrouter.com/ai_gateway/docs/models) 返回的 `id` 逐字一致,命名规则见[模型命名与查询](https://platform.lyrouter.com/ai_gateway/docs/model-names)。 - 省略 `model` 且工作空间没有默认模型时,返回 400 `you must provide a model parameter`(`error.code` 为 `missing_model`);`model` 不是字符串时返回 400 `invalid type for 'model': expected a string`(`invalid_model`)。 - 虚拟模型和 `lyrouter/auto` 用在图像、视频、语音接口上时,返回 403 `Model is not available in the model plaza`,这些接口请写具体的模型 ID。 ## 全部端点 所有端点使用同一个 Base URL 和同一套鉴权: | 方法 | 路径 | 用途 | 文档 | | --- | --- | --- | --- | | POST | `/v1/chat/completions` | 对话生成(OpenAI Chat Completions 格式) | [Chat Completions](https://platform.lyrouter.com/ai_gateway/docs/chat-completions) | | POST | `/v1/responses` | 对话生成(OpenAI Responses 格式) | [Responses](https://platform.lyrouter.com/ai_gateway/docs/responses-api) | | POST | `/v1/messages` | 对话生成(Anthropic Messages 格式) | [Anthropic Messages](https://platform.lyrouter.com/ai_gateway/docs/anthropic-messages) | | GET | `/v1/models` | 列出这个 API Key 可调用的模型 | [列出模型](https://platform.lyrouter.com/ai_gateway/docs/models) | | POST | `/v1/embeddings`、`/v1/rerank` | 文本向量、重排序 | [创建向量](https://platform.lyrouter.com/ai_gateway/docs/embeddings)、[文档重排](https://platform.lyrouter.com/ai_gateway/docs/rerank) | | POST | `/v1/images/generations`、`/v1/images/edits` | 图像生成、编辑 | [多模态能力](https://platform.lyrouter.com/ai_gateway/docs/multimodal) | | POST | `/v1/videos`、`/v1/videos/regenerations`、`/v1/videos/context` | 提交视频任务 | [异步任务](https://platform.lyrouter.com/ai_gateway/docs/async) | | GET、DELETE | `/v1/videos/{id}`、`/v1/videos/{id}/content` | 查询任务、下载产物、取消任务 | [异步任务](https://platform.lyrouter.com/ai_gateway/docs/async) | 全部接口按能力分组的说明见[API 文档](https://platform.lyrouter.com/ai_gateway/docs/api-overview),网关自定义的请求头和响应头见[网关扩展请求头与响应头](https://platform.lyrouter.com/ai_gateway/docs/gateway-headers)。 ## 地址与鉴权类错误 OpenAI 兼容接口的错误体为 `{"error": {"message": "...", "type": "...", "code": "..."}}`,`code` 只在部分错误上出现。`/v1/messages` 上的错误会转换为 Anthropic 格式 `{"type": "error", "error": {"type": "authentication_error", "message": "..."}}`,`message` 原文不变,没有 `code`。 | 状态码 | 报错原文 | 原因与处理 | | --- | --- | --- | | 404 | `{"error_msg":"404 Route Not Found"}` | 路径或方法不存在:Base URL 重复了 `/v1`、路径末尾多了 `/`、拼错端点,或用 GET 调用了只接受 POST 的接口。按上文「地址」核对完整 URL。这个响应不是标准错误体,也不会转换为 Anthropic 格式 | | 401 | `missing credentials` | 没有带 API Key,或 `Authorization` 写成了 `Bearer `(带空格)而后面没有密钥。加上 `Authorization: Bearer ` 或 `x-api-key` | | 401 | `invalid authorization scheme, expected 'Bearer'` | `Authorization` 不是 `Bearer ` 格式,例如写成小写的 `bearer`、只写密钥,或只写 `Bearer` 而后面没有空格 | | 401 | `invalid api key` | Key 复制不完整或带了空白字符,或已删除、停用、过期;新建的 Key 需要几秒同步 | | 401 | `api key verification unavailable` | 平台暂时无法校验密钥,稍后重试 | | 400 | `unsupported content-type: application/x-www-form-urlencoded, only application/json is supported` | JSON 请求的 `Content-Type` 不是 `application/json`。cURL 用 `-d` 发送却没写 `-H "Content-Type: application/json"` 时就是这种情况。OpenAI 兼容接口上这个响应是一行纯文本,不是 JSON,但响应头目前仍是 `Content-Type: application/json`,解析前先判断正文是否为 JSON | | 402 | `subscription expired; renew to continue` | 账户订阅已到期,续费后恢复,见[模型不可用](https://platform.lyrouter.com/ai_gateway/docs/unavailable#余额与订阅) | | 403 | `api key expired`、`your IP address is not allowed`、`ip access control misconfigured` | 见上文「API Key 自身的限制」 | | 403 | `Model is not available in the model plaza` | 工作空间没有开通该模型,或在图像、视频、语音接口上用了虚拟模型或 `lyrouter/auto`,见[模型不可用](https://platform.lyrouter.com/ai_gateway/docs/unavailable) | 响应中不包含请求 ID。提交问题时,记录调用时间、端点、模型、API Key 名称和报错原文;能在 **日志分析** 中找到这次请求时,再附上日志详情顶部的 Request ID。401 请求无法归属到 Key,不会出现在日志中。全部错误码见[错误码与请求标识](https://platform.lyrouter.com/ai_gateway/docs/errors)。 ## 常见问题 ### OpenAI SDK 的 Base URL 少写了 `/v1`,为什么也能调通? **答:** 网关同时接受不带版本前缀的路径,`https://api.lyrouter.com/chat/completions` 与 `/v1/chat/completions` 等效。其他工具和 SDK 未必这样拼接路径,请统一写成 `https://api.lyrouter.com/v1`。 ### 同一个 API Key 能同时给 OpenAI 和 Anthropic 客户端使用吗? **答:** 可以。Key 属于工作空间,与协议无关;两种客户端调用同一个模型 ID 时,费用、配额和日志都记在这个 Key 下。日志的「API 路径」列可以区分请求来自哪个接口。 ### 请求被路由到了哪个服务商,从响应里能看出来吗? **答:** 响应中没有服务商信息,`model` 字段也是上游返回的值。在 **日志分析** 中打开这次请求,「模型(实际)」和「服务商」显示最终命中的模型和通道,见[查看实际路由](https://platform.lyrouter.com/ai_gateway/docs/route-log)。 --- # 模型命名与查询 来源: https://platform.lyrouter.com/ai_gateway/docs/model-names 请求中的 `model` 写模型 ID,格式为 `厂商/模型`(例如 `deepseek/deepseek-v4-flash`),区分大小写,必须与模型广场或 `GET /v1/models` 返回的值逐字一致。另有两类特殊名称:`@vmodel/<名称>` 调用虚拟模型,`lyrouter/auto` 调用 Auto 智能路由。客户端始终写模型 ID,服务商那边的真实模型名(包括 BYOK 的接入点编号)由网关替换,不要写进请求。 ## 模型 ID 的格式 | 组成 | 示例 | 说明 | | --- | --- | --- | | 厂商 | `deepseek`、`qwen`、`anthropic`、`openai`、`google` | 斜杠前是开发模型的厂商,不是提供服务的服务商。同一模型由多个服务商提供时,模型 ID 只有一个 | | 模型名 | `deepseek-v4-flash`、`qwen3.7-plus`、`claude-sonnet-4.6` | 包含规格和版本号,写法以模型目录为准 | - **逐字一致**:大小写、标点与目录中的模型 ID 完全相同,前后不带空格。网关不做大小写转换、不补厂商前缀,也不把相近的名称当作同一个模型。 - **版本号照抄**:`anthropic/claude-sonnet-4.6` 的版本号用点号,写成 `anthropic/claude-sonnet-4-6` 找不到这个模型。 - **不同版本是不同的 ID**:同一系列的不同规格、版本使用不同的模型 ID,网关不会把旧 ID 自动指向新版本。更换版本的步骤见[模型版本与下线](https://platform.lyrouter.com/ai_gateway/docs/versions)。 - **显示名称不能调用**:模型广场卡片标题(如「DeepSeek V4 Flash」)只用于展示;`GET /v1/models` 的 `display_name` 同理。 下表列出常见写法的结果(假设工作空间已开通 `deepseek/deepseek-v4-flash` 和 `anthropic/claude-sonnet-4.6`): | 请求中的 `model` | 结果 | | --- | --- | | `deepseek/deepseek-v4-flash` | 正确 | | `DeepSeek/deepseek-v4-flash` | 找不到(大小写不同) | | `deepseek-v4-flash` | 找不到(缺少厂商前缀);Codex 客户端例外,见下文 | | `deepseek/deepseek-v4-flash `(末尾有空格) | 找不到 | | `anthropic/claude-sonnet-4-6` | 找不到(版本号写法不同) | | `DeepSeek V4 Flash` | 找不到(显示名称) | | `ep-20260101xxxxxx-xxxxx` | 找不到(服务商的接入点编号) | 「找不到」时的表现取决于工作空间是否在 **智能路由** 中设置了默认模型: - **设置了默认模型**:对话类请求改由默认模型回答,HTTP 状态是 200。程序拿到了回答,但不是你想调用的模型。 - **没有设置默认模型**:返回 403 `Model is not available in the model plaza`(`error.code` 为 `model_not_available`)。 在 **日志分析** 中对比「模型(请求)」和「模型(实际)」:两者不同、且「模型(实际)」是默认模型时,说明请求中的名称没有匹配上。默认模型的行为见[通道选择与路由策略](https://platform.lyrouter.com/ai_gateway/docs/routing#默认模型)。 ## 特殊名称 | 名称 | 作用 | 规则 | | --- | --- | --- | | `@vmodel/<名称>` | 调用工作空间中已启用的[虚拟模型](https://platform.lyrouter.com/ai_gateway/docs/presets) | `<名称>` 只含小写字母、数字和连字符,以字母或数字开头,区分大小写。旧前缀 `@preset/<名称>` 与之等价 | | `lyrouter/auto` | 按任务难度在已开通的模型中挑选,见[Auto 智能路由](https://platform.lyrouter.com/ai_gateway/docs/auto) | 固定写法 | - **适用接口**:`lyrouter/auto` 只适合 `/v1/chat/completions`、`/v1/messages` 和 `/v1/responses`;虚拟模型除这三个接口外,也可以用于向量与重排接口(其模型列表须全部是向量或重排模型,见[创建向量](https://platform.lyrouter.com/ai_gateway/docs/embeddings)和[文档重排](https://platform.lyrouter.com/ai_gateway/docs/rerank))。两者用在图像、视频接口上都返回 403 `Model is not available in the model plaza`。 - **名称失效**:虚拟模型被停用、删除或改名后,旧名称不再匹配。设置了默认模型时由默认模型回答,否则返回 503 `all routed candidates exhausted`。 - **在日志中显示**:通过这两类名称调用时,日志「路由追踪」的「虚拟模型」显示虚拟模型名称(不带 `@vmodel/`)或 `lyrouter/auto`,「模型(实际)」显示实际回答的模型。 ## 省略 `model` 请求体没有 `model`,或写成 `""`、`null` 时,网关使用工作空间的默认模型。没有设置默认模型时返回 400 `you must provide a model parameter`(`missing_model`);`model` 不是字符串时返回 400 `invalid type for 'model': expected a string`(`invalid_model`)。生产代码请始终写明模型 ID,避免默认模型调整后行为随之改变。 ## Codex 客户端的名称补全 Codex 的部分界面只能选择不带厂商前缀的模型名(如 `gpt-5.5`)。网关识别到 Codex 客户端发来的请求时,给不含斜杠的模型名自动补上 `openai/`,即 `gpt-5.5` 按 `openai/gpt-5.5` 调用。已经带斜杠的名称不受影响,其他客户端也不做这种补全。在 Codex 中调用非 OpenAI 模型时,请在配置文件中填写完整的模型 ID,见[Codex](https://platform.lyrouter.com/ai_gateway/docs/codex)。 ## BYOK 与上游模型名 使用 [BYOK](https://platform.lyrouter.com/ai_gateway/docs/byok) 接入自己的服务商凭证后,客户端仍然写模型 ID,网关在发往服务商时换成映射的上游模型名: | 名称 | 示例 | 写在哪里 | | --- | --- | --- | | 模型 ID | `deepseek/deepseek-v4-pro` | 请求的 `model`、虚拟模型、Auto 候选范围、安全围栏模型策略 | | 上游模型名 | `deepseek-v4-pro`,或火山方舟的 `ep-*` 接入点编号 | 只出现在网关发给服务商的请求中,由 BYOK 的模型映射决定 | - **上游名不能当模型 ID**:请求中写 `ep-*` 等上游名,按「找不到」处理,见上文。 - **同一个模型 ID 可能对应不同上游名**:平台通道和各个 BYOK 通道各有自己的映射,网关按实际选中的通道替换。客户端代码不需要关心是哪一个。 - **自定义服务商也映射到模型 ID**:自定义服务商的每个上游模型都要对应一个平台模型目录中的模型,不能新建模型 ID,见[模型映射与来源配置](https://platform.lyrouter.com/ai_gateway/docs/mapping)。 - **核对实际发出的名称**:在日志详情的「原始报文」中查看「上游请求」,其中的 `model` 是上游模型名。正文只在工作空间开启全文日志后保存,失败的请求除外。 响应体中的 `model` 字段是上游返回的值,通常是上游模型名,不一定等于请求时写的模型 ID。程序需要记录「调用了哪个模型」时,请记录自己发送的模型 ID,或以日志的「模型(实际)」为准。 ## 查询可用的名称 | 方式 | 得到什么 | 适合 | | --- | --- | --- | | 工作空间 **模型广场** | 已开通的模型及其服务商、价格;点击模型 ID 旁的复制按钮 | 人工挑选模型,见[如何选择模型](https://platform.lyrouter.com/ai_gateway/docs/choose) | | [`GET /v1/models`](https://platform.lyrouter.com/ai_gateway/docs/models) | 这个 API Key 可调用的模型 ID,以及已启用的 `@vmodel/<名称>` 和 `lyrouter/auto` | 程序获取列表、填充模型选择器 | | **虚拟模型** 页面 | 虚拟模型的调用名称 | 当前账号管理员管理虚拟模型;普通成员用 `GET /v1/models` 查询名称 | `GET /v1/models` 已经按安全围栏的模型策略过滤,比模型广场更接近「这个 Key 实际能调用什么」。 ## 常见问题 ### 模型广场能看到这个模型,为什么调用时找不到? **答:** 先确认它在「专属可用模型」中,而不是「可启用」或「需接入」;再用调用时的 API Key 请求 `GET /v1/models`,确认列表中有这个 ID。不在列表中,说明没有开通,或被安全围栏的模型策略限制了,见[模型授权](https://platform.lyrouter.com/ai_gateway/docs/authorization)。在列表中却仍然失败,按报错原文对照[模型不可用](https://platform.lyrouter.com/ai_gateway/docs/unavailable)。 ### 客户端只能填不带斜杠的模型名,怎么办? **答:** Codex 由网关自动补 `openai/` 前缀。其他只接受固定名称的客户端,可以创建一个[虚拟模型](https://platform.lyrouter.com/ai_gateway/docs/presets),把 `@vmodel/<名称>` 填进客户端;客户端连 `@` 和 `/` 都不接受时,请换用支持自定义模型名的客户端或配置方式,见[工具兼容性与接入总览](https://platform.lyrouter.com/ai_gateway/docs/tools)。 ### Claude Code 发出的请求用了 Claude 官方模型名,为什么失败? **答:** Claude Code 的后台任务和模型别名会使用 Claude 官方模型名(如 `claude-haiku-4-5`),这不是 LYRouter 的模型 ID。按[Claude Code](https://platform.lyrouter.com/ai_gateway/docs/claude-code)补齐各个模型变量,全部填 LYRouter 的模型 ID,再在日志的「模型(请求)」中确认没有遗漏。 --- # 流式响应 来源: https://platform.lyrouter.com/ai_gateway/docs/streaming 请求中设置 `"stream": true` 后,Chat Completions、Responses 和 Anthropic Messages 三种对话接口都以 SSE(Server-Sent Events)逐段返回内容。三种协议的事件格式、结束标记和 `usage` 的位置各不相同,客户端要按所用协议解析,并以协议的结束标记判断输出是否完整。本章讲协议格式与客户端实现;流式中断、超时的排查见[超时与流式中断](https://platform.lyrouter.com/ai_gateway/docs/stream-errors)。 ## 开启流式 | 接口 | 开启方式 | 响应 `Content-Type` | | --- | --- | --- | | [Chat Completions](https://platform.lyrouter.com/ai_gateway/docs/chat-completions)(`/v1/chat/completions`) | `"stream": true` | `text/event-stream` | | [Responses](https://platform.lyrouter.com/ai_gateway/docs/responses-api)(`/v1/responses`) | `"stream": true` | `text/event-stream` | | [Anthropic Messages](https://platform.lyrouter.com/ai_gateway/docs/anthropic-messages)(`/v1/messages`) | `"stream": true` | `text/event-stream` | - 请求在开始输出之前就被拒绝时(鉴权失败、余额不足、模型不可用等),返回的是普通的 HTTP 错误响应,不是事件流:网关拒绝的请求是 JSON 错误体(`/v1/messages` 为 Anthropic 错误格式),500 / 504 是 HTML 页面。解析事件流之前先检查状态码和 `Content-Type`。 - 流式输出一旦开始,网关不再换通道;上游失败时的处理见下文「中途失败」。 ## SSE 的基本格式 一个事件由若干行组成,以一个空行结束: ```text event: <事件名> data: ``` - `data:` 行是事件内容;同一事件有多行 `data:` 时,按换行拼接。Chat Completions 只有 `data:` 行,Responses 和 Anthropic Messages 还有 `event:` 行给出事件名。 - 冒号后的空格可有可无:`data: {...}` 与 `data:{...}` 按 SSE 规范都合法,实际的流中两种都会出现,自己写解析器时要兼容。 - 还可能有 `id:` 等其他字段行,例如 Responses 流的每个事件前都有一行 `id:`,不需要时忽略即可。 - 以 `:` 开头的行是注释,部分上游用它保持连接,解析时忽略。 - 网络上的一个数据块可能只包含半个事件,也可能包含多个事件。请把数据累积到缓冲区,遇到空行再处理一个完整事件。 ## Chat Completions 每个事件是一行 `data: `,最后以 `data: [DONE]` 结束: ```text data: {"id":"chatcmpl-9f1c2a7e4b","object":"chat.completion.chunk","created":1791950400,"model":"MODEL_ID","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]} data: {"id":"chatcmpl-9f1c2a7e4b","object":"chat.completion.chunk","created":1791950400,"model":"MODEL_ID","choices":[{"index":0,"delta":{"content":"秋风起,"},"finish_reason":null}]} data: {"id":"chatcmpl-9f1c2a7e4b","object":"chat.completion.chunk","created":1791950400,"model":"MODEL_ID","choices":[{"index":0,"delta":{"content":"落叶黄。"},"finish_reason":null}]} data: {"id":"chatcmpl-9f1c2a7e4b","object":"chat.completion.chunk","created":1791950400,"model":"MODEL_ID","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]} data: {"id":"chatcmpl-9f1c2a7e4b","object":"chat.completion.chunk","created":1791950400,"model":"MODEL_ID","choices":[],"usage":{"prompt_tokens":18,"completion_tokens":12,"total_tokens":30,"prompt_tokens_details":{"cached_tokens":0}}} data: [DONE] ``` | 内容 | 位置 | | --- | --- | | 正文增量 | `choices[0].delta.content` | | 思考过程增量 | `choices[0].delta.reasoning_content`(个别上游为 `delta.reasoning`) | | 工具调用增量 | `choices[0].delta.tool_calls`,按 `index` 拼接,见[工具调用](https://platform.lyrouter.com/ai_gateway/docs/tool-call) | | 结束原因 | 倒数几个 chunk 中的 `choices[0].finish_reason` | | 用量 | `choices` 为空数组的那个 chunk 的 `usage` | | 结束标记 | `data: [DONE]` | - 网关总会把 `stream_options` 设为 `{"include_usage": true}`,所以一定有带 `usage` 的 chunk,它的 `choices` 是空数组。读取 `choices[0]` 前先判断数组非空。 - 由 Anthropic 协议通道服务时,chunk 由网关转换生成:带 `usage` 的 chunk 只有 `prompt_tokens`、`completion_tokens`、`total_tokens`,其中 `prompt_tokens` 不含缓存命中,缓存数量请在[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)中查看。 - 字段的含义与日志四项 Token 的对应关系见 [Chat Completions](https://platform.lyrouter.com/ai_gateway/docs/chat-completions)。 ## Responses 每个事件带事件名,`data` 中的 `type` 与事件名相同,`sequence_number` 递增。每个事件前还有一行 `id:`,下面的片段省略了它: ```text event: response.created data: {"type":"response.created","sequence_number":0,"response":{"id":"resp_68f1a2b3","object":"response","created_at":1791950400,"status":"queued","model":"MODEL_ID","output":[],"usage":null}} event: response.output_item.added data: {"type":"response.output_item.added","sequence_number":2,"output_index":0,"item":{"id":"msg_68f1a2c4","type":"message","status":"in_progress","role":"assistant","content":[]}} event: response.output_text.delta data: {"type":"response.output_text.delta","sequence_number":4,"item_id":"msg_68f1a2c4","output_index":0,"content_index":0,"delta":"秋风起,"} event: response.output_text.delta data: {"type":"response.output_text.delta","sequence_number":5,"item_id":"msg_68f1a2c4","output_index":0,"content_index":0,"delta":"落叶黄。"} event: response.output_text.done data: {"type":"response.output_text.done","sequence_number":6,"item_id":"msg_68f1a2c4","output_index":0,"content_index":0,"text":"秋风起,落叶黄。"} event: response.completed data: {"type":"response.completed","sequence_number":9,"response":{"id":"resp_68f1a2b3","object":"response","status":"completed","model":"MODEL_ID","output":[{"id":"msg_68f1a2c4","type":"message","status":"completed","role":"assistant","content":[{"type":"output_text","text":"秋风起,落叶黄。","annotations":[]}]}],"usage":{"input_tokens":18,"input_tokens_details":{"cached_tokens":0},"output_tokens":12,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":30}}} ``` | 事件 | 含义 | | --- | --- | | `response.created`、`response.in_progress` | 响应已创建、正在生成。`response.created` 中的 `status` 可能是 `queued` | | `response.output_item.added` / `.done` | 一个输出项开始 / 结束,类型为 `message`、`reasoning`、`function_call` 等 | | `response.content_part.added` / `.done` | 消息中的一个内容块开始 / 结束 | | `response.output_text.delta` / `.done` | 文本增量(`delta`)/ 该内容块的完整文本(`text`) | | `response.reasoning_text.delta` / `.done` | 推理文本增量 / 完整推理文本,推理模型会返回 | | `response.function_call_arguments.delta` / `.done` | 函数调用参数增量 / 完整参数,见[工具调用](https://platform.lyrouter.com/ai_gateway/docs/tool-call) | | `response.completed` | 正常结束,`response.usage` 是本次用量 | | `response.incomplete` | 未完整生成就结束,例如达到 `max_output_tokens` | | `response.failed`、`error` | 生成失败、上游报告错误 | - 网关原样转发通道返回的 Responses 事件,不追加 `stream_options`,也通常没有 `data: [DONE]`。 - 用量在 `response.completed` 的 `response.usage` 中:`input_tokens` 包含缓存命中,命中数量在 `input_tokens_details.cached_tokens`。 ## Anthropic Messages ```text event: message_start data: {"type":"message_start","message":{"id":"msg_01XFDUDYJgAACzvnptvVoYEL","type":"message","role":"assistant","model":"MODEL_ID","content":[],"usage":{"input_tokens":18,"output_tokens":0}}} event: content_block_start data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}} event: content_block_delta data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"秋风起,"}} event: content_block_delta data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"落叶黄。"}} event: content_block_stop data: {"type":"content_block_stop","index":0} event: message_delta data: {"type":"message_delta","delta":{"stop_reason":"end_turn"},"usage":{"input_tokens":18,"output_tokens":12}} event: message_stop data: {"type":"message_stop"} ``` | 事件 | 含义 | | --- | --- | | `message_start` | 消息开始,`message.usage` 中有输入 Token 数 | | `content_block_start` | 一个内容块开始,类型为 `text`、`thinking` 或 `tool_use` | | `content_block_delta` | 增量:`text_delta`(正文)、`thinking_delta`(思考)、`signature_delta`(思考块签名)、`input_json_delta`(工具参数) | | `content_block_stop` | 内容块结束 | | `message_delta` | `delta.stop_reason`(`end_turn`、`max_tokens`、`tool_use` 等)和最终 `usage` | | `message_stop` | 正常结束 | | `ping` | 保持连接,忽略即可 | | `error` | 错误 | - 以 `message_delta` 中的 `usage` 为准。由 OpenAI 兼容通道服务时,事件由网关转换生成,`message_start` 中的 `input_tokens` 为 0,最终数量只在 `message_delta` 中。有缓存读取或写入时,`message_delta.usage` 还分别带 `cache_read_input_tokens`、`cache_creation_input_tokens`。 - `input_tokens` 不含缓存读取和缓存写入,计算方法见[调用费用与缓存计费](https://platform.lyrouter.com/ai_gateway/docs/estimate)。 ## 结束标记与 usage 一览 | 接口 | 正常结束 | usage 在哪里 | 中途失败的错误事件 | | --- | --- | --- | --- | | Chat Completions | `data: [DONE]` | `choices` 为空数组的 chunk | `data: {"error": {...}}` | | Responses | `response.completed` 事件 | `response.completed` 的 `response.usage` | `response.failed` 事件 | | Anthropic Messages | `message_stop` 事件 | `message_delta` 的 `usage` | `event: error` | 没有收到正常结束标记就断开的流,一律按失败处理。 ## 中途失败 流式输出开始后上游中断或超时,网关不换通道,在流的末尾补一个错误事件后结束连接: ```text data: {"error": {"message": "upstream timed out after the response had started", "type": "api_error", "code": "stream_interrupted"}} ``` ```text event: error data: {"type": "error", "error": {"type": "api_error", "message": "upstream timed out after the response had started"}} ``` - 第一种用于 Chat Completions,第二种用于 Anthropic Messages。Responses 补的是 `response.failed` 事件,`response.error.code` 为 `server_error`,`sequence_number` 接着流中已发出的事件编号: ```text event: response.failed data: {"type": "response.failed", "sequence_number": 42, "response": {"id": "resp_...", "object": "response", "status": "failed", "error": {"code": "server_error", "message": "upstream timed out after the response had started"}}} ``` - 超时时 `message` 为 `upstream timed out after the response had started`,连接或读取失败时为 `upstream failed after the response had started`。 - 出现错误事件后不会再有 `data: [DONE]`、`message_stop` 或 `response.completed`。上游自己在流中发出的错误事件(例如 Anthropic 的 `overloaded_error`)会按你调用的协议转给你。 - OpenAI、Anthropic 官方 SDK 收到对应格式的错误事件会抛出异常。日志中这类请求的状态是 200,原因和重试建议见[超时与流式中断](https://platform.lyrouter.com/ai_gateway/docs/stream-errors)。 ## 客户端实现要点 - **按完整事件解析**:累积数据、遇到空行再处理;拼接多行 `data:`;忽略注释行和不认识的事件;`data: [DONE]` 不是 JSON,要先判断再解析。 - **以结束标记判断完整**:收到结束标记才把结果当作完整输出;收到错误事件或连接提前关闭,都按失败处理,重试前做好去重(例如已经执行过的工具操作)。 - **超时**:网关等待上游时,两段数据之间最多等 6 分钟。客户端的读取超时设得比 6 分钟长,并优先使用两次读取之间的空闲超时,而不是整次请求的总超时。 - **代理不缓冲**:应用与 LYRouter 之间有 Nginx 等反向代理时,关闭响应缓冲(Nginx 设置 `proxy_buffering off`),并把代理的读超时设得比 6 分钟长,否则内容会攒成一大块到达,或被代理提前断开。 - **命令行测试**:`curl` 加 `-N` 关闭输出缓冲,才能看到逐段到达的事件。 下面是不依赖 SDK、手动解析 Chat Completions 事件流的写法,可作为其他语言实现的参考: **流式请求示例** cURL: ```bash curl -N https://api.lyrouter.com/v1/chat/completions \ -H "Authorization: Bearer $LYROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"MODEL_ID","stream":true,"messages":[{"role":"user","content":"写两行关于秋天的诗"}]}' ``` Python: ```python import json import os import requests resp = requests.post( "https://api.lyrouter.com/v1/chat/completions", headers={"Authorization": f"Bearer {os.environ['LYROUTER_API_KEY']}"}, json={ "model": "MODEL_ID", "stream": True, "messages": [{"role": "user", "content": "写两行关于秋天的诗"}], }, stream=True, timeout=(10, 400), # 连接超时 10 秒;两次读取之间最多等 400 秒 ) resp.raise_for_status() resp.encoding = "utf-8" done = False data_lines = [] for line in resp.iter_lines(decode_unicode=True): if line.startswith(":"): continue # 注释行 if line.startswith("data:"): data_lines.append(line[5:].lstrip()) continue if line != "" or not data_lines: continue # event: 等其他字段,或多余的空行 data = "\n".join(data_lines) # 空行:一个完整事件 data_lines = [] if data == "[DONE]": done = True break event = json.loads(data) if "error" in event: raise RuntimeError(event["error"].get("message")) for choice in event.get("choices", []): print(choice.get("delta", {}).get("content") or "", end="", flush=True) if event.get("usage"): print("\n", event["usage"]) if not done: raise RuntimeError("流在结束标记之前中断,输出不完整") ``` Node.js: ```js const resp = await fetch("https://api.lyrouter.com/v1/chat/completions", { method: "POST", headers: { Authorization: `Bearer ${process.env.LYROUTER_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ model: "MODEL_ID", stream: true, messages: [{ role: "user", content: "写两行关于秋天的诗" }], }), }); if (!resp.ok) throw new Error(`HTTP ${resp.status}: ${await resp.text()}`); const decoder = new TextDecoder(); let buffer = ""; let done = false; for await (const bytes of resp.body) { buffer = (buffer + decoder.decode(bytes, { stream: true })).replace(/\r\n/g, "\n"); let end; while (!done && (end = buffer.indexOf("\n\n")) !== -1) { const block = buffer.slice(0, end); // 一个完整事件 buffer = buffer.slice(end + 2); const data = block .split("\n") .filter((line) => line.startsWith("data:")) .map((line) => line.slice(5).trimStart()) .join("\n"); if (!data) continue; // 注释或其他字段 if (data === "[DONE]") { done = true; break; } const event = JSON.parse(data); if (event.error) throw new Error(event.error.message); const text = event.choices?.[0]?.delta?.content; if (text) process.stdout.write(text); if (event.usage) console.log("\n", event.usage); } if (done) break; } if (!done) throw new Error("流在结束标记之前中断,输出不完整"); ``` 使用官方 SDK 时,SDK 已经处理了事件解析和结束标记,用法见 [Chat Completions](https://platform.lyrouter.com/ai_gateway/docs/chat-completions) 的流式示例;Responses 与 Anthropic SDK 的流式写法见 [Responses](https://platform.lyrouter.com/ai_gateway/docs/responses-api) 和 [Anthropic Messages](https://platform.lyrouter.com/ai_gateway/docs/anthropic-messages)。 ## 常见问题 ### 最后一个 chunk 的 `choices` 为什么是空数组? **答:** 网关总会开启 `include_usage`,上游在结束前单独发送一个只带 `usage` 的 chunk,它的 `choices` 为空。代码中直接读取 `choices[0]` 会出错,请先判断数组非空。这个 chunk 无法关闭。 ### `stream: true` 却收到了一个 JSON 错误,而不是事件流? **答:** 请求在开始输出之前就被拒绝了,例如鉴权失败、余额不足或模型不可用,网关按普通响应返回状态码和错误体。按状态码处理,见[错误码与请求标识](https://platform.lyrouter.com/ai_gateway/docs/errors)。 ### 流式输出很久才一次性出现? **答:** 通常是中间的代理缓冲了响应。用 `curl -N` 直接请求 LYRouter 对比;直连正常、经过代理不正常时,关闭代理的响应缓冲。如果直连也要等很久才有第一段内容,在[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)中查看「首 Token」,见[超时与流式中断](https://platform.lyrouter.com/ai_gateway/docs/stream-errors)。 ### 没有收到结束标记,已经收到的内容能用吗? **答:** 不能当作完整结果。网关在中途失败时补发错误事件,上游直接断开时可能连错误事件都没有。请把这次调用视为失败,按需重试,并处理好重复内容和已执行工具的去重。 --- # 工具调用 来源: https://platform.lyrouter.com/ai_gateway/docs/tool-call 工具调用(Function Calling)让模型以结构化参数请求调用你定义的函数:应用在请求中声明工具,模型返回要调用的函数名和参数,应用自己执行函数,再把结果发回给模型,由模型给出最终回答。LYRouter 只负责转发和协议转换,不会执行你的任何业务操作。Chat Completions、Responses、Anthropic Messages 三种接口的工具结构不同,网关会在 Chat Completions 与 Anthropic 协议之间自动转换,本章以 Chat Completions 为主给出完整示例,并说明转换时发生了什么。 ## 工作流程 1. 在请求的 `tools` 中定义函数:名称、用途描述、参数的 JSON Schema。 2. 模型决定调用工具时,响应的 `message.tool_calls` 中给出每个调用的 `id`、函数名和参数(JSON 字符串),`finish_reason` 一般为 `tool_calls`。 3. 应用解析参数,校验后执行函数。 4. 把模型返回的 assistant 消息原样追加到 `messages`,再为每个调用追加一条 `role: tool` 消息,`tool_call_id` 填对应调用的 `id`。 5. 再次请求。模型根据工具结果回答,或者继续调用工具,直到响应中不再有 `tool_calls`。 判断是否需要执行工具,请看响应里有没有 `tool_calls`(Anthropic Messages 中为 `tool_use` 块),不要只看 `finish_reason`(`stop_reason`):例如阿里云百炼在 `tool_choice` 指定函数时,可能返回 `tool_calls` 而 `finish_reason` 为 `stop`;通过 Anthropic Messages 用 `{"type": "tool"}` 指定工具时,目前会返回 `tool_use` 块,但 `stop_reason` 为 `end_turn`(`any`、`auto` 时正常)。下文的示例代码按 `message.tool_calls` 判断。 ## 定义工具 ```json { "type": "function", "function": { "name": "get_weather", "description": "查询指定城市当前的天气。用户询问天气、气温时调用。", "parameters": { "type": "object", "properties": { "city": { "type": "string", "description": "城市名,例如 北京" }, "unit": { "type": "string", "enum": ["celsius", "fahrenheit"] } }, "required": ["city"] } } } ``` | 字段 | 说明 | | --- | --- | | `type` | 固定为 `function` | | `function.name` | 函数名,只用字母、数字、下划线和连字符,同一请求内不重复 | | `function.description` | 说明什么时候该调用、返回什么。描述越具体,模型越容易正确选择工具 | | `function.parameters` | 参数的 JSON Schema,顶层为 `object`。长整数 ID 请定义为 `string`,原因见下文「跨协议转换」 | | `function.strict` | 是否严格按 Schema 生成参数,透传给 OpenAI 兼容通道,是否生效取决于模型;Anthropic 协议通道不转发 | 模型必须支持工具调用,在模型广场的模型详情中确认。 ## 完整的两轮示例 ### 第 1 轮:发送问题和工具定义 ```bash curl https://api.lyrouter.com/v1/chat/completions \ -H "Authorization: Bearer $LYROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "MODEL_ID", "messages": [ {"role": "user", "content": "北京现在天气怎么样?"} ], "tools": [{ "type": "function", "function": { "name": "get_weather", "description": "查询指定城市当前的天气。", "parameters": { "type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"] } } }] }' ``` 模型决定调用工具,返回: ```json { "id": "chatcmpl-5d1e8b20a3", "object": "chat.completion", "created": 1791950400, "model": "MODEL_ID", "choices": [ { "index": 0, "message": { "role": "assistant", "content": null, "tool_calls": [ { "id": "call_8f2a1c", "type": "function", "function": { "name": "get_weather", "arguments": "{\"city\":\"北京\"}" } } ] }, "finish_reason": "tool_calls" } ], "usage": { "prompt_tokens": 96, "completion_tokens": 18, "total_tokens": 114 } } ``` `arguments` 是 JSON **字符串**,需要自己解析。`content` 可能为 `null` 或空字符串,也可能带一段说明文字。 ### 第 2 轮:发回工具结果 把上一轮的 assistant 消息原样放回,后面接一条 `role: tool` 消息。`tools` 保持与第 1 轮相同: ```bash curl https://api.lyrouter.com/v1/chat/completions \ -H "Authorization: Bearer $LYROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "MODEL_ID", "messages": [ {"role": "user", "content": "北京现在天气怎么样?"}, {"role": "assistant", "content": null, "tool_calls": [ {"id": "call_8f2a1c", "type": "function", "function": {"name": "get_weather", "arguments": "{\"city\":\"北京\"}"}} ]}, {"role": "tool", "tool_call_id": "call_8f2a1c", "content": "{\"city\":\"北京\",\"condition\":\"晴\",\"temperature_c\":22}"} ], "tools": [{ "type": "function", "function": { "name": "get_weather", "description": "查询指定城市当前的天气。", "parameters": { "type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"] } } }] }' ``` 模型根据工具结果回答: ```json { "id": "chatcmpl-5d1e8b20b7", "object": "chat.completion", "created": 1791950403, "model": "MODEL_ID", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "北京现在晴,气温 22°C。" }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 142, "completion_tokens": 14, "total_tokens": 156 } } ``` 一次返回多个 `tool_calls` 时,在 assistant 消息之后为每个调用各追加一条 `role: tool` 消息,然后再发起下一次请求。 ## 可运行的最小循环 下面的程序把上面两轮写成循环:执行模型请求的工具,直到模型给出最终回答,最多 5 轮。安装 SDK 和设置环境变量见[完成第一次模型调用](https://platform.lyrouter.com/ai_gateway/docs/quickstart)。 **工具调用循环** Python: ```python import json import os from openai import OpenAI client = OpenAI( api_key=os.environ["LYROUTER_API_KEY"], base_url="https://api.lyrouter.com/v1", ) tools = [ { "type": "function", "function": { "name": "get_weather", "description": "查询指定城市当前的天气。", "parameters": { "type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"], }, }, } ] def get_weather(city): # 换成真实的天气查询 return {"city": city, "condition": "晴", "temperature_c": 22} TOOL_FUNCTIONS = {"get_weather": get_weather} messages = [{"role": "user", "content": "北京现在天气怎么样?"}] for _ in range(5): # 限制循环次数 response = client.chat.completions.create( model="MODEL_ID", messages=messages, tools=tools ) message = response.choices[0].message if not message.tool_calls: print(message.content) break # 原样追加 assistant 消息(含 tool_calls) messages.append(message.model_dump(exclude_none=True)) for call in message.tool_calls: func = TOOL_FUNCTIONS.get(call.function.name) try: args = json.loads(call.function.arguments or "{}") result = func(**args) if func else {"error": "unknown tool"} except Exception as exc: # 参数不合法或执行失败,把错误告诉模型 result = {"error": str(exc)} messages.append( { "role": "tool", "tool_call_id": call.id, "content": json.dumps(result, ensure_ascii=False), } ) ``` Node.js: ```js import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.LYROUTER_API_KEY, baseURL: "https://api.lyrouter.com/v1", }); const tools = [ { type: "function", function: { name: "get_weather", description: "查询指定城市当前的天气。", parameters: { type: "object", properties: { city: { type: "string" } }, required: ["city"], }, }, }, ]; function getWeather({ city }) { // 换成真实的天气查询 return { city, condition: "晴", temperature_c: 22 }; } const toolFunctions = { get_weather: getWeather }; const messages = [{ role: "user", content: "北京现在天气怎么样?" }]; for (let turn = 0; turn < 5; turn++) { const response = await client.chat.completions.create({ model: "MODEL_ID", messages, tools, }); const message = response.choices[0].message; if (!message.tool_calls?.length) { console.log(message.content); break; } messages.push(message); // 原样追加 assistant 消息(含 tool_calls) for (const call of message.tool_calls) { const fn = toolFunctions[call.function.name]; let result; try { const args = JSON.parse(call.function.arguments || "{}"); result = fn ? fn(args) : { error: "unknown tool" }; } catch (err) { result = { error: String(err) }; // 参数不合法或执行失败,把错误告诉模型 } messages.push({ role: "tool", tool_call_id: call.id, content: JSON.stringify(result), }); } } ``` ## tool_choice 与并行调用 | `tool_choice` | 含义 | 发往 Anthropic 协议通道时 | | --- | --- | --- | | 不写,或 `"auto"` | 模型自行决定是否调用 | `{"type": "auto"}` | | `"required"` | 必须调用至少一个工具 | `{"type": "any"}` | | `{"type": "function", "function": {"name": "get_weather"}}` | 必须调用指定的工具 | `{"type": "tool", "name": "get_weather"}` | | `"none"` | 不调用工具 | 不转发,模型仍可能调用工具。不希望调用时,请不要传 `tools` | - `parallel_tool_calls: false` 要求一次最多返回一个调用,透传给 OpenAI 兼容通道,是否生效取决于模型;发往 Anthropic 协议通道时会被去掉,模型仍可能一次返回多个调用。应用应始终按数组处理 `tool_calls`。 - 强制调用(`"required"` 或指定函数)且请求没有写 `enable_thinking` / `thinking_budget` 时,阿里云百炼通道会被自动加上 `enable_thinking: false`,因为这类上游在思考模式下不接受强制工具调用。 ## 流式下拼接工具参数 流式请求中,工具调用分多个 chunk 到达:第一个分片带 `id`、`type` 和函数名,之后的分片只带 `arguments` 的一段。 ```text data: {"id":"chatcmpl-5d1e8b20a3","object":"chat.completion.chunk","created":1791950400,"model":"MODEL_ID","choices":[{"index":0,"delta":{"role":"assistant","content":null,"tool_calls":[{"index":0,"id":"call_8f2a1c","type":"function","function":{"name":"get_weather","arguments":""}}]},"finish_reason":null}]} data: {"id":"chatcmpl-5d1e8b20a3","object":"chat.completion.chunk","created":1791950400,"model":"MODEL_ID","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\"city\":"}}]},"finish_reason":null}]} data: {"id":"chatcmpl-5d1e8b20a3","object":"chat.completion.chunk","created":1791950400,"model":"MODEL_ID","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\"北京\"}"}}]},"finish_reason":null}]} data: {"id":"chatcmpl-5d1e8b20a3","object":"chat.completion.chunk","created":1791950400,"model":"MODEL_ID","choices":[{"index":0,"delta":{},"finish_reason":"tool_calls"}]} data: {"id":"chatcmpl-5d1e8b20a3","object":"chat.completion.chunk","created":1791950400,"model":"MODEL_ID","choices":[],"usage":{"prompt_tokens":96,"completion_tokens":18,"total_tokens":114}} data: [DONE] ``` - 以 `tool_calls[].index` 为键分组,同一 `index` 的 `arguments` 按到达顺序拼接成完整字符串。 - `id` 和函数名取第一个非空的值。部分上游会在后续分片里重复发送空字符串的 `id` 和 `name`,不要用空值覆盖。 - 收到带 `finish_reason` 的 chunk 或流结束后再解析参数 JSON,中途的片段不是合法 JSON。`finish_reason` 不一定是 `"tool_calls"`,见上文「工作流程」。 - Anthropic Messages 中对应的是 `content_block_start`(`tool_use` 块,带 `id` 和 `name`)和多个 `input_json_delta`,按块的 `index` 拼接 `partial_json`;Responses 中是 `response.output_item.added`(`function_call` 项)和 `response.function_call_arguments.delta`,`response.function_call_arguments.done` 给出完整参数。事件格式见[流式响应](https://platform.lyrouter.com/ai_gateway/docs/streaming)。 ## 三种协议的结构对照 | 环节 | Chat Completions | Responses | Anthropic Messages | | --- | --- | --- | --- | | 定义工具 | `{"type": "function", "function": {"name", "description", "parameters"}}` | `{"type": "function", "name", "description", "parameters"}`,没有 `function` 包裹层 | `{"name", "description", "input_schema"}` | | 模型发起调用 | `message.tool_calls[]`:`id`、`function.name`、`function.arguments`(JSON 字符串) | `output[]` 中 `type: "function_call"` 的项:`call_id`、`name`、`arguments`(JSON 字符串) | `content[]` 中 `type: "tool_use"` 的块:`id`、`name`、`input`(JSON 对象) | | 表示需要工具结果 | `message.tool_calls` 非空(`finish_reason` 一般为 `"tool_calls"`) | `output` 中有 `function_call` 项 | `content` 中有 `tool_use` 块(`stop_reason` 一般为 `"tool_use"`) | | 发回结果 | `{"role": "tool", "tool_call_id": "...", "content": "..."}` | 在 `input` 中追加 `{"type": "function_call_output", "call_id": "...", "output": "..."}` | 在 `role: "user"` 消息中放 `{"type": "tool_result", "tool_use_id": "...", "content": "..."}` 块 | | 对应关系 | `tool_call_id` = `tool_calls[].id` | `call_id` = `function_call.call_id` | `tool_use_id` = `tool_use.id` | | 强制调用 | `"required"` / 指定 `function.name` | `"required"` / `{"type": "function", "name": "..."}` | `{"type": "any"}` / `{"type": "tool", "name": "..."}` | | 禁止并行 | `parallel_tool_calls: false` | `parallel_tool_calls: false` | `tool_choice.disable_parallel_tool_use: true` | Responses 的调用与回传: ```json {"type": "function_call", "id": "fc_68f1b0a1", "call_id": "call_8f2a1c", "name": "get_weather", "arguments": "{\"city\":\"北京\"}", "status": "completed"} {"type": "function_call_output", "call_id": "call_8f2a1c", "output": "{\"condition\":\"晴\",\"temperature_c\":22}"} ``` Anthropic Messages 的调用与回传: ```json {"role": "assistant", "content": [{"type": "tool_use", "id": "toolu_01A09q90qw90lq917835lq9", "name": "get_weather", "input": {"city": "北京"}}]} {"role": "user", "content": [{"type": "tool_result", "tool_use_id": "toolu_01A09q90qw90lq917835lq9", "content": "{\"condition\":\"晴\",\"temperature_c\":22}"}]} ``` Responses 请求由网关原样转发,不做工具结构的转换。用 `previous_response_id` 接续时,网关只用它识别会话,接续请求不一定发往创建上一条响应的上游,详见 [Responses](https://platform.lyrouter.com/ai_gateway/docs/responses-api)。 ## 跨协议转换 Chat Completions 请求由 Anthropic 协议通道服务、或 Anthropic Messages 请求由 OpenAI 兼容通道服务时,网关转换工具相关的结构: | 方向 | 网关的处理 | | --- | --- | | Chat Completions → Anthropic 协议通道 | `tools[].function` 转为 `name`、`description`、`input_schema`,只转换 `type: "function"` 的工具,`strict` 不转发;历史中的 `tool_calls[].function.arguments` 解析为 `input` 对象,不是合法 JSON 时按 `{}` 发送;每条 `role: tool` 消息转为一条带 `tool_result` 块的 user 消息;`tool_choice` 按上表转换,`parallel_tool_calls` 去掉。响应中的 `tool_use` 块转回 `tool_calls`,`stop_reason: "tool_use"` 转为 `finish_reason: "tool_calls"` | | Anthropic Messages → OpenAI 兼容通道 | `tools` 转为 `type: "function"` 的工具;`tool_use` 块转为 `tool_calls`,`input` 序列化为 `arguments` 字符串;`tool_result` 块转为 `role: tool` 消息,`is_error` 不转发;`tool_choice` 的 `auto`、`any`、`tool` 分别转为 `"auto"`、`"required"`、指定函数,`{"type": "none"}` 和 `disable_parallel_tool_use` 不转发。响应中的 `tool_calls` 转回 `tool_use` 块,参数不是合法 JSON 时 `input` 为 `{}`;`stop_reason` 按上游的 `finish_reason` 换算(`tool_calls` 转为 `tool_use`,`stop` 转为 `end_turn`),与有没有 `tool_calls` 无关 | 另外,网关在发出请求前还会: - **固定 JSON 键序**:把发往上游的请求体中所有 JSON 对象的键按固定顺序重新排列(数组顺序不变),并对历史消息中 `tool_calls[].function.arguments`、Responses `input` 中 `function_call` 项的 `arguments` 字符串里的 JSON 做同样的处理。客户端每轮把同一个参数对象写成不同键序时,上游看到的字节仍然相同,提示词缓存不会因此失效。参数不是合法 JSON 对象、或含有连续 15 位以上数字时保持原样。这一处理只影响发往上游的请求,不改变返回给你的内容。 - **数字精度**:网关解析并重新编码 JSON 时,数字最多保留 14 位有效数字。Anthropic Messages 的 `input` 对象、以及跨协议转换时的工具参数都会经过解析,19 位的订单号、雪花 ID 等长整数会变成科学计数法,请在参数 Schema 中定义为 `string`。 - **思考内容**:发往 OpenAI 兼容通道前,历史 assistant 消息上的 `reasoning_content` 会被删除。DeepSeek 系列例外:思考模式要求回传当前轮的思考内容,所以最后一条 user 消息之后的 assistant 消息上非空的 `reasoning_content` 会保留;DeepSeek 仍因缺少它返回 400 时,网关补上空值后在同一通道重试一次。由开启思考的 Anthropic 协议通道服务时,非流式响应的 `message` 带有 `reasoning_blocks`(LYRouter 扩展字段),把 assistant 消息原样放回,网关才能把带签名的思考块交还上游。 ## 注意事项 - **工具结果和补充说明分开发送**:通过 Anthropic Messages 调用时,把 `tool_result` 块和给模型的补充文字放在两条消息里,不要放进同一条 user 消息,以便在转换到 OpenAI 兼容通道时完整保留。 - **执行失败也要回传**:工具出错时,把错误信息写进结果内容(例如 `{"error": "城市不存在"}`),让模型据此调整;`tool_result` 的 `is_error` 标记在转换到 OpenAI 兼容通道时不会保留。 - **校验后再执行**:模型生成的参数可能不完整或不合法,执行前按 Schema 校验,并检查调用方是否有权执行该操作。有副作用的工具(下单、发邮件、删除数据)先让用户确认,并为每次操作携带幂等标识,避免流式中断后重试造成重复执行。 - **限制循环次数**:为工具循环设置最大轮数和总超时,防止模型反复调用。 - **工具定义保持稳定**:同一会话中不要增删或调整工具的顺序和内容,否则之后的提示词缓存都无法命中,见[降低成本与优化缓存](https://platform.lyrouter.com/ai_gateway/docs/cost-practice)。 - **日志会保存工具调用**:模型返回的工具调用(函数名与参数)在全文日志关闭时也会保存,参数中不要放密码等敏感信息,见[日志内容与数据处理](https://platform.lyrouter.com/ai_gateway/docs/privacy)。 ## 常见问题 ### 模型没有调用工具,直接给出了回答? **答:** 先确认所选模型支持工具调用;再检查工具的 `description` 是否说明了什么情况下调用。需要确保调用时,把 `tool_choice` 设为 `"required"` 或指定函数。 ### 强制调用工具时,上游返回 400? **答:** 部分模型在思考模式下不接受强制工具调用,例如阿里云百炼返回 `The tool_choice parameter does not support being set to required or object in thinking mode`。不写思考参数时,网关会为阿里云百炼通道自动关闭思考;如果请求中自己写了 `enable_thinking: true` 或 `thinking_budget`,请去掉,或把 `tool_choice` 改为 `"auto"`。 ### 第 2 轮请求报错,提示找不到工具调用 ID 或消息顺序不对? **答:** 检查三点:assistant 消息是否原样放回且带 `tool_calls`;每个调用是否都有一条 `role: tool` 消息,`tool_call_id` 与调用的 `id` 一致;`role: tool` 消息是否紧跟在对应的 assistant 消息之后。报错原文由上游返回,在[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)详情「原始报文」的「上游响应」中查看。 ### 在日志里怎么看工具调用? **答:** 打开[请求日志](https://platform.lyrouter.com/ai_gateway/docs/logs)详情的「对话」页签,「工具调用」中列出请求定义的工具和 `tool_choice`,以及模型返回的每个调用的函数名与参数。路由到哪个服务商、是否发生协议转换,在「服务商」和「原始报文」的「上游请求」中确认。 --- # 异步任务 来源: https://platform.lyrouter.com/ai_gateway/docs/async 视频生成通常需要几分钟,LYRouter 以异步任务的方式提供:`POST /v1/videos` 提交后立即返回一个以 `aigwt_` 开头的任务 ID,之后用 `GET /v1/videos/{id}` 查询状态,完成后用 `GET /v1/videos/{id}/content` 下载视频。网关会替你向服务商轮询任务进度,你的查询只读取网关记录的状态;费用在任务完成时结算,失败或超时的任务不收费。各模型的参数、尺寸和计费单位见[多模态能力](https://platform.lyrouter.com/ai_gateway/docs/multimodal),本页只讲任务的生命周期。 ## 生命周期 | 步骤 | 方法与路径 | 返回 | | --- | --- | --- | | 1. 提交 | `POST https://api.lyrouter.com/v1/videos` | 任务对象,`status` 为 `queued` | | 2. 查询 | `GET https://api.lyrouter.com/v1/videos/{id}` | 任务对象,`status` 随进度变化 | | 3. 下载 | `GET https://api.lyrouter.com/v1/videos/{id}/content` | 302 跳转到视频文件地址 | | 删除 | `DELETE https://api.lyrouter.com/v1/videos/{id}` | 任务已结束时返回任务对象并带 `"deleted": true`;任务记录不会因此删除,进行中的任务返回 409 | - **提交**:鉴权与其他接口相同。请求体可以是 JSON,也可以是 `multipart/form-data`(OpenAI 官方 SDK 的 `videos.create()` 使用这种格式);用表单提交时,`input_reference` 只能填可公开访问的 `https://` 地址:目前上传文件不会报错,但文件会被忽略,任务按没有参考视频的方式生成并照常计费;`first_frame`、`last_frame`、`reference_image`、`reference_audio` 请用 JSON 提交,目前它们在表单里会被换成占位值转发给服务商,导致提交被服务商拒绝或任务失败。参数见[多模态能力](https://platform.lyrouter.com/ai_gateway/docs/multimodal)中的「视频通用参数」和各模型章节。 - **同一模型的其他任务**:部分模型还提供 `POST /v1/videos/regenerations`(视频升清)和 `POST /v1/videos/context`(上下文增强,产出的是文本),它们返回同样的任务对象,用同样的方式查询,见[多模态能力](https://platform.lyrouter.com/ai_gateway/docs/multimodal)。 - **谁能查询**:同一工作空间内的任意 API Key 都能查询、下载该工作空间的任务;其他工作空间的 Key 查询时返回 404。 - **只接受具体模型**:虚拟模型和 `lyrouter/auto` 不能用于视频接口,失败时也不会改用默认模型。 ## 任务对象 提交、查询返回的都是同一种任务对象。下面是一个已完成任务的示例: ```json { "id": "aigwt_volcengine_videos_MXgno8VlzuzZtJl0kq83jA", "object": "video", "model": "doubao-seedance-2-0-mini-260615", "status": "completed", "progress": 100, "created_at": 1791950400, "completed_at": 1791950538, "expires_at": 1792555200, "seconds": 5, "size": "1280x720", "usage": { "duration_seconds": 5, "completion_tokens": 108900 } } ``` | 字段 | 说明 | | --- | --- | | `id` | 网关的任务 ID,格式为 `aigwt_<服务商>_<任务类型>_<随机串>`。它不是服务商的任务 ID,向服务商报障时请用 `error.provider_request_id` | | `object` | 固定为 `video` | | `model` | 实际调用的上游模型名,可能与请求中的模型 ID 写法不同 | | `status` | `queued`、`in_progress`、`completed`、`failed`,见下表 | | `progress` | 完成前为 `0`,完成后为 `100`,不表示中间进度,请以 `status` 判断 | | `created_at` / `completed_at` | 提交时间、结束时间(Unix 秒)。`completed_at` 只在任务结束后出现 | | `expires_at` | 任务记录的过期时间,提交后 7 天。过期后查询返回 404 | | `seconds` / `size` | 原样回显提交时的值 | | `output_text` | 仅上下文增强任务有,为增强后的提示词 | | `error` | 仅 `failed` 时出现,见下文「失败的任务」 | | `usage` | 任务完成后的计量:视频任务为 `duration_seconds`(视频秒数),按 Token 计费的模型(如 Seedance)另有 `completion_tokens`;上下文增强任务为 `completion_tokens` | | `status` | 含义 | 你需要做的 | | --- | --- | --- | | `queued` | 已受理,尚未开始生成 | 继续轮询 | | `in_progress` | 服务商正在生成 | 继续轮询 | | `completed` | 已完成 | 调用 `/content` 下载,或读取 `output_text` | | `failed` | 已失败 | 读取 `error`,不收费 | ## 失败的任务 失败的任务查询时仍返回 HTTP 200,`status` 为 `failed`,原因在 `error` 中: ```json { "id": "aigwt_volcengine_videos_Qw3hTz0bVn1sLk8pYc4dRe", "object": "video", "model": "doubao-seedance-2-0-mini-260615", "status": "failed", "progress": 0, "created_at": 1791950400, "completed_at": 1791950482, "expires_at": 1792555200, "seconds": 5, "error": { "code": "OutputVideoSensitiveContentDetected", "message": "The request failed because the output video may contain sensitive information.", "provider_request_id": "021791950538123abcdef", "retryable": false } } ``` | `error.code` | 含义 | | --- | --- | | `deadline_exceeded` | 提交后 24 小时仍未完成。目前这个状态不会同步到查询接口,`GET /v1/videos/{id}` 可能一直显示 `queued` 或 `in_progress`,请按下文「设置等待上限」处理 | | `canceled` | 任务被取消。目前不支持取消进行中的任务,正常使用不会出现 | | `upstream_error` | 服务商报告失败,但没有给出可识别的错误码 | | 服务商的错误码 | 原样返回,例如 `InvalidParameter`、`OutputVideoSensitiveContentDetected` 等 | - `error.provider_request_id`:服务商自己的请求标识,联系服务商或 LYRouter 支持时提供它。没有时不出现。 - `error.retryable`:`false` 表示原样重试也不会成功(例如参数不合法、内容审核未通过),需要修改请求;`true` 表示可以重试。网关无法判断时不出现这个字段,请不要把缺失当成 `false`。 - 以上失败都不收费。 ## 轮询建议 - **间隔**:提交后约 10 秒开始查询,之后逐步放宽到每 30 秒一次。网关在后台按自己的节奏向服务商轮询,查询得更频繁不会更早拿到结果。 - **只在完成后下载**:任务未完成时调用 `/content` 返回 409。这类 4xx 也会计入 API Key 的错误率,频繁调用可能触发[熔断](https://platform.lyrouter.com/ai_gateway/docs/rate-errors),请先查询到 `completed` 再下载。 - **查询失败不等于任务失败**:查询超时或网络错误时,保留任务 ID 继续查询,不要重新提交。重新提交会生成一个新任务并再次计费。 - **设置等待上限**:提交 24 小时后仍未完成的任务不会再有结果,也不收费,可以停止轮询。在控制台工作空间的 **多媒体生成** 页面按任务 ID 搜索,可以看到任务的「状态」(如「生成中」「已过期」)、「失败原因」和产物。 - **服务商并发已满**:提交时返回 429 `upstream_concurrency_full` 表示该服务商账户的并发任务已满,这个限制按服务商账户共享,换一个 API Key 也一样,请稍后重新提交。 ## 下载产物 `GET /v1/videos/{id}/content` 返回 302,`Location` 头是服务商提供的带签名的视频地址。让客户端跟随跳转即可下载(cURL 加 `-L`,Python `httpx` 设 `follow_redirects=True`,Node.js 的 `fetch` 默认跟随)。只想拿到地址时不跟随跳转,读取 `Location` 头: ```bash curl -s -o /dev/null -w '%{redirect_url}\n' \ https://api.lyrouter.com/v1/videos/$TASK_ID/content \ -H "Authorization: Bearer $LYROUTER_API_KEY" ``` - 视频地址在任务完成时确定,之后每次调用 `/content` 都跳转到同一个地址。地址的有效期由服务商决定,通常为 24 小时,过期后无法通过网关重新获取,请拿到后立即下载或转存到自己的存储。 - 上下文增强任务的结果是 `output_text` 中的文本,没有 `/content` 可下载。 ## 计费与结算 - **价格在提交时锁定**:提交之后再调价,不影响这个任务的费用。 - **数量按实际结果计算**:任务完成时,按服务商实际返回的计量(如视频秒数、Token 数)计费,而不是按请求中填写的值。各模型的计费单位和分档见[多模态能力](https://platform.lyrouter.com/ai_gateway/docs/multimodal)。 - **完成时扣费**:费用在任务变为 `completed` 时结算;`failed` 的任务(包括超时)不收费。提交请求本身不产生费用。 - **在日志中查看**:在[日志](https://platform.lyrouter.com/ai_gateway/docs/logs)列表的 **自定义列** 中打开「任务类型」「费用」两列。提交请求的「任务类型」显示「异步」,任务结算前「费用」显示「结算中」,结算后显示该任务的费用。打开日志详情会看到「创建任务的这次请求本身不产生费用,钱记在它拉起的任务上」以及任务 ID,切换到「整个任务」可查看任务的「结算状态」和「任务费用」。失败的任务不会结算,日志列表可能一直显示「结算中」,请以 **多媒体生成** 页面中的任务状态为准。 - **配额**:任务的费用在结算时计入适用的信用点[配额](https://platform.lyrouter.com/ai_gateway/docs/quota)。 ## 完整示例:提交、轮询、下载 把 `MODEL_ID` 换成模型广场中的视频模型 ID,并按该模型支持的取值填写 `seconds`、`size`(见[多模态能力](https://platform.lyrouter.com/ai_gateway/docs/multimodal))。cURL 示例需要 `jq`,请保存为脚本文件后用 `bash` 运行(出错时用 `exit` 退出)。 **视频任务示例** cURL: ```bash BASE=https://api.lyrouter.com/v1 AUTH="Authorization: Bearer $LYROUTER_API_KEY" # 1. 提交任务;没拿到任务 ID 就打印响应并退出,不要继续轮询 RESP=$(curl -s "$BASE/videos" -H "$AUTH" -H "Content-Type: application/json" \ -d '{"model":"MODEL_ID","prompt":"一只柯基在草地上奔跑,阳光穿过树叶","seconds":5}') TASK_ID=$(echo "$RESP" | jq -r '.id // empty') if [ -z "$TASK_ID" ]; then echo "提交失败:$RESP"; exit 1; fi echo "task: $TASK_ID" # 2. 轮询:从 10 秒开始,逐步放宽到 30 秒,直到结束;最多等 2 小时 DELAY=10 GIVE_UP_AT=$(( $(date +%s) + 2 * 3600 )) while true; do if [ "$(date +%s)" -gt "$GIVE_UP_AT" ]; then echo "$TASK_ID 仍在生成,可稍后用同一个 ID 继续查询"; exit 1 fi sleep $DELAY DELAY=$(( DELAY * 3 / 2 > 30 ? 30 : DELAY * 3 / 2 )) TASK=$(curl -s "$BASE/videos/$TASK_ID" -H "$AUTH") STATUS=$(echo "$TASK" | jq -r '.status') echo "status: $STATUS" case "$STATUS" in completed|failed) break ;; queued|in_progress|"") ;; # 空值多为网络抖动:保留任务 ID 继续查 *) echo "查询出错:$TASK"; exit 1 ;; esac done # 3. 完成则下载,失败则打印原因 if [ "$STATUS" = "completed" ]; then curl -sL "$BASE/videos/$TASK_ID/content" -H "$AUTH" -o video.mp4 else echo "$TASK" | jq '.error' fi ``` Python: ```python import os import time import httpx BASE = "https://api.lyrouter.com/v1" HEADERS = {"Authorization": f"Bearer {os.environ['LYROUTER_API_KEY']}"} with httpx.Client(headers=HEADERS, timeout=60) as client: # 1. 提交任务 resp = client.post(f"{BASE}/videos", json={ "model": "MODEL_ID", "prompt": "一只柯基在草地上奔跑,阳光穿过树叶", "seconds": 5, }) resp.raise_for_status() dropped = resp.headers.get("X-Gateway-Unsupported-Parameters") if dropped: print("这些参数没有生效:", dropped) task = resp.json() task_id = task.get("id") if not task_id: raise RuntimeError(f"没有拿到任务 ID:{task}") print("task:", task_id) # 2. 轮询:从 10 秒开始,逐步放宽到 30 秒;最多等 2 小时 delay, give_up_at = 10, time.time() + 2 * 3600 while task["status"] in ("queued", "in_progress"): if time.time() > give_up_at: raise TimeoutError(f"{task_id} 仍在生成,可稍后用同一个 ID 继续查询") time.sleep(delay) delay = min(delay * 1.5, 30) try: resp = client.get(f"{BASE}/videos/{task_id}") resp.raise_for_status() except httpx.TransportError: continue # 网络抖动:保留任务 ID 继续查,不要重新提交 task = resp.json() if task["status"] == "failed": err = task.get("error", {}) raise RuntimeError(f"{err.get('code')}: {err.get('message')}") # 3. 下载:接口返回 302,跟随跳转即可 with client.stream("GET", f"{BASE}/videos/{task_id}/content", follow_redirects=True, timeout=600) as video: video.raise_for_status() with open("video.mp4", "wb") as f: for chunk in video.iter_bytes(): f.write(chunk) print("已保存 video.mp4,用量:", task.get("usage")) ``` Node.js: ```js import { writeFile } from "node:fs/promises"; const BASE = "https://api.lyrouter.com/v1"; const headers = { Authorization: `Bearer ${process.env.LYROUTER_API_KEY}` }; const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); // 1. 提交任务 const submit = await fetch(`${BASE}/videos`, { method: "POST", headers: { ...headers, "Content-Type": "application/json" }, body: JSON.stringify({ model: "MODEL_ID", prompt: "一只柯基在草地上奔跑,阳光穿过树叶", seconds: 5, }), }); if (!submit.ok) throw new Error(await submit.text()); let task = await submit.json(); if (!task.id) throw new Error(`没有拿到任务 ID:${JSON.stringify(task)}`); console.log("task:", task.id); // 2. 轮询:从 10 秒开始,逐步放宽到 30 秒 let delay = 10_000; while (task.status === "queued" || task.status === "in_progress") { await sleep(delay); delay = Math.min(delay * 1.5, 30_000); let resp; try { resp = await fetch(`${BASE}/videos/${task.id}`, { headers }); } catch { continue; // 网络抖动:保留任务 ID 继续查,不要重新提交 } if (!resp.ok) throw new Error(await resp.text()); task = await resp.json(); } if (task.status === "failed") { throw new Error(`${task.error?.code}: ${task.error?.message}`); } // 3. 下载:fetch 默认跟随 302 跳转 const video = await fetch(`${BASE}/videos/${task.id}/content`, { headers }); if (!video.ok) throw new Error(`download failed: ${video.status}`); await writeFile("video.mp4", Buffer.from(await video.arrayBuffer())); console.log("saved video.mp4", task.usage); ``` ## 常见错误 错误响应为 `{"error":{"message":"...","type":"...","code":"..."}}`。 | 状态码 | `error.message` | `error.code` | 原因与处理 | | --- | --- | --- | --- | | 404 | `video task not found` | `not_found` | 任务 ID 不存在、已超过 7 天、属于其他工作空间,或传入的是服务商的任务 ID。确认使用提交时返回的 `aigwt_` ID | | 409 | `video is not ready yet` | `not_ready` | 任务还没完成(或已失败)就调用了 `/content`。先查询到 `completed` | | 409 | `cancelling an in-flight video task is not supported: ...` | `cancel_not_supported` | 对进行中的任务调用了 `DELETE`。服务商不提供取消接口,请等待任务结束 | | 429 | `upstream concurrency full` | `upstream_concurrency_full` | 服务商账户的并发任务已满,换 API Key 无效,稍后重新提交 | | 400 | 具体参数的校验原文 | `invalid_parameter` | 视频参数不合法,例如尺寸、时长不在模型支持的范围内。按报错修改,见[多模态能力](https://platform.lyrouter.com/ai_gateway/docs/multimodal) | | 400 | `unsupported parameters for this model: <参数名>` | `unsupported_parameters` | 带了 `X-Gateway-Strict-Parameters: true` 且有模型不支持的参数,见[网关扩展请求头与响应头](https://platform.lyrouter.com/ai_gateway/docs/gateway-headers) | | 403 | `Model is not available in the model plaza` | `model_not_available` | 模型没有在本工作空间开通,或使用了虚拟模型、`lyrouter/auto`。换用已开通的具体模型 ID | - 用表单提交时 `input_reference` 只能传 URL。目前上传文件**不会报错**,文件会被忽略,任务按没有参考视频的方式生成并照常计费;只有填了非 URL 的文本(如 `video.mp4`)时才返回 400 纯文本 `input_reference must be a URL; uploading a file is not supported by this gateway (pass a publicly reachable https:// URL instead)`。这类由网关返回的纯文本报错,响应头目前仍是 `Content-Type: application/json`,解析前请先判断正文是不是 JSON。 - 提交时服务商拒绝请求的,状态码和报错原文由服务商决定。完整列表见[错误码与请求标识](https://platform.lyrouter.com/ai_gateway/docs/errors)。 --- # 网关扩展请求头与响应头 来源: https://platform.lyrouter.com/ai_gateway/docs/gateway-headers 除了 OpenAI、Anthropic 的标准字段,LYRouter 还约定了几个请求头、响应头和特殊模型名:用请求头控制参数校验、声明会话、要求原生直通,从响应头读取被丢弃的参数和配额余量,用特殊模型名调用虚拟模型、Auto 智能路由或默认模型。这些约定都是可选的,不使用时按标准协议正常调用。HTTP 头名不区分大小写。 ## 速查 | 名称 | 方向 | 作用 | 适用接口 | | --- | --- | --- | --- | | `X-Gateway-Strict-Parameters: true` | 请求 | 有参数会被丢弃时,改为返回 400 | 图像、视频 | | `x-session-id` | 请求 | 声明会话,日志按会话归组;原样转发给上游 | 全部 | | `x-gateway-passthrough: require` | 请求 | 要求 Anthropic 原生直通,做不到就返回 400 | `/v1/messages` | | `X-Title` | 请求 | 在日志「客户端」列标识你的应用 | 全部 | | `X-Gateway-Unsupported-Parameters` | 响应 | 列出被网关丢弃的参数 | 图像、视频 | | `x-aigw-quota-<指标>-limit` / `-remaining` / `-reset` | 响应 | 适用配额的上限、剩余量和重置时间 | 调用模型的接口 | | `anthropic-ratelimit-*` | 响应 | Anthropic 格式的限额信息 | `/v1/messages` | | `Retry-After`、`X-RateLimit-Reason`、`X-RateLimit-Reset` | 响应 | API Key 被熔断或封禁 | 调用模型的接口 | | `@vmodel/<名称>`、`@preset/<名称>` | 模型名 | 调用虚拟模型 | 对话类接口等 | | `lyrouter/auto` | 模型名 | Auto 智能路由 | 对话类接口 | | 省略 `model` | 模型名 | 使用工作空间默认模型 | 全部模型接口 | ## 请求头 ### X-Gateway-Strict-Parameters 图像和视频接口会把所选模型不支持的参数丢掉、继续执行,并在响应头 `X-Gateway-Unsupported-Parameters` 中列出。带上这个请求头后,出现会被丢弃的参数时网关直接返回 400,不调用上游、不计费。 - **取值**:只认小写的 `true`,其他值(包括 `True`、`1`)等同于没带。 - **适用接口**:`/v1/images/generations`、`/v1/images/edits`、`/v1/videos`、`/v1/videos/regenerations`、`/v1/videos/context`。对话接口在跨协议转换时去掉的参数不受它控制,见 [Chat Completions](https://platform.lyrouter.com/ai_gateway/docs/chat-completions)。 ```bash curl https://api.lyrouter.com/v1/images/generations \ -H "Authorization: Bearer $LYROUTER_API_KEY" \ -H "Content-Type: application/json" \ -H "X-Gateway-Strict-Parameters: true" \ -d '{"model":"MODEL_ID","prompt":"一只戴墨镜的柴犬","guidance_scale":7}' ``` 所选模型不支持 `guidance_scale` 时返回: ```json { "error": { "message": "unsupported parameters for this model: guidance_scale", "type": "invalid_request_error", "code": "unsupported_parameters" } } ``` 各模型支持哪些参数见[多模态能力](https://platform.lyrouter.com/ai_gateway/docs/multimodal)。 ### x-session-id 为一段对话指定一个固定的会话 ID(例如每个会话生成一个 UUID),同一会话的每次请求都带上同一个值。用于日志归组时,`x-session` 与它等价。 - **日志归组**:[日志](https://platform.lyrouter.com/ai_gateway/docs/logs)的「会话」列按这个值把请求归为一组,来源显示「声明(客户端 x-session-id)」,也可以按「会话 ID」筛选。不带这个头时,网关根据对话内容推断会话,来源显示「推断(网关派生)」,标签末尾带 `≈`。 - **原样转发**:网关把这个头原样转发给上游,不改值。 - **上游会话保持**:平台为少数通道开启了会话保持时,你没带这个头,网关会自动补一个 `X-Session-Id: aigw-<哈希>`;带了就用你的值。是否影响上游的缓存或实例分配由服务商决定。 - **不影响网关选路**:网关自己的会话保持按「API Key + 模型」进行,见[通道选择与路由策略](https://platform.lyrouter.com/ai_gateway/docs/routing),与这个头无关。 **请求示例** cURL: ```bash curl https://api.lyrouter.com/v1/chat/completions \ -H "Authorization: Bearer $LYROUTER_API_KEY" \ -H "Content-Type: application/json" \ -H "x-session-id: 6f1c7e2a-3b4d-4e5f-9a8b-1c2d3e4f5a6b" \ -d '{"model":"MODEL_ID","messages":[{"role":"user","content":"继续上次的话题"}]}' ``` Python: ```python import os import uuid from openai import OpenAI client = OpenAI( api_key=os.environ["LYROUTER_API_KEY"], base_url="https://api.lyrouter.com/v1", ) session_id = str(uuid.uuid4()) # 每段对话生成一次,之后每轮都复用 completion = client.chat.completions.create( model="MODEL_ID", messages=[{"role": "user", "content": "继续上次的话题"}], extra_headers={"x-session-id": session_id}, ) ``` Node.js: ```js import { randomUUID } from "node:crypto"; import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.LYROUTER_API_KEY, baseURL: "https://api.lyrouter.com/v1", }); const sessionId = randomUUID(); // 每段对话生成一次,之后每轮都复用 const completion = await client.chat.completions.create( { model: "MODEL_ID", messages: [{ role: "user", content: "继续上次的话题" }], }, { headers: { "x-session-id": sessionId } }, ); ``` ### x-gateway-passthrough 通过 `/v1/messages` 调用 Anthropic 协议的通道时,网关默认会把请求转换为内部格式再转换回去。带上 `x-gateway-passthrough: require` 表示「请求体必须原样发给上游,不允许转换」:满足不了时网关返回 400,并说明是哪一项条件不满足,不会悄悄改走转换。 | 取值 | 行为 | | --- | --- | | `require`(不区分大小写) | 必须原样直通,做不到就返回 400 | | `prefer`、其他值或不带 | 默认行为:能直通就直通,不能就转换,请求照常完成 | - 这个头只给网关看,不会转发给上游。 - LYRouter 公共网关目前没有开启原生直通,带 `require` 的请求都会返回 400,不需要时不要发送这个头。 被拒绝时的报错原文为 ``native passthrough was required by `x-gateway-passthrough: require` but is not available for this request (<原因>)``。在 `/v1/messages` 上它以 Anthropic 错误格式返回(`invalid_request_error`),在其他接口上(如 `/v1/responses`)是一行纯文本,但响应头目前仍是 `Content-Type: application/json`,解析前请先判断正文是否为 JSON。括号中各原因码的含义与处理方法见[协议兼容性与限制](https://platform.lyrouter.com/ai_gateway/docs/compatibility#原生直通)。 ### X-Title 在请求头中带上 `X-Title: <应用名>`,网关没有从其他特征识别出已知工具(如 Claude Code、Cursor)时,[日志](https://platform.lyrouter.com/ai_gateway/docs/logs)的「客户端」列显示这个应用名,用量分析中也按它统计客户端分布。这个头会原样转发给上游。 ## 响应头 ### X-Gateway-Unsupported-Parameters 图像、视频请求中有参数被网关丢弃时,响应带上这个头,值为逗号分隔的参数名,例如 `X-Gateway-Unsupported-Parameters: response_format` 或 `guidance_scale,watermark`。请求本身照常执行。生产环境建议检查这个头,或者直接用 `X-Gateway-Strict-Parameters: true` 把丢弃变成报错。 ### x-aigw-quota-* 有[配额](https://platform.lyrouter.com/ai_gateway/docs/quota)适用于这次调用时,响应带上配额头。成功的响应和配额触顶的 429 会带,很多 400 也会带,例如 `Content-Type` 不对、模型不支持所调用的接口、上游返回的 400、原生直通被拒绝;401、403、503 和缺少 `model` 的 400(`missing_model`)不带。每个适用的指标三项: | 响应头 | 含义 | | --- | --- | | `x-aigw-quota-<指标>-limit` | 上限。`credits` 为整信用点,其余为 Token 数或请求数 | | `x-aigw-quota-<指标>-remaining` | 剩余量,按发出请求时的用量计算,不含本次请求的消耗;不会小于 0 | | `x-aigw-quota-<指标>-reset` | 下次重置时间,RFC 3339 格式的 UTC 时刻。目前这个值比实际重置时刻晚:按天、按月的配额约晚 2 分钟(例如在 `16:00:00Z` 重置的按月配额,返回的是 `16:02:00Z`~`16:02:06Z`),按分钟计的配额约晚 1 分钟,各次请求之间还会相差几秒。只用它估计重置时间,不要用于精确计时。没有重置周期的总量配额不带这一项 | 指标为 `credits`、`tokens`、`requests`、`input-tokens`、`output-tokens`。同一指标有多条配额同时适用时(例如 API Key 配额和工作空间配额),给出剩余量最少的那一条。 ```text x-aigw-quota-credits-limit: 2000 x-aigw-quota-credits-remaining: 1532 x-aigw-quota-credits-reset: 2026-10-31T16:02:00Z x-aigw-quota-requests-limit: 600 x-aigw-quota-requests-remaining: 597 x-aigw-quota-requests-reset: 2026-10-14T06:31:00Z ``` 用 SDK 读取响应头: **读取响应头** cURL: ```bash curl -s -D - -o /dev/null https://api.lyrouter.com/v1/chat/completions \ -H "Authorization: Bearer $LYROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"MODEL_ID","messages":[{"role":"user","content":"你好"}]}' \ | grep -i '^x-aigw-quota-' ``` Python: ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["LYROUTER_API_KEY"], base_url="https://api.lyrouter.com/v1", ) raw = client.chat.completions.with_raw_response.create( model="MODEL_ID", messages=[{"role": "user", "content": "你好"}], ) print(raw.headers.get("x-aigw-quota-credits-remaining")) completion = raw.parse() ``` Node.js: ```js import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.LYROUTER_API_KEY, baseURL: "https://api.lyrouter.com/v1", }); const { data: completion, response } = await client.chat.completions .create({ model: "MODEL_ID", messages: [{ role: "user", content: "你好" }] }) .withResponse(); console.log(response.headers.get("x-aigw-quota-credits-remaining")); ``` 配额头只出现在调用模型的接口上(对话、Responses、Messages、向量、重排、图像、语音和视频提交),`/v1/models`、视频任务查询等接口不带。配额用完后的 429 见[429:限流与配额](https://platform.lyrouter.com/ai_gateway/docs/rate-errors)。 ### Retry-After、X-RateLimit-Reason、X-RateLimit-Reset 这组头只在 API Key 因错误率过高被网关熔断或封禁时出现: | 场景 | 状态码 | 响应头 | | --- | --- | --- | | 临时熔断(`api_key_circuit_open`) | 429 | `Retry-After: <秒数>`、`X-RateLimit-Reason: api_key_circuit_open`、`X-RateLimit-Reset: <解除时刻的 Unix 秒>` | | 永久封禁(`api_key_permanently_banned`) | 403 | `X-RateLimit-Reason: api_key_permanently_banned` | - 配额用完的 429 不带 `Retry-After`,请按错误体中的 `reset_at` 或 `x-aigw-quota-*-reset` 等待。 - 上游服务商自己的 `Retry-After` 只在 `/v1/messages` 上转发给你。 - 处理方法见[429:限流与配额](https://platform.lyrouter.com/ai_gateway/docs/rate-errors)和[401 / 403:鉴权与权限](https://platform.lyrouter.com/ai_gateway/docs/auth-errors)。 ### anthropic-ratelimit-* 通过 `/v1/messages` 调用时,响应带 Anthropic 格式的限额头,供 Claude Code 等客户端调整请求节奏: - 服务这次请求的上游返回了 `anthropic-ratelimit-*` 时,网关原样转发(连同上游的 `Retry-After`),这些数字是上游账户的限额。 - 上游没有返回、而你有请求数或 Token 配额时,网关按配额生成 `anthropic-ratelimit-requests-*`、`-tokens-*`、`-input-tokens-*`、`-output-tokens-*` 的 `-limit`、`-remaining`、`-reset`。信用点配额没有对应的 Anthropic 头,请看 `x-aigw-quota-credits-*`。 同一个响应里 `anthropic-ratelimit-*` 与 `x-aigw-quota-*` 的数字不同是正常的:前者可能来自上游,后者始终是你在 LYRouter 的配额。 ### 请求 ID 网关不在响应头中返回请求 ID。排查某次调用时,在控制台日志详情顶部复制 Request ID,见[错误码与请求标识](https://platform.lyrouter.com/ai_gateway/docs/errors)。 部分上游(如 GLM 系列模型的通道)的响应体里会出现 `"request_id":"aigw-…"`:这是网关自动补的会话 ID(`X-Session-Id`,见上文「x-session-id」)被上游回显,不是 LYRouter 的 Request ID。请求带了 `x-session-id` 时,回显的就是你传的值。 ## 特殊模型名 | 写法 | 含义 | 可用接口 | | --- | --- | --- | | `@vmodel/<名称>` | 调用工作空间的[虚拟模型](https://platform.lyrouter.com/ai_gateway/docs/presets) | `/v1/chat/completions`、`/v1/messages`、`/v1/responses`;虚拟模型的模型列表全部是向量或重排模型时,也可用于 `/v1/embeddings`、`/v1/rerank` | | `@preset/<名称>` | 虚拟模型的旧前缀,与 `@vmodel/` 等价 | 同上 | | `lyrouter/auto` | [Auto 智能路由](https://platform.lyrouter.com/ai_gateway/docs/auto),在候选模型中按请求意图选择 | `/v1/chat/completions`、`/v1/messages`、`/v1/responses` | | 省略 `model`,或写成 `""`、`null` | 使用工作空间的[默认模型](https://platform.lyrouter.com/ai_gateway/docs/routing) | 所有需要 `model` 的接口 | - 虚拟模型和 `lyrouter/auto` 用在图像、视频、语音接口上时返回 403 `Model is not available in the model plaza`,这些接口只接受具体的模型 ID。 - 启用中的虚拟模型和 `lyrouter/auto` 会出现在 `GET /v1/models` 的结果中,见[列出模型](https://platform.lyrouter.com/ai_gateway/docs/models)。 - 省略 `model` 而工作空间没有设置默认模型时,返回 400 `you must provide a model parameter`(`missing_model`)。默认模型通常是对话模型,在向量、重排、语音接口上省略 `model` 多半得到 400 `unsupported_model_api`,这些接口请始终写明模型 ID。模型 ID 的写法见[模型命名与查询](https://platform.lyrouter.com/ai_gateway/docs/model-names)。 --- # 错误码与请求标识 来源: https://platform.lyrouter.com/ai_gateway/docs/errors LYRouter 拒绝一次调用时返回 4xx 或 5xx 状态码。OpenAI 兼容接口的错误体是 `{"error": {"message", "type", "code"}}`,`/v1/messages` 上转换为 Anthropic 格式,另有少数响应是 HTML 页面或一行纯文本。按状态码和 `error.message` 原文在本页速查表中找到条目,就能判断问题出在请求本身、账户与配置,还是平台或上游服务商,以及该怎么处理。网关不在响应头里返回请求 ID,需要定位某次调用时,请到 **日志分析** 打开这次请求的详情,复制顶部的 Request ID。 ## 错误响应格式 ### OpenAI 兼容格式 除 `/v1/messages` 外,各接口(Chat Completions、Responses、Embeddings、图像、视频等)的错误体默认是: ```json { "error": { "message": "insufficient credit balance", "type": "insufficient_quota", "code": "insufficient_credit_balance" } } ``` | 字段 | 说明 | | --- | --- | | `message` | 报错原文,以英文为主,个别为中文。本页列出的原文与网关返回逐字一致,`<...>` 表示会被替换的部分 | | `type` | 错误类别,如 `invalid_request_error`、`permission_error`、`access_denied`、`guardrail_blocked`、`insufficient_quota`、`rate_limit_error`、`billing_unavailable`、`service_unavailable`、`api_error` | | `code` | 机器可读的标识,只有部分错误才有,没有时整个字段不出现。同一句 `message` 可能对应多个 `code`(如 `insufficient credit balance`),程序分支请优先按 `code` 判断 | | 附加字段 | 个别错误才带:配额 429 的 `limit`、`used`、`reset_at` 等,熔断 429 的 `retry_after`、`blocked_until`,上游空响应体补全的 `upstream_status`、`generated_by` 等 | ### Anthropic 格式(`/v1/messages`) 通过 `/v1/messages` 调用时,网关自己的错误和上游的错误都会转换成 Anthropic 格式,`message` 保持原文: ```json { "type": "error", "error": { "type": "authentication_error", "message": "invalid api key" } } ``` | HTTP 状态码 | `error.type` | | --- | --- | | 400、402、422 | `invalid_request_error` | | 401 | `authentication_error` | | 403 | `permission_error` | | 404 | `not_found_error` | | 413 | `request_too_large` | | 429 | `rate_limit_error` | | 503、529 | `overloaded_error` | | 500、502、504 及其他 5xx | `api_error` | 转换后不再带 `error.code` 和附加字段(如 `limit`、`retry_after`),响应头照常保留。本页的报错原文在 `/v1/messages` 上同样适用,需要区分具体原因时,以「状态码 + `message`」为准,或在日志中查看这次请求。 上表的 404 → `not_found_error` 不适用于路径或 HTTP 方法不存在的 404:例如用 GET 调用 `/v1/messages`,返回的是 404 `{"error_msg":"404 Route Not Found"}`,不转换为 Anthropic 格式。 ### 不是 JSON 错误体的响应 | 情形 | 状态码 | 响应体 | | --- | --- | --- | | 连接上游失败、等待上游超时 | 500、504 | HTML 错误页 | | `Content-Type` 不对、multipart 请求格式不对、要求的原生直通无法满足(`/v1/messages` 上转换为 Anthropic 格式,见上文) | 400 | 一行纯文本,如 `unsupported content-type: text/plain, only application/json is supported` | | 工作空间设置了默认模型,而请求体不是合法 JSON 或为空 | 400 | `{"message": "..."}`,外层没有 `error` | | 路径或 HTTP 方法不存在,如 `/v1/v1/chat/completions`、用 GET 调用 `/v1/chat/completions` | 404 | `{"error_msg": "404 Route Not Found"}` | 目前网关返回的纯文本 400,响应头 `Content-Type` 仍是 `application/json`,直接按 JSON 解析会失败,部分 SDK 会报「无法解析响应」。稳妥的做法是先看状态码,再判断正文是否为 JSON(尝试解析),能解析时依次取 `error.message`、`message`、`error_msg`,都取不到时记录响应原文的前几百个字符: **读取错误响应** cURL: ```bash # -i 同时输出状态行和响应头(如 Retry-After、x-aigw-quota-*) curl -sS -i https://api.lyrouter.com/v1/chat/completions \ -H "Authorization: Bearer $LYROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"MODEL_ID","messages":[{"role":"user","content":"你好"}]}' ``` Python: ```python import os import requests # 需要先 pip install requests,OpenAI SDK 不附带 resp = requests.post( "https://api.lyrouter.com/v1/chat/completions", headers={"Authorization": f"Bearer {os.environ['LYROUTER_API_KEY']}"}, json={"model": "MODEL_ID", "messages": [{"role": "user", "content": "你好"}]}, timeout=400, # 长于网关等待上游的 6 分钟 ) if resp.status_code >= 400: try: body = resp.json() except ValueError: # HTML 错误页或纯文本 body = {} err = body.get("error", body) if isinstance(body, dict) else {} message = err.get("message") or err.get("error_msg") or resp.text[:300] print(resp.status_code, err.get("code"), message) ``` Node.js: ```js const resp = await fetch("https://api.lyrouter.com/v1/chat/completions", { method: "POST", headers: { Authorization: `Bearer ${process.env.LYROUTER_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ model: "MODEL_ID", messages: [{ role: "user", content: "你好" }] }), }); if (!resp.ok) { const text = await resp.text(); let err = {}; try { const body = JSON.parse(text); err = body.error ?? body; } catch { // HTML 错误页或纯文本 } console.log(resp.status, err.code, err.message ?? err.error_msg ?? text.slice(0, 300)); } ``` ## 速查表 「谁来处理」中的「管理员」指当前账号管理员或工作空间管理员,「联系支持」表示需要平台处理。 | 状态码 | 报错原文(`error.message`) | `error.code` | 原因 | 谁来处理 | | --- | --- | --- | --- | --- | | 400 | `you must provide a model parameter` | `missing_model` | 没写 `model`,工作空间也没有默认模型 | 调用方 | | 400 | `invalid type for 'model': expected a string` | `invalid_model` | `model` 不是字符串 | 调用方 | | 400 | `request body must be a JSON object` | `invalid_json` | 请求体不是合法的 JSON 对象;部分版本返回 `missing_model` | 调用方 | | 400 | `could not get parse JSON request body: <解析错误>` | —(外层无 `error`) | 同上,工作空间设置了默认模型时 | 调用方 | | 400 | `unsupported content-type: <类型>, only application/json is supported` | —(纯文本) | `Content-Type` 不是 JSON | 调用方 | | 400 | ``multipart body has no non-empty `model` field`` 等 | —(纯文本) | multipart 请求体缺字段或取值不对 | 调用方 | | 400 | `This model does not support the <接口> API` 等 | `unsupported_model_api` 等 | 模型不支持该接口、操作或输入类型 | 调用方换模型 | | 400 | `unsupported parameters for this model: <参数名>` | `unsupported_parameters` | 严格模式下传了模型不支持的参数 | 调用方 | | 400 | 具体参数的校验原文 | `invalid_parameter` | 图像、视频等接口的参数或 multipart 内容不合法 | 调用方 | | 400 | ``native passthrough was required by `x-gateway-passthrough: require` ...`` | —(`/v1/messages` 上为 Anthropic 格式,其他接口为纯文本) | 要求原生直通,但这次请求无法直通 | 调用方 | | 401 | `missing credentials` | — | 没带 API Key | 调用方 | | 401 | `invalid authorization scheme, expected 'Bearer'` | — | `Authorization` 头格式不对 | 调用方 | | 401 | `invalid api key` | — | Key 不存在、已删除、停用或过期 | 调用方 / 管理员 | | 401 | `api key verification unavailable` | — | 平台密钥校验服务暂时不可用 | 稍后重试 | | 402 | `insufficient credit balance` | `insufficient_credit_balance` 等 | 账户余额不足 | 账号管理员充值 | | 402 | `subscription expired; renew to continue` | — | 订阅已到期 | 账号管理员续费 | | 403 | `api key expired` | — | Key 已过有效期 | 新建 Key | | 403 | `your IP address is not allowed` | — | 来源 IP 不在 Key 的白名单中 | 调用方 / Key 创建者 | | 403 | `ip access control misconfigured` | — | Key 的 IP 白名单无效 | Key 创建者 | | 403 | `api key workspace is unavailable` | — | 暂时读不到工作空间配置 | 稍后重试 | | 403 | `Model is not available in the model plaza` | `model_not_available` | 工作空间没有开通该模型 | 管理员 / 换模型 | | 403 | `Request blocked by guardrail policy` | `guardrail_*` | 请求被安全围栏拦截 | 调用方 / 管理员 | | 403 | `Response blocked by guardrail policy` | `guardrail_sensitive` | 模型的回答被安全围栏拦截 | 调用方 / 管理员 | | 403 | `Subject is blocked by an active security ban` | `guardrail_subject_banned` | Key 被安全围栏封禁 | 管理员 | | 403 | `该 API Key 已被永久封禁,无法恢复,请删除后创建新的 API Key。` | `api_key_permanently_banned` | Key 第 5 次触发错误率熔断 | 修复程序后新建 Key | | 404 | `404 Route Not Found`(字段为 `error_msg`) | — | 路径或 HTTP 方法不对 | 调用方 | | 404 / 409 | `video task not found`、`video is not ready yet` 等 | `not_found` 等 | 视频任务不存在、未完成或不能取消 | 调用方 | | 429 | `rate limit exceeded on <对象> <指标>/<窗口>` | — | 配额或预算已用完 | 等待重置 / 管理员调额 | | 429 | `API Key 因最近 60 秒错误率过高已临时熔断,请在 N 秒后重试。` | `api_key_circuit_open` | Key 错误率过高被临时熔断 | 修复后按 `Retry-After` 等待 | | 429 | `all upstream credentials for this model are rate limited` | `upstream_quota_exhausted` | 该模型所有上游凭证都达到限额 | 稍后重试 / 换模型 | | 429 | `upstream concurrency full` | `upstream_concurrency_full` | 异步任务的上游并发已满 | 稍后重试 | | 500 | HTML 错误页 | — | 连接上游失败或读取响应出错 | 稍后重试 | | 500 | `sync spec needs the upstream model name for the path` 等 | `model_unresolved` 等 | 平台侧通道配置问题 | 联系支持 | | 503 | `all routed candidates exhausted` | `no_route_candidate` | 找不到可服务的模型或通道 | 调用方 / 管理员 | | 503 | `No configured credential can serve this model` | `no_route_candidate` | 该模型没有可用凭证 | 管理员 | | 503 | `Workspace model projection is unavailable` | `workspace_model_projection_unavailable` | 暂时读不到工作空间的模型配置 | 稍后重试 | | 503 | `billing balance is temporarily unavailable` | `billing_maintenance` 等 | 暂时无法确认账户余额 | 平台(部分可稍后重试,持续出现时联系支持) | | 503 | `Platform supplier cost snapshot is unavailable` | `supplier_cost_snapshot_not_ready` | 该模型的通道价格未就绪 | 换模型并联系支持 | | 504 | HTML 错误页 | — | 等待上游响应超时 | 稍后重试 | | 上游的状态码 | 上游的报错原文 | 上游定义,或 `upstream_*` | 上游服务商拒绝了请求 | 视原文而定 | ## 400:请求格式或参数 本节的 400 都由网关在把请求发往上游之前返回。 ### 模型字段与请求体 | 报错原文 | `error.code` | 含义与处理 | | --- | --- | --- | | `you must provide a model parameter` | `missing_model` | `model` 缺失、为 `""` 或 `null`(请求体为空时同样如此),且工作空间没有在 **智能路由** 中设置默认模型。在请求中写上模型 ID,可用 [`GET /v1/models`](https://platform.lyrouter.com/ai_gateway/docs/models) 查询 | | `invalid type for 'model': expected a string` | `invalid_model` | `model` 写成了数字、对象等。设置了默认模型也不会顶替,请改成字符串形式的模型 ID | | `request body must be a JSON object` | `invalid_json` | 请求体是字符串、数字等合法 JSON,但不是对象;请求体不是合法 JSON 时,原文为 `could not get parse JSON request body: <解析错误>`,`error.code` 同样是 `invalid_json`。部分版本对这两种请求体都返回 `you must provide a model parameter`(`missing_model`);请求体是 JSON 数组时也返回 `missing_model`。检查引号、逗号和转义,以及请求体是否真的放进了 `-d` / `json=` | | `could not get parse JSON request body: <解析错误>`(原文如此) | — | 工作空间设置了默认模型时,非法 JSON 返回这一句,响应体为 `{"message": "..."}`;请求体为空时是 `could not get body: request body is empty`。处理同上 | 设置了默认模型时,不写 `model` 的对话请求会改由默认模型回答,不会收到 `missing_model`。默认模型的设置见[通道选择与路由策略](https://platform.lyrouter.com/ai_gateway/docs/routing)。 ### Content-Type 与 multipart(纯文本响应) | 报错原文 | 含义与处理 | | --- | --- | | `unsupported content-type: <类型>, only application/json is supported` | 请求头 `Content-Type` 不是 `application/json`。JSON 接口请设置 `Content-Type: application/json`,不带这个头时按 JSON 处理。`/v1/images/edits` 和 `/v1/videos` 同时接受 JSON 和 `multipart/form-data` | | ``multipart body has no non-empty `model` field`` | multipart 请求体里没有非空的 `model` 表单字段。工作空间没有默认模型时,先返回的是 `you must provide a model parameter` | | `request body is empty` | multipart 请求体为空 | | ``<字段> must be `true` or `false` in multipart form data`` | `/v1/videos` 的 multipart 请求中,`watermark`、`generate_audio` 只接受字面量 `true` 或 `false`,`1`、`yes`、`True` 都会被拒绝 | | `input_reference must be a URL; uploading a file is not supported by this gateway (pass a publicly reachable https:// URL instead)` | `/v1/videos` 的 multipart 请求中,`input_reference`(参考视频)要传公网可访问的 `https://` 地址,不支持上传文件 | ### 模型不支持该接口或输入 `type` 为 `invalid_request_error`,按 `error.code` 区分: | `error.code` | 报错原文 | 含义 | | --- | --- | --- | | `unsupported_model_api` | `This model does not support the <接口> API` | 模型不支持这一类接口,`<接口>` 为 `chat_completions`、`responses`、`embeddings`、`rerank`、`images`、`videos` 之一。例如用对话模型调用图像生成接口 | | `unsupported_model_operation` | `This model does not support the <操作> operation` | 模型支持这一类接口,但不支持其中这个操作,如 `images_edits`、`videos_regenerations` | | `unsupported_model_input` | `This model accepts text input only` | 给只接受文本的模型发送了图片、音频或文件 | 处理:在 **模型广场** 查看模型支持的接口与输入类型,换用支持的模型,见[模型能力与兼容性](https://platform.lyrouter.com/ai_gateway/docs/capabilities)。 ### 参数不被支持或取值不合法 **`unsupported parameters for this model: <参数名>`(`unsupported_parameters`)**:请求带了 `X-Gateway-Strict-Parameters: true`,而请求中有所选模型不支持的参数。不带这个请求头时,网关丢弃这些参数照常调用,并在响应头 `X-Gateway-Unsupported-Parameters` 中列出参数名。这两个头目前只覆盖图像、视频接口;对话接口在跨协议转换时丢弃的参数(如 `response_format`、`seed`、`n`)既不触发这个错误,也不写这个响应头,见[网关扩展请求头与响应头](https://platform.lyrouter.com/ai_gateway/docs/gateway-headers)。处理:删掉报错中列出的参数,或换用支持它们的模型。 **`invalid_parameter`**:`error.message` 直接说明是哪个参数、哪里不对,常见的有: | 报错原文 | 含义 | | --- | --- | | `seconds must be a positive whole number of seconds` | 视频时长必须是正整数秒 | | `watermark must be a boolean`、`generate_audio must be a boolean` | JSON 请求中这两个字段必须是布尔值 | | `size implies an aspect ratio this model does not support: <取值>` | `size` 对应的宽高比该模型不支持 | | `cannot read the multipart body`,或具体原因如 `truncated multipart body: no closing delimiter`、`inline file parts exceed the limit of 31457280 bytes` | 需要转换格式的模型读不出 multipart 请求体:请求体被截断、文件合计超过 30 MB 等 | | `cannot rewrite the multipart model field: <原因>` | 网关无法把 multipart 中的 `model` 字段替换成上游的模型名,请求没有发出。确认 `model` 是普通文本字段;持续出现时联系支持 | 各参数的取值范围见[多模态能力](https://platform.lyrouter.com/ai_gateway/docs/multimodal)。 ### 原生直通无法满足 原文:``native passthrough was required by `x-gateway-passthrough: require` but is not available for this request (<原因>)`` 请求带 `x-gateway-passthrough: require` 表示「请求体必须原样发给 Anthropic 协议的上游,不允许转换」。网关做不到时直接拒绝,而不是悄悄转换;回退到非 Anthropic 协议的通道时也会以这个错误结束。在 `/v1/messages` 上,这个错误按 Anthropic 格式返回,`message` 与上面的原文一致:`{"type":"error","error":{"type":"invalid_request_error","message":"native passthrough …"}}`;在其他接口上是一行纯文本。括号里是否决的原因: | 原因 | 含义 | | --- | --- | | `client_protocol` | 不是通过 `/v1/messages` 调用 | | `route_disabled` | 接口没有开启请求侧原生直通 | | `wire_protocol` | 选中的通道不是 Anthropic 协议上游 | | `endpoint_type` | 不是对话接口 | | `channel_disabled` | 该通道关闭了原生直通 | | `preset_injection` | 使用的虚拟模型会改写请求体(追加系统提示词、设置或锁定参数、缓存策略) | | `shape_oai` | 请求体不是 Anthropic 格式 | | `decision_error` | 网关判定过程出错 | 目前 `/v1/messages` 没有开启请求侧原生直通,带这个请求头的请求会以 `route_disabled` 被拒绝。去掉这个请求头(或改为 `prefer`),请求即按正常的协议转换路径处理,见[Anthropic Messages](https://platform.lyrouter.com/ai_gateway/docs/anthropic-messages)。 ## 401:鉴权失败 401 的请求无法归属到任何工作空间,日志中查不到。各条原因的详细排查见[401 / 403:鉴权与权限](https://platform.lyrouter.com/ai_gateway/docs/auth-errors)。 | 报错原文 | 含义与处理 | | --- | --- | | `missing credentials` | 请求没有携带 API Key。加上 `Authorization: Bearer `,Anthropic 风格的客户端也可以用 `x-api-key: `。通过环境变量配置的工具,修改后需要新开终端 | | `invalid authorization scheme, expected 'Bearer'` | `Authorization` 头不是 `Bearer ` 格式。`Bearer` 区分大小写,`bearer sk-...`、直接写密钥、`Basic ...` 都会被拒绝;只写 `Bearer` 而没有密钥也返回这一句。同时带 `Authorization` 和 `x-api-key` 时只读 `Authorization` | | `invalid api key` | 网关找不到这个 Key:复制不完整或带了空格、换行;Key 已删除、停用或过期;所属工作空间或创建人已停用;Key 刚创建、还没同步到网关(通常几秒)。被永久封禁的 Key 是例外:删除后仍返回 403 `api_key_permanently_banned`。重新复制完整的 Key,明文丢失时删除后新建,见[创建工作空间与 API Key](https://platform.lyrouter.com/ai_gateway/docs/api-keys) | | `api key verification unavailable` | 平台的密钥校验服务暂时不可用,与 Key 是否正确无关。稍后重试,持续出现时查看[服务状态](https://platform.lyrouter.com/ai_gateway/docs/status) | ## 402:余额不足或订阅到期 | 报错原文 | `error.code` | 含义与处理 | | --- | --- | --- | | `insufficient credit balance` | `insufficient_credit_balance` | 账户 Credits 余额已用完;使用 BYOK 且需要支付平台服务费时,余额不足以支付服务费。由账号管理员在 **订阅充值** 充值 | | `insufficient credit balance` | `balance_missing` | 账户还没有余额记录,通常是从未充值。充值后恢复;已充值仍出现时联系支持 | | `insufficient credit balance` | `billing_entity_missing` | 网关找不到这个 Key 对应的计费账户,属于平台侧数据问题,联系支持 | | `subscription expired; renew to continue` | — | 账户订阅已到期且已过宽限期,该账户下所有工作空间的调用都会被拒绝。续费后恢复;没有订阅的账户不会收到这个错误 | `type` 为 `insufficient_quota`。余额检查发生在调用之前:余额大于 0 就能发起调用,一次调用可能把余额扣成负数,之后的调用才被拒绝。余额不足时网关不会改用其他通道或计费方式。计费规则见[计费规则与信用点](https://platform.lyrouter.com/ai_gateway/docs/billing)。 ## 403:访问被拒绝 ### API Key 与来源 | 报错原文 | `error.code` | 含义与处理 | | --- | --- | --- | | `api key expired` | — | Key 已超过有效期,网关在每次请求时检查。新建一个 Key 替换它;过期一段时间后,同一个 Key 改为返回 401 `invalid api key` | | `your IP address is not allowed` | — | Key 开启了 IP 白名单,请求的来源 IP 不在名单中(`type` 为 `permission_error`)。网关按到达时的出口 IP 判断,经公司网络、代理或云服务器调用时,出口 IP 可能与本机看到的不同 | | `ip access control misconfigured` | — | Key 的 IP 白名单为空或含无效的 IP / CIDR,网关拒绝所有请求。由 Key 创建者或账号管理员修正白名单 | | `api key workspace is unavailable` | — | Key 有效,但网关暂时读不到所属工作空间的配置,属于平台侧临时问题,稍后重试 | | `该 API Key 已被永久封禁,无法恢复,请删除后创建新的 API Key。` | `api_key_permanently_banned` | Key 第 5 次触发错误率熔断,被永久封禁,不能解除;删除旧 Key 后它仍返回同样的 403。刚触发封禁时原文是 `该 API Key 因多次高错误率请求已被永久封禁,无法恢复,请删除后创建新的 API Key。`,封禁同步到网关后改为本行原文。先修复持续报错的程序再新建 Key,否则新 Key 也会被熔断 | 永久封禁的响应头带 `X-RateLimit-Reason: api_key_permanently_banned`,被拒绝的请求不写入日志。 ### 模型未开通 **`Model is not available in the model plaza`**(`model_not_available`,`type` 为 `access_denied`):Key 所属工作空间的 **模型广场** 中,这个模型的所有服务商都处于未开通状态。 - 管理员在 **模型广场** 开通该模型,或调用方改用已开通的模型。 - 在图像、视频接口上使用 `@vmodel/<名称>` 或 `lyrouter/auto` 也会返回这个错误:这些接口只接受具体的模型 ID。 - 工作空间设置了默认模型时,请求的模型未开通的对话请求通常改由默认模型回答,可在日志的「模型(实际)」中确认。详见[模型不可用](https://platform.lyrouter.com/ai_gateway/docs/unavailable)。 ### 安全围栏 **`Request blocked by guardrail policy`**(`type` 为 `guardrail_blocked`):请求命中了工作空间安全围栏的阻断策略,没有发给模型。原文不含策略名称或命中内容,按 `error.code` 判断策略类型: | `error.code` | 命中的策略 | | --- | --- | | `guardrail_client` | 客户端访问控制:按来源 IP、工具名或 User-Agent 限制调用 | | `guardrail_context` | 意图安全检测:请求意图被判定有风险 | | `guardrail_sensitive` | 敏感信息检测:请求含个人信息、凭证或敏感关键词 | | `guardrail_injection` | 提示词注入检测:请求疑似提示词注入 | | `guardrail_model` | 模型访问控制:所选模型不在允许范围内,对虚拟模型按实际选中的模型检查 | - **`Response blocked by guardrail policy`**(`guardrail_sensitive`):非流式请求的回答命中了敏感信息策略。上游已经生成回答,这次调用照常计费;流式请求已开始输出,不会中断,命中的内容打码后输出。 - **`Subject is blocked by an active security ban`**(`guardrail_subject_banned`):意图安全检测策略的动作设为封禁,命中后触发它的 Key 被封禁,期间所有请求都被拒绝。到达策略设置的自动解封时间后解除,或由管理员在 **安全事件** 中提前解除。 同样的请求重试会得到同样的结果。调用方可以调整请求内容或换用允许的模型;管理员在 **安全事件** 查看命中详情,在 **安全围栏** 调整策略,见[安全围栏与语义审计](https://platform.lyrouter.com/ai_gateway/docs/guardrails)。 ## 404 / 409:路径与资源不存在 | 状态码 | 报错原文 | `error.code` | 含义与处理 | | --- | --- | --- | --- | | 404 | `404 Route Not Found`(响应体为 `{"error_msg": ...}`) | — | 网关没有这个路径,或该路径不接受这个 HTTP 方法。常见原因是 Base URL 多写或少写了 `/v1`(OpenAI SDK 的 `base_url` 应为 `https://api.lyrouter.com/v1`,Anthropic SDK 为根地址),见[接入地址与鉴权](https://platform.lyrouter.com/ai_gateway/docs/call-gateway)。这类请求在日志中查不到 | | 404 | `video task not found` | `not_found` | 视频任务 ID 不存在、已过期,或属于其他工作空间 | | 409 | `video is not ready yet` | `not_ready` | 任务还没有成功完成,暂时不能下载视频。继续轮询任务状态 | | 409 | `cancelling an in-flight video task is not supported: ...` | `cancel_not_supported` | 不能取消进行中的任务(上游不提供取消接口)。等任务结束后仍可删除 | `POST /v1/responses` 中的 `previous_response_id` 由上游服务商校验,出错时返回上游的错误,见[Responses](https://platform.lyrouter.com/ai_gateway/docs/responses-api)。视频任务本身失败时,查询接口返回 HTTP 200,任务对象的 `status` 为 `failed`,`error.code` 为 `deadline_exceeded`(超时,目前查询接口可能看不到,见[异步任务](https://platform.lyrouter.com/ai_gateway/docs/async))、`canceled`(已取消),或上游给出的错误码(缺省为 `upstream_error`),有时还带上游的请求 ID `error.provider_request_id`,见[异步任务](https://platform.lyrouter.com/ai_gateway/docs/async)。 ## 429:限流、熔断与上游限额 | 报错原文 | `error.code` | 含义与处理 | | --- | --- | --- | | `rate limit exceeded on <对象> <指标>/<窗口>` | — | Key 的预算或安全围栏的配额策略已达上限,如 `rate limit exceeded on apikey total_tokens/day`。错误体带 `limit`、`used`、`reset_at`(配额策略还带 `policy_code`、`policy_name`)。等到 `reset_at` 之后再调用,或请管理员调高额度 | | `API Key 因最近 60 秒错误率过高已临时熔断,请在 N 秒后重试。` | `api_key_circuit_open` | 这个 Key 最近 60 秒至少 100 次请求、其中 90% 以上失败,被临时熔断。响应头 `Retry-After` 给出等待秒数,错误体的 `retry_after`、`blocked_until`(UTC)与之一致。先修复失败原因再等待 | | `all upstream credentials for this model are rate limited` | `upstream_quota_exhausted` | 能服务这个模型的所有上游通道或凭证都达到了各自的限额,错误体带 `metric`、`window`。稍后重试或换用其他模型;只走 BYOK 时请管理员检查凭证限额 | | `upstream concurrency full` | `upstream_concurrency_full` | 异步任务提交(如 `POST /v1/videos`)时,上游账号的并发任务数已满,请求没有发出。稍后重试 | - **配额字段**:`<对象>` 为 `apikey`、`member`、`dept`、`ws`;`<指标>` 为 `requests`、`total_tokens`、`prompt_tokens`、`completion_tokens`、`credits`;`<窗口>` 为 `minute`、`minutes`、`day`、`month`、`total`(累计,不会重置)。窗口按北京时间对齐,用量在请求完成后才计入。 - **响应头**:配置了配额时,对话、向量等经过网关选路和配额检查的调用(成功的响应和被配额拦下的 429 都算)都带 `x-aigw-quota-<指标>-limit` / `-remaining` / `-reset`,指标为 `credits`、`tokens`、`requests`、`input-tokens`、`output-tokens`;`/v1/messages` 另带 `anthropic-ratelimit-*`,但 Credits 没有对应的头,只配置了 Credits 配额时网关不生成 `anthropic-ratelimit-*`。 - **Retry-After**:只有熔断(`api_key_circuit_open`)设置,同时带 `X-RateLimit-Reason: api_key_circuit_open` 和 `X-RateLimit-Reset`(Unix 秒);配额 429 不带。上游自己的 `Retry-After` 只在 `/v1/messages` 上转发。 - **熔断阶梯**:第 1 次 30 秒、第 2 次 2 分钟、第 3 次 10 分钟、第 4 次 12 小时,第 5 次永久封禁,次数在 Key 的整个生命周期内累计。网关返回的 402、403、429 也计为失败;被熔断的请求不写入日志。 完整说明见[429:限流与配额](https://platform.lyrouter.com/ai_gateway/docs/rate-errors)和[预算、配额与限流](https://platform.lyrouter.com/ai_gateway/docs/quota)。 ## 500 / 504:连接上游失败或等待超时 | 状态码 | 响应体 | 含义 | | --- | --- | --- | | 504 | HTML 错误页 | 等待上游响应超时,或连接上游超时 | | 500 | HTML 错误页 | 连接上游失败(如连接被拒绝、TLS 握手失败),或读取上游响应时出错 | - 网关等待上游的读超时为 6 分钟;流式请求按相邻两段输出的间隔计算,持续有输出就不会超时。 - 返回之前,网关已按[失败重试与备用模型](https://platform.lyrouter.com/ai_gateway/docs/fallback)的规则尝试过其他通道,所有候选都失败后才返回。流式请求开始输出后不再换通道,见下文「流式输出中途的错误事件」。 - 处理:使用有上限的指数退避重试;生成很长的内容时改用 `stream: true`;在日志「各阶段耗时」中查看上游耗时,详见[超时与流式中断](https://platform.lyrouter.com/ai_gateway/docs/stream-errors)。 ### 配置类 500(JSON 错误体) 以下 500 带 JSON 错误体(`type` 为 `api_error`),表示平台侧的通道或格式转换配置有问题,与请求内容无关,重试通常无效。请记下 Request ID 联系支持,并换用其他模型: | `error.code` | 报错原文 | | --- | --- | | `model_unresolved` | `sync spec needs the upstream model name for the path` | | `spec_error` | `unusable sync body shape: <原因>`、`unusable async submit spec: <原因>` | | `unsupported_configuration` | `remove_model is not supported on multipart endpoints` | | `encode_failed` | `failed to encode request body: <原因>` | ## 503:无可用通道、计费或配置暂不可用 | 报错原文 | `error.code` | 含义与处理 | | --- | --- | --- | | `all routed candidates exhausted` | `no_route_candidate` | 找不到任何可以服务这次请求的模型或通道。常见原因是 `@vmodel/<名称>` 写错、虚拟模型不存在或已停用,或模型没有可用的通道。检查 `model` 字段;名称无误时请管理员检查 **模型广场** 和 **自带密钥(BYOK)** | | `No configured credential can serve this model` | `no_route_candidate` | 模型的通道在本工作空间没有可用凭证:平台通道没有开通,或 BYOK 凭证都不可用,见 [BYOK](https://platform.lyrouter.com/ai_gateway/docs/byok) | | `Workspace model projection is unavailable` | `workspace_model_projection_unavailable` | 网关暂时读不到工作空间的模型配置,属于平台侧问题,稍后重试 | | `Platform supplier cost snapshot is unavailable`、`BYOK supplier cost snapshot is unavailable` | `supplier_cost_snapshot_not_ready` | 能服务这个模型的通道还没有配置好价格,网关无法计费。网关会先尝试其他通道,都不可用时才返回。换用其他模型,并把模型 ID 告知支持人员 | | `billing balance is temporarily unavailable` | 见下表 | 网关暂时无法确认账户余额,为避免错误扣费而拒绝调用。这不是余额不足 | `billing balance is temporarily unavailable` 的 `type` 为 `billing_unavailable`,按 `error.code` 判断能否自行恢复: | `error.code` | 含义 | 重试是否有用 | | --- | --- | --- | | `billing_maintenance` | 账户计费正处于核对或维护状态,该账户下所有调用都被拒绝 | 无用,联系支持 | | `billing_store_error`、`billing_store_protocol_error`、`byok_release_failed` | 平台计费服务临时故障 | 稍后可能恢复 | | `invalid_balance`、`byok_billing_config_missing`、`byok_reservation_terminal` | 平台侧计费数据或配置异常 | 无用,联系支持 | OpenAI、Anthropic 等官方 SDK 默认会自动重试 503,但 `no_route_candidate`、`billing_maintenance`、`supplier_cost_snapshot_not_ready` 不改请求或配置就不会恢复。 ## 上游服务商返回的错误 网关把上游服务商返回的错误状态码和响应体**原样**转发给你,日志「状态说明」列的来源显示为「上游」。 - **先换通道**:上游返回错误或连接失败时,网关按工作空间的选路策略在同一模型的其他通道上重试,全部失败时你收到**最后一次**尝试的上游错误。设置了默认模型时,对话请求还可能改由默认模型回答,见[失败重试与备用模型](https://platform.lyrouter.com/ai_gateway/docs/fallback)。 - **上游 401 / 403**:通常是上游凭证被拒绝。使用 BYOK 时,请在服务商处确认 API Key 有效、额度充足,并在 BYOK 中重新测试连接。 - **`/v1/messages`**:上游错误同样转换为 Anthropic 格式。 ### 上游返回空响应体 上游只返回错误状态码、没有响应体时,网关补一个错误体,并用 `generated_by: "ai-gateway"` 标明由网关生成: ```json { "error": { "message": "upstream <服务商> returned HTTP 429 for POST <路径> with an empty response body", "type": "rate_limit_error", "code": "upstream_rate_limited", "upstream_status": 429, "generated_by": "ai-gateway" } } ``` | 上游状态码 | `error.code` | | --- | --- | | 400 | `upstream_invalid_request` | | 401 | `upstream_unauthorized` | | 403 | `upstream_forbidden` | | 404 | `upstream_not_found` | | 408 | `upstream_timeout` | | 413 | `upstream_payload_too_large` | | 429 | `upstream_rate_limited` | | 其他 4xx、5xx | `upstream_error` | 上游在响应头中带了自己的请求 ID 时,错误体还会多一个 `upstream_request_id`,向服务商报障时用它。 ### 上游在成功响应里声明了错误 个别上游会返回 HTTP 2xx、却在响应体里声明失败,多见于图像、视频生成。网关把它改写为错误响应,状态码取上游声明的错误,`error.code` 为 `upstream_rejected`(上游拒绝了请求)或 `upstream_no_artifact`(上游没有产出图像或视频,带 `upstream_finish_reason`),`upstream_status` 是上游原本的 2xx 状态码。这类错误不换通道重试,请按 `error.message` 调整请求内容。 ## 流式输出中途的错误事件 上面列出的网关拒绝都发生在开始输出之前,`stream: true` 的请求同样收到普通的错误响应和对应状态码,而不是 SSE 事件。 流式输出开始后(状态码已经是 200),上游中断或超时时,网关不再换通道,而是在流的末尾补一个错误事件,然后结束连接: **OpenAI 兼容接口**(Chat Completions、Responses 等): ```text data: {"error": {"message": "upstream timed out after the response had started", "type": "api_error", "code": "stream_interrupted"}} ``` **Anthropic Messages**(`/v1/messages`): ```text event: error data: {"type": "error", "error": {"type": "api_error", "message": "upstream timed out after the response had started"}} ``` - 超时时 `message` 为 `upstream timed out after the response had started`,连接或读取失败时为 `upstream failed after the response had started`。 - 上游自己在流中发出的错误事件(如 Anthropic 的 `overloaded_error`)按你调用的协议转给你。OpenAI、Anthropic 官方 SDK 收到这两种错误事件都会抛出 API 错误。 - 出现错误事件时不会再有结束标记(`data: [DONE]`、`message_stop`、`response.completed`)。请把「没有收到结束标记」当作这次调用失败,不要把已收到的部分输出当作完整结果。 各协议的事件结构见[流式响应](https://platform.lyrouter.com/ai_gateway/docs/streaming),重试与去重建议见[超时与流式中断](https://platform.lyrouter.com/ai_gateway/docs/stream-errors)。 ## 哪些错误可以重试 | 处理方式 | 错误 | | --- | --- | | 有上限的指数退避重试 | 500、504(HTML);502 `failed to reach upstream`;401 `api key verification unavailable`;403 `api key workspace is unavailable`;429 `upstream_quota_exhausted`、`upstream_concurrency_full`;503 `workspace_model_projection_unavailable`、`billing_store_error` 类;流式 `stream_interrupted` | | 按指定时间等待 | 429 `api_key_circuit_open`:等 `Retry-After` 秒;配额 429:等到 `reset_at` 之后 | | 修改请求或配置后再调用 | 全部 400、401 `missing credentials` / `invalid authorization scheme` / `invalid api key`、402、大部分 403、404、409;503 `no_route_candidate`、`supplier_cost_snapshot_not_ready`、`billing_maintenance`;配置类 500 | 不要对 4xx 做无间隔的自动重试:网关返回的 402、403、429 都计入错误率熔断,持续失败的程序很快会让 Key 被熔断,第 5 次熔断即永久封禁。 ## 请求标识 ### 网关不返回请求 ID LYRouter 不在响应头里返回请求 ID。响应体中的 `id`(如 `chatcmpl-...`、`msg_...`、`resp_...`)是协议对象的 ID,不能在日志中按它查找。要定位某次调用,请在客户端记下调用时间、接口路径、模型和 API Key 名称,再到日志中找到这次请求。 ### 从日志详情取 Request ID 1. 在工作空间左侧菜单打开 **日志分析**。日志在调用结束后几秒内可以查到。 2. 用「时间范围」「API Key」「模型」「状态码」等条件筛选。列表的「时间」是请求结束的时间。 3. 点击这一行打开「日志详情」,顶部「Request ID」后面就是这次请求的标识,选中后复制。 Request ID 可以粘贴到日志搜索框中重新找到这条日志。普通成员只能看到自己创建的 API Key 产生的日志。以下请求在日志中查不到:401、路径不存在的 404、被错误率熔断(429 `api_key_circuit_open`)或永久封禁(403 `api_key_permanently_banned`)拒绝的请求,以及 `GET /v1/models`。这些情况请提供调用时间、接口路径和完整报错。日志的完整用法见[通过日志定位调用问题](https://platform.lyrouter.com/ai_gateway/docs/logs)。 ### 日志中的其他标识 | 标识 | 在哪里看 | 用途 | | --- | --- | --- | | Request ID | 日志详情顶部 | 唯一标识一次请求,联系支持时提供 | | 会话 ID | 列表「会话」列的标签(在 **自定义列** 中打开),鼠标停留可见;「添加筛选」中可按「会话 ID」筛选 | 查看同一段对话的全部请求。客户端可用 `x-session-id` 请求头声明会话 | | 任务 ID | `POST /v1/videos` 返回的 `id`(`aigwt_` 开头);异步任务日志详情切换到「整个任务」 | 查询任务状态与产物,排查异步任务 | | 上游请求 ID | 日志详情「原始报文」中「③ 上游响应」的响应头(各服务商头名不同,如 `x-request-id`);空响应体补全错误的 `upstream_request_id`;失败视频任务的 `error.provider_request_id` | 向上游服务商报障,使用 BYOK 时联系你自己的服务商 | ### 提交问题时附上什么 | 信息 | 说明 | | --- | --- | | Request ID | 日志中能找到这次请求时附上 | | 调用时间 | 精确到分钟,注明时区 | | 接口与模型 | 方法和路径(如 `POST /v1/chat/completions`)、请求中的 `model`、是否流式 | | 完整报错 | HTTP 状态码和完整响应体(含 `error.code` 和附加字段);流式中断时附最后收到的几个事件 | | API Key 名称 | 只提供名称 | | 客户端 | 工具或 SDK 的名称与版本;超时问题附客户端的超时设置;IP 白名单问题附出口 IP | | 相关标识 | 任务 ID、会话 ID、上游请求 ID(有的话) | 发送前请脱敏: - 不要发送 API Key 明文、完整的 `Authorization` 或 `x-api-key` 请求头,以及你在服务商处的 BYOK 密钥。 - 提示词、回答和上传文件中的个人信息、业务数据先删除或替换;能用最小的复现内容说明问题时,不要附原文。 - 从日志「原始报文」复制的内容不含凭据类请求头,但正文可能包含敏感信息,发送前请检查。 --- # 协议兼容性与限制 来源: https://platform.lyrouter.com/ai_gateway/docs/compatibility LYRouter 提供 Chat Completions、Anthropic Messages、Responses 三种对话接口,而每个服务商通道只使用一种上游协议:OpenAI 兼容或 Anthropic。客户端接口与通道协议不同时,网关自动转换请求、响应、流式事件和错误格式;转换只保留双方都有对应含义的字段,其余字段会被去掉或改写,且不会写进响应头。Responses 请求不做协议转换,只能由提供 Responses 接口的通道服务。依赖特定参数、缓存标记或 `usage` 字段的应用,请按本页确认实际组合下的行为。 ## 客户端接口 × 通道协议 | 客户端调用的接口 | OpenAI 兼容通道 | Anthropic 协议通道 | | --- | --- | --- | | Chat Completions(`/v1/chat/completions`) | 按原格式发送,网关只调整推理参数,删除缓存标记和历史消息中的 `reasoning_content`(DeepSeek 系列保留当前轮 assistant 消息上的 `reasoning_content`) | 转换为 Messages 请求;响应和流式事件转换回 Chat 格式 | | Anthropic Messages(`/v1/messages`) | 转换为 Chat Completions 请求;响应和流式事件转换回 Anthropic 格式 | 先转换为内部的 Chat 结构,再转换回 Messages 发送;平台开启原生直通时可以原样发送,见下文 | | Responses(`/v1/responses`) | 原样发送到通道的 Responses 接口;通道没有该接口时由上游返回错误 | 不可用。模型声明了接口范围且不含 Responses 时,网关直接返回 400 `This model does not support the responses API` | - **通道由网关选择**:同一个模型可能同时有两种协议的通道,失败重试时也可能换到另一种协议的通道,所以同一个请求在不同时间可能经过不同的转换。要确认某次请求实际发出的格式,在 **日志分析** 的日志详情中查看「服务商」,以及「原始报文」中的「上游请求」。原始报文的正文只在工作空间开启全文日志后保存,失败的请求除外。 - **不需要转换的组合最保真**:Chat Completions 客户端走 OpenAI 兼容通道、Responses 客户端走提供 Responses 接口的通道时,请求基本按原样发送。对字段有严格要求的应用,可以请当前账号管理员在模型详情中只保留同协议的来源,见[应用接入多个服务商](https://platform.lyrouter.com/ai_gateway/docs/multi-provider)。 - **网关拒绝在先**:模型目录声明了接口或输入范围时,不符合的请求(如对话模型调用图像接口、给只收文本的模型发图片)在转换之前就返回 400,见[模型能力与兼容性](https://platform.lyrouter.com/ai_gateway/docs/capabilities#网关拒绝的请求)。 ## Chat Completions → Anthropic 协议通道 | 请求字段 | 处理 | | --- | --- | | `role` 为 `system`、`developer` 的消息 | 合并为 Anthropic 的 `system`,多条之间以空行连接。**只接受字符串形式的 `content`**,写成内容数组的 system / developer 消息会被丢弃 | | `user`、`assistant` 消息的 `content` | 字符串原样转换;内容数组中只转换 `text` 和 `image_url`(data URL 转为 base64 图片,http(s) 地址转为 URL 图片),`input_audio`、`file` 等其他类型丢弃 | | `tool` 消息、`assistant.tool_calls` | 分别转为 `tool_result` 块和 `tool_use` 块;`arguments` 解析为 JSON 对象,解析失败时为空对象 | | `assistant.reasoning_content` | 不转发 | | `tools` | 转为 `name`、`description`、`input_schema`(取自 `parameters`) | | `tool_choice` | `auto` → `auto`,`required` → `any`,指定函数 → `tool`;`none` 不转发,请求带 `tools` 时模型仍可能调用工具 | | `max_tokens`、`max_completion_tokens` | 转为 `max_tokens`;两者都没有时补 4096 | | `stop` | 转为 `stop_sequences`,字符串会变成单元素数组 | | `metadata` | 只保留 `user_id`,其他键丢弃 | | `enable_thinking`、`thinking_budget` | 转为 `thinking`:有预算时为 `{"type": "enabled", "budget_tokens": N}`,只开启没有预算时为 `{"type": "adaptive"}`,关闭时不发送 | | `n`、`logprobs`、`top_logprobs`、`response_format`、`frequency_penalty`、`presence_penalty`、`seed`、`parallel_tool_calls`、`logit_bias`、`functions`、`function_call`、`reasoning_effort`、`stream_options` | 丢弃 | | 其他字段(`temperature`、`top_p`、`top_k`、`stream`、`service_tier` 等) | 原样发送;Anthropic 不认识的字段由上游决定是否接受 | 响应转换回 Chat 格式:文本块合并为 `message.content`,`tool_use` 块转为 `tool_calls`,思考内容放在 `reasoning_content`;`stop_reason` 映射为 `finish_reason`(`end_turn`、`stop_sequence`、`pause_turn`、`refusal` → `stop`,`max_tokens` → `length`,`tool_use` → `tool_calls`)。因为 `n` 被丢弃,`choices` 始终只有一项。 **强制调用工具时关闭思考**:`tool_choice` 为 `required` 或指定函数、且请求没有写推理参数时,网关替你关闭思考,避免上游以「思考模式不支持强制工具调用」拒绝请求。这条规则对任何接口发往 Anthropic 协议通道或阿里云百炼等使用 `enable_thinking` 的通道都生效。 ## Anthropic Messages → 通道 `/v1/messages` 请求先转换为内部的 Chat 结构,再按通道协议发出。经过这一步后: | 请求内容 | 处理 | | --- | --- | | `system`(字符串或文本块数组) | 合并为一段文本,多个块以空行连接;多个块上的 `cache_control` 只保留最后一个 | | 消息中的块 | 转换 `text`、`image`、`tool_use`、`tool_result`、`thinking`、`redacted_thinking`;`document` 等其他类型的块丢弃 | | 同一条 user 消息中既有 `tool_result` 又有文本或图片 | 只保留 `tool_result`。需要附带的文本请放在下一条 user 消息中 | | `tools` | 按 `name`、`description`、`input_schema` 转换。只有 `type` 和 `name` 的服务端工具(如 `web_search`)会变成同名的普通函数工具,由客户端自己执行 | | `tool_choice` | `auto`、`any`、`tool` 转换;`none` 和 `disable_parallel_tool_use` 不转发 | | `max_tokens`、`stop_sequences`、`stream`、`temperature`、`top_p`、`top_k`、`service_tier` | 保留 | | `thinking` | `{"type": "disabled"}` 视为关闭,其他类型视为开启,`budget_tokens` 保留为思考预算;发往 Anthropic 协议通道时还原为带预算的 `enabled` 或不带预算的 `adaptive` | | `metadata`、`context_management`、`output_config` | 发往 Anthropic 协议通道时还原(`metadata` 只保留 `user_id`);发往 OpenAI 兼容通道时删除 | | 其他顶层字段 | 不转发 | 发往 **OpenAI 兼容通道** 时,思考开关按服务商的写法传递:阿里云百炼等通道收到 `enable_thinking` / `thinking_budget`;OpenAI、DeepSeek 官方通道不支持这两个字段,会被删除;网关没有适配的服务商原样收到这两个字段,是否生效由上游决定。`output_config` 中的 effort 设置不会换算成 `reasoning_effort`。历史消息中的思考块和全部 `cache_control` 标记也会删除。 响应转换回 Anthropic 格式: - `stop_reason` 只会是 `end_turn`、`max_tokens`、`tool_use` 三种,上游的 `stop_sequence`、`pause_turn`、`refusal` 都变为 `end_turn`,响应中不出现 `stop_sequence` 字段(流式与非流式相同)。这一点对 Anthropic 协议通道同样适用。 - OpenAI 兼容通道返回的思考内容(`reasoning_content`)在流式响应中转为 `thinking` 事件,不带签名;非流式响应中不包含思考内容。 - 回答只有思考内容(例如在思考阶段就被 `max_tokens` 截断)时,非流式响应的 `content` 目前是空对象 `{}`,而不是空数组 `[]`。按数组遍历 `content` 前请先判断类型。 - 发往 Anthropic 协议通道时,思考块的签名原样往返,可以在下一轮回传。历史消息中有不带签名的思考块(例如上一轮由 OpenAI 兼容通道回答)时,这一轮去掉全部历史思考块,并且不开启思考,避免上游因签名校验失败而拒绝。 ## 推理参数 三个推理参数分属不同服务商,网关不在它们之间换算,只按选中的通道删掉对方不认识的字段。除 Anthropic 协议一行外,下表各行指 OpenAI 兼容通道: | 通道 | `reasoning_effort` | `enable_thinking` | `thinking_budget` | | --- | --- | --- | --- | | OpenAI | 保留 | 删除 | 删除 | | Anthropic 协议 | 删除 | 转为 `thinking` | 转为 `thinking` | | 阿里云百炼(含通义千问) | 删除 | 保留 | 保留 | | DeepSeek 官方 | 删除 | 删除 | 删除(思考由模型决定) | | 其他服务商 | 原样发送 | 原样发送 | 原样发送 | 同一模型的不同通道可能属于不同行。需要稳定的推理行为时,请为每个通道验证,或用[虚拟模型](https://platform.lyrouter.com/ai_gateway/docs/presets)固定推理参数。 ## 缓存标记 `cache_control` | 组合 | 处理 | | --- | --- | | `/v1/messages` → Anthropic 协议通道 | 保留 `system`、文本块和工具定义上的标记;多个 `system` 块的标记合并为一个;打在图片块或 `tool_result` 块上的标记不转发 | | `/v1/chat/completions` → Anthropic 协议通道 | 保留内容数组中文本、图片部分和 `tools` 中各工具上的标记;system 消息的标记写在消息对象上(与 `role`、`content` 同级),`content` 用字符串 | | 任意接口 → OpenAI 兼容通道 | 全部删除,包括阿里云百炼等支持显式缓存的服务商。这些通道依靠上游的自动前缀缓存 | - **1 小时缓存**:标记中写 `"ttl": "1h"` 时,网关把 `anthropic-beta` 请求头设为 `extended-cache-ttl-2025-04-11`,替换客户端在该请求头中的原有值。 - **虚拟模型的缓存设置**:虚拟模型开启了缓存且请求本身没有任何标记时,网关只在发往 Anthropic 协议通道时给系统提示词加标记;请求自带标记时以请求为准。 - 标记是否生效、命中了多少,在日志的「显式缓存创建」和「输入(缓存命中)」中查看,优化方法见[降低成本与优化缓存](https://platform.lyrouter.com/ai_gateway/docs/cost-practice)。 ## `usage` 字段 响应中的 `usage` 在不同组合下统计方式不同: | 客户端接口 ← 通道 | 响应中的 `usage` | | --- | --- | | Chat Completions ← OpenAI 兼容 | 上游原样返回:`prompt_tokens` 包含缓存命中部分,命中数在 `prompt_tokens_details.cached_tokens`(DeepSeek 为 `prompt_cache_hit_tokens`) | | Chat Completions ← Anthropic 协议 | `prompt_tokens` 等于上游的 `input_tokens`,**不含**缓存命中和缓存写入;非流式响应另带 `cache_read_input_tokens`、`cache_creation_input_tokens`,流式最后一个 chunk 只有 `prompt_tokens`、`completion_tokens`、`total_tokens` | | Anthropic Messages ← Anthropic 协议 | `input_tokens` 不含缓存,`cache_read_input_tokens`、`cache_creation_input_tokens` 只在大于 0 时出现 | | Anthropic Messages ← OpenAI 兼容 | `input_tokens` = 上游 `prompt_tokens` − 缓存命中数,`cache_read_input_tokens` = 缓存命中数,`output_tokens` = 上游 `completion_tokens` | | Responses | 上游原样返回:`input_tokens` 包含缓存命中部分,命中数在 `input_tokens_details.cached_tokens` | - 流式 Chat Completions 中,网关总会请求 `usage`,最后一个 chunk 带用量;Responses 和 Anthropic Messages 按各自协议在结束事件中给出用量。 - **请求日志已统一**:日志中的「输入(缓存未命中)」「输入(缓存命中)」「输出」「显式缓存创建」四项按同一方式换算,互不重叠,不受协议组合影响。核对费用、统计命中率时以日志和用量分析为准,不要直接累加不同组合下的 `prompt_tokens`。 ## 错误格式与流式结束标记 | 客户端接口 | 错误响应体 | 流式正常结束 | 流式输出开始后上游中断 | | --- | --- | --- | --- | | Chat Completions | `{"error": {"message", "type", "code"}}`,`code` 只在部分错误上出现 | `data: [DONE]` | 补一个 `data: {"error": {..., "code": "stream_interrupted"}}`,没有 `data: [DONE]` | | Anthropic Messages | `{"type": "error", "error": {"type", "message"}}`,没有 `code` | `event: message_stop` | 补一个 `event: error`,没有 `message_stop` | | Responses | 与 Chat Completions 相同;上游的错误原样转发 | `response.completed` 事件,没有 `[DONE]` | 补一个 `response.failed` 事件(`error.code` 为 `server_error`),没有 `response.completed` | - `/v1/messages` 上的网关错误和上游错误都转换为 Anthropic 格式,`message` 原文不变,`error.type` 按状态码确定(如 401 → `authentication_error`,429 → `rate_limit_error`,503 → `overloaded_error`)。 - 连接上游失败或等待超时的 500 / 504 返回 HTML 错误页,不是 JSON,任何接口都一样,见[超时与流式中断](https://platform.lyrouter.com/ai_gateway/docs/stream-errors)。 - 对话接口在转换中丢弃的参数不写进 `X-Gateway-Unsupported-Parameters` 响应头;这个响应头和 `X-Gateway-Strict-Parameters` 请求头目前只用于图像、视频接口,见[网关扩展请求头与响应头](https://platform.lyrouter.com/ai_gateway/docs/gateway-headers)。 完整错误码见[错误码与请求标识](https://platform.lyrouter.com/ai_gateway/docs/errors)。 ## Responses 的服务端状态 Responses 请求原样转发,`store`、`background`、`previous_response_id` 都由上游处理,响应对象保存在创建它的上游: | 操作 | 网关的处理 | 限制 | | --- | --- | --- | | 带 `previous_response_id` 的新请求 | 用它把请求归入同一会话(日志的「会话」列),然后照常选择通道 | 不保证落到同一个上游。换了通道或凭证时,新的上游找不到上一轮响应,返回上游的错误 | - **多轮对话**:「最低价」「负载均衡」策略会在 30 分钟内把同一 API Key 对同一模型的请求保持在同一通道,多数接续请求会落回原上游,但失败重试、策略切换或保持期过后仍可能换通道,见[通道选择与路由策略](https://platform.lyrouter.com/ai_gateway/docs/routing)。需要可靠的多轮对话时,在客户端保存历史,每轮把完整上下文放进 `input` 发送。 - **虚拟模型的参数**:通过 Responses 调用虚拟模型时,「推理参数」按 Chat Completions 的字段名合并进请求,例如 `max_tokens` 不会换成 `max_output_tokens`。上游不接受这些字段时会返回 400,供 Responses 客户端使用的虚拟模型请只设置两种接口同名的参数(如 `temperature`、`top_p`)。 ## 原生直通 原生直通让 `/v1/messages` 请求在发往 Anthropic 协议通道时跳过上文的转换:请求体除 `model` 换成上游模型名外按客户端发来的内容发送,响应按上游返回的字节原样返回,计费和日志不受影响。平台可以只开启响应原样返回,也可以请求、响应都开启;**默认都关闭**,所有 `/v1/messages` 请求都经过转换。 需要确保请求未被改写的客户端,可以加请求头要求直通,做不到时网关拒绝请求,而不是悄悄转换: ```bash curl https://api.lyrouter.com/v1/messages \ -H "x-api-key: $LYROUTER_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -H "x-gateway-passthrough: require" \ -H "Content-Type: application/json" \ -d '{"model": "MODEL_ID", "max_tokens": 1024, "messages": [{"role": "user", "content": "你好"}]}' ``` | `x-gateway-passthrough` | 行为 | | --- | --- | | 不带,或 `prefer` | 能直通就直通,不能时自动走转换,请求照常完成 | | `require`(不区分大小写) | 必须直通;不能直通时返回 400 ``native passthrough was required by `x-gateway-passthrough: require` but is not available for this request (<原因>)`` | 括号中的原因说明是哪一项条件不满足: | 原因 | 含义 | 处理 | | --- | --- | --- | | `route_disabled` | 平台没有为该接口开启请求原样发送(默认状态) | 去掉这个请求头,接受转换 | | `client_protocol` | 请求不是发往 `/v1/messages` 的 | 这个请求头只对 Anthropic Messages 有效 | | `wire_protocol` | 选中的通道不是 Anthropic 协议 | 换用由 Anthropic 协议通道服务的模型 | | `endpoint_type` | 不是对话请求 | 去掉这个请求头 | | `channel_disabled` | 平台对这个通道关闭了直通 | 换用其他模型或去掉请求头 | | `preset_injection` | 虚拟模型设置了系统提示词、推理参数、锁定参数或缓存,需要改写请求 | 直接调用模型 ID,或去掉虚拟模型中的这些设置 | | `shape_oai` | 请求体含 OpenAI 专有字段(如 `response_format`、`n`),或消息角色不只是 `user` / `assistant`,或工具是 OpenAI 格式 | 改成纯 Anthropic 格式的请求 | | `decision_error` | 网关判断时出错 | 稍后重试;持续出现时联系支持 | 直通只作用于请求实际发往的那个通道;失败重试换到 OpenAI 兼容通道时,带 `require` 的请求同样返回 400。 ## 常见问题 ### 设置了 `response_format`,为什么返回的不是 JSON? **答:** 请求被路由到 Anthropic 协议通道时,`response_format` 在转换中被丢弃。在日志中确认这次请求的「服务商」;需要稳定的 JSON 输出时,在提示词中写明格式,或只保留 OpenAI 兼容的来源,见[模型能力与兼容性](https://platform.lyrouter.com/ai_gateway/docs/capabilities)。 ### 用 Claude Code 调用 Claude 模型,请求会被改写吗? **答:** 会经过一次转换,但思考块签名、缓存标记、`metadata`、`context_management`、`output_config` 都会还原。需要注意的是 `document` 块、与 `tool_result` 同在一条消息中的文本、服务端工具和 `stop_reason` 的细分值,见上文「Anthropic Messages → 通道」。缓存命中情况在日志的「输入(缓存命中)」中确认。 ### 同一个应用同时用 OpenAI SDK 和 Anthropic SDK,用量怎么统一统计? **答:** 不要直接汇总响应中的 `usage`,两种格式对缓存的计数方式不同。请以请求日志和 **用量分析** 为准,它们已把四项 Token 换算成同一方式,见[通过日志定位调用问题](https://platform.lyrouter.com/ai_gateway/docs/logs)和[用量归因与分析](https://platform.lyrouter.com/ai_gateway/docs/analytics)。 --- # 在 AI 工具中使用本文档 来源: https://platform.lyrouter.com/ai_gateway/docs/ai-tools 本文档的每一页都有给 AI 读的 Markdown 版本,另有整站目录、全文合集、OpenAPI 规格和一个 MCP 服务。让 DeepSeek、ChatGPT、Claude、Cursor、Claude Code 等工具按 LYRouter 的接口写代码时,把下面任一份交给它,比让它凭记忆猜更准确。 下文的地址都在控制台域名 `https://platform.lyrouter.com` 上,不是网关地址 `https://api.lyrouter.com`。 ## 选择哪一种 | 用途 | 交给 AI 的内容 | | --- | --- | | 就某一页提问 | 页面顶部的「复制为 AI 阅读友好的格式」 | | 让 AI 自己找相关的页 | [llms.txt](https://platform.lyrouter.com/llms.txt) | | 一次把全部文档交给 AI | [llms-full.txt](https://platform.lyrouter.com/llms-full.txt) | | 生成客户端代码、校验请求 | [OpenAPI 规格](#openapi-规格) | | 在编辑器或命令行里随时查文档 | [MCP 服务](#mcp-服务) | ## 页面上的按钮 每页标题下方有 **复制为 AI 阅读友好的格式** 按钮:复制本页的 Markdown,粘贴到任意 AI 对话中即可提问。复制内容开头写有本页地址;站内链接已改成完整地址,截图换成文字说明,代码块原样保留。 ## 每页的 Markdown 地址 在页面地址后加 `.md`,就是这一页的 Markdown 版本,内容与「复制为 AI 阅读友好的格式」相同: | 页面 | Markdown 地址 | | --- | --- | | `https://platform.lyrouter.com/ai_gateway/docs/errors` | `https://platform.lyrouter.com/ai_gateway/docs/errors.md` | | `https://platform.lyrouter.com/ai_gateway/docs/errors/en` | `https://platform.lyrouter.com/ai_gateway/docs/errors/en.md` | 英文版的地址带 `/en`;只有中文的文章没有 `en.md`。 ## llms.txt 与 llms-full.txt 按 [llms.txt 约定](https://llmstxt.org) 提供两个文件: | 文件 | 内容 | | --- | --- | | [`/llms.txt`](https://platform.lyrouter.com/llms.txt) | 文档目录:每页的标题、Markdown 地址和一句摘要,中文在前、英文在后,末尾列出 OpenAPI 规格和 MCP 服务的地址 | | [`/llms-full.txt`](https://platform.lyrouter.com/llms-full.txt) | 全部中文文章的 Markdown 合集,每篇以 `---` 分隔、开头写有原文地址 | `llms-full.txt` 较长,适合上下文窗口大的模型,或作为知识库文件上传。只需要部分内容时,先给 `llms.txt`,让 AI 按目录抓取所需的页。 ## OpenAPI 规格 | 文件 | 范围 | | --- | --- | | [lyrouter-openapi.yaml](https://platform.lyrouter.com/ai_gateway/api-spec/lyrouter-openapi.yaml) | 对话(Chat Completions、Responses、Anthropic Messages)、向量、重排、列出模型 | | [multimodal-openapi.yaml](https://platform.lyrouter.com/ai_gateway/api-spec/multimodal-openapi.yaml) | 图像生成与编辑、视频任务等多模态接口 | 两份都是 OpenAPI 3.1,可以直接交给 AI 作为接口依据,也可以用代码生成器得到客户端: ```bash npx openapi-typescript https://platform.lyrouter.com/ai_gateway/api-spec/lyrouter-openapi.yaml \ -o ./src/lyrouter-api.d.ts ``` 规格描述的是网关对外的接口;某个模型实际接受哪些参数,以各接口页和[协议兼容性与限制](https://platform.lyrouter.com/ai_gateway/docs/compatibility)为准。 ## MCP 服务 文档提供一个 MCP 服务,地址为: ```text https://platform.lyrouter.com/api/v1/docs/mcp ``` 传输方式为 Streamable HTTP,不需要 API Key。服务提供两个工具: | 工具 | 作用 | | --- | --- | | `search_docs` | 按关键词或问题搜索文档(中英文均可),返回匹配页的标题、页面地址、Markdown 地址和摘要 | | `get_doc` | 按页面标识(如 `errors`)或页面地址读取一页的完整 Markdown,可选中文或英文 | 在 Claude Code 中添加: ```bash claude mcp add --transport http lyrouter-docs https://platform.lyrouter.com/api/v1/docs/mcp ``` 在 Cursor 中,把下面的配置写入 `~/.cursor/mcp.json`(只对当前项目生效时写入项目的 `.cursor/mcp.json`): ```json { "mcpServers": { "lyrouter-docs": { "url": "https://platform.lyrouter.com/api/v1/docs/mcp" } } } ``` 其他支持远程 MCP 的工具,按其说明添加同一地址即可。添加后,向 AI 提问时说明「查 LYRouter 文档」,它会调用上面的工具取得最新内容。 ## 常见问题 ### AI 说打不开文档地址,怎么办? **答:** 部分 AI 产品在对话中不能联网,或不能访问任意地址。改用「复制为 AI 阅读友好的格式」,把内容直接粘贴进对话。 ### AI 给出的参数和本文档不一致,以哪个为准? **答:** 以本文档为准。AI 可能混用了 OpenAI、Anthropic 官方文档或旧版本的内容,可以把相关页的 Markdown 交给它重新回答。