← Все статьи

OpenAI Responses API после Assistants: паттерны миграции и архитектурное руководство

Assistants API прекращает работу 26 августа. Это руководство описывает конкретные паттерны Responses API для команд, которые уже мигрировали: управление состоянием диалога без серверных threads, оркестрация инструментов, streaming и кросс-провайдерный routing через OpenAI-совместимый gateway.

· TheRouter

Assistants API прекращает работу 26 августа 2026 года. Если вы читаете этот текст, дедлайн либо завтра, либо уже прошёл. Чеклисты миграции и разбор полётов опубликованы в других статьях блога. Здесь речь пойдёт о другом: вы уже переехали с Assistants, и теперь нужно грамотно строить на Responses API.

Ниже — практическое архитектурное руководство: как работает состояние диалога без серверных Threads, как оркестрация инструментов заменяет Run-объекты, чем отличается streaming и какую роль играет кросс-провайдерный routing через OpenAI-совместимый gateway.

Что Responses API даёт по сравнению с Assistants

Assistants API управлял состоянием за вас: Threads хранили сообщения, Runs опрашивались на завершение, сервер оркестрировал вызовы инструментов по шагам. Удобно, но привязывает. Thread и Run объекты существовали только на серверах OpenAI. Их нельзя было воспроизвести через другого провайдера, кэшировать локально или проинспектировать полное состояние оркестрации в собственной инфраструктуре.

Responses API заменяет этот серверный жизненный цикл stateless (или опционально stateful) моделью запросов. Каждый вызов POST /v1/responses принимает массив input и возвращает массив output. Модель может вызвать несколько инструментов в рамках одного запроса. Состояние — у вас.

Ключевые изменения, влияющие на архитектурные решения:

  • Нет серверных threads. Состояние диалога передаётся через previous_response_id, управляется через Conversations API или воспроизводится вручную в input.
  • Встроенный agentic loop. Модель может в одном запросе последовательно вызывать web search, file search, code interpreter, function calls и MCP, без polling.
  • Типизированные элементы вывода. Вместо choices[0].message — массив output с отдельными элементами reasoning, message, function_call, web_search_call.
  • Лучшая утилизация кэша. OpenAI сообщает об улучшении cache hit rate на 40–80% по сравнению с Chat Completions при эквивалентных нагрузках.

Управление состоянием диалога без серверных Threads

Assistants хранили историю диалога в объектах Thread. Responses API предлагает три подхода к состоянию с разным балансом переносимости и сложности.

Вариант 1: previous_response_id (самый простой, только OpenAI)

Передайте id предыдущего ответа для связывания turns:

first = client.responses.create(
    model="gpt-5.6",
    input="Объясни теорему CAP.",
)

second = client.responses.create(
    model="gpt-5.6",
    input="Теперь приведи конкретный пример.",
    previous_response_id=first.id,
)

Это ближайший аналог Assistants Threads. OpenAI хранит контекст на сервере и автоматически его воспроизводит. Компромисс: этот параметр специфичен для OpenAI. Responses API DeepSeek не поддерживает previous_response_id (это stateless API). Если нужна кросс-провайдерная переносимость, используйте варианты 2 или 3.

Вариант 2: Conversations API (новый, только OpenAI)

Conversations API обеспечивает persistent именованные диалоги. Полезно, когда несколько сессий должны ссылаться на одну историю. Как и previous_response_id, это только OpenAI.

Вариант 3: Ручное воспроизведение состояния (переносимый)

Добавляйте полный массив output каждого ответа к массиву input следующего запроса:

history = [{"role": "user", "content": "Объясни теорему CAP."}]

response = client.responses.create(
    model="gpt-5.6",
    input=history,
    store=False,
)

# Воспроизводим все output-элементы, включая зашифрованные reasoning
history += response.output
history.append({"role": "user", "content": "Приведи пример."})

next_response = client.responses.create(
    model="gpt-5.6",
    input=history,
    store=False,
)

Этот подход работает с любым провайдером, поддерживающим формат input Responses API. DeepSeek принимает ту же структуру input (message, function_call, function_call_output, reasoning, web_search_call). Цена — управление хранением и воспроизведением ложится на вас, а длинные диалоги увеличивают потребление token на каждый запрос.

Как выбрать: используйте ручное воспроизведение, если маршрутизируете через нескольких провайдеров или хотите полный контроль. Используйте previous_response_id, если работаете только с OpenAI и хотите минимум кода. Не смешивайте подходы в одном диалоге.

