> ## Content Index
> Fetch the complete content index at: https://matveev.tech/llms.txt
> Use this file to discover other available public pages before exploring further.

# WebSocket Mode в OpenAI API: агенты быстрее на 40%
- URL: https://matveev.tech/openai-websocket-mode-api/
- Published: 2026-02-25T10:47:42.000Z
- Updated: 2026-02-25T12:16:33.000Z
- Description: OpenAI добавили WebSocket-режим в Responses API. Вместо HTTP-запроса на каждый tool-вызов агента — одно постоянное соединение с инкрементальными инпутами. До 40% ускорения на длинных цепочках.
- Author: Pavel Matveev
- Tags: OpenAI, Разработка, Dev Tools, Агенты, Гайд

> **TL;DR:** OpenAI добавили WebSocket-режим в Responses API. Вместо отдельного HTTP-запроса на каждый ход агента — одно постоянное соединение, куда отправляешь только новые данные. На воркфлоу с 20+ tool-вызовами это даёт до 40% ускорения.

Если ты строишь агентов на OpenAI API, то наверняка знаешь боль: каждый tool-вызов — это отдельный HTTP-запрос, новый TLS-хендшейк, повторная отправка контекста. Когда агент делает 3-5 вызовов — терпимо. Но когда их 20-30 (а в сложных сценариях типа автономного кодинга или оркестрации бывает и больше) — накладные расходы складываются в заметную задержку.

WebSocket Mode решает это. Открываешь одно соединение — и гоняешь через него весь диалог с моделью.

## Как это работает

Идея простая: вместо REST-вызовов ты подключаешься по WebSocket к `wss://api.openai.com/v1/responses` и отправляешь события `response.create`. Формат тела — тот же, что и в обычном Responses API, только без полей `stream` и `background` (они тут не нужны).

```python
from websocket import create_connection
import json
import os

ws = create_connection(
    "wss://api.openai.com/v1/responses",
    header=[
        f"Authorization: Bearer {os.environ['OPENAI_API_KEY']}",
    ],
)

ws.send(
    json.dumps(
        {
            "type": "response.create",
            "model": "gpt-5.2",
            "store": False,
            "input": [
                {
                    "type": "message",
                    "role": "user",
                    "content": [{"type": "input_text", "text": "Найди функцию fizz_buzz()"}],
                }
            ],
            "tools": [],
        }
    )
)

```

Получил ответ — отправляешь следующий ход. И так весь цикл.

## Инкрементальные инпуты — главная фишка

Самое ценное здесь не сам WebSocket, а то, что каждый следующий ход отправляет только новые данные. Вместо пересылки всего контекста целиком (как в HTTP-режиме) ты передаёшь `previous_response_id` плюс только новые элементы:

```python
ws.send(
    json.dumps(
        {
            "type": "response.create",
            "model": "gpt-5.2",
            "store": False,
            "previous_response_id": "resp_123",
            "input": [
                {
                    "type": "function_call_output",
                    "call_id": "call_123",
                    "output": "результат вызова инструмента",
                },
                {
                    "type": "message",
                    "role": "user",
                    "content": [{"type": "input_text", "text": "Теперь оптимизируй это."}],
                },
            ],
            "tools": [],
        }
    )
)

```

Сервис держит предыдущий ответ в in-memory кэше прямо на соединении. Продолжение из этого кэша — быстро, потому что не нужно ничего читать с диска.

Важный момент: кэш хранит только последний ответ. Если что-то пошло не так (4xx/5xx), кэш сбрасывается, и продолжить с того же `previous_response_id` уже не получится.

## Warmup — прогрев запроса

Есть полезная опция: отправить `response.create` с `generate: false`. Модель не генерирует ответ, но готовит внутреннее состояние: загружает инструкции, tools, кастомные сообщения. Следующий настоящий запрос стартует быстрее.

По сути, это prefetch для LLM. Знаешь, какие инструменты будешь использовать, прогрей заранее, пока пользователь ещё печатает.

## Компактификация контекста

При длинных сессиях контекст разрастается. Два способа его сжать:

