Гибкий диалог chat-agent: причины отказов и следующая доработка
Дата: 06.10.2026. Источники: код переработки на e4bfe285306fc225c3d445ade16296021bd934f3 и read-only проверка открытой пользовательской сессии. Основной checkout содержит более старую версию; ссылки ниже закреплены на SHA переработки.
Статус: требование показа причин отказов зафиксировано. Целевая схема ниже — предложение для обсуждения; изменения приложений и deployment не выполнялись.
Зафиксированное требование: конкретная причина отказа
Показывать причину рядом с ответом, а не только общую фразу "Не удалось сформировать ответ". Указывать этап, понятное объяснение и машинный код; пояснять доступное действие, если оно действительно помогает. Подробности связывать с соответствующим request_id.
- Для
context_budget_exceeded: "Не удалось подготовить запрос: данные карты переполнили контекст модели". Технические подробности должны сохранять исходный код ошибки. - Ошибка генерации ответа и ошибка передачи микрофона — разные события. Нельзя представлять сбой WSS как причину отказа LLM без подтверждённой связи.
- Различать запрос, который не выполнен, и ответ, который сформирован частично. Не показывать "Незавершённый ответ" как единственное объяснение любого отказа.
- При частично выполненной задаче показывать подтверждённые результаты шагов и причину остановки.
- Проверка приёмки: ошибки контекста, инструмента, очереди и аудиотранспорта отображаются со своей причиной и принадлежат своей сессии/запросу; диагностические подробности не содержат credentials и полного содержимого разговора.
Что помешало гибкости
Отказ от жёстких сценариев остаётся целью. Возврат генеративного router перед каждым запросом не требуется. Новый общий цикл уже умеет выбирать и сочетать инструменты; сохранённые графы обслуживают явно активный workflow.
- Память блокирует следующие ходы.
Dialogотправляет артефакты вcontext.entitiesи повторно внутриcontext.state.artifact_memory.Engineсохраняет геометрию маршрута, а TokenBudget сокращает только сообщения истории. В проверенной сессии после маршрута следующие запросы получилиcontext_budget_exceeded. Причина отказов подтверждена history; механизм переполнения подтверждён кодом. Новый точный подсчёт токенов каждого prompt в этой проверке не выполнялся. - Модель не получает автоматически всё, что показано на карте.
init_mapпубликует аэропорты и позицию в UI, но не записывает эти исходные факты в память Agent. Новый диалог должен сам вызватьget_current_position; подсказка не устанавливает явного правила сначала получить доступную позицию при запросе "ближайший ко мне". Уточнение города может заменить это действие. - Каталог действий узкий. Доступны пять конкретных инструментов.
search_airports_nearbyпринимает город и радиус, возвращает расстояния по возрастанию. Полный каталог и поиск по имени существуют в HTTP API, но не объявлены модели как инструменты. Параметров сортировки, координатного центра и лимита в текущем NATS-инструменте нет. Модель может выбрать максимальное расстояние среди полученных строк, но не гарантировать самый удалённый аэропорт за пределами этой выборки. - Приёмка не покрыла продолжение после маршрута. Контрольный corpus содержит короткий разговор, поиск аэропортов и уточнения рейса. Цепочки "маршрут → следующий запрос", полнота полезного результата и исходное состояние карты должны иметь отдельные проверки. DONE сам по себе не доказывает выполнение пользовательской цели.
Текущие авиационные данные демонстрационные: четыре московских аэропорта, фиксированная позиция в Москве, синтетическая погода и маршрут-дуга. Самый удалённый объект нужно искать в явно обозначенной области данных; результат такого каталога нельзя выдавать за глобальный поиск.
Как работает сейчас: новый запрос
Исходный Mermaid
flowchart TD
U["Реплика пользователя"] --> A["Core → Agent → Ruby"]
A --> C["Контекст и каталог пяти инструментов"]
P["Память: полная геометрия маршрута"] -->|"дважды в следующем prompt"| C
C --> B{"Вход помещается в 6144 токена?"}
B -->|"нет"| E["Общий текст отказа в интерфейсе"]
B -->|"да"| M["Модель: ответ или tool calls"]
M -->|"tool calls"| V["Проверка имени и аргументов"]
V --> T["Выполнение инструмента"]
T -->|"полный JSON результата"| C
M -->|"итоговый ответ"| F["Ответ и накопленные команды карты"]
F -->|"сохранить артефакты"| PМодель выбирает действия динамически. Полные результаты инструментов остаются в текущем диалоге; результаты карты сохраняются для следующих ходов. Переполнение обязательного контекста останавливает запрос, даже если убрать всю старую историю. Команды карты общего цикла публикуются после его завершения.
Как должно работать: предложение
Исходный Mermaid
flowchart TD
U["Реплика пользователя"] --> C["Цель и компактные факты:<br/>позиция, история, выбранные объекты"]
P["Краткая память и ссылки на артефакты"] --> C
C --> M["Модель выбирает следующий шаг"]
M -->|"tool call"| V["Общий исполнитель:<br/>схема, права, deadline, бюджет"]
V --> T["Разрешённый инструмент"]
T --> R["Результат или конкретная ошибка"]
R -->|"компактные данные"| M
R -->|"тяжёлые артефакты"| S["Хранилище → карта"]
R -->|"подтверждённые факты и ссылки"| P
M -->|"кандидат итогового ответа"| K["Проверка фактов и выполненных действий"]
K -->|"результат подтверждён"| F["Ответ пользователю"]
K -->|"осталось действие"| M
V -->|"продолжение невозможно"| E["Конкретная причина остановки"]
K -->|"данных недостаточно"| EМодель определяет последовательность, общий исполнитель проверяет и выполняет разрешённые действия. Полные геометрии и большие выборки передаются карте и хранятся отдельно; модель получает координаты концов, расстояние, идентификаторы, краткое описание и ссылку на артефакт. Доступные факты имеют источник и обозначенную область данных. Ошибка шага возвращается модели, когда корректировка допустима; терминальный отказ объясняется пользователю. Для уточнения задаётся вопрос только о действительно недоступных данных.
Для поиска аэропортов предлагается расширить общий инструмент параметрами центра, фильтров, сортировки по расстоянию и лимита. Это операции над данными, а не отдельные сценарии "ближайший", "самый удалённый" или "маршрут". Точный API и состав разрешённого каталога ещё нужно согласовать.
Сохраняются ограничение 10 инструментальных действий, общий deadline 120 секунд и серверная проверка прав/аргументов. Обычный разговор должен по-прежнему обходиться одной генерацией.
Проверяемый результат следующего этапа
- После построения маршрута минимум 20 следующих ходов проходят без
context_budget_exceeded; размер обязательного контекста ограничен и измерен. - Поиск ближайшего к доступной позиции сначала получает эту позицию; при её отсутствии задаёт точное уточнение. Демонстрационная позиция явно обозначается.
- Ближайший/самый удалённый/по имени/по фильтру выполняются над обозначенной выборкой; координаты и расстояния подтверждены инструментами.
- Новое сочетание "найти объект → узнать погоду → построить маршрут" не требует нового workflow ID или сценарного графа.
- Итоговое "маршрут построен" связано с успешным инструментальным результатом и артефактом карты; частичный результат и ошибка различимы.
- Приёмка учитывает полезный результат, количество генераций, размер prompt, длительности и точные коды ошибок, а не только DONE.
Ссылки на реализацию проверенного снимка
- Новый диалог и передача контекста.
- Выбор нового диалога и совместимость активных графов.
- Сохранение геометрии в памяти.
- Токеновый бюджет.
- Каталог разрешённых инструментов.
- Ограничения поиска и демонстрационные данные.
- Исходные данные карты отправляются в UI.
- Контрольный corpus.