Skip to content

[Spec] SayPlan 통합 — Scene Graph 기반 숙고 트랙 (verify / replan) #2

Description

@Taeyoung96

대상: ZER01NE 백엔드 오케스트레이터 개발자
참고 위키: https://github.com/zero1ne-26/doc/wikiSYSTEM_DESIGN · OSS_INTEGRATION · LOCAL_LLM_HYBRID_ROUTING
첨부 다이어그램(FigJam): Figma 6월 1주차 논의 사항

요약

현재 오케스트레이터는 assemble → call_claude → guardrail → dispatch단발 반응형이다. 이 명세는 SayPlan을 프레임워크로 얹지 않고 패턴으로 이식하여, guardrailreject-only 에서 verify-and-replan 으로 승격하고, 그 중심에 offline 사전 구축한 scene graph를 두어 "탐색 → 실패 → 재탐색 → 실행"을 실제 로봇 행동 + UI 스트리밍으로 관측 가능하게 만든다.

핵심 결정 사항 (확정)

  1. 패턴으로 채택 — SayPlan 레포를 의존성/서비스로 얹지 않고, 2 스테이지·2 루프 패턴을 orchestrator 내부에 이식한다.
  2. 두 트랙 분리 — 기존 단발 반응 트랙은 유지(NFR < 1.5s), SayPlan은 숙고 트랙(신규)으로 분리.
  3. Scene Graph는 offline 사전 구축 — 런타임 구조는 정적. (SayPlan 원본의 pre-built 3DSG 가정과 일치)
  4. 로봇 명령 디스패치는 MCP(mcp-robot-adapter) 채택 — 직접 in-process 호출은 stop 등 초저지연 특수 케이스 fallback으로만.
  5. 재시도 캡 N = 1~2 / 신규 MQTT 토픽 0개 — 루프는 orchestrator 내부에서 종결.

1. SayPlan 개요 (개발자용)

SayPlan = 3D Scene Graph(JSON 그래프) + LLM으로 로봇 task plan을 생성하는 프레임워크. 2 스테이지, 2 루프. (FigJam ① 참조)

  • 입력: 자연어 명령 + 환경의 3D Scene Graph (계층 floor → room → asset → object, 각 노드에 state · affordance · predicate)
  • STAGE 1 — Semantic Search: 그래프를 collapse()(상위만 노출)한 뒤 LLM이 expand(node)/contract(node)로 task에 필요한 부분그래프만 탐색. 탐색 과정이 스텝 단위로 관측 가능.
  • STAGE 2 — Iterative Replanning: 부분그래프로 LLM이 action 시퀀스 생성 → Scene Graph Simulator가 affordance·predicate로 실행가능성 검증 → 실패 시 텍스트 피드백("cannot pick: fridge not open")을 되먹여 재계획. 경로는 전통 path planner에 위임.
  • 2 루프: ① 재계획(STAGE 2 내부): 계획이 막힘 → 계획만 수정. ② 재탐색(STAGE 2 → STAGE 1): 부분그래프에 필요한 객체가 없음 → 탐색으로 복귀해 다른 노드 펼침.

2. 왜 필요한가

guardrail은 잘못된 tool call을 거부 + 메트릭만 남긴다(SYSTEM_DESIGN §9.3). 단발 인사·옵션 노출엔 충분하나 세 지점에서 한계:

  1. 다단계 과업의 견고성bring, §16의 6단계 여정처럼 여러 행동이 엮인 task는 한 번의 tool call로 끝나지 않는다. 중간 제약 위반을 거부만 하지 말고 사유를 LLM에 되먹여 고친 계획을 받아야 한다 → 환각으로 인한 비실행 계획을 거의 0으로.
  2. 그라운딩 — LLM 단독은 "그 물체가 실제로 있는지/집을 수 있는지"를 모른다. scene graph의 state·affordance를 simulator가 검증하면 계획이 환경에 묶인다.
  3. 전시 연출 가치(핵심) — UI 오버레이는 이미 reasoning을 스트리밍한다. expand/contract·재계획 스텝을 흘리면 "AI가 공간을 뒤지며 생각하고, 막히면 다시 길을 찾는" 과정이 보인다. 탐색·재탐색은 비용이 아니라 콘텐츠.

단발 반응에는 SayPlan이 과하다. 하지만 보여줄 인지 과정 + 다단계 실행 보증이 필요한 순간엔 정확히 그 빈자리를 채운다.


3. 통합 전략

3.1 두 트랙 분리 (가장 중요한 결정)

트랙 용도 지연 scene graph
반응 트랙 (기존 유지) zone 입장 인사, look_at, 옵션 노출 NFR < 1.5s 사용 안 함
숙고 트랙 (신규, SayPlan) bring, 장기 시나리오, "생각하는 모습" 데모 NFR 미적용 (탐색이 곧 연출) 탐색·검증의 중심

라우팅: 트리거 시점에 숙고 필요?(task 종류·playbook 기준)로 분기. (FigJam ③ 참조)