Первый вариант: серверная компактификация через `context_management` с `compact_threshold`. Всё происходит автоматически при генерации. Ты продолжаешь отправлять `response.create` как обычно, ничего менять не надо.

Второй: standalone-эндпоинт `/responses/compact`. Вызываешь отдельно через HTTP, получаешь сжатое окно контекста. После этого начинаешь новую цепочку на WebSocket с этим окном как `input`:

```python
# Компактифицируем через HTTP
compacted = client.responses.compact(
    model="gpt-5.2",
    input=long_input_items_array,
)

# Стартуем новую цепочку с компактным контекстом
ws.send(
    json.dumps(
        {
            "type": "response.create",
            "model": "gpt-5.2",
            "store": False,
            "input": [
                *compacted.output,
                {
                    "type": "message",
                    "role": "user",
                    "content": [{"type": "input_text", "text": "Продолжай отсюда."}],
                },
            ],
            "tools": [],
        }
    )
)

```

## Ограничения, которые стоит знать

Соединение живёт максимум 60 минут. После этого нужно переподключиться.

На одном соединении запросы выполняются строго последовательно, один за другим. Если нужен параллелизм, открывай несколько соединений.

Сервис хранит в памяти только последний ответ текущего соединения. Это, кстати, и причина совместимости с Zero Data Retention и `store=false`: кэш живёт только в оперативке и не пишется на диск.

## Что делать при разрыве соединения

Соединение может закрыться по таймауту, из-за сети или ещё по какой-то причине. Дальше зависит от настроек.

Если `store=true` и у тебя есть response ID, просто открываешь новый WebSocket и продолжаешь с `previous_response_id`. Будет чуть медленнее (гидрация из хранилища вместо кэша), но работает.

Если `store=false` или ZDR, а ID уже вылетел из кэша, придёт ошибка `previous_response_not_found`. Тогда начинаешь новую цепочку с полным контекстом.

Ну и третий вариант: если ты до этого вызывал `/responses/compact`, используешь сохранённое окно как базовый `input` для нового запроса.

## Когда это реально полезно

Не для каждого проекта. Если у тебя простой чат-бот с одним-двумя tool-вызовами, HTTP-стриминг работает ничем не хуже. WebSocket Mode для ситуаций, где агент делает десятки tool-вызовов за сессию: автономный кодинг, data pipeline, сложная оркестрация. По данным OpenAI, на цепочках из 20+ вызовов разница доходит до 40%.

## Вывод

По сути, WebSocket Mode не меняет логику приложения. Формат запросов тот же, tools те же. Меняется только транспорт, а на агентных воркфлоу это может дать заметную разницу.

Мне нравится, что OpenAI не стали городить отдельный API, а встроили это в существующий Responses. Переход минимальный: оборачиваешь payload в `response.create`, подключаешься через WebSocket вместо HTTP, и добавляешь логику реконнекта.

## Что ещё почитать

- [Мультиагенты в OpenAI Codex — настройка и примеры](https://matveev.tech/codex-multi-agent-setup/) — если хочешь масштабировать агентные воркфлоу
- [Как экономить токены в Cursor и Claude Code](https://matveev.tech/kak-ekonomit-tokeny-cursor-claude-code/) — ещё способы оптимизации при работе с LLM
- [Codex от OpenAI теперь работает прямо в JetBrains IDE](https://matveev.tech/codex-openai-jetbrains-ide/) — другие обновления экосистемы OpenAI

## FAQ

**Можно ли использовать WebSocket Mode с store=false?** Да. Кэш предыдущего ответа хранится только в памяти на соединении и не записывается на диск. Режим полностью совместим с Zero Data Retention.

**Сколько запросов можно отправить на одном соединении?** Сколько угодно, но последовательно — один за другим. Лимит по времени — 60 минут на одно соединение.

**На сколько это быстрее обычного HTTP?** По данным OpenAI, на воркфлоу с 20+ tool-вызовами ускорение достигает примерно 40%. На коротких цепочках разница будет минимальной.

**Нужно ли менять формат запросов?** Нет, payload тот же, что и в Responses API. Убираешь `stream` и `background`, оборачиваешь в `response.create` — и всё работает.