← Все статьи

Миграция с OpenAI Assistants API на Responses API: руководство по архитектуре routing

OpenAI Assistants API будет отключен 26 августа 2026 года. Это руководство объясняет сопоставление объектов Assistants и Responses, изменения в коде, миграцию состояния, tool loops и проверки для routing gateways перед cutover.

· TheRouter

Миграция с OpenAI Assistants API на Responses API: руководство по routing-архитектуре

OpenAI Assistants API будет отключен 26 августа 2026 года. Путь замены — Responses API: Assistants становятся версионируемыми Prompts, Threads становятся Conversations, Runs становятся Responses, а Run steps становятся output Items. Если production-агенты проходят через routing gateway, относитесь к этому как к архитектурной миграции, а не к простому переименованию endpoint: инвентаризируйте openai.beta.*, сначала переводите новые сессии на Responses, переносите историю Thread только при необходимости, заново тестируйте tool loops и streaming, а fallback routing оставляйте только на проверенных chat/response путях.

Это evergreen-руководство для команд, которые уже знают deadline, но должны выполнить миграцию надежно. Фокус — кодовая миграция и routing decisions; продуктовые утверждения ограничены: TheRouter маршрутизирует OpenAI-compatible запросы через настроенных providers и поддерживает provider/model routing и fallback там, где это поддержано live product path. Мы не обещаем поддержку всех моделей, нулевые простои или гарантированно самый дешёвый routing.

Ответ за 30 секунд

  • OpenAI сообщает, что Assistants API deprecated и будет отключен 26 августа 2026 года после достижения feature parity в Responses API (OpenAI Assistants migration guide, получено 2026-06-21).
  • Сопоставление объектов: Assistants → Prompts, Threads → Conversations, Runs → Responses, Run steps → Items (OpenAI Assistants migration guide, получено 2026-06-21).
  • Автоматической миграции Threads-to-Conversations нет; OpenAI рекомендует переводить новые пользовательские чаты на Conversations и backfill старых Threads только при необходимости (OpenAI Assistants migration guide, получено 2026-06-21).
  • File search в Responses API — hosted tool на vector stores, который возвращает file-search call items и message items с citations (OpenAI File search guide, получено 2026-06-21).
  • Для пользователей TheRouter важно ограничивать routing claims: /v1/responses есть в repo и переводит Responses-shaped requests через chat-compatible provider paths, но provider-specific hosted tools нужно тестировать отдельно для каждого provider перед production rollout.

Что меняется при переходе от Assistants к Responses

Старый Assistants API объединял поведение, состояние и выполнение в постоянных объектах на стороне OpenAI. Responses API разделяет эти слои, чтобы у кода приложения и routing gateway были более чёткие границы.

Assistants APIАналог эпохи ResponsesВлияние на миграцию
AssistantPromptПеренесите инструкции, схемы инструментов и ожидания по структурированному выводу в версионируемый prompt или в конфигурацию, которой владеет приложение.
ThreadConversationConversation хранит потоки items, а не только сообщения. Новые conversations получают новые ID.
RunResponseВыполнение — это response-запрос; циклы вызова инструментов становятся явной логикой приложения.
Run stepItemItem может быть сообщением, вызовом инструмента, выводом инструмента, рассуждением, цитатой и другими обобщёнными выводами.

OpenAI описывает Responses как более простую модель: отправляйте input items и получайте output items, при необходимости используя объекты prompt и conversation для хранения конфигурации и контекста (OpenAI Assistants migration guide, получено 2026-06-21). Эта простота помогает routing, но она же переносит ответственность в ваше приложение: повторы, обрезку контекста, выполнение инструментов и стратегию раскатки нужно проектировать осознанно.

Сначала найдите все затронутые callsites

Начните с инвентаризации кода. Опасные паттерны обычно легко найти через grep:

grep -R "openai\.beta\.assistants\|openai\.beta\.threads\|threads\.runs\|assistant_id\|thread_id" \
  app/ services/ workers/ scripts/