Оркестрация инструментов: от polling Run к agentic loop

Assistants API требовал опроса Run-объектов для проверки, хочет ли модель вызвать инструмент, затем отправки вывода инструмента и повторного опроса. Многоинструментный диалог мог потребовать четыре-пять round trip.

Responses API это устраняет. Если в запросе настроены tools, модель может вызвать несколько инструментов и включить их результаты в рамках одного API-вызова (для встроенных инструментов: web search, file search, code interpreter). Для пользовательских function calls вы всё ещё подаёте вывод вручную, но цикл запрос/ответ проще:

import json

response = client.responses.create(
    model="gpt-5.6",
    input="Какая сейчас погода в Токио и Нью-Йорке?",
    tools=[{
        "type": "function",
        "name": "get_weather",
        "description": "Получить текущую погоду для города",
        "parameters": {
            "type": "object",
            "properties": {"city": {"type": "string"}},
            "required": ["city"],
            "additionalProperties": False,
        },
        "strict": True,
    }],
)

tool_outputs = []
for item in response.output:
    if item.type == "function_call":
        result = get_weather(json.loads(item.arguments)["city"])
        tool_outputs.append({
            "type": "function_call_output",
            "call_id": item.call_id,
            "output": json.dumps(result),
        })

final = client.responses.create(
    model="gpt-5.6",
    input=[
        *response.output,
        *tool_outputs,
    ],
    tools=[{...}],
    previous_response_id=response.id,
)

Встроенные инструменты, заменяющие функции Assistants

Функция AssistantsЗамена в Responses APIПримечания
Code Interpreter{"type": "code_interpreter"}Выполняет Python в sandbox, возвращает текст/изображения
File Search (Retrieval){"type": "file_search", "vector_store_ids": [...]}Та же инфраструктура vector store
Function calling{"type": "function", ...}Формат запроса отличается от Chat Completions
Web browsing (beta){"type": "web_search"}Серверное выполнение, цитаты в output

Кросс-провайдерная поддержка инструментов

Responses API DeepSeek поддерживает типы инструментов function и web_search. Другие встроенные инструменты (file_search, code_interpreter, computer_use, mcp) игнорируются без ошибок. При мультипровайдерном routing для agentic-нагрузок необходимо учитывать доступность инструментов по каждому провайдеру.

OpenAI-совместимость означает, что провайдер предоставляет endpoint chat-completions, чей контракт запроса и ответа достаточно близок к API OpenAI, чтобы немодифицированный вызов OpenAI SDK работал после замены трёх значений: API key, base URL, название модели. Минимальная поверхность на практике —POST /v1/chat/completions с messages, model и потоковым ответом в форме OpenAI.

Streaming: от delta-чанков к семантическим событиям

Chat Completions streaming отправляет delta-объекты с инкрементальным контентом. Responses API использует семантические server-sent events (SSE). Каждое событие имеет поле type, описывающее происходящее:

Тип событияЗначение
response.createdЗапрос принят, начата генерация
response.output_text.deltaИнкрементальный текст (аналог delta из Chat Completions)
response.function_call_arguments.deltaИнкрементальный JSON аргументов function call
response.reasoning_text.deltaТекст цепочки рассуждений (при включённом reasoning)
response.output_item.added / .doneЭлемент output (message, function_call и т.д.) начат/завершён
response.completedФинальное событие с полным объектом ответа и usage
response.failedОшибка при генерации
stream = client.responses.create(
    model="gpt-5.6",
    input="Подведи итоги последних трендов в AI-исследованиях.",
    stream=True,
)

for event in stream:
    if event.type == "response.output_text.delta":
        print(event.delta, end="")
    elif event.type == "response.completed":
        print(f"\n\nTokens: {event.response.usage.total_tokens}")

Сообщения data: [DONE] нет. Поток завершается событием response.completed, response.incomplete или response.failed.

Responses API DeepSeek поддерживает ту же структуру SSE-событий, что обеспечивает консистентное поведение streaming при routing между OpenAI и DeepSeek через совместимый gateway.

Кросс-провайдерный routing

Формат input/output Responses API становится кросс-провайдерным стандартом, но степень поддержки различается:

ПровайдерПоддержка Responses APIОсновные ограничения
OpenAIПолнаяЭталонная реализация
DeepSeekЧастичнаяНет previous_response_id, store, background, Conversations API. Инструменты ограничены function и web_search. Неподдерживаемые параметры игнорируются без ошибок.
DashScope (Qwen)Через Chat CompletionsDashScope использует OpenAI-совместимый Chat Completions. Формат Responses API нативно не поддерживается, но модели Qwen доступны через routing Chat Completions.

