# chat-agent: результат переработки · 06.10.2026

Чат перешёл на одну генерацию для обычного разговора, ограниченные очереди и
потоковый ответ. WebRTC и PCM через WSS вынесены в отдельные ingress. Работающий
стэк называется `chat-agent`; Git-репозиторий по-прежнему `webrtc-komaroff`.
Voice, H100, Ollama, TURN, OAuth и платформу наблюдаемости эта поставка не меняла.

Главный выигрыш получен в исполнении диалога: убраны лишняя генерация router и
последовательное ожидание независимых сессий в Agent. Сама модель по-прежнему
выполняет одну генерацию за раз. Точность распознавания этой работой не улучшалась.

## Что подтверждено отдельно

| Уровень | Доказательство |
|---|---|
| Исходники и проверки C3 | `e9122e017baaeab26bea2fd2603214fe473077ee`, [pipeline 4930](<https://git.giscloud.ru/voice-chat/webrtc-komaroff/-/pipelines/4930>) |
| Опубликованные приложения C3 | Все восемь собственных OCI revisions совпали с `e9122e0`; [build 9886](<https://git.giscloud.ru/voice-chat/webrtc-komaroff/-/jobs/9886>) и [consumers 9887](<https://git.giscloud.ru/voice-chat/webrtc-komaroff/-/jobs/9887>) — success |
| Конфигурация и переключение | [Preflight 9888](<https://git.giscloud.ru/voice-chat/webrtc-komaroff/-/jobs/9888>) и [deploy 9889](<https://git.giscloud.ru/voice-chat/webrtc-komaroff/-/jobs/9889>) — success; точные 15 прежних сервисов заменены 13 новыми |
| Фактический runtime C3 | Insight подтвердил running/health/image identity, сети и mounts всех 13 сервисов; [inventory](</experiments/voice-ai/archive/w/DOCS/evidence/chat-agent-c3-runtime.json>) |
| Реальные сценарии | 33/33 контрольных хода, 12 WebRTC и 5 WSS; voice-файлы, stages, семь benchmark-конфигураций, summary и диагностика |
| Найденное исправление Core | `a479e520f4e8416d52afe8658757ed0fb400b526`, [pipeline 4932](<https://git.giscloud.ru/voice-chat/webrtc-komaroff/-/pipelines/4932>): четыре checks и [выборочная сборка Core/RTC/WSS 9897](<https://git.giscloud.ru/voice-chat/webrtc-komaroff/-/jobs/9897>) — success; Core и оба ingress обновлены listener, healthy, revision `a479e52`; [postcheck](</experiments/voice-ai/archive/w/DOCS/evidence/chat-agent-c3-postcheck.json>) |

Повторный HTTP-запрос без явного `turn_id` раньше получал новый turn UUID и
ложный `request_id_conflict`. Core теперь использует `request_id` как стабильный
turn, если клиент его не передал. Явный turn и редактирование сохраняют свой
контракт. Два одновременных POST и повтор после завершения дали 200/DONE: одна
генерация в Tempo, две строки истории, повтор завершился за 127 мс.
[Evidence идемпотентности](</experiments/voice-ai/archive/w/DOCS/evidence/chat-agent-c3-idempotency.json>).
Исправление и две HTTP-регрессии:
[diff a479e52](<https://git.giscloud.ru/voice-chat/webrtc-komaroff/-/commit/a479e520f4e8416d52afe8658757ed0fb400b526>).

## Один запрос проходит ограниченный путь

```mermaid
flowchart LR
  U[Текст или ASR final] --> C[Core: request_id и срок]
  C --> A[Agent: порядок в сессии, 3 исполнителя]
  A --> R[Ruby: dialog_step либо прежний граф]
  R --> L[LLM: одна генерация]
  L -->|текст по частям| A
  L -->|native tool calls| T[Проверка схемы → tools]
  T --> R
  A --> P[(История и итог PostgreSQL)]
  A -->|session / request / generation / sequence| F[Свой интерфейс]
```

Agent сохраняет порядок внутри одного чата и выбирает независимые сессии
справедливо. Для нового обычного разговора Ruby сразу вызывает модель; при
необходимости она запрашивает инструменты. Сервер проверяет имя и все аргументы
до исполнения. Активные и pending-сценарии продолжают использовать свои графы.
Проверенное новое сочетание `search_airports_nearby` + `get_weather` использовало
два инструмента и две генерации в одном связанном trace. Погода и другие
демонстрационные авиационные данные остаются fixtures, а не живым внешним API.
[Evidence инструментов](</experiments/voice-ai/archive/w/DOCS/evidence/chat-agent-c3-tools.json>).

Общий deadline — 120 с. Agent: 3 работающих / 9 ожидающих / до 2 ожидающих на
сессию; Ruby: 3 / 3; LLM: 1 / 3. Бюджет tools — 10 действий. Отмена и успешное
завершение согласуются одним владельцем; микрофон останавливается отдельным
действием. [Контракт выполнения](</experiments/voice-ai/archive/w/DOCS/CHAT_AGENT_EXECUTION.md>).

## До и после на одинаковой контрольной серии

Использованы [cases.json](</experiments/voice-ai/archive/w/tests/benchmark/cases.json>), одна модель
`qwen3:30b`, ASR streaming и WAV 3,025 с. SHA256 WAV:
`bbdc8147226297b2a56f177b2b70a750dcfc44bbf57498e7ef2befe9c921a42a`.
После речи источник продолжал silent PCM. Квантили R7; наблюдаемые загрузки
модели прогретые. Холодная серия и разрешение физического микрофона не измерялись.

| Показатель | C0 p50 / p95, с | C3 p50 / p95, с | Образцы до / после |
|---|---:|---:|---:|
| Обычный полный текстовый ответ | 14,969 / 20,951 | 3,112 / 3,978 | 12 / 12 |
| Первый видимый фрагмент обычного ответа | В C0 не измерен | 3,025 / 3,890 | — / 12 |
| ASR final → полный ответ, нагрузка 1/2/3 | 46,007 / 89,399 | 14,103 / 23,225 | 11 / 12 |
| Готовое локальное SDP → connected | 1,394 / 1,559 | 1,629 / 1,880 | 12 / 12 |
| Начало WAV → ASR final | 3,803 / 3,993 | 3,815 / 4,020 | 11 / 12 |
| Номинальный конец WAV → ASR final | 0,778 / 0,968 | 0,790 / 0,995 | 11 / 12 |

Медиана обычного ответа снизилась на 79%, p95 — на 81%. У голосового ответа
после ASR выигрыш составил 69% / 74%. Это короткая контрольная серия, не SLO
и не прогноз ёмкости production. До переработки один из 33 ходов завершился
ошибкой аудиотранспорта; после — 33/33 DONE. Обычные 12 ответов требуют 12
генераций вместо 26; весь corpus — 36 генераций на 33 ответа вместо 62 на 32.

Подключение WebRTC остаётся ниже цели 3 с по медиане, но в этой серии стало
немного медленнее C0, где Trickle уже работал. Снижение с примерно 16 с до 1,25 с
относится к [отдельной поставке Trickle](</experiments/voice-ai/archive/w/DOCS/WEBRTC_TRICKLE_ACCEPTANCE_2026-10-05.md>).
Рост ASR p95 после номинального конца WAV — 2,8%, ниже принятого порога 10%.
Речь иногда распознана неверно: содержательно «4» получено в 5/12 RTC и 4/5 WSS.
Это ограничивает оценку полезного ответа и не скрывается за transport DONE.

У пяти WSS-подключений ready p50 / p95 — 0,357 / 0,381 с; WAV → final —
3,586 / 3,603 с; final → ответ — 5,618 / 16,005 с. Эта отдельная серия имеет
пять одиночных ходов: сравнивать её напрямую с RTC нагрузкой 1/2/3 нельзя.

Исходные числа: [C0](</experiments/voice-ai/archive/w/DOCS/CHAT_AGENT_BASELINE_C0.md>),
[C3 browser measurements](</experiments/voice-ai/archive/w/DOCS/evidence/chat-agent-c3-series.json>),
[C3 Tempo spans](</experiments/voice-ai/archive/w/DOCS/evidence/chat-agent-c3-telemetry.json>).

## Аудио, отмена, история и разделение чатов

Все 12 RTC-прогонов подтвердили ICE/DTLS connected, растущие RTP counters,
серверный TURN relay и декодирование PCM. Один Core принимает ASR final;
два ingress используют общий PCM FIFO. Проверка четвёртого WSS-подключения при
трёх активных RTC дала явный отказ до передачи PCM: ноль chunks и байт.
Максимальная частота **периодического** flush по метрике — 3,997/с на connection.
End/abort flush считаются отдельно. [Контракт аудио](</experiments/voice-ai/archive/w/DOCS/AUDIO_TRANSPORTS.md>).

Legacy offer без Trickle тоже проверен: прежний 10-секундный snapshot сбора,
затем 5,234 с на answer и 6,502 с от POST до connected. Путь `prflx → relay`,
DTLS connected, 59 RTP packets и span первого PCM. Ожидание полного gathering
не завершилось за 15 с; вариант без клиентского STUN не установил media.
Неверный ICE-токен закрыл WS с 1008 за 471 мс без выдачи кандидатов; удаление
своего соединения действующим токеном вернуло 204.
[ICE compatibility evidence](</experiments/voice-ai/archive/w/DOCS/evidence/chat-agent-c3-ice-compatibility.json>).

После hotfix `a479e52` отдельно повторены современные RTC и WSS: connected
за 1,581 / ready за 0,404 с, настоящий PCM, partial → final → фрагменты → DONE,
по две записи истории. Оба потока остановлены, временная оснастка удалена.
Оба новых распознавания были неточными и привели к уточнению; они не добавлены
в сопоставимый corpus. [Postcheck](</experiments/voice-ai/archive/w/DOCS/evidence/chat-agent-c3-postcheck.json>).

Живая отмена длинного ответа завершилась за 1,179 с, отмена редактирования —
за 0,786 с. После reload отменённые черновики помечены; исходные две записи
редактируемого диалога имеют прежние SHA256. Snapshot своей сессии доступен,
чужой session UUID получает 404. Завершённые контрольные сессии восстанавливают
историю. Фактическая остановка вычисления на внешнем GPU не доказана.
[Evidence отмены и истории](</experiments/voice-ai/archive/w/DOCS/evidence/chat-agent-c3-cancellation.json>).

Два настоящих интерфейса проверены одновременно: пока первый выполнял два
инструмента и отображал карту, второй сохранил свой текст и статусы.
Проверка команд карты дополнительно покрыта frontend-тестами; отдельного
live-измерения позиции камеры второго интерфейса нет. Общий `user123` сохранён.
Фильтрация событий по session/request не заменяет отдельные NATS ACL для каждого
пользователя: транспортная изоляция пользователей остаётся отдельной работой.

## Voice продолжает работать на прежней поставке

Неизменённый voice `5d1d9591` проверен настоящим файлом и NATS progress/result:
обычная transcription, combined diarization, staged Transcribe → Diarize →
Combine, benchmark и summary. Завершены четыре H100-конфигурации и три явно
выбранных CPU sidecar. Короткий WAV дал одного говорящего; WER/DER не измерялись.
CPU не включался как автоматический fallback. Свежий Insight подтвердил все
16 работающих сервисов, прежние image identities, один live bridge и общий
том bench/summary: [runtime postcheck](</experiments/voice-ai/archive/w/DOCS/evidence/chat-agent-c3-postcheck.json>).

Все **55 прежних benchmark-записей** совпали по агрегированному SHA256 полных
строк; после семи тестов summary содержит 62 записи. В описании старого метода
исправлена только неточная запись separator: использовался newline U+000A,
не буквальные символы backslash-n. Исходный checksum сохранён.

Diagnostics Run smoke: 31 рабочая проверка OK, включая ASR, model requests,
workflow, tools, PG и browser `/ws`. Прямой HTTP ingress H100 недоступен в
информационной группе; рабочие NATS requester-пути прошли. Это ограничение
соседнего контура сохраняется. [Voice evidence](</experiments/voice-ai/archive/w/DOCS/evidence/chat-agent-c3-voice.json>).

## Размеры и цена изменения

Для образов сравнивается весь состав из 13 сервисов, включая новые ingress и
tokenizer. Manifest config IDs сверены с фактическими контейнерами; неизменённые
платформенные images используют прежние проверенные manifests.

| Показатель всего стэка | C0 | C3 e9122e0 | Изменение |
|---|---:|---:|---:|
| Сумма rootfs, общие layers повторяются | 3 685,21 МБ | 3 251,97 МБ | −11,8% |
| Сумма compressed layers + configs с повторами | 1 459,41 МБ | 1 230,68 МБ | −15,7% |
| Уникальные compressed layers | 1 217,10 МБ | 978,72 МБ | −19,6% |
| Production LOC, альтернативные исходники включены | 21 230 | 22 358 | +5,3% |
| Активный production LOC | 14 762 | 15 890 | +7,6% |
| Tests LOC | 2 510 | 4 637 | +84,7% |
| Operations LOC | 641 | 1 223 | +90,8% |
| Весь считаемый Git-код, включая tests/operations | 24 381 | 28 218 | +15,7% |

МБ десятичные. Это размеры образов, а не место на диске: тома, внешние модели,
registry attestations и повторное размещение layers на nodes не входят.
Core сократился с 2 893 до 1 321 строк, LLM — с 1 489 до 1 086, но ingress,
контракты, отмена, UI и тесты увеличили общий код. «Кода стало меньше» для всего
проекта было бы неверным выводом. Подсчёт использует tracked physical lines;
YAML, JSON, Dockerfiles и inline-код HTML не включены. Снимок образов относится к corpus release `e9122e0`;
последующий hotfix увеличил rootfs Core на 56 байт, размеры ingress сохранились.
[Image evidence](</experiments/voice-ai/archive/w/DOCS/evidence/chat-agent-c3-image-footprints.json>),
[точные SHA и LOC](</experiments/voice-ai/archive/w/DOCS/evidence/chat-agent-c3-code-count.json>).

В одинаковых трёхминутных idle-окнах непосредственно перед и после миграции
**C2 → C3** working set всего стэка: 700,95 → 570,12 МБ (−18,7%), CPU:
0,120 → 0,177 ядра (+48%). C2 содержал 15 сервисов, C3 — 13. Это сравнение
последнего промежуточного состава, а не всей переработки относительно C0.
Единственная idle-точка C0 была 476,79 МБ; она не равнозначна среднему окна C3.
Сравнимого idle CPU-окна C0 нет.

Во время corpus C3: mean/max working set 555,50 / 579,31 МБ, CPU 0,299 / 0,642
ядра. Шаг metrics 15 с, CPU rate 60 с. В основных Python process CPU заметно
меньше container CPU; измерение healthcheck-child показало около 0,49 CPU-с на
пробу раз в 10 с. Этот снимок снят до последующей
[оптимизации healthcheck C4](</experiments/voice-ai/archive/w/DOCS/CHAT_AGENT_HEALTHCHECK_C4.md>): в двух свежих idle-окнах
CPU снизился с 0,197 до 0,049 ядра; RAM не сократилась. Числа C2/C3 выше сохранены
как история. Сокращение RAM не означает сокращения CPU.
[Resources](</experiments/voice-ai/archive/w/DOCS/evidence/chat-agent-c3-resources.json>),
[idle до миграции](</experiments/voice-ai/archive/w/DOCS/evidence/chat-agent-c2-idle-before-c3.json>).

## Проверки, доступ и оставшиеся границы

Pipeline 4932: Python 85 passed + 28 subtests, frontend 21 passed,
Ruby 38 examples / 0 failures, отдельный Ruby/NATS/PostgreSQL integration job
прошёл. Пятнадцать Python skips не считаются выполненными проверками: реальные
NATS/PG и media entrypoints проверяются дополнительно integration job и живыми
сценариями. Тесты точных aiortc 1.14.0 / aioice 0.10.2 подтверждают DTLS/RTP/PCM
при зависшем STUN, поздние кандидаты и cleanup; private adapter остаётся нашим.

Без OAuth новые защищённые HTTP/WS возвращают 302 на вход, не UI/101.
Четыре прежних application/admin hosts с путями UI/API/WS дали 404 поверх
доверенного TLS нового host. Это проверка маршрутов, а не удаления wildcard DNS.
[Access evidence](</experiments/voice-ai/archive/w/DOCS/evidence/chat-agent-c3-access.json>).

Исходники альтернативных runtimes сохранены, но в production их нет.
GPU scheduling, decoder hang и длинная фраза (№25/26/30) остаются у voice.
Несколько владельцев media, ICE restart и автоматическая смена транспорта
не реализованы. Thinking-модель скрывает рассуждение до видимого текста,
поэтому streaming не гарантирует немедленного первого слова.

Project/agent documentation обновлена через source codex-workspace и штатный
sync; active project `py-faster-whisper` сохранён. OpenWiki пропущен по явному
решению пользователя. Его прежние generated страницы не подтверждают C3;
актуальные источники — код, этот отчёт,
[архитектура](</experiments/voice-ai/archive/w/DOCS/ARCHITECTURE.md>) и [deployment runbook](</experiments/voice-ai/archive/w/DOCS/DEPLOYMENT.md>).

Проверены 325 относительных targets и 311 Git permalinks без потерянных файлов.
Оба HTML deck прошли standalone validator. Семь файлов project overlay совпали
с runtime; `validate`, `sync --company monitorsoft` и `doctor` прошли.
[Links](</experiments/voice-ai/archive/w/DOCS/evidence/chat-agent-c3-links.json>),
[workspace parity](</experiments/voice-ai/archive/w/DOCS/evidence/chat-agent-c3-workspace.json>).
