chat-agent · состояние после C4 · 06.10.2026

chat-agent: от запроса к ответу

БраузерНаш chat-agentvoice / модельОтвет + историяВход → обработка → внешний inference → пользовательский результат

Чат принимает текст или голос, показывает ответ по частям и сохраняет историю. Исполнение ограничено очередями и общим сроком. Распознавание, модель, TURN и OAuth остаются у прежних внешних владельцев.

Код: src_core/main.py · stack/webrtc.drs

chat-agent · состояние после C4 · 06.10.2026

Два стэка связаны общим NATS

chat-agentдиалог + ingressОбщий NATSvoiceASR + файлыPCM в voice; partial/final обратно в единственный Core

Диалогом и аудиоподключениями владеет chat-agent. Voice принимает прежний PCM-контракт и возвращает partial/final. Разделение позволяет менять чат без поставки voice; общий NATS и его доступность остаются общей зависимостью.

Код: stack/webrtc.drs · src_shared/audio.py · src_core/audio_admission.py

Схемы и контракты · сверка 06.10.2026

Модель вызываем через Ruby, части ответа идут в Agent

Coretext / ASR finalAgentочередь / попыткаRuby + AsyncGraphdialog_step / графLLM adaptermode + contextOllama proxyHTTPS APIRPCRPCRPCHTTPchat.agent.streamJSON delta: LLM → AgentPostgreSQLистория + workflow stateAPI gatewayпять fixture toolsTCP 5432JSON RPCЗапрос к LLM: mode/input/constraints · ответ: response_text + tool_calls либо error

Core передаёт текст или ASR final в Agent. Ruby вызывает LLM и получает проверенный ответ; части текста параллельно идут прямо в Agent через NATS. Обычный разговор требует одной генерации, tools могут потребовать следующих. История хранится в PostgreSQL, текущая попытка - в памяти Agent.

Код: Agent + stream · Ruby RPC · LLM reply / delta · состояние попытки

chat-agent · состояние после C4 · 06.10.2026

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

discoverсхемы пяти toolsМодельnative callsПроверкаимя + аргументыTool → LLMответНет исполнения до полной проверки batch

Ruby получает каталог через nats.tools.discover, проверяет имена и JSON-аргументы до исполнения всего набора вызовов. Затем последовательно вызывает nats.tools.{name}. Пять tools пока возвращают демонстрационные fixtures. Активные и pending-графы сохранены; общий срок 120 s, бюджет до 10 действий.

Код: src_langgraph_rb_node/lib/src_langgraph_rb_node/runtime/dialog.rb · src_api_gateway/main.py · src_shared/contracts/tools.py

Схемы и контракты · сверка 06.10.2026

Два аудиотранспорта сходятся в один PCM-контракт

БраузерWebRTC: основнойWSS: по выборуwebrtc_ingressRTP → decoderresampler + FIFOaudio_ws_ingressPCM16LE, частота браузераresampler + FIFOОбщий NATSheader JSON + PCMmono 16 kHzCorelease + лимит 3 потоковSDP / ICE · JSONDTLS-SRTP · RTPWSS · binary PCM20 ms / 640 PCM bytesТот же wire envelopeCore ↔ ingress: chat.agent.audio.control · JSON admission / heartbeat / end

WebRTC передаёт защищённый RTP; codec согласуется в SDP. WSS передаёт mono PCM16LE с частотой браузера. Каждый ingress отдельно переводит звук в 16 kHz и пакует его для NATS. Общий PCM-модуль - код внутри ingress; Core выдаёт допуск, но не принимает медиапакеты.

Код: WebRTC · WSS · PCM envelope · admission

Схемы и контракты · сверка 06.10.2026

Четыре адреса - четыре разных потока данных

Адрес на chat-agent.gis-master.ruКто принимаетЧто передаётся
HTTPS POST /core/offerWebRTC ingressJSON с SDP offer → SDP answer
WSS /core/ice/{connection_id}WebRTC ingressJSON auth / candidate / end
WSS /audio/wsWSS ingressstart JSON → binary PCM16LE → end JSON
WSS /wsОбщий NATSПротокол NATS; payload событий - JSON

База HTTPS: https://chat-agent.gis-master.ru; для сокетов - wss://chat-agent.gis-master.ru. Все четыре маршрута проходят OAuth. ICE дополнительно проверяет token подключения. /ws возвращает статусы и ответ, /audio/ws передаёт звук. Текст, история и отмена идут в остальные /core/*, которые обслуживает Core.

Код: routes / OAuth · ICE JSON · PCM start/end · NATS over WSS

Схемы и контракты · сверка 06.10.2026

Voice возвращает текст, Core запускает диалог

