← Docs hub

보이스 프로필 연동 규격

이 페이지는 E2E Sample 참고 자료다. 직접 구현 협의는 담당별 범위, DeviceAgent ↔ AI-Agent 구현 요청서, DeviceAgent ↔ 등록 App 구현 요청서를 사용한다. 아래 APP·Backend·IoTAgent의 API·토픽은 외부 담당들이 협의할 제품 설계를 강제하지 않는다.

09-17 변경: 관심사 원본은 서버로 이전했다. App의 최초 등록 후·상시 변경은 HTTPS 저장이며, AI-Agent 조회는 반대 방향인 AI-Agent → DeviceAgent → IoTAgent → 서버다. 신규 필드·토픽·그림. 아래 interestsSet/interestsGet은 이전 로컬 규격으로 현재 AI-Agent가 SERVER_OWNED_PERSONALIZATION을 반환한다.

담당별 시작 위치

이 페이지는 전체 연결과 시나리오의 기준이다. 실제 코딩에 필요한 필드·타입·예제는 아래 상세 명세에서 확인한다.

내가 개발하는 모듈 연결할 상대 구현할 내용 상세 명세
DeviceAgent Registration App·AI-Agent·IotAgent Binder 요청 분기, 호출자 검증, 등록 화면 실행, callback 중계, commit 저장/응답 함수·Bundle 명세
IotAgent DeviceAgent·AWS IoT Core MQTT 구독/발행, action→method 변환, JSON↔Bundle 타입 보존, 실패 결과 반환 IoT Core 토픽 명세 + callback 배선
모바일 App AWS Backend 등록·취소·조회·삭제 API, 등록 상태 실시간 표시, 오류 화면 HTTPS API + 실시간 상태
AWS Backend·관제 모바일 App·IotAgent 계정/기기 권한, MQTT 요청/결과 연결, 상태 API, Cloud 저장/ACK HTTPS·MQTT 명세
Registration App DeviceAgent 경유 AI-Agent 등록 제어 Bundle 전송, 상태 callback 표시 등록 제어 + 상태 callback
AI-Agent DeviceAgent 녹음/식별 실행, 상태 생성, 프로필 commit, 관리 결과 프로필 전달 + 관리 API

상세 명세에서 확인할 것

기기 Binder는 등록 App ↔ DeviceAgent와 AI-Agent ↔ DeviceAgent로 나눠 요청·응답 값을 확인한다.

문서 들어 있는 내용 이 문서만으로 확정하지 않는 것
등록 App·AI-Agent ↔ DeviceAgent 인터페이스 정의 실제 함수, 메서드별 필수 입력, Android 타입, 수신 대상, 비동기 결과, Kotlin 예제 제품 Cloud 저장 완료 처리
IoTAgent ↔ IoT Core 토픽 명세 발행·구독 주체, 9종 action, JSON 필드·결과, 상태/대화 이벤트, QoS·만료·오류 임베딩 업로드·Cloud ACK의 미확정 wire format
모바일·관제 HTTPS·MQTT 명세 URL/method, JSON 예제, 토픽과 발행/구독, 타입 변환, HTTP 오류, SSE 제품 인증 API, 임베딩 업로드 wire format, Cloud ACK 토픽

현재 코드에 있는 계약과 제품에서 추가 정의할 계약을 혼동하지 않는다. 추가 항목은 Cloud 전달 경계에 모았다.

읽는 순서

  1. 아래 흐름도에서 내 모듈의 송신·수신 상대를 확인한다.
  2. 담당별 상세 명세에서 요청 Bundle/JSON과 결과 callback을 한 쌍으로 구현한다.
  3. 상태·오류 표를 화면과 Backend 처리에 연결한다.
  4. 상세 명세의 구현 확인 항목으로 정상·실패·취소를 각각 시험한다.

먼저 보는 결론

  1. 모바일 App은 HTTPS만 사용하고 MQTT에 직접 연결하지 않는다.
  2. A1에서 MQTT에 연결하는 모듈은 IotAgent 하나다.
  3. DeviceAgent는 요청과 호출자를 검증하고 Binder 메시지를 중계한다.
  4. 등록 App은 UI를, OnDevice Agent Service는 녹음·검증·프로필 생성을 담당한다.
  5. 한 작업은 시작부터 종료까지 같은 requestId를 사용한다.
  6. 원본 음성과 Query Embedding은 MQTT·Cloud로 보내지 않는다.
  7. 현재 로컬 PoC와 제품 AWS 연동은 같은 것이 아니다.

보이스 프로필 프로토콜 흐름

프로토콜 흐름 크게 보기

구현 상태 표시