Затем классифицируйте каждое использование:

  1. Чаты новых сессий. Мигрируйте их первыми, потому что они не требуют конвертации истории.
  2. Долгоживущие пользовательские Threads. Решите, переносить ли историю в Conversations или закрывать старые сессии с UX-передачей.
  3. Агенты с интенсивным использованием инструментов. Явно перепишите tool loop и добавьте интеграционные тесты.
  4. Потоки retrieval / file-search. Пересоберите допущения о vector store и обработку цитат вокруг file search в Responses.
  5. Фоновые задачи. Замените опрос Runs на обработку жизненного цикла response, включая идемпотентность и контроль повторов.

Не ждите идеальной конвертации за один заход. Более безопасный путь — окно двойной работы: новые сессии на Responses, старые Threads в режиме только чтения или с выборочным backfill, и мониторинг, который сравнивает качество ответов, долю вызовов инструментов, задержку и стоимость.

До/после: минимальный chat flow

Паттерн Assistants обычно создаёт или переиспользует Thread, добавляет сообщение, создаёт Run, опрашивает его, а затем получает сообщения. Responses сворачивает это в один response-вызов с опциональным состоянием Conversation.

До: Assistants + Thread + Run

from openai import OpenAI
import time

client = OpenAI(api_key="<OPENAI_API_KEY>")

thread = client.beta.threads.create()
client.beta.threads.messages.create(
    thread_id=thread.id,
    role="user",
    content="Summarize the deployment risks.",
)

run = client.beta.threads.runs.create(
    thread_id=thread.id,
    assistant_id="asst_...",
)

while run.status in ("queued", "in_progress"):
    time.sleep(1)
    run = client.beta.threads.runs.retrieve(thread_id=thread.id, run_id=run.id)

messages = client.beta.threads.messages.list(thread_id=thread.id)
print(messages.data[0].content[0].text.value)

После: Responses API

from openai import OpenAI

client = OpenAI(api_key="<OPENAI_API_KEY>")

response = client.responses.create(
    model="gpt-5.5",
    input=[{
        "role": "user",
        "content": [{"type": "input_text", "text": "Summarize the deployment risks."}],
    }],
)

print(response.output_text)

Когда нужен серверный контекст, создайте Conversation и передавайте её ID в response-вызовах. Когда нужен контекст, которым владеет приложение, храните собственную историю сообщений / items и отправляйте нужное окно каждый раз. Важное решение при миграции — не синтаксис, а то, кто владеет состоянием после исчезновения Assistants.

Миграция Threads в Conversations без лишней миграции

OpenAI заявляет, что не будет предоставлять автоматический инструмент для миграции Threads в Conversations, и рекомендует переводить новые пользовательские threads на Conversations, выполняя backfill старых по мере необходимости (OpenAI Assistants migration guide, получено 2026-06-21).

Практическая политика:

  • Не выполняйте backfill заброшенных threads. Держите архив и мигрируйте только когда пользователь заново открывает сессию.
  • Сначала переносите текст. Конвертируйте пользовательский текст в input_text, а текст ассистента — в output_text; изображения, файлы и выводы инструментов обрабатывайте вторым проходом.
  • Храните метаданные отдельно. Метаданные Thread и Conversation — не полный аудит-лог. Ведите собственную таблицу сопоставления: old_thread_id, new_conversation_id, user_id, migrated_at, migration_version.
  • Отмечайте конвертации с потерями. Если Run step, вывод инструмента или цитату из файла нельзя представить точно, зафиксируйте этот пробел и не меняйте поведение молча.
  • Тестируйте обрезку контекстного окна. Conversations могут хранить потоки items, но вам всё равно нужна политика по стоимости, задержке и старым артефактам инструментов.

Лёгкий каркас backfill:

from openai import OpenAI

client = OpenAI(api_key="<OPENAI_API_KEY>")

def backfill_thread(thread_id: str):
    items = []
    for page in client.beta.threads.messages.list(thread_id=thread_id, order="asc").iter_pages():
        for message in page.data:
            content = []
            for part in message.content:
                if part.type == "text":
                    content.append({
                        "type": "input_text" if message.role == "user" else "output_text",
                        "text": part.text.value,
                    })
            if content:
                items.append({"role": message.role, "content": content})

    return client.conversations.create(items=items)

