Doubao API предоставляет OpenAI-совместимый интерфейс, но «совместимость» не означает «копировать всё подряд». Легче всего застрять на трёх вещах: в Base URL написали /v1, в model указали отображаемое имя вместо model ID или ID точки доступа, а при первом вызове включили глубокое размышление, из-за чего вывод обрезался. Ниже по порядку проходим curl и Python, затем разбираем потоковый вывод, вызов инструментов, типичные ошибки и чек-лист миграции.
Примечание: Doubao, Volcano Ark, Volcano Engine и ByteDance — товарные знаки или названия продуктов ByteDance и связанных компаний; OpenAI — товарный знак своего правообладателя. Статья носит технический характер и не подразумевает аффилированность, агентские отношения или поддержку со стороны перечисленных компаний. Интерфейсы, модели и квоты могут меняться; сверяйтесь с официальной документацией и страницей тарифов.
1. Три вещи перед подключением
| Параметр | Прямое подключение Volcano Ark | Единый шлюз |
|---|---|---|
| Base URL | https://ark.cn-beijing.volces.com/api/v3 |
https://ai.zhongshangqihang.com/v1 |
| Аутентификация | Authorization: Bearer <ARK_API_KEY> |
Authorization: Bearer <ключ шлюза> |
| model | Model ID или ID точки доступа ep- |
По списку моделей на сайте |
| Кому подходит | Только Doubao, самостоятельная регистрация и счёт | Несколько моделей, единый счёт и квоты |
Ключ и Base URL используются парой. Официальный ключ с адресом шлюза или ключ шлюза с официальным адресом обычно сразу дают 401. При смене входа меняйте оба параметра вместе.
2. Base URL и путь запроса: /api/v3, а не /v1
Официальный адрес плоскости данных — https://ark.cn-beijing.volces.com/api/v3, путь чата — /chat/completions, полный адрес — https://ark.cn-beijing.volces.com/api/v3/chat/completions. Здесь нет привычного для OpenAI префикса /v1; если добавить /v1, получите 404.
Регион указан в домене (cn-beijing). Если ресурсы находятся в другом регионе, ориентируйтесь на адрес из консоли и документации. Документация также предупреждает, что в некоторых случаях, например с Coding Plan, используется другой Base URL; ошибка может привести к дополнительным списаниям, поэтому перед сменой тарифа сверяйтесь.
3. Что указывать в model: Model ID или ID точки доступа
Документация описывает два способа вызова:
- Предустановленный вывод: укажите Model ID, например
doubao-seed-2-1-pro-260915, создавать точку доступа заранее не нужно. - Пользовательская точка вывода: укажите ID точки доступа, обычно начинающийся с
ep-; подходит для фиксированного развёртывания, тонкого управления или дообученных LoRA-моделей.
Model ID содержит дату версии; не пишите отображаемые имена вроде «Doubao 2.1 Pro» и не добавляйте суффикс по памяти. При подписи Access Key (AK/SK) в model обязательно указывается ID точки доступа; при использовании API-ключа по документации можно указать Model ID или ID точки доступа. Если возвращается InvalidEndpointOrModel.ModelIDAccessDisabled, аккаунт не поддерживает прямой вызов по Model ID — нужно создать точку доступа.
4. Минимальный запрос через curl
Сначала отключите глубокое размышление, чтобы уменьшить число переменных. Пример для официального входа:
export ARK_API_KEY="ваш API-ключ Volcano Ark"
export ARK_MODEL_ID="doubao-seed-2-1-pro-260915"
curl "https://ark.cn-beijing.volces.com/api/v3/chat/completions" \
-H "Authorization: Bearer $ARK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "'"$ARK_MODEL_ID"'",
"messages": [{"role": "user", "content": "Ответь только OK"}],
"thinking": {"type": "disabled"},
"max_tokens": 32
}'
Если вернулся 200 и в choices[0].message.content есть текст, ключ, адрес и модель верны. При 404 сначала проверьте, есть ли в model суффикс версии и не нужен ли ID ep-; при 401 проверьте ключ и заголовок, а не баланс.
5. Вызов из Python через OpenAI SDK
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["ARK_API_KEY"],
base_url="https://ark.cn-beijing.volces.com/api/v3",
)
resp = client.chat.completions.create(
model=os.environ.get("ARK_MODEL_ID", "doubao-seed-2-1-pro-260915"),
messages=[
{"role": "system", "content": "Ты технический ассистент, отвечай кратко."},
{"role": "user", "content": "Объясни в трёх предложениях, что такое точка вывода."},
],
max_tokens=512,
extra_body={"thinking": {"type": "disabled"}},
)
print(resp.choices[0].message.content)
print(resp.usage)
OpenAI SDK не знает поле thinking, поэтому оно передаётся через extra_body; если шлюз или модель его не поддерживают, поле можно убрать. После успешного вызова посмотрите входные и выходные токены в usage, затем определяйте тайм-ауты, параллелизм и бюджет.
6. Потоковый вывод: delta, reasoning_content и [DONE]
При stream=True сервер возвращает данные по частям через SSE; объект ответа — chat.completion.chunk, текст — в choices[0].delta.content, размышления — в delta.reasoning_content, finish_reason появляется только в последнем chunk, в конце приходит data: [DONE].
stream = client.chat.completions.create(
model=os.environ["ARK_MODEL_ID"],
messages=[{"role": "user", "content": "Напиши пример Python для чтения CSV"}],
stream=True,
stream_options={"include_usage": True},
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="")
Блок размышления может иметь пустой content; не предполагайте текст в каждом chunk. Слишком малый max_tokens обрежет вывод. При обрыве сети уже полученные данные остаются, поэтому клиент должен уметь сохранить частичный результат и решить, повторять ли запрос.
7. Вызов инструментов: tools, tool_calls и порядок возврата
tools описывается близко к OpenAI: каждый инструмент содержит type: "function" и function, где обязательны name, description и parameters; parameters использует JSON Schema. Когда модель решает вызвать инструмент, finish_reason равен tool_calls, а message.tool_calls[i].function.arguments — строка JSON, которую нужно разобрать самостоятельно.
Порядок возврата нельзя нарушать: сначала добавьте в диалог сообщение assistant с tool_calls, затем для каждого вызова добавьте сообщение role: "tool" с соответствующим tool_call_id и результатом, после чего снова обратитесь к модели, пока finish_reason не перестанет быть tool_calls. parallel_tool_calls по умолчанию true; значение false ограничивает вызов одним инструментом за раз. В потоковом режиме приращения вызова инструмента содержат index, и arguments нужно накапливать по этому index.
8. Типичные ошибки: 401, 404, 429
| HTTP | Типичный код | Значение | Что делать |
|---|---|---|---|
| 401 | AuthenticationError |
Ключ отсутствует, недействителен или нет Bearer |
Скопировать ключ заново, проверить Authorization |
| 404 | InvalidEndpointOrModel.NotFound |
Модель или точка доступа не существует, нет прав в пространстве | Скопировать полный ID из консоли, проверить регион и пространство |
| 404 | ModelNotOpen |
Модель не открыта в аккаунте | Открыть модель в консоли Ark |
| 404 | InvalidEndpointOrModel.ModelIDAccessDisabled |
Аккаунт не поддерживает прямой вызов по Model ID | Создать пользовательскую точку доступа и использовать ep- ID |
| 400 | InvalidParameter, MissingParameter |
Не хватает параметра, неверный тип или модель не поддерживает параметр | Сверить с документацией, убрать лишнее, начать с минимального запроса |
| 403 | AccessDenied, AccountOverdueError |
Нет прав или отрицательный баланс | Проверить ключ и права пространства, погасить задолженность |
| 429 | RateLimitExceeded.* |
Превышены RPM/TPM или всплеск трафика | Снизить параллелизм, экспоненциальная задержка, при необходимости запросить повышение |
| 500/503 | InternalServiceError, ServerOverloaded |
Сбой или перегрузка upstream | Небольшая пауза, повтор, подготовить резервный канал |
9. Чек-лист миграции
При переходе с официального подключения на шлюз или между шлюзами проверяйте по порядку:
- Зафиксируйте набор реальных промптов, запишите текущий вывод, время и
usageкак базу сравнения. - Меняйте
base_urlиapi_keyодновременно, не только один из них. - Заново сверьте сопоставление имён моделей на странице тарифов, не используйте старые имена.
- Проверьте стриминг: время до первого токена,
delta.content,finish_reasonи[DONE]. - Проверьте вызов инструментов:
tools,tool_calls, возвратtool_call_idи порядок шагов. - Проверьте поддержку расширений
thinking,reasoning_effortи различия значений по умолчанию. - Настройте тайм-ауты соединения и чтения; повторяйте только 429, 5xx и тайм-ауты; операции записи делайте идемпотентными.
- Сначала переведите 5–10% трафика и наблюдайте 3–7 дней, сохранив официальное подключение как канал отката.
Если нужен единый вход, создайте тестовый ключ на странице регистрации; покрытие моделей и тарификация — на странице тарифов. ZSQH AI Gateway — независимый сторонний сервис, не связанный с ByteDance.
Читайте также:
Частые вопросы
Нужно ли добавлять /v1 к Base URL?
Нет. OpenAI-совместимый вход Volcano Ark — https://ark.cn-beijing.volces.com/api/v3, путь чата — /chat/completions; добавление /v1 даёт 404. Адрес шлюза обычно заканчивается на /v1, не смешивайте их.
В model указывать Model ID или ID точки доступа с ep-?
Для предустановленного вывода — Model ID; для пользовательской точки доступа — ID ep-; при подписи Access Key обязательно указывается ID точки доступа. Если возвращается ModelIDAccessDisabled, нужно создать точку доступа, а не менять ключ.
Включать ли глубокое размышление при первом вызове?
Рекомендуется сначала выключить и проверить связь минимальным запросом. Некоторые модели Doubao включают глубокое размышление по умолчанию: сначала идёт блок размышления, и при малом max_tokens основной текст легко обрезается. Включайте по задаче после проверки цепочки.
Почему в потоковом выводе нет содержимого?
Сначала проверьте stream=True, затем — не читаете ли вы только delta.content и не игнорируете пустые блоки; размышления находятся в delta.reasoning_content. Также проверьте max_tokens, сетевой буфер и прокси — не собирает ли он SSE в один ответ.
Зачем возвращать assistant tool_calls?
Протокол требует, чтобы сообщение assistant содержало tool_calls, а каждое сообщение role: "tool" соответствовало результату по tool_call_id. Без этого модель может повторно вызвать инструмент или вернуть 400. В потоковом вызове параметры нужно накапливать по index.
