Files
lightweight-cobot/docs/superpowers/specs/2026-11-10-llm-graph-execution-design.md
T

54 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Исполнение графов Qwen3 в Webots: согласованная архитектура
## Цель и границы
Новая система получает текущую сцену Webots, выдаёт `scene_json` для внешнего вызова Qwen3, принимает готовый JSON-граф модели и выполняет только его. Номер одного из 20 опытов задаёт **исходный набор объектов**, но не диктует цель или эталонную последовательность. Например, в сцене опыта 20 допустим отдельный запрос «возьми присоску, переместись в рабочую позицию, верни присоску»: исполнитель не должен самостоятельно наносить герметик или переносить люк. Вызов Qwen3, оценивание качества модели и инфраструктура сравнения с эталоном входят в последующий проект, а не в этот.
Создать два ROS 2 пакета: `iiwa_scene_context` (снимок сцены и `scene_json`) и `iiwa_llm_plan_executor` (проверка и исполнение графа). Минимальные изменения существующих `iiwa_experement` и `iiwa_web` допустимы для запуска мира и для API/MCP. Реальный робот пока не подключать. Будущая замена источника сцены и физических навыков должна быть возможна через адаптеры, без переписывания валидатора графа.
## Что обнаружено в проекте
`iiwa_experement` уже создаёт сцены, предоставляет `/iiwa_experement/scene_ready`, состояние объектов `/iiwa_experement/object_state`, команды захвата `/iiwa_experement/object_command`, измеренную геометрию, мост сцены MoveIt и эталонные операции. В `mode=view` supervisor работает только на чтение; `mode=execute` сразу запускает эталон. Для внешнего графа требуется третий `mode=planner`: supervisor с разрешёнными действиями, без эталонного runner, без TCP gizmo. Старые два режима сохраняют прежнюю семантику.
`iiwa_web` уже публикует FastAPI и получает MCP через `FastMCP.from_fastapi`. Для новых функций следует добавить тонкие маршруты в этот сервер, а не запускать второй HTTP/MCP сервер.
Приложенные `generated.train.jsonl` (4499 строк) и `generated.validation.jsonl` (500 строк) содержат общий процесс переноса в хранилище, без Grant-объектов и инструментов. Они используют в ответах `pick`, `move_to_storage`, `inspect`. Текущий `planner_dataset/assets/response-format.json` описывает другой список навыков, а показанный пользователем граф добавляет `align`. Поэтому исполнитель не должен слепо импортировать какую-либо одну из этих схем; нужна собственная версия контракта, совместимая с опубликованными `available_skills` и с оговорёнными алиасами.
## Подход к исполнению
Выбран **граф + реестр навыков**. Движения, неизбежные внутри одного навыка, задаются его проверяемым контрактом: например, `grab` может сам подойти сверху, опуститься, захватить и подняться до сохранённой высоты, если явных узлов `approach`/`lower`/`lift` не было. Если они уже выполнялись, повторного движения нет. Это геометрические фазы **того же** действия, а не добавление нового технологического задания.
Исполнитель не придумывает следующую деталь, нужный инструмент или цель из номера эксперимента. Если `grab(cap)` требует вакуумный инструмент, а в `patron` его нет, граф должен явно содержать взятие инструмента; иначе предзапусковая проверка возвращает `replan_required` без движения. `release` инструмента **не возвращает его автоматически**. Для возврата граф должен явно содержать перемещение к гнезду `vacuum_socket` и затем `release(vacuum, vacuum_socket)` либо `dock_tool(vacuum, vacuum_socket)`; оба последних навыка только выполняют стыковку и отделение в уже достигнутом гнезде. `release(vacuum)` из `work` без подходящего места для инструмента отклоняется, присоска остаётся в `patron`. Если граф заканчивается в `work` с присоской в `patron`, она остаётся там до следующего явного задания. Новый процесс может подключить другой адаптер и свои контракты; неизвестный навык или объект не исполняется.
Рассмотренный, но отвергнутый подход — переписывать граф модели и автоматически вставлять недостающие технологические действия. Это могло бы выполнить лишние операции при произвольных запросах. Второй отвергнутый подход — напрямую переводить ID навыка в фиксированную траекторию без проверки текущей позы и состояния; он не учитывает смещения объектов и ветви событий.
## Снимок сцены и интерфейсы
`iiwa_scene_context` собирает **текущий** состав и логическое состояние из `ScenarioSpec` и живого supervisor, а не из эталонного маршрута. Внешний `scene_json` сохраняет поля, ожидаемые Qwen3: `domain`, `components`, `destinations`, `tools`, `initial_state`, `cameras`, `available_skills`, `skill_contracts`, `service_objects`, `recovery_attempts_per_component`. ID соответствуют Webots: `cap`, `vacuum`, `vacuum_socket`, `screw_1`…`screw_10`, `hatch_seat`, `hole_1`…`hole_4`, `work` и т. д. Гнездо каждого присутствующего инструмента публикуется как отдельная именованная цель. Список зависит от реально присутствующих объектов. Абсолютные координаты в модельный `scene_json` не передаются: навык `detect` получает актуальную позу при исполнении.
Транспортный конверт содержит `experiment_id`, `scene_revision`, время снимка, версию состояния supervisor и сам объект `scene_json`. `scene_revision` меняется при дискретном изменении сцены или владения объектом, но не на каждом кадре движения удерживаемой детали. Версия графа передаётся отдельно; исполнитель отвергает граф, построенный по устаревшей сцене. Снимок доступен как ROS 2 сервис `/iiwa_scene_context/get_scene` (ответ с JSON), ROS 2 топик `/iiwa_scene_context/scene_json` с transient-local QoS, HTTP `GET /planner/scene` и одноимённый инструмент MCP через существующий `iiwa_web`. Контракты навыков берутся из серверного реестра, а не из текста, который прислала модель.
## Приём и переходы графа
`iiwa_llm_plan_executor` получает готовый ответ Qwen3, `scene_revision` и `run_id` через ROS 2 сервис `/iiwa_llm_plan_executor/submit`; HTTP `POST /planner/runs` и MCP передают то же через адаптер `iiwa_web`. Модель в этой версии вызывается **вне** проекта. После успешной проверки исполнитель публикует принятый граф без изменений в ROS 2 топик `/iiwa_llm_plan_executor/plan` (`std_msgs/String`, JSON-конверт с `run_id`, `scene_revision` и исходным `response`, QoS transient-local, глубина 1), прежде чем выполнять первый узел. Отклонённый граф в этом топике не появляется; причина отказа доступна в ответе приёма и статусе. Выполнение асинхронно, не более одного активного графа на робота. Отдельный топик `/iiwa_llm_plan_executor/status` сообщает текущий узел, полученное событие, выбранное ребро и итоговый терминал; HTTP и MCP дают те же сведения. Отмена останавливает движение и сохраняет состояние захвата. Для запроса статуса **по `run_id`** добавить сервис `GetRunStatus.srv` в существующий `iiwa_msgs` (`string run_id` в запросе, `bool found` и `string status_json` в ответе); стандартный `Trigger` не имеет поля запроса.
Предзапусковая проверка: строгий JSON без лишних исполняемых полей; `status=blocked` не запускает робот; уникальные ID, известный `entry`, только разрешённые навыки/объекты/цели/события/терминалы, все ссылки существуют, достижимость узлов, предел размера/числа шагов, безопасные ветви для отказа и столкновения, допустимые условия владения инструментом и деталью. Каждый результат навыка выбирает **ровно одно** ребро графа. Терминалы: `completed`, `replan_required`, `operator_required`. На `replan_required` система останавливается и отдаёт свежий `scene_json`; повторный вызов Qwen3 делает внешний клиент. `completed` означает выполнение переданного графа и его зарегистрированных постусловий, а не доказательство, что модель правильно поняла произвольный русский запрос.
## Семантика движения и наблюдения
При `detect` робот сначала отходит от контакта по оси к сохранённой высоте, затем переходит в `work`. Ждёт свежий кадр `/d455_top/image_raw`, берёт точную позу из supervisor и возвращает `found`/`not_found`/`failed`. Для объекта, требующего близкого контроля, конфигурация навыка задаёт безопасную точку обзора и повторный кадр с `/camera/color` или `/camera/depth`; поза всё ещё берётся из supervisor. Задача компьютерного зрения по RGB/D в этот этап не входит.
`approach` ставит рабочий кончик над объектом и сохраняет позу/высоту подхода. `lower` движется вдоль оси к контакту. `grab` при необходимости выполняет недостающие фазы подхода и опускания, подтверждает захват через supervisor и поднимается **к сохранённой позе подхода**. Явный `lift` после этого подтверждает достигнутую высоту и не дублирует подъём. `transfer` идёт к указанной цели на безопасной высоте, `align` меняет ориентацию только на высоте. `release` опускается в указанном безопасном месте установки/передачи, отпускает и поднимается к сохранённой высоте; для инструмента разрешено только его именованное гнездо. `dock_tool` выполняет ту же локальную стыковку инструмента в гнезде без скрытого переноса к стойке. `retreat` не выполняет горизонтальное перемещение до осевого отвода. Для винта отпускание у отверстия означает передачу виртуальному человеку, без вкручивания.
Рабочий кончик направлен вниз. Предпочтительная ось 7 — значение в `work` (сейчас 0 рад); начальный жёсткий коридор ±90° и максимальный наклон рабочего инструмента 10° задаются в конфигурации и уточняются проверкой достижимости. Перед каждым планом используются текущие суставы как IK seed, ограничения MoveIt на `joint7` и ориентацию, а перед исполнением — проверка каждой точки траектории, столкновений и скачков суставов. При недостижимости в этом коридоре исполнитель сообщает отказ; не выбирает ветвь IK с поворотом примерно на −180°. Поворот кисти или возврат в `work` допустим только после осевого подъёма. На каждом переходе между узлами проверяется свежесть состояния сцены и робота.
Для этого `iiwa_llm_plan_executor` нужен собственный адаптер планирования на установленном MoveItPy: текущий `MoveToPose.action` не передаёт ограничение `joint7`. Он повторно использует геометрию и обновление сцены из `iiwa_experement`, но не запускает эталонную последовательность. Физический слой остаётся сменным для будущей адаптации к реальному роботу.
## Поддерживаемые навыки первого этапа
Реестр поддерживает имена из показанного графа и необходимые действия с текущими объектами Grant: `detect`, `approach`, `lower`, `grab`, `lift`, `transfer`, `align`, `release`, `retreat`, `capture`, `verify`, `stop`, `wait_scene_clear`, `inspect_state`, `notify_operator`, `dispense`, `dock_tool`, `handoff_screw`. Для графов из обучающего набора описать и проверить совместимые алиасы `pick`, `move_to_storage`, `inspect`; их запуск разрешать лишь при поддерживаемом типе объекта и места назначения в текущей сцене. Любой другой навык (включая `tighten`, если у отверстия нет установленного винта) получает отказ до движения. Каталог можно расширять новым обработчиком и контрактом, без изменения движка графа.
## Проверки и результат этапа
Пакетные тесты проверяют формат снимка, контракт навыков, валидацию графа и переходы, физические фазы на поддельном backend, ограничения суставов и API/MCP адаптеры. Минимальные пробы Webots должны подтвердить произвольные короткие запросы в одной и той же сцене: взять и вернуть присоску; обнаружить люк; взять люк и установить; выбрать один из десяти винтов и передать у указанного отверстия; остановка и перепланирование после отказа. Это проверка работоспособности двух пакетов, **не** система оценивания Qwen3 и не сравнение 20 экспериментов с эталоном.