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. Чек-лист миграции

При переходе с официального подключения на шлюз или между шлюзами проверяйте по порядку:

  1. Зафиксируйте набор реальных промптов, запишите текущий вывод, время и usage как базу сравнения.
  2. Меняйте base_url и api_key одновременно, не только один из них.
  3. Заново сверьте сопоставление имён моделей на странице тарифов, не используйте старые имена.
  4. Проверьте стриминг: время до первого токена, delta.content, finish_reason и [DONE].
  5. Проверьте вызов инструментов: tools, tool_calls, возврат tool_call_id и порядок шагов.
  6. Проверьте поддержку расширений thinking, reasoning_effort и различия значений по умолчанию.
  7. Настройте тайм-ауты соединения и чтения; повторяйте только 429, 5xx и тайм-ауты; операции записи делайте идемпотентными.
  8. Сначала переведите 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.