Архитектура routing

При маршрутизации трафика Responses API через gateway типа TheRouter:

  1. Stateless-запросы маршрутизируются без проблем. При использовании ручного воспроизведения состояния (вариант 3 выше) один и тот же запрос можно направить любому провайдеру, поддерживающему формат input Responses API.
  2. Stateful-параметры специфичны для провайдера. previous_response_id, store: true и Conversations API работают только когда запросы попадают в OpenAI. Router не может синтезировать серверное состояние для другого провайдера.
  3. Доступность инструментов различается. Запросы с web_search или function можно направлять провайдерам, которые их поддерживают. Запросы с file_search или code_interpreter должны идти в OpenAI.
  4. Fallback требует осторожности. Если OpenAI недоступен и fallback идёт на DeepSeek, приложение должно обрабатывать отсутствие встроенных инструментов, которые DeepSeek не поддерживает.

TheRouter маршрутизирует OpenAI-совместимые запросы через настроенных провайдеров. Для трафика Responses API это означает, что запросы с ручным воспроизведением состояния и инструментами типа function маршрутизируются к любому совместимому endpoint. Запросы, зависящие от специфичных для OpenAI функций (previous_response_id, встроенные инструменты помимо function и web_search), следует фиксировать на OpenAI.

Чеклист production-готовности

Перед выводом интеграции Responses API в production проверьте каждый пункт:

Обработка ошибок

  • Обрабатывайте события response.failed в streaming и проверяйте поле status в синхронных ответах
  • Реализуйте логику retry для ответов 429 (rate limit) и 500+ (серверные ошибки)
  • Устанавливайте max_output_tokens для предотвращения неконтролируемых расходов на генерацию

Учёт token

  • Читайте usage.input_tokens и usage.output_tokens из объекта ответа
  • Для reasoning-моделей output_tokens_details.reasoning_tokens показывает потребление token на цепочку рассуждений
  • Cache hit token отображаются в input_tokens_details.cached_tokens

Управление состоянием

  • При ручном воспроизведении надёжно сохраняйте массивы output (база данных, не только in-memory)
  • Зашифрованные reasoning-элементы нужно воспроизводить as-is для сохранения контекста reasoning-моделей
  • Устанавливайте store: false, если не хотите, чтобы OpenAI сохранял ответы

Поведение при fallback

  • Протестируйте каждого провайдера с вашей реальной конфигурацией инструментов
  • Логируйте и настройте оповещения, когда fallback-провайдер молча игнорирует неподдерживаемые инструменты
  • Рассмотрите отдельные правила routing для agentic (с большим количеством инструментов) и простых генерационных запросов

Валидация миграции

  • Убедитесь, что парсинг ответа корректно обрабатывает элементы output_text и function_call
  • Подтвердите, что structured output работает с text.format вместо response_format
  • Запустите интеграционные тесты и с OpenAI, и хотя бы с одним альтернативным провайдером

FAQ

Responses API дороже Chat Completions?

Для эквивалентной генерации текста без встроенных инструментов цена за token одинакова. OpenAI сообщает о лучшей утилизации кэша в Responses, что может снизить фактические затраты. Встроенные инструменты вроде web search тарифицируются отдельно.

Можно ли использовать Responses API с reasoning-моделями?

Да. Начиная с GPT-5.4, reasoning-модели получили улучшенную работу с инструментами в Responses API. Chat Completions не поддерживает вызов инструментов с reasoning_effort, отличным от none, для GPT-5.4 и новее.

Что будет с существующими интеграциями Chat Completions?

Chat Completions остаётся поддерживаемым. Об отказе от него не объявлялось. Однако новые возможности (встроенные инструменты, Conversations API, background mode) доступны только в Responses.

Responses API DeepSeek работает идентично OpenAI?

Нет. DeepSeek поддерживает базовый формат запроса/ответа, function calling и web search, но не поддерживает stateful-функции (previous_response_id, store, Conversations API) и встроенные инструменты file_search, code_interpreter. Неподдерживаемые параметры игнорируются без ошибок.

Можно ли в одном приложении совмещать Chat Completions и Responses API?

Да, но не разделяйте между ними состояние. Chat Completions использует messages/choices, Responses — input/output. Это два отдельных endpoint с разной структурой объектов.

Дополнительные материалы

Модели, упомянутые в статье

Помощь и контакты