OpenAI добавили WebSocket режим — кому не пох?
Какое вам дело до новости “OpenAI добавили WebSocket режим”? Ожидаете тут увидеть что сократили 100 ms на handshake или какой-то такой нишевой теме и создали инфоповод?) Ох колллеги всё не так просто как же не просто.
С одной стороны, конечно, пофиг что крутится внутри агента)) Если работает то лучше не мешать. Но давайте посмотрим внимательнее на процесс со стороны сети…
Вы открыли Claude Code. Написали: “давай переведём сервис погоды с Google на Яндекс”. Агент пошёл работать — читает файлы, сканирует структуру, смотрит импорты. Прошло 40 сек, он вернулся с планом рефакторинга. А сколько раз он сходил в API? И что именно отправил?
Допустим агент сделал 12 tool call’ов — пока изучал репу. Предлагаю рассмотреть что происходит на каждом шаге. Коллеги я оч старался делая табличку так что настоятельно рекомендую ознакомиться подробнее.
| Клиент отправил | Сервер вернул | Получено, ток | Отправлено, ток | Суммарно отправлено, ток |
|---|---|---|---|---|
| system prompt + описания 18 инструментов + CLAUDE.md + memory + “переведи сервис погоды с Google на Яндекс” | Посмотрю структуру. Glob("src/**/*") |
45 | 20к | 20к |
(весь контекст) + результат Glob("src/**/*") |
Вижу weather-сервис. Read("src/services/weather.ts") |
30 | 22к | 42к |
(весь контекст) + результат Read("src/services/weather.ts") |
Тут Google Maps API. Grep("fetchWeather") |
35 | 26к | 68к |
(весь контекст) + результат Grep("fetchWeather") |
В трёх файлах. Read("src/config.ts") |
20 | 28к | 96к |
(весь контекст) + результат Read("src/config.ts") |
Нашёл GOOGLE_MAPS_KEY. Read("src/routes/dashboard.ts") |
15 | 30к | 126к |
(весь контекст) + результат Read("src/routes/dashboard.ts") |
fetchWeather на строке 84. Read("src/cron/sync.ts") |
18 | 33к | 159к |
(весь контекст) + результат Read("src/cron/sync.ts") |
Проверю тесты. Read("tests/weather.test.ts") |
22 | 35к | 194к |
(весь контекст) + результат Read("tests/weather.test.ts") |
Посмотрю .env. Read(".env") |
8 | 36к | 230к |
(весь контекст) + результат Read(".env") |
WebSearch("Yandex Weather API") |
60 | 37к | 267к |
(весь контекст) + результат WebSearch(...) |
WebFetch("https://yandex.ru/dev/weather/...") |
200 | 39к | 306к |
(весь контекст) + результат WebFetch(...) |
Вот план: 1) заменить GoogleWeatherClient на YandexWeatherClient… | 400 | 43к | 349к |
Каждый tool call — конец генерации. Модель не “ждёт” результат. Она выключилась. После каждого использования локальной тулзы агент отправляет всю историю заново. System prompt, user message, все предыдущие ответы, все результаты предыдущих tool call’ов — всё целиком. И зачастую в ответ получает десяток токенов. 349 тысяч токенов отправлено, 663 получено.
Если вы читали пост про налог на контекст — вы понимаете что контекст и так жирный ещё до первого промпта)) А тут он ещё и пересылается при каждой итерации. А че так плохо? Tool calling прикрутили сбоку к API который проектировался для чатов — “написал → ответила → написал”. Один request — один response. Агент это другой паттерн: один промпт порождает десятки взаимодействий с моделью. Инфраструктура для этого просто не была рассчитана.
Окей, а теперь вернёмся к той самой новости.
OpenAI добавили WebSocket режим в Responses API. Не замена REST/SSE — дополнительный режим, заточенный под агентные сессии с кучей tool call’ов.
Как это работает с WebSocket: клиент открывает одно соединение и держит его. После каждого tool call’а отправляет только previous_response_id + результат последнего tool call’а. Не весь контекст — только новое. Сервер помнит всё что было раньше, потому что соединение то же самое. По данным OpenAI: до ~40% ускорения для сессий с 20+ tool call’ами.
Мысль, которая — я знаю — вас посетила: КЭШ
Мы шлём одни и те же токены по кругу — так давайте их кэшировать. И кэш действительно есть! Провайдеры API (OpenAI, Anthropic) умеют кэшировать контекст. Работает так: вы отправляете 30к токенов, сервер их обрабатывает и запоминает результат вычислений. В следующий раз когда вы отправляете 32к — сервер видит что первые 30к он уже обрабатывал, и прогоняет через модель только новые 2к.
Кэш попадает в 80-90% случаев при типичных агентных сессиях. Обработка закэшированных токенов стоит в 10 раз дешевле обычных. То есть из наших 349к токенов большая часть обрабатывается по сниженной цене. Кэш экономит деньги и ускоряет получение первого токена.
Но вот в чём штука: вы всё равно отправляете все 32 тысячи токенов по сети. Каждый раз. Кэш экономит вычисления на стороне сервера, но не убирает пересылку данных. Почему нельзя послать только новые 2к? Потому что сервер должен получить весь текст, посчитать хэш и сверить — есть ли в кэше результат обработки именно этой последовательности. Без полного текста хэш не посчитать.
WebSocket решает именно это. Строго говоря, previous_response_id работает и в REST — Responses API уже stateful, сервер хранит состояние на диске. Но при каждом HTTP-запросе это состояние нужно поднять заново. WebSocket держит его в оперативке пока соединение живо. Отправляете только previous_response_id + новые данные — не надо пересылать контекст, не надо хэшировать. Кэш решал проблему “дорого обрабатывать”. WebSocket решает проблему “зачем вообще пересылать”.
И вот что тут важнее самого WebSocket’а: архитектура агентных API ещё не устоялась. Мы наблюдаем фундаментальные улучшения сейчас не от новых моделей, а от инженерных решений вокруг них. Сколько ещё таких решений лежит на поверхности? Думайте.
Контекстрот. Подписаться.