Считайте это отправной точкой, а не готовым конвертером. Мультимодальные входы, цитаты из файлов, артефакты code-interpreter и выводы инструментов требуют дополнительного сопоставления и проверки.

Tool calls и file search требуют больше всего тестов

Assistants скрывал большую часть цикла выполнения за Runs. Responses возвращает output items, включая items вызова инструментов, а ваше приложение отправляет результаты инструментов обратно. Это делает поведение более явным, что лучше для наблюдаемости, но также означает, что логика повторов может случайно повторно выполнить вызов инструмента, если вы не добавите идемпотентность.

Для file search OpenAI документирует file_search как hosted-инструмент Responses API на базе vector stores. Когда модель его вызывает, ответ включает output item file_search_call и message item с цитатами (OpenAI File search guide, получено 2026-06-21).

Чеклист миграции для инструментов:

  1. Вынесите схемы инструментов из объектов Assistant в версионируемые определения prompt / конфигурации.
  2. Добавьте ключ идемпотентности к каждому вызову инструмента с внешними побочными эффектами.
  3. Логируйте каждый item вызова инструмента и item результата инструмента вместе с response ID.
  4. Решите, какие инструменты можно повторять автоматически, а какие требуют подтверждения человеком или приложением.
  5. Для file search проверьте ID vector store, фильтры по метаданным, рендеринг цитат и настройку максимального числа результатов.
  6. Для hosted-инструментов, таких как web search, computer use, MCP и file search, тестируйте именно тот provider path, который будете использовать в production.

Последствия для routing gateway

Миграция меняет то, где живут routing-решения. В Assistants выбор модели мог быть встроен в объект Assistant. В Responses модель — часть response-запроса. Это лучше согласуется с routing на уровне gateway, потому что каждый запрос может нести model ID, политику fallback и ограничения провайдера.

Для OpenAI-совместимого routing в стиле TheRouter разделяйте три слоя:

СлойБезопасное routing-утверждениеЧто всё ещё нужно тестировать
Текстовый response-запросTheRouter может маршрутизировать OpenAI-совместимые запросы через настроенных провайдеров там, где live endpoint поддерживает форму запроса.Точное соответствие полей запроса/ответа для вашей версии SDK.
Цепочка fallbackTheRouter поддерживает fallback-цепочки models на совместимых chat-completion путях (TheRouter Model Fallbacks, получено 2026-06-21).Уместен ли fallback для stateful tool loops и поддерживают ли все кандидаты одни и те же инструменты.
Hosted-инструменты OpenAIOpenAI документирует hosted-инструменты, такие как file search, для Responses.Может ли путь через не-OpenAI провайдера или gateway сохранить семантику hosted-инструментов. Не считайте это данностью.

Это разграничение предотвращает частую ошибку миграции: предположение, что раз генерация текста маршрутизируется корректно, то и любая hosted-функция Responses от OpenAI тоже маршрутизируется корректно. Hosted-инструменты и stateful conversations — это поведение продуктового слоя, а не просто инференс модели.

До/после: routing через TheRouter там, где путь поддержан

Если ваша Responses-нагрузка ориентирована на текст и совместима с проверенным вами маршрутом, шаблон base URL повторяет другие OpenAI-совместимые миграции.

from openai import OpenAI

client = OpenAI(
    base_url="https://api.therouter.ai/v1",
    api_key="<THEROUTER_API_KEY>",
)

response = client.responses.create(
    model="openai/gpt-5",
    input="Classify this support ticket and return JSON.",
)

Для fallback на совместимых chat-completion потоках TheRouter документирует массив models в порядке приоритета: TheRouter пробует первую модель и повторяет со следующей, когда маршрут падает из-за простоя, лимитов частоты или отказа модерации (TheRouter Model Fallbacks, получено 2026-06-21). Используйте fallback для агентов осторожно: все кандидаты fallback должны поддерживать один и тот же формат вывода и контракт инструментов.

import OpenAI from 'openai';

const client = new OpenAI({
  baseURL: 'https://api.therouter.ai/v1',
  apiKey: process.env.THEROUTER_API_KEY,
});

