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

18 KiB
Raw Blame History

Исполнение графов 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 экспериментов с эталоном.