3.2 채택 / 비채택

SayPlan 요소 채택 비고
Iterative replanning + simulator 피드백 가장 큰 가치. guardrailverify 승격
Scene graph 표현 + 탐색/재탐색 ◎ (숙고 트랙) 전시 연출 + bring 그라운딩
collapse/expand (토큰 절감 목적) 4 zone은 토큰 문제 없음 → 탐색 연출 용도로만 사용
Dijkstra path planner SPOT SDK/ROS2 + world↔odom 정합(SYSTEM_DESIGN §8.3.2)이 담당
Semantic search (스케일 목적) 소규모 환경엔 무가치

3.3 경계·주의 (충돌 방지)

  • 안전은 mcp-robot-adapter에 그대로. simulator는 과업 실현가능성만 판단(피드백 생성). 물리 안전(e-stop·proximity·zone fence)의 권위는 어댑터다. 이중 구현 금지.
  • 지연 예산: 재계획 1회 = Claude 호출 1회. 반응 트랙 단발 유지, 숙고 트랙도 재시도 캡 N = 1~2(원본 5회는 실시간엔 과함). LOCAL_LLM_HYBRID_ROUTING 채택 시 재검증 re-prompt는 저렴/로컬 티어로, 메인 결정만 Opus로.
  • 신규 MQTT 토픽 0개 — 루프는 orchestrator 내부에서 종결(SYSTEM_DESIGN §16.6 정신 유지).
  • HA vs LangGraph 경계(OSS_INTEGRATION §7): 단순 룰은 HA, 컨텍스트 의존 결정은 orchestrator. simulator는 후자.

4. 디스패치 방식 결정 — MCP 채택

기준 MCP (mcp-robot-adapter) 직접 in-process 호출
아키텍처 일관성 전 시스템이 MCP → 일관 특례 발생
안전 인터록·명령 큐·이종 로봇 추상화 어댑터가 소유 (설계대로) shim 재구현 필요
권한 분리·테스트성 용이 (orchestrator만 호출, ACL) 약함
지연 SSE 홉 (LAN, 수 ms) 더 빠름

결론: MCP 채택. 숙고 트랙은 NFR에 묶이지 않고, 안전·이종 로봇 책임이 어댑터에 모이는 것이 설계(SYSTEM_DESIGN §3.3·§7.3·§7.4)와 일치. 직접 호출은 stop 같은 초저지연 케이스에서만 fallback으로 문서화.


5. Scene Graph 명세 (offline 사전 구축)

5.1 형식

  • 직렬화: JSON (NetworkX 호환). 경로: config/scene_graph/<site>.json (PoC: config/scene_graph/home.json).
  • 계층(노드 종류): site → zone → asset → object (+ pose/waypoint, agent).
  • 빌드: offline 도구로 1회 구축 → 검수 → 고정. 런타임 중 구조 변경 없음.

5.2 노드 스키마

노드 주요 필드
zone id, name, polygon_world, connected_waypoints[]
asset id, zone, pose_world, state(open/closed/...), affordances[](open, close, release...)
object id, parent(asset|zone), state, affordances[](pickup...), attributes
pose/waypoint id, xy_world, links[] — GraphNav waypoint와 정합
agent robot_id, location(zone/pose) — 런타임 overlay

5.3 정적 / 동적 분리 (중요)

  • 정적 (offline 고정): zone·asset·object 구조, pose, affordance, 위치. 전시 prop은 움직이지 않는다는 전제.
  • 동적 (런타임 overlay): 로봇 위치(robot/+/state), zone 점유(Frigate). 정적 구조 위에 얇게 덮음.
  • SayPlan의 "정적 맵 가정" 한계는 본 프로젝트에서 의도된 설계가 된다. live re-mapping 불필요.

5.4 collapse / expand 처리

  • 4 zone 규모라 그래프 전체가 LLM 컨텍스트에 들어감 → 토큰 절감 목적의 collapse 불필요.
  • expand/contract관측 가능한 탐색 연출 용도로만 유지(숙고 트랙 UI 스트리밍). 정적 그래프 위를 스텝 단위로 훑는 형태.

6. 로봇 명령 명세 (mcp-robot-adapter 노출)

공통 규약

  • robot_idconfig/robots.yaml 레지스트리로 런타임 검증 (literal 박지 말 것).
  • 모든 명령은 결과 반환: { status, detail, observations?, pose? }. fire-and-forget 금지 — 반환이 곧 verify/replan 피드백.
  • 안전 인터록은 어댑터 소유(orchestrator는 whitelist·clamp만). stop은 항상 큐 최우선·즉시 preempt.
  • status enum: ok | arrived | blocked | failed | rejected | stopped.
