19.comToMe DeviceAgent Contract
이 문서는 /home/silogood/work/19.comToMe 폴더의 ComeToMe 설계를 DeviceAgent/SoC 업체가 실제 구현 계약으로 옮길 때 필요한 항목을 정리한다.
기준 원본:
/home/silogood/work/19.comToMe/docs/strategy/short-term/com-to-me-system-design.md
/home/silogood/work/19.comToMe/docs/strategy/short-term/com-to-me-speaker-recognition-service-scenario.md
/home/silogood/work/19.comToMe/docs/diagrams/com-to-me-flow.mmd
/home/silogood/work/19.comToMe/docs/diagrams/com-to-me-speaker-recognition-service.svg
1. 핵심 결론
ComeToMe는 단순히 set 함수 하나로 끝나는 ODL 명령이 아니다. 호출어, 의도 분류, stage gate, 화자인식, DoA, 회전, Vision, AMR, FollowMe, 후속 task가 이어지는 장기 device workflow다.
따라서 구현 책임은 아래처럼 나누는 것이 맞다.
| 계층 | 책임 |
|---|---|
| Cloud A2A Planner | 사용자 발화를 ODL 및 comeToMe device intent로 정리하고, command type과 slot을 명시한다. |
| On-device Bridge | Cloud의 device_task_requests를 DeviceAgent submitTask 또는 submitWorkflow 호출로 변환한다. |
| DeviceAgent TaskManager | ComeToMe task lifecycle, stage gate, timeout, cancel, stale event, callback/reason 계약을 관리한다. |
| SoC Domain Modules | DoA, Rotation, Vision, AMR, FollowMe, Speaker, Location Resolver의 실제 기능을 수행한다. |
Cloud가 DoA/Vision/AMR 단계마다 LLM으로 판단하면 안 된다. 정상 진행은 DeviceAgent 내부 상태 머신이 처리하고, Cloud는 실패/차단/사용자 결정 필요 이벤트에서만 개입한다.
2. Cloud에서 내려가는 최소 intent
Cloud는 아래 수준까지 내려주면 충분하다.
2.1 사용자 방향 기반
{
"method": "submitTask",
"taskMethod": "comeToMe",
"source": "cloud_a2a",
"cloud_workflow_id": "wf_cometome_001",
"cloud_step_id": "step_1",
"cloud_output_key": "cometome_result",
"commandType": "user_direction",
"utterance": "나에게와",
"rolloutStage": "0-1"
}
2.2 등록 장소 기반
{
"method": "submitTask",
"taskMethod": "comeToMe",
"source": "cloud_a2a",
"cloud_workflow_id": "wf_cometome_002",
"cloud_step_id": "step_1",
"cloud_output_key": "cometome_result",
"commandType": "place_name",
"roomName": "거실",
"rawTarget": "거실로와",
"rolloutStage": "0-2"
}
2.3 후속 연속동작 포함
{
"method": "submitWorkflow",
"workflowName": "come_to_me_followup_workflow",
"source": "cloud_a2a",
"cloud_workflow_id": "wf_cometome_003",
"subTasks": [
{
"taskMethod": "comeToMe",
"commandType": "place_name",
"roomName": "거실",
"rolloutStage": "2",
"cloud_step_id": "step_1",
"cloud_output_key": "cometome_arrival_context"
},
{
"taskMethod": "deviceFollowupAction",
"inputFrom": "cometome_arrival_context",
"cloud_step_id": "step_2",
"cloud_output_key": "followup_result"
}
]
}
3. DeviceAgent 내부 task lifecycle
DeviceAgent는 comeToMe를 받으면 아래 순서의 상태 머신으로 처리해야 한다.
submitTask(comeToMe)
-> task_id 생성
-> stage gate 확인
-> commandType 분기
- user_direction: DoA -> Rotation -> Vision -> target_pose
- place_name: LocationResolver -> registered pose -> target_pose
-> AMR 이동
-> 도착 후 사용자 확인
-> FollowMe 시작
-> stage >= 2이면 후속 task context 생성
-> 완료 또는 실패 event 발행
각 내부 단계는 독립 모듈이지만, 순서 제어와 실패 정책은 TaskManager가 가진다.
4. Stage gate 계약
원본 설계의 rollout stage를 그대로 계약화하면 아래와 같다.
| Stage | 허용 command | 필수 gate | 금지/보류 |
|---|---|---|---|
| 0-1 | "나에게와" 사용자 방향 기반 |
ComeToMe intent, DoA, Rotation, Vision, AMR, FollowMe | 화자인식, 등록 장소 이동, 공간인식, 후속 기능 |
| 0-2 | 0-1 + "거실로와" 등 등록 장소 기반 |
Location Resolver, registered room pose, map validation | 화자인식, 후속 기능 |
| 1 | 0-2 + 등록 화자 확인 | Speaker profile, threshold/margin, overlap/noise stop | 공간 기반 후속 연속동작 |
| 2 | 화자/공간 확인 후 후속 연속동작 | speaker_id, room/context, chained task context | 능동 추천 자동 실행 |
| 3 | 후속 기능 제안 | user confirmation | 사용자 확인 없는 자동 실행 |
DeviceAgent는 stage 밖 기능을 실행하면 안 된다. 예를 들어 stage 0-1에서 "거실로와"가 들어오면 AMR 이동을 시작하지 않고 FEATURE_STAGE_UNAVAILABLE 또는 ROOM_NAVIGATION_STAGE_DISABLED 계열 reason을 올려야 한다.
5. 필수 데이터 모델
5.1 ComeToMe task context
{
"task_id": "tm_task_001",
"taskMethod": "comeToMe",
"rolloutStage": "1",
"commandType": "user_direction",
"roomName": "",
"speaker_id": "spk_001",
"map_id": "home_map_001",
"target_pose": {
"x": 1.25,
"y": 2.4,
"theta": 0.0
},
"state": "MOVING_TO_TARGET",
"retry_count": 0,
"cloud_workflow_id": "wf_cometome_001",
"cloud_step_id": "step_1",
"cloud_output_key": "cometome_result"
}
5.2 Registered location
{
"locationId": "loc_living_room_001",
"ownerSpeakerId": "spk_001",
"roomName": "거실",
"aliases": ["거실", "큰방"],
"pose": {
"x": 3.2,
"y": 1.8,
"theta": 1.57
},
"mapId": "home_map_001",
"updatedAtMs": 1760000000000
}
5.3 Speaker verification result
{
"speakerId": "spk_001",
"displayName": "사용자1",
"score": 0.62,
"margin": 0.14,
"threshold": 0.5,
"accepted": true,
"reason": "ACCEPTED"
}
6. Callback / event 계약
정상 진행 event는 Cloud로 올라가도 되지만 Cloud LLM을 다시 돌리면 안 된다. Cloud 판단이 필요한 event만 requires_cloud_decision=true로 올린다.
6.1 정상 event
{
"eventName": "PROGRESS",
"task_id": "tm_task_001",
"taskMethod": "comeToMe",
"state": "VISION_TARGET_FOUND",
"cloud_workflow_id": "wf_cometome_001",
"cloud_step_id": "step_1",
"progress": 55,
"requires_cloud_decision": false,
"eventPayload": {
"doaAngleDeg": 42.0,
"visionConfidence": 0.82,
"distanceM": 2.1
}
}
6.2 실패 event
{
"eventName": "FAILED",
"task_id": "tm_task_001",
"taskMethod": "comeToMe",
"state": "SPEAKER_GATE",
"cloud_workflow_id": "wf_cometome_001",
"cloud_step_id": "step_1",
"reason_code": "SPEAKER_VERIFICATION_FAILED",
"reason_params": {
"rolloutStage": "1",
"score": 0.42,
"threshold": 0.5,
"margin": 0.03,
"commandType": "user_direction"
},
"requires_cloud_decision": true,
"suggested_action": "ASK_USER_RETRY_OR_ENROLL"
}
7. Reason code 표준 후보
| 영역 | reason_code | 의미 | Cloud 판단 필요 |
|---|---|---|---|
| Stage | FEATURE_STAGE_UNAVAILABLE |
현재 rollout stage에서 요청 기능 미지원 | true |
| Intent | LOW_INTENT_CONFIDENCE |
ComeToMe 의도 confidence 부족 | true |
| Speaker | SPEAKER_PROFILE_NOT_FOUND |
등록 화자 profile 없음 | true |
| Speaker | SPEAKER_VERIFICATION_FAILED |
score/margin/잡음/다화자 조건 실패 | true |
| Location | ROOM_NOT_FOUND |
등록된 roomName 없음 | true |
| Location | ROOM_NAME_AMBIGUOUS |
동일/유사 방 이름으로 target 확정 불가 | true |
| Location | LOCATION_POSE_INVALID |
등록 pose가 현재 map에서 유효하지 않음 | true |
| DoA | DOA_CONFIDENCE_LOW |
음원 방향 confidence 부족 | false 또는 true |
| Vision | PERSON_NOT_FOUND |
회전 후 사용자 미감지 | true |
| Vision | VISION_OUT_OF_RANGE |
전방 120도/3m 안정 범위 밖 | true |
| AMR | PATH_BLOCKED |
목표 지점까지 경로 차단 | true |
| AMR | NAVIGATION_FAILED |
이동 실패/timeout | true |
| FollowMe | FOLLOW_TARGET_LOST |
도착 후 추종 대상 소실 | true |
| Task | TASK_CANCELLED_BY_USER |
사용자 취소 | false |
| Task | STALE_EVENT |
이전 task event가 늦게 도착 | false |
8. 업체 구현 범위
업체가 최소로 구현해야 하는 항목은 아래다.
| 구현 항목 | 완료 기준 |
|---|---|
comeToMe task method |
submitTask.taskMethod=comeToMe 수신 및 task_id 생성 |
| Stage gate | 0-1, 0-2, 1, 2, 3별 허용 기능과 금지 기능 분리 |
| Command type resolver | user_direction, place_name 분기와 slot 보존 |
| Location resolver | roomName -> locationId/pose/mapId 조회, 미등록/중복/invalid reason 반환 |
| Speaker gate | stage 1 이상에서 profile/score/margin/다화자/잡음 조건 판단 |
| DoA/Rotation/Vision chain | user_direction에서 target_pose 생성까지 순차 실행 |
| AMR navigation binding | target_pose 이동 요청, 완료/실패 callback 연결 |
| FollowMe binding | 도착 후 추종 대상 확인 및 FollowMe 시작 |
| Task event listener | QUEUED/RUNNING/PROGRESS/COMPLETED/FAILED/BLOCKED/PAUSED 발행 |
| Trace propagation | cloud_workflow_id, cloud_step_id, cloud_output_key를 모든 callback에 유지 |
| Timeout/cancel/stale event | 늦은 event 무시, 중복 task 정책, 사용자 취소 처리 |
9. 검증 fixture
ADB가 없을 때도 우선 JSON fixture로 아래를 검증해야 한다.
| Fixture | 입력 | 기대 |
|---|---|---|
cometome_01_user_direction_stage_01 |
rolloutStage=0-1, commandType=user_direction |
DoA/Vision/AMR/FollowMe chain 시작 |
cometome_02_place_stage_disabled |
rolloutStage=0-1, commandType=place_name, roomName=거실 |
FEATURE_STAGE_UNAVAILABLE |
cometome_03_place_success |
rolloutStage=0-2, 등록 roomName=거실 있음 |
registered pose 기반 AMR 이동 |
cometome_04_room_not_found |
rolloutStage=0-2, roomName=서재 미등록 |
ROOM_NOT_FOUND |
cometome_05_speaker_gate_failed |
rolloutStage=1, score threshold 미달 |
SPEAKER_VERIFICATION_FAILED |
cometome_06_path_blocked |
AMR 경로 차단 | PATH_BLOCKED, requires_cloud_decision=true |
cometome_07_stale_event |
이전 task_id event 수신 |
STALE_EVENT, Cloud replan 없음 |
10. 업체에 반드시 확인할 질문
| 질문 | 결정 필요 이유 |
|---|---|
실제 task method 이름을 comeToMe로 확정할 수 있는가 |
Cloud/On-device contract 고정 필요 |
공통 TaskManager에 붙일 것인가, ComeToMeTaskManager를 별도 둘 것인가 |
상태 머신 책임과 코드 소유권 결정 |
| DoA/Vision/AMR/FollowMe callback payload에 어떤 필드를 줄 수 있는가 | reason/event schema 확정 필요 |
| roomName/pose/mapId store는 어디에서 관리하는가 | 0-2 장소 이동의 필수 의존성 |
| speaker profile store와 개인정보 정책은 누가 구현하는가 | stage 1 기능의 필수 의존성 |
| FollowMe 시작 시 seed target을 받을 수 있는가 | 도착 후 대상 연속성 검증 방식 결정 |
| Vision은 bbox 외에 distance/bearing을 줄 수 있는가 | target_pose 생성과 안정성 판단에 필요 |
| AMR target_pose frame은 map frame인가 local frame인가 | 등록 좌표와 이동 좌표의 정합성 결정 |
| 동시에 여러 ComeToMe task를 허용할 것인가 | 중복 호출/취소 정책 결정 |