const completion = await client.chat.completions.create({
  model: 'openai/gpt-5',
  extra_body: {
    models: ['anthropic/claude-sonnet-4.5', 'google/gemini-3.5-flash'],
  },
  messages: [{ role: 'user', content: 'Draft the migration test plan.' }],
});

Fallback — это устойчивость, а не гарантия нулевых простоев. Если падают все кандидаты или fallback-модель не может выполнить тот же контракт инструментов / схемы, запрос должен завершиться явной ошибкой.

План rollout до 26 августа

Отталкивайтесь от дедлайна и планируйте в обратную сторону:

ОкноНаправление работКритерий выхода
СейчасИнвентаризируйте использование Assistants и ранжируйте по трафику, выручке и сложности инструментов.Все callsites openai.beta.* закреплены за владельцем.
Следующие 1–2 неделиПереведите новые сессии на Responses; сохраните читаемость старых Threads.Новые пользовательские сессии больше не создают Threads.
Следующие 2–4 неделиВыполняйте backfill только активных Threads; мигрируйте retrieval и tool loops.Ключевые сценарии проходят интеграционные тесты на Conversations/Responses.
За 30 дней до cutoverЗапустите двойной мониторинг и shadow-оценки.Качество, задержка, стоимость и доля ошибок вызова инструментов в пределах порогов.
Последние 2 неделиЗаморозьте изменения Assistants и подготовьте rollback.Кодовый путь Assistants отключён, кроме аварийного fallback.

План rollback не означает возврат к Assistants навсегда — этот API отключается. Он означает, что вы можете временно направить часть трафика на ранее проверенную реализацию Responses, отключить рискованные инструменты или откатиться к более простому chat-сценарию во время отладки.

Testing checklist для routing teams

Прежде чем объявить миграцию завершённой, протестируйте эти сценарии сквозным образом:

  • Непрерывность conversation: многоходовой контекст сохраняется между запросами и пользовательскими сессиями.
  • Идемпотентность инструментов: повторы не дублируют внешние побочные эффекты.
  • Streaming: разбор событий работает для текстовых дельт, вызовов инструментов, событий завершения и ошибок.
  • Цитаты из файлов: цитаты рендерятся корректно и ведут к нужным загруженным файлам.
  • Семантика fallback: кандидаты fallback имеют одинаковую схему инструментов, схему вывода и ограничения безопасности.
  • Учёт использования: расход токенов и метаданные биллинга фиксируются как для обычных, так и для fallback-ответов.
  • Ошибки провайдера: лимиты частоты, простои провайдера, отказы модерации и ошибки неподдерживаемых инструментов классифицируются отдельно.
  • Наблюдаемость: логи включают response ID, conversation ID, обслужившую модель, позицию fallback и ID вызовов инструментов.

Внутренние ссылки для более широкой миграции

Если это часть более крупного проекта по routing между провайдерами, дополните это руководство:

FAQ

Responses API — это просто Chat Completions под новым именем?

Нет. Responses использует input и output items, поддерживает Conversations и предоставляет hosted-инструменты вроде file search. Chat Completions остаётся более простым интерфейсом «сообщение на входе / сообщение на выходе».

Можно ли продолжать использовать старые Thread ID после 26 августа?

Нет. Планируйте так, будто endpoint Thread и Run из Assistants API перестанут работать в день отключения. Если вы выполняете backfill активных сессий, храните собственное сопоставление старых Thread ID с новыми Conversation ID.

Должна ли каждая нагрузка Assistants использовать Conversations?

Не обязательно. Для stateless или короткоживущих сценариев проще передавать историю, которой владеет приложение, в каждый вызов Responses. Используйте Conversations, когда управляемая провайдером история items снижает сложность сильнее, чем добавляет привязку.

Может ли fallback-routing переключать провайдеров посреди conversation?

Иногда да, но не считайте это безопасным для агентов с интенсивным использованием инструментов. Кандидаты fallback должны иметь одинаковый контракт инструментов, схему вывода и допущения о контексте. Протестируйте многоходовое поведение и вызовы инструментов перед включением fallback для production-сессий агентов.

Источники

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