01Перестали заставлять чаты ждать друг друга
Раньше Agent обрабатывал запрос целиком внутри одного обработчика. Долгий запрос задерживал следующие. Для простого разговора модель сначала выбирала сценарий, а потом отдельно писала ответ.
Теперь у Agent три обработчика и ограниченная очередь: девять ожидающих запросов, максимум два от одной сессии. Порядок внутри чата сохраняется. Независимые чаты могут выполнять подготовку и инструменты параллельно. У LLM пока одна активная генерация и три места ожидания: возможности GPU мы не увеличивали.
Обычный разговор обходится одной генерацией. Текст приходит частями. События связаны с конкретным чатом и запросом, поэтому чужой ответ или команда карты не должны попадать в открытый чат.
Вместо разных таймаутов по цепочке действует общий бюджет 120 секунд активной работы. Отмена доходит до следующих этапов; новые инструменты после неё не запускаются. "Остановить микрофон" и "Отменить ответ" стали отдельными действиями.
02Агент собирает решение из инструментов
Раньше модель выбирала один из трёх Ruby-сценариев. Новая задача часто требовала нового графа. Теперь Pydantic AI ведёт диалог с моделью и принимает типизированные вызовы разрешённых инструментов.
В Code Mode модель пишет небольшой код, который читает данные через восемь разрешённых функций и считает результат в Monty. Ещё три инструмента отдельно показывают точки, маршрут и предлагают сохранение плана. Названия и аргументы проверяются до выполнения.
Monty ограничен 64 МиБ памяти и 10 секундами вычислений. Доступа к файлам, сети и секретам нет. Общий бюджет запроса - десять инструментальных действий, включая вложенные вызовы. Ошибку нового агента больше не маскируем переходом в старый сценарий.
Модель заменили на Qwen3.8-27B-FP8 через существующий vLLM на H100. Путь сохранили: Agent → NATS → наш LLM gateway → существующий requester → vLLM. Вход считаем tokenizer этой модели: до 6144 токенов, ответ до 2048. Старый Ruby оставлен для совместимости с незавершёнными сценариями.
Код: native tools, подтверждение и Monty, бюджет и запрос к модели.
03Модель предлагает, пользователь разрешает запись
В начале запроса Core фиксирует положение самолёта, состояния аэропортов и погоду. Все инструменты работают с этим снимком. Данные не меняются под запросом, пока он ждёт очередь.
Черновик хранится в PostgreSQL без автоматического таймаута, переживает reload и перезапуск. При подтверждении проверяем положение, использованные данные и версию плана. Повторный клик не создаёт вторую запись. Для изменения уже сохранённого плана снова требуется подтверждение.
Заодно исправили составные запросы: расчёт и ответ должны появиться до ожидания решения. При отказе или подтверждении вычисленный текст сохраняется. Сам факт сохранения сообщаем по результату БД, без дополнительной генерации, которая могла бы его переиначить.
04У аудио появился общий, управляемый путь
WebRTC вынесли из Core в отдельный ingress. Добавили второй вход по WSS. Core отвечает за запросы, историю, общий лимит подключений и приём финальной транскрипции.
/audio/ws выбирается отдельно.Остатки аудио теперь накапливаются в FIFO, а не дополняются тишиной после каждого входного пакета. На выходе - кадры по 20 мс: 640 байт PCM. Padding остаётся только в окончательном хвосте.
Аудио публикуется сразу. Подтверждающий NATS flush выполняется раз в 250 мс на соединение вместо каждого кадра: примерно четыре раза в секунду вместо пятидесяти на поток. Завершение и ошибка вызывают отдельный обязательный flush.
Очередь ограничена двумя секундами аудио. Ошибка публикации завершает поток явно. Максимум - три аудиоподключения; четвёртое получает "сервер занят" до передачи звука. Ожидание краткого обрыва согласовали: восемь секунд на обеих сторонах.
05Агент работает с видимыми данными
Добавили 64 реальных аэропорта РФ и перемещаемый самолёт, положение которого принадлежит конкретному чату и сохраняется после reload. Каталог аэропортов остаётся на карте, а результаты агента выделяются отдельно. Подписи показывают код и состояние; при приближении добавляют подробности.
Клик открывает карточку аэропорта. Менять можно открытость и доступность полос. Координаты и длины полос справочные. Демопогоду заменили OpenWeather: на карте есть погодные слои, а для расчётов используются отдельные численные данные. Ключ остаётся на сервере; погода кешируется и проверяется на давность. Если её нет, агент должен объяснить это, а не выдумывать значения.
Ошибки стали конкретнее: этап, причина, возможное действие и идентификатор запроса. Добавили ссылки на настоящую трассу в Tempo и Phoenix. Диагностика сохраняется вместе с сообщением. Phoenix развёрнули отдельно; корпоративный экспорт телеметрии сохранили. В трассы не отправляем разговоры, аудио, координаты и секреты.
Код: погода и кеш, настоящие Trace ID и Span ID, отдельный стэк Phoenix.
06Что получилось и что осталось
В контрольной серии 6 октября проверили эффект очередей и удаления лишнего router. Отдельно заменили тяжёлые Python health-пробы на лёгкие HTTP-проверки через curl.
| Показатель | Было | Стало |
|---|---|---|
| Медиана полного обычного ответа | 14,97 с | 3,11 с |
| Медиана от ASR final до ответа, нагрузка 1/2/3 | 46,01 с | 14,10 с |
| CPU всего стэка в простое после исправления healthcheck | 0,197 ядра | 0,049 ядра |
Источники: C3: одинаковая модель qwen3:30b, по 12 текстовых ответов; C4: два трёхминутных окна простоя. Это короткие замеры, не обещание такой скорости на любой нагрузке.
За эти дни собственный стэк получил имя chat-agent. Имя Git-репозитория осталось прежним. Сокращение ожидания ответа подтверждено; новый агент умеет сочетать инструменты и ждать подтверждения без занятого worker. Общий размер кода и образов после добавления новых библиотек здесь не пересчитываем.
Как это связано с исходным списком
| Пункты | Что сделали | Граница результата |
|---|---|---|
| 10-12 | Общий deadline, отмена, ограниченные очереди | Внешний GPU не обещаем мгновенно остановить |
| 16-21 | Новый агент, инструменты, native схемы, одна генерация обычного ответа, streaming | Инструментальные задачи могут требовать несколько генераций |
| 22-24, 27-29 | Общий FIFO, владелец задач, лимит трёх потоков, явные отказы, редкий flush | Согласован grace period; автоматического reconnect пока нет |
| 25, 26, 30 | Оставлены владельцу voice | GPU и decoder не перерабатывали |
| 40, 44 | Медиа отделено от Core, ICE-адаптер изолирован | Несколько media replicas и замена private patch не реализованы |
| 1 | user123 оставлен по решению пользователя | Разделение чатов опирается на session ID |