voice streaming bridgestt_whisper_to_natsVAD + границы фразВнешний GPU ASRfaster-whisper workerPCM → текстto.inference.webrtc.asr.audio.{stream_id}from.inference.webrtc.asr.events.{stream_id}Через общий NATS, account remap и leafnode; на GPU prefix inference.webrtc.asr.*Coreпроверка stream/phraseAgentновый ход диалогаwebrtc.komaroff.asr.text.{session_id} · JSONнепустой finalРезультат: partial / final / rejected / error + session_id, stream_id, phrase_id, revision, text

Ingress публикует звук в webrtc.komaroff.asr.stream.{session_id}. Voice выделяет фразы и отправляет PCM к GPU по NATS; ответ возвращает в Core как JSON. Partial показываем в UI, непустой final запускает Agent один раз. Файловый API voice и диаризация в live-путь не входят.

Код: voice bridge · GPU contract · final → Agent · NATS remap

Схемы и контракты · сверка 06.10.2026

Части ответа и окончательный результат идут отдельно

LLMJSON deltaAgentпроверка + snapshotОбщий NATSJSON UI eventsБраузерфильтр сессииstreamUI event/wschat.agent.stream → Agent → nats.events.user123 → NATS protocol over WSS /wsCoreитог HTTP POSTRPC replyHTTP JSON

Agent публикует response_fragment, request_state, итог message и команды client. Core публикует asr_result и audio_status в тот же nats.events.user123. Frontend проверяет session/request/attempt/generation/sequence до показа текста и команд карты. После reconnect берёт snapshot или историю; replay UI-событий здесь нет.

Код: fragments / snapshot · итог / команды · ASR / audio status · фильтр UI

Было → исправлено

Основные ошибки были в управлении работой

ПроблемаИзменение
Router генерировал отдельно от ответаdialog_step: текст либо tools за одну генерацию
Agent последовательно ждал независимые чатыТри исполнителя, очередь по сессиям, общий срок
UI принимал ответы и статусы соседейПроверка session/request/generation до отображения
Каждый PCM-пакет вызывал flushFIFO, publish сразу, flush раз в 250 мс

Исправления убрали лишнее ожидание и сделали границы работы явными. Один долгий запрос больше не занимает единственный Agent callback. Общий NATS account сохранён: фильтр UI решает смешивание сообщений, но отдельные права каждого пользователя ещё нужны.

Код: dialog.rb · execution.py · requestState.ts · audio.py

Замеры C3 · 06.10.2026

Диалог ускорился, распознавание сохранило свою задержку

C0 → C3, секундыp50p95
Обычный текст, n=1214,97 → 3,1120,95 → 3,98
ASR final → ответ46,01 → 14,1089,40 → 23,23
RTC connected, n=121,39 → 1,631,56 → 1,88
Начало WAV → ASR final3,80 → 3,823,99 → 4,02

В той же контрольной серии C3 завершил 33/33 хода с 36 генерациями. Обычный ответ ускорился благодаря одной генерации и новым очередям. Trickle был поставлен раньше; подключение здесь немного медленнее C0, но ниже цели 3 с. ASR p95 после конца WAV вырос на 2,8%. Короткая синтетическая речь иногда искажается; WER/DER не измерены.

Evidence: приёмка C3 · browser measurements · cases.json

Исправление C4 · Core и два аудио-ingress

Healthcheck больше не запускает Python

Было · каждые 10 сDockerЗапуск Python → HTTP/healthz + готовность NATSСтало · каждые 10 сDockercurl → полный HTTP 200Тот же /healthz и NATS503, redirect, отказ соединения и зависший ответ → ошибка проверки

Каждые 10 секунд Docker проверяет Core и оба ingress. Для одного локального HTTP-запроса раньше запускался Python; теперь работает curl. Полный HTTP 200 и готовность NATS остались обязательными. В 90 пробах реальных образов CPU одной проверки был ниже 29 мс; это снизило фоновую нагрузку всего стэка.

Код: Core Dockerfile · ingress Dockerfile · проверки отказов · результаты C4

Итог после C4 · весь стэк · 06.10.2026

После healthcheck CPU в простое снизился на 75%

Показатель и база сравненияДо → после
CPU в простое, перед → после C40,197 → 0,049 ядра, -75,0%
Память в простое, перед → после C4547,57 → 553,41 МБ, +1,1%
Сумма rootfs образов, C0 → C43 685,21 → 3 256,25 МБ, -11,6%
Активный production-код, C0 → C414 762 → 15 890 строк, +7,6%

CPU и память сравнили в одинаковых окнах простоя по 180 с: 13 сервисов, без активных запросов. RAM не сократилась. Сама пересборка healthcheck добавила 4,27 МБ rootfs относительно C3. Rootfs повторно учитывает общие слои, без томов и внешних моделей; свежий compressed-размер C4 не подтверждён. Полная серия диалога относится к C3, после C4 прошли короткие проверки текста, RTC и WSS.

Замеры: метод и результат C4 · CPU / RAM / runtime · подсчёт production-кода

1 / 10

Служебные вложения доступны в исходном архиве.