표시 의미
구현됨 현재 소스에서 경로와 검증 로직을 확인함
PoC 전용 로컬 Gateway·MQTT·시스템 프로퍼티를 이용한 시험 경로
제품 필요 AWS Backend/IotAgent/DeviceAgent에 추가 연동이 필요한 부분

계약 버전

범위 contractVersion
등록·프로필 조회·삭제 voice-profile-v2
서버 관심사 조회·응답 voice-personalization-v1

지원하지 않는 버전은 실행하지 않는다. 제품에서는 오류 응답까지 반환해야 하며, 현재 일부 수신 경로는 로그만 남기고 반환하므로 보완이 필요하다.

통신 경계

송신 → 수신 방식 현재 상태 목적
모바일 App → AWS Backend HTTPS/JSON 제품 필요 등록·취소·조회·삭제·관심사 요청
AWS Backend ↔ AWS IoT Core AWS SDK/MQTT 제품 필요 기기 명령과 상태 전달
PC Gateway ↔ 로컬 MQTT HTTP/SSE + MQTT PoC 전용 AWS 없이 모바일 Sample 시험
MQTT → IotAgent MQTT JSON 명령 수신 구현됨 A1의 MQTT 단일 진입점
IotAgent ↔ DeviceAgent Binder Bundle 구현됨 JSON과 기기 내부 계약 변환
DeviceAgent ↔ 등록 App Binder callback + Activity 구현됨 화면 실행과 실시간 상태 전달
DeviceAgent ↔ OnDevice Agent Service Binder Bundle 구현됨 등록 제어·프로필 전달·관리 API

등록 메시지 흐름

보이스 프로필 등록 메시지 흐름

등록 메시지 흐름 크게 보기

프로필 조회와 삭제 흐름

모바일 App의 목록은 Gateway 캐시가 아니라 A1 기기에 로컬 저장된 프로필을 조회한다. 조회는 기기에 저장된 프로필 목록이며 Cloud 동기화 완료 목록이 아니다. 삭제는 voiceId를 기준으로 로컬 프로필·임베딩을 정리한다. 서버 관심사 삭제는 서버 후속 처리다. DeviceAgent의 전달 대기 사본 삭제는 별도 시도이며 실패해도 기존 성공 결과가 전달될 수 있다. 전체 사본 삭제나 Cloud 삭제 완료로 해석하지 않는다.

보이스 프로필 조회와 삭제 흐름

프로필 조회와 삭제 흐름 크게 보기

서버 관심사 조회 흐름

관심사는 서버가 voiceId를 기준으로 관리하고 모바일 App에서 변경한다. AI-Agent가 getVoicePersonalization을 요청하면 DeviceAgent → IoTAgent → 서버로 전달하고, 역방향 voicePersonalizationResult 콜백의 interestCodes:ArrayList<String>으로 받는다. AI-Agent 로컬 DB 조회가 아니다. 현재 샘플 MQTT 경로와 실제 AWS 운영 연결은 구분한다.

서버 관심사 저장과 기기 조회 흐름

관심사 흐름 크게 보기

전체 시나리오 흐름

등록 시작, 진행 상태, 완료와 Cloud ACK, 취소·실패, 목록 조회·삭제를 한 화면에서 확인할 수 있다. 실선은 현재 기기 구현 경로이고, 보라색 점선은 제품 AWS 연동에서 추가해야 하는 경로다.

보이스 프로필 전체 시나리오 흐름

전체 시나리오 흐름 크게 보기

모바일 HTTPS API

아래 경로는 현재 PC Gateway와 모바일 Sample App에서 동작한다. 제품 AWS Backend는 같은 의미를 유지해 구현한다.

Method Path 설명
POST /voice-profiles/enrollments 등록 시작
GET /voice-profiles/enrollments/{requestId} 등록 상태 조회
POST /voice-profiles/enrollments/{requestId}/cancel 등록 취소
GET /voice-profiles?deviceId=... 기기 등록 화자 조회
DELETE /voice-profiles/{voiceId}?deviceId=... 화자 삭제
GET /voice-profiles/{voiceId}/interests 관심사 조회
PUT /voice-profiles/{voiceId}/interests 관심사 저장
GET /voice-events?deviceId=... PoC 실시간 SSE 이벤트

등록 시작 요청

{
  "contractVersion": "voice-profile-v2",
  "requestId": "vp-20260911-0001",
  "method": "startVoiceProfileEnrollment",
  "deviceId": "A1-001",
  "nickname": "silogood",
  "locale": "ko-KR",
  "personalizationEnabled": true,
  "issuedAtMs": 1789092000000,
  "expiresAtMs": 1789092300000
}
필드 설명 규칙
requestId 한 등록 작업의 추적 ID 재시도해도 같은 작업이면 유지
deviceId 대상 A1 기기 Backend가 접근 권한 확인
nickname 표시 이름 식별 키로 사용하지 않음
locale 등록 화면·발화 언어 예: ko-KR, en-US
personalizationEnabled 개인화 사용 여부 true 또는 false
issuedAtMs 명령 생성 시각 Unix epoch millisecond
expiresAtMs 명령 만료 시각 현재 Sample은 생성 후 5분

MQTT 계약

토픽

방향 토픽 QoS 상태
Backend → A1 skmg/airbot/{deviceId}/v1/command/voiceProfileEnrollment 1 권장 명령 수신 구현됨
A1 → Backend skmg/airbot/{deviceId}/v1/response/voiceProfileEnrollment/{requestId} 1 권장 로컬 Bridge만 구현됨

상태 이벤트와 최종 결과는 현재 PoC에서 같은 response 토픽에 발행된다. 제품 AWS에서도 requestId가 포함된 동일 응답 경로를 사용하면 모바일·Backend의 상관관계 처리가 단순해진다.

명령 봉투

{
  "action": "start",
  "payload": {
    "contractVersion": "voice-profile-v2",
    "requestId": "vp-20260911-0001",
    "nickname": "silogood",
    "locale": "ko-KR",
    "personalizationEnabled": true,
    "issuedAtMs": 1789092000000,
    "expiresAtMs": 1789092300000
  }
}
action DeviceAgent 메서드 계약
start startVoiceProfileEnrollment voice-profile-v2
cancel cancelVoiceProfileEnrollment voice-profile-v2
list listVoiceProfiles voice-profile-v2
delete deleteVoiceProfile voice-profile-v2
interestsSet setVoiceProfileInterests voice-memory-v1
interestsGet getVoiceProfileInterests voice-memory-v1

상태 이벤트

{
  "contractVersion": "voice-profile-v2",
  "method": "voiceProfileStateChanged",
  "requestId": "vp-20260911-0001",
  "stateSequence": 8,
  "state": "SET_ACCEPTED",
  "setIndex": 2,
  "setCount": 5,
  "progress": 100,
  "reasonCode": "",
  "terminal": false,
  "nickname": "silogood"
}
필드 설명
stateSequence UI가 이전보다 큰 값만 반영하는 상태 순번. 현재 생성 완료·품질 실패 경로의 송신 순번 보완 필요
state 등록 상태 enum
setIndex / setCount 현재 녹음 세트와 전체 세트 수
progress 현재 단계 진행률 0..100
reasonCode 실패·대기 이유. 성공이면 빈 문자열 가능
terminal true면 더 이상 진행되지 않는 최종 상태
voiceId COMPLETED에서 필수

Binder 메서드

등록 화면과 세션 제어

메서드 호출 방향 설명
getVoiceProfileEnrollmentState 등록 App → Service 최신 상태 복구
startVoiceProfileEnrollment DeviceAgent/등록 App → Service 등록 시작
retryVoiceProfileSet 등록 App → Service 실패한 세트 재녹음
pauseVoiceProfileEnrollmentForExit 등록 App → Service 나가기 확인 동안 일시 정지
cancelVoiceProfileEnrollment 등록 App/IotAgent → Service 등록 취소
setVoiceProfilePersonalization 등록 App → Service 개인화 설정 저장
retryVoiceProfileCreation 등록 App → Service 로컬 프로필 생성 재시도
retryVoiceProfileDelivery 등록 App → Service DeviceAgent 전달 재시도
closeVoiceProfileRegistration 등록 App → Service 등록 UI 종료
voiceProfileStateChanged Service → 등록 App/IotAgent 실시간 상태 이벤트

프로필 전달과 관리

요청 결과 설명
commitVoiceProfile voiceProfileCommitResult 생성 프로필을 DeviceAgent에 전달
listVoiceProfiles voiceProfileListResult 등록 화자 조회
deleteVoiceProfile voiceProfileDeleteResult 프로필과 관련 데이터 삭제
setVoiceProfileInterests voiceProfileInterestsResult 관심사 저장
getVoiceProfileInterests voiceProfileInterestsResult 관심사 조회

등록 상태 enum

값 의미 terminal
WAITING_START 사용자 시작 대기 false
RECORDING_SET 현재 세트 녹음 중 false
SET_ACCEPTED 현재 세트 통과 false
SET_REJECTED 현재 세트 거절, 재녹음 가능 false
PERSONALIZATION_SETTINGS 개인화 사용 여부 선택. 발음 수정 아님 false
CREATING_LOCAL_PROFILE 임베딩·Voice ID 생성 false
PENDING_DEVICE_DELIVERY DeviceAgent 전달 중 false
COMPLETED 등록 완료 true
PROFILE_FAILED 시작 거절 또는 로컬 프로필 생성 실패 시작 거절 true / 생성 실패 false
DELIVERY_FAILED DeviceAgent 또는 Cloud 전달 미완료, 재시도 가능 false
CANCELLED 사용자·원격 취소 true

SET_REJECTED, PROFILE_FAILED, DELIVERY_FAILED는 재시도 UI를 제공할 수 있지만 해당 상태 이벤트 자체는 현재 세션 결과를 나타낸다.

오류와 대기 코드

오디오·임베딩 검사

코드 의미 권장 UI
NO_SPEECH 음성 샘플 없음 다시 녹음
TOO_SHORT 유효 길이 부족 더 길게 말하도록 안내
INVALID_AUDIO 유효하지 않은 샘플 다시 녹음
TOO_QUIET 음량 부족 기기에 가까이 말하도록 안내
TOO_LOUD 클리핑 과다 조금 떨어져 말하도록 안내
AUDIO_BIAS DC 편향 과다 다시 녹음
INSUFFICIENT_SPEECH 실제 발화 구간 부족 문장을 이어 말하도록 안내
TOO_NOISY 신호 대 잡음비 부족 조용한 곳에서 다시 녹음
INVALID_EMBEDDING 임베딩 값·차원 오류 프로필 생성 재시도
INCONSISTENT_SPEAKER 세트 간 동일 화자 조건 미달 같은 사용자가 다시 등록

취소·전달

코드 의미 현재 처리
USER_CANCELLED 등록 App에서 취소 임시 데이터 정리
MOBILE_CANCELLED 모바일 원격 취소 같은 requestId 세션 취소
DEVICE_DELIVERY_REJECTED DeviceAgent가 프로필 payload 거절 DELIVERY_FAILED
DEVICE_OUTBOX_FAILED 암호화 대기 저장 실패 commit 거절
WAITING_CLOUD_SYNC DeviceAgent 저장은 성공, Cloud ACK 미연결 DELIVERY_FAILED, 제품 연동 필요
LOCAL_TEST_ACK PoC 강제 완료 Cloud 완료로 해석 금지

프로필 commit 계약

Service가 DeviceAgent에 전달하는 필드는 다음과 같다.

필드 필수 설명
requestId O 등록 요청 추적 ID
voiceId O Service가 생성한 식별 ID
nickname O 표시 이름
locale O 기본 언어
personalizationEnabled O 개인화 사용 여부
referenceEmbedding O 등록 대표 임베딩. 원본 음성이 아님

현재 DeviceAgent는 payload를 검증한 뒤 EncryptedSharedPreferences 기반 대기 저장소에 저장한다.

{
  "contractVersion": "voice-profile-v2",
  "method": "voiceProfileCommitResult",
  "requestId": "vp-20260911-0001",
  "accepted": true,
  "cloudSynced": false,
  "reasonCode": "WAITING_CLOUD_SYNC"
}

현재 대기 저장소에 구현된 기능은 save()와 removeByVoiceId()다. 목록 조회, 재부팅 후 자동 재전송, Cloud ACK 수신 및 ACK 후 삭제는 제품 구현이 필요한 기능이다.

순서·중복·만료 처리

<a id="implementation-gaps"></a>

현행 한계와 담당별 보완

아래는 구현 완료 항목이 아니라 제품 적용 전 남은 작업이다. 실제 메서드·기본값은 Binder 13절을 함께 확인한다.

담당 현재 확인된 한계 완료 조건
AI-Agent 같은 start가 세트 초기화 동일 요청 재수신은 기존 상태 반환, 녹음 중복 시작 없음
AI-Agent 생성 중 취소 후 늦은 완료, 700ms 후속 작업 실행 가능 취소·새 요청 이후 이전 작업이 상태·저장 결과를 되살리지 않음
AI-Agent 이전 session 복사로 상태 순번 역전 가능 모든 상태 경로에서 순번 증가; UI가 완료/오류를 놓치지 않음
AI-Agent·등록 App 생성 실패 후 세트가 비워져 생성 재시도 무동작 가능 남은 데이터에 맞춰 재녹음 또는 재생성을 안내
등록 App·DeviceAgent·IotAgent 충돌·화면 실행 실패·잘못된 요청이 원격에 무응답일 수 있음 실패를 같은 requestId로 전달하고 모바일 대기 종료
DeviceAgent UID에 속한 패키지 중 하나가 허용되면 통과 공유 UID 신뢰 범위를 명시하고 개별 앱 구분 필요 시 인증 방식 보완
AI-Agent·DeviceAgent 로컬 삭제는 전체 트랜잭션 아님; 대기 사본 제거 실패가 성공 응답에 가려짐 부분 실패 표시, 재시도·재조회로 각 사본 삭제 확인
IotAgent·AWS Backend 제품 결과 발행·임베딩 업로드·Cloud ACK 미연결 업로드 형식·저장 ACK·실패 응답 확정 후 실제 AWS 연동
DeviceAgent·AI-Agent·AWS Backend ACK 대기 타이머·재부팅 복구 미완성 대기 저장 조회·재전송·늦은 ACK 처리·성공 후 정리 검증

등록 Service의 세션/pending은 메모리다. DeviceAgent의 암호화 대기 파일이 있다고 해서 Service 세션이 재부팅 후 자동 복구되는 것은 아니다.

보안과 데이터 제한

PoC 실행 경로

현재 로컬 시험은 다음 경로를 사용한다.

모바일 Sample App
  → HTTP/SSE
PC Gateway :8788
  → 로컬 MQTT :1883
IotAgent VoiceProfileMqttTestBridge
  → DeviceAgent → 등록 App / OnDevice Agent Service

IotAgent 시험 Bridge는 persist.sys.vp.mqtt_test_uri로 활성화한다. adb reverse tcp:1883 tcp:1883은 USB/ADB 연결 시험용이며 제품 통신 경로가 아니다.

제품 구현 점검표

항목 현재 완료 조건
제품 MQTT 명령 수신 구현됨 AWS IoT Core에서 시작·취소·조회·삭제 확인
제품 MQTT response/event 발행 미연결 IotAgent가 상태와 결과를 AWS에 발행
계정-voiceId 연결 미구현 Backend Registry 저장·조회·삭제
Reference Embedding 업로드 미구현 암호화 업로드와 접근 통제
Cloud ACK 미구현 DeviceAgent까지 ACK 반환
대기 데이터 재전송 미구현 재부팅·네트워크 복구 후 자동 재시도
ACK 후 대기 데이터 삭제 미구현 성공 ACK에 한해 삭제
원본 음성 비전송 구현됨 로그·Binder·MQTT에서 PCM/WAV 없음 확인

연동 시험 순서

아래는 완료 판정에 필요한 시험 목록이며 모두 통과했다는 결과표가 아니다. 특히 중복 시작·생성 중 취소·순번 역전은 위 보완 이후 회귀 시험이 필요하다.

  1. 같은 requestId가 모바일, Gateway/Backend, MQTT, IotAgent, DeviceAgent, Service 로그에 남는지 확인한다.
  2. WAITING_START → RECORDING_SET → ... → COMPLETED와 증가하는 stateSequence를 확인한다.
  3. 실패 세트에서 SET_REJECTED와 정확한 reasonCode가 오는지 확인한다.
  4. 취소 후 녹음이 멈추고 CANCELLED, terminal=true가 오는지 확인한다.
  5. COMPLETED에 유효한 voiceId가 있는지 확인한다.
  6. 등록 후 list 결과와 기기 로컬 매칭 결과가 같은 voiceId인지 확인한다.
  7. 패킷·로그·저장소에 원본 PCM/WAV가 없는지 확인한다.
  8. 제품 AWS 경로에서는 Cloud ACK 전후의 대기 저장 유지·삭제를 별도로 확인한다.

/health 성공이나 빈 profile 목록 응답은 연결만 증명한다. 등록 성공은 같은 requestId의 COMPLETED + terminal=true + voiceId까지 확인해야 한다.

구현 근거와 상세 문서

기준 코드는 VoiceProfileContract.java, CmdTopic.java, VoiceProfileMqttTestBridge.java, DeviceAgent.java, VoiceProfilePendingStore.java, VoiceProfileIpcContract.kt와 ForegroundService.kt다.

Keyboard shortcuts

⌘K / Ctrl+KOpen command palette
/Focus search
g hGo to home
g pGo to projects
g sGo to sessions
j / kNext / prev row (tables)
?Show this help
EscClose dialogs

Structured queries

Mix key:value filters with free text in the palette:

type:sessionOnly session pages
project:llm-wikiFilter by project name (substring)
model:claudeFilter by model name (substring)
date:>2026-03-01Sessions after a date
date:<2026-04-01Sessions before a date
tags:rustPages mentioning a tag/topic
sort:dateSort results by date (newest first)

Example: type:session project:llm-wiki date:>2026-04 sort:date