명령 input 반환 안전/비고 구현 출처
describe_scene robot_id, target? observations[] { label, rel_pos, affordances, confidence } 신규 (VLM/GroundingDINO)
goto robot_id, destination(zone/waypoint) arrived / blocked(detail) / failed, pose proximity·zone fence 검증 GraphNav
stop robot_id stopped 최우선, 즉시 SPOT SDK
look_at robot_id, target ok SPOT SDK
gesture robot_id, name(enum) ok SDK 프리셋
follow robot_id, target, max_distance_m status proximity 지속 검증 SPOT SDK
(later) bring robot_id, object, destination status object affordance=pickup 그래프 검증 후 STAGE 2 KAIST + grasping

각 명령의 상세 input_schema(JSON)는 mcp-robot-adapter에 정의. 위 표는 계약 요약.

6.1 describe_scene의 역할 (offline 그래프 전제)

그래프를 offline으로 완성했으므로 describe_scene그래프 빌더가 아니다. 두 용도:

  1. 그라운딩 검증 — 행동 전 "그래프상 object가 실제로 앞에 있나" 대조. 불일치 시 detail로 피드백 → 재계획/재탐색.
  2. 전시 연출 — "AI가 앞을 보고 묘사하는" 스텝을 UI 스트리밍.

정적 그래프 = 계획의 기준, describe_scene = 현실과의 대조. 어긋나는 순간이 재탐색 트리거.


7. 디스패치 · 피드백 규약 (숙고 트랙)

  1. dispatch 노드 → MCP 호출 → CommandResult 수신.
  2. observations가 있으면 그래프의 동적 overlay만 갱신(구조 불변).
  3. status ∈ {blocked, failed, rejected}detail을 LLM 피드백으로 주입:
    • 제약 위반/실패 → STAGE 2 재계획 (재시도 캡 N = 1~2).
    • 객체 불일치/도달 불가 → STAGE 1 재탐색.
  4. 캡 초과 → rule-based 폴백(SYSTEM_DESIGN §9.4).
  5. 신규 MQTT 토픽 0개 — 루프는 orchestrator 내부에서 종결.

8. SayPlan ↔ ZER01NE 매핑

SayPlan ZER01NE 대응
LLM Claude (Anthropic API) — call_claude
3D Scene Graph config/scene_graph/<site>.json → NetworkX (offline 구축, orchestrator 로드)
Scene Graph Simulator simulate 노드 (과업 실현가능성 검증)
Semantic Search (expand/contract) semantic_search 노드 (숙고 트랙, UI 스트리밍)
Iterative Replanning verifycall_claude 피드백 루프 (캡 N회)
Path Planner (Dijkstra) SPOT SDK / GraphNav (채택 안 함)
실행 dispatchmcp-robot-adapter → 로봇

9. 로드맵 (마일스톤 연계)

단계 작업 비고
M3 반응 트랙 + verify-and-replan 루프(평평한 상태 검증 버전) guardrailverify 승격. scene graph 없이도 재계획 루프 동작
M3+ / bring 결정 후 offline scene graph + semantic_search/simulate 노드 추가 → 숙고 트랙 완성 KAIST 로봇·bring 확정과 동기화(SYSTEM_DESIGN §15)
M4~M5 숙고 트랙 UI 스트리밍 연출, 폴백·캡 튜닝, 부하 리허설

10. 구현 산정

항목 신규/기존 비고
offline scene graph 빌드 도구 신규 1회성, 검수 후 고정
config/scene_graph/home.json 신규 PoC 인스턴스
mcp-robot-adapter 명령 노출 기존 확장 §6 명령 등록 + 안전 인터록
describe_scene perceiver 신규 VLM/GroundingDINO — 유일한 무거운 신규 작업
orchestrator 숙고 서브그래프 신규 STAGE 1/2 + 2 루프 + 캡/폴백 (§7)
goto/stop/look_at/gesture/follow 기존 SPOT SDK·GraphNav 제공

11. 작업 체크리스트 (이슈 트래킹)

  • offline scene graph 빌드 도구 작성
  • config/scene_graph/home.json 구축 → 검수 → 고정
  • mcp-robot-adapterdescribe_scene / goto / stop 등록 (+ 안전 인터록)
  • describe_scene perceiver (VLM/GroundingDINO) 구현
  • orchestrator 숙고 서브그래프: semantic_searchplansimulate + 2 루프 + 캡(N=1~2) + 폴백
  • 반응/숙고 트랙 라우팅(숙고 필요?) 구현
  • 숙고 트랙 스텝 → UI 오버레이 스트리밍 연동
  • PoC 시연 루프 end-to-end 검증

12. 수용 기준 (Acceptance Criteria)

  • home zone에서 goto → describe_scene → (불일치/없음) 재탐색 goto → describe_scene → 실행이 동작한다.
  • 제약 위반·실패 시 detail 피드백으로 재계획/재탐색이 트리거되고, 캡(N) 초과 시 rule-based 폴백으로 수렴한다.
  • 탐색·재탐색·재계획 스텝이 UI 오버레이에 실시간 스트리밍된다.
  • 물리 안전(e-stop·proximity·zone fence)은 mcp-robot-adapter에서만 강제되며 orchestrator에 중복 구현되지 않는다.
  • 신규 MQTT 토픽이 추가되지 않는다.

13. 참고

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions