Speaker Identity Service Planning
이 문서는 Voice ID를 제품 서비스 identity 체계 안에서 어떻게 정의할지 정리한다.
현재 제품에는 최소 세 종류의 사용자 식별 단서가 존재한다.
- 컨트롤 앱 계정: 앱 로그인 계정이며, 계정에 사용자 이름이 붙어 있다.
- 바이탈 사인 얼굴 사용자 ID: 얼굴 인식 기반 건강 상태 체크 이력의 기준 ID다.
- 화자 인식 Voice ID: 음성 임베딩 기반으로 “누가 말했는지”를 추정하는 ID다.
핵심 결론은 OnDevice가 Voice ID와 Reference Embedding을 만들고 화자를 식별하며, Cloud는 둘을 Voice Sync Registry에 동기화한 뒤 Voice ID를 Person Profile에 연결한다는 것이다. Cloud Registry가 Reference Embedding을 보관하더라도 런타임 화자 매칭은 하지 않는다. Voice ID를 계정 또는 얼굴 ID와 무조건 1:1 대응시키면 안 된다. 계정, 얼굴, 목소리는 각각 다른 인증 강도와 생성 시점, 실패 모드, 개인정보 리스크를 가진다.
1. 왜 1:1 대응이 위험한가
| 항목 | 계정 | 바이탈 사인 얼굴 ID | Voice ID |
|---|---|---|---|
| 생성 주체 | 앱/계정 시스템 | 얼굴 인식/바이탈 사인 기능 | A1 OnDevice 화자 등록 |
| 입력 데이터 | 로그인/프로필 이름 | 얼굴 영상/얼굴 특징 | 음성/WAV/임베딩 |
| 인증 강도 | 계정 소유 기반 | 얼굴 매칭 기반 | 음성 매칭 기반 |
| 공유 가능성 | 가족 공용 계정 가능 | 얼굴은 개인 단위 | 목소리는 유사/변화 가능 |
| 실패 모드 | 로그인/권한 문제 | 조명/각도/마스크/카메라 | 소음/거리/감기/다화자 |
| 개인정보 민감도 | 계정 정보 | 생체/건강 정보 | 생체/음성 정보 |
| 적합한 역할 | 권한/소유/동의 | 건강 이력 기준 | 현재 발화 주체/context |
따라서 아래처럼 강제하면 위험하다.
voice_id == face_id == account_user_name
권장 구조는 다음이다.
Control App Account
-> Person Profile
-> linked_voice_ids[]
-> linked_vital_face_ids[]
-> display_name
-> consent_state
-> authority_level
-> personalization_profile
즉 Voice ID는 “계정”도 아니고 “얼굴 ID”도 아니다. Voice ID는 현재 발화의 주체를 추정하는 context key이고, 서비스가 개인화/건강 이력/권한을 쓰려면 Person Profile에 연결되어야 한다.
2. 권장 Identity 모델
2.1 계층 구조
| 계층 | 역할 | 예시 |
|---|---|---|
account_id |
앱/클라우드 계정 식별 | 가족 대표 계정, 관리자 계정 |
account_display_name |
계정에 붙은 사용자 이름 | “최용재” |
person_id |
실제 서비스 사용자 프로필 | person_001 |
voice_id |
한 기기의 로컬 음성 템플릿 등록 단위 | vp_opaque_uuid |
vital_face_id |
얼굴/바이탈사인 사용자 단위 | face_001 |
external_identity |
Google/Apple 등 외부 계정 연동 | google_sub, apple_sub |
권장 관계:
account_id 1 --- N person_id
person_id 1 --- N voice_id
person_id 1 --- N vital_face_id
person_id 1 --- N external_identity
이 구조를 쓰는 이유:
- 가족 공용 계정에서 여러 사람을 지원할 수 있다.
- 한 사람이 여러 voice sample 또는 여러 기기에서 등록한 voice_id를 가질 수 있다.
- 얼굴 인식과 화자 인식이 서로 실패해도 전체 identity가 무너지지 않는다.
- Google 계정 연동 같은 외부 identity를 나중에 추가해도 구조가 유지된다.
Voice ID는 nickname, account ID, device serial, embedding hash로 만들지 않는다. 한 사람이
여러 A1에 등록하면 기기마다 다른 Voice ID가 만들어지고, Cloud가 이들을 같은
person_id에 연결한다. nickname 변경은 Voice ID를 바꾸지 않으며, 삭제 후 재등록은 새
Voice ID를 만든다.
2.2 연결 상태
| 상태 | 의미 | 서비스 정책 |
|---|---|---|
unlinked |
voice_id는 있으나 person_id와 연결되지 않음 | 개인 건강/민감 정보 접근 금지 |
suggested |
얼굴/계정/이름 유사성으로 연결 후보 | 앱에서 확인 필요 |
linked |
사용자가 앱에서 연결 승인 | 개인화/이력 조회 가능 |
verified |
강한 인증 또는 반복 검증 완료 | 민감 서비스 허용 범위 확대 |
revoked |
연결 해제/삭제 | 이력 접근 중단, 캐시 삭제 |
3. 바이탈 사인 연동 서비스 확장
화자 인식이 Person Profile에 연결되면 다음 서비스가 가능해진다.
예시 발화:
내 최근 바이탈 상태 어때?
지난주보다 스트레스가 높아졌어?
요즘 심박 상태를 설명해줘.
내 건강 체크 이력 요약해줘.
서비스 흐름:
1. 사용자가 발화한다.
2. 온디바이스가 로컬 Voice ID를 추정한다.
3. Cloud가 Voice ID를 person_id에 조회하고 linked/verified 상태인지 확인한다.
4. person_id와 연결된 vital_face_id를 조회한다.
5. vital sign history를 가져온다.
6. Cloud LLM 또는 온디바이스 응답 계층이 안전한 요약을 생성한다.
7. 민감 정보이므로 신뢰도/권한/주변 사용자 상태에 따라 응답 범위를 제한한다.
정책:
| 조건 | 응답 가능 범위 |
|---|---|
| voice_id linked + 단일 화자 + confidence high | 개인 바이탈 이력 요약 가능 |
| voice_id linked but confidence medium | 확인 질문 후 제한 요약 |
| unknown speaker | 개인 이력 접근 금지 |
| multi-speaker/overlap | 개인 이력 접근 금지 |
| 주변 사용자 존재 가능 | 상세 수치 대신 앱 확인 유도 또는 확인 질문 |
| 미성년/게스트 권한 | 보호자/관리자 정책 필요 |
주의:
- 바이탈 사인은 건강 정보 성격이 있으므로 일반 개인화보다 높은 동의/권한 기준이 필요하다.
- LLM은 진단을 해서는 안 되며, “기록 기반 요약/추세 설명/앱 확인 안내” 수준으로 제한해야 한다.
- 신뢰도 낮은 voice_id로 건강 이력을 읽어주는 것은 제품 리스크가 크다.
4. 컨트롤 앱 계정과의 관계
현재 조건:
- 컨트롤 앱에는 계정이 있다.
- 계정당 사용자 객체가 붙는 구조가 아니라, 계정에 사용자 이름이 붙는 형태로 이해된다.
이 상태에서 Voice ID를 앱 계정에 바로 붙이면 아래 문제가 생긴다.
| 문제 | 설명 |
|---|---|
| 가족 공용 계정 | 한 계정으로 여러 사람이 제품을 쓰면 voice_id와 account_name이 불일치한다. |
| 이름 중복/변경 | 계정 표시 이름은 identity key로 안정적이지 않다. |
| 권한 모호성 | 계정 소유자와 실제 발화자가 다를 수 있다. |
| 삭제 범위 | 계정 삭제, voice 삭제, face 삭제가 서로 다른 범위일 수 있다. |
권장:
- 앱 계정은 소유/관리/동의의 루트로 둔다.
- 실제 사용자는
Person Profile로 별도 관리한다. - 계정 표시 이름은
person.display_name의 초기 후보로만 사용한다. - voice_id, face_id, Google 계정은
Person Profile에 link되는 방식으로 관리한다.
5. Google 계정 연동 확장성
Google 계정 연동은 Voice ID 자체를 대체하지 않는다. Google 계정은 외부 인증/캘린더/개인 서비스 연결을 위한 identity provider다.
확장 예시:
| 서비스 | 필요한 연결 |
|---|---|
| 개인 일정 읽기 | person_id -> google_sub -> calendar permission |
| 개인 루틴 추천 | person_id -> preference profile -> schedule/vital/device history |
| 개인 알림 | person_id -> external identity or app push token |
| 음성 기반 권한 확인 | voice_id -> person_id -> account role |
| 건강/바이탈 요약 | voice_id -> person_id -> vital_face_id |
권장 모델:
{
"person_id": "person_001",
"display_name": "용재",
"linked_identities": {
"voice_ids": ["voice_001"],
"vital_face_ids": ["face_001"],
"external_accounts": [
{
"provider": "google",
"subject": "google_sub_hash",
"scopes": ["calendar.readonly"],
"linked_at": "2026-07-07T00:00:00Z"
}
]
},
"consent_state": {
"voice_personalization": true,
"vital_history_summary": true,
"external_calendar": false
}
}
6. 개인화 서비스 기획 방향
6.1 Must
| 기능 | 이유 |
|---|---|
| Voice ID를 Person Profile에 연결/해제 | 개인화의 기본 단위 |
| voice_id confidence 기반 응답 범위 제한 | 오인식 리스크 방지 |
| unknown/multi-speaker에서 민감 정보 차단 | 개인정보/건강 정보 보호 |
| 앱에서 연결 상태 확인/수정 | 사용자 통제권 |
| voice_id 삭제와 history 삭제 | 개인정보 관리 |
6.2 Should
| 기능 | 이유 |
|---|---|
| Voice ID와 Vital Face ID 연결 | 바이탈 이력 설명 서비스 확장 |
| 사용자별 선호 공간/모드/스케줄 기억 | 로봇 개인화 가치 |
| 권한 등급 | 가족/게스트/아이 상황 대응 |
| Google 계정 연동 | 일정/루틴/외부 서비스 확장 |
6.3 Could
| 기능 | 이유 |
|---|---|
| 감정/긴급도 추정 | 사용자 상태 context 확장 |
| 다중 화자 회의식 요약 | 가정 내 여러 사용자 context |
| 프로필 자동 merge suggestion | voice/face/account 연결 편의성 |
7. 성능/UX 리스크: 화자인식 지연
화자인식은 STT 이후 추가 처리로 들어가기 때문에 응답 지연이 생긴다.
현재 예상:
STT 완료 후 speaker identification 추가 지연: 약 0.5초 이내
리스크:
| 리스크 | 설명 |
|---|---|
| 체감 응답 지연 | 사용자는 STT가 끝난 뒤 바로 응답을 기대한다. |
| Cloud fallback 지연 누적 | STT -> speaker ID -> Cloud LLM -> TTS 순서면 전체 턴 시간이 늘어난다. |
| 다화자/겹침 분석 비용 | diarization까지 매번 수행하면 짧은 명령에서도 비용이 생긴다. |
| 저사양/부하 상황 | 로봇 이동/청정/센서 처리와 동시에 실행 시 latency 변동 가능 |
대응:
| 대응 | 설명 |
|---|---|
| 단계적 적용 | 민감/개인화 기능에만 speaker ID를 blocking 처리한다. |
| fast path | 일반 기능은 speaker context 없이 먼저 처리하고, speaker 결과는 memory/profile에 후처리 반영한다. |
| cache/recent speaker | 직전 화자 boost와 최근 화자 cache로 반복 발화 비용을 줄인다. |
| timeout policy | 0.5초 내 결과가 없으면 speaker_state=unknown_timeout으로 내려가 기존 기능을 유지한다. |
| async enrichment | Cloud 요청에는 unknown으로 보내고, speaker 결과가 늦게 나오면 다음 turn context에 반영한다. |
| UX copy | 민감 정보 접근 시에만 “사용자 확인 중입니다” 같은 짧은 안내를 사용한다. |
권장:
- 모든 발화에 speaker identification을 blocking으로 걸지 않는다.
- 건강/계정/개인 일정/개인 memory/권한이 필요한 기능에만 blocking gate를 적용한다.
- 이동/청정 같은 일반 명령은 정책에 따라
unknown에서도 확인 질문 또는 제한 실행이 가능해야 한다.
8. 의사결정이 필요한 질문
| 질문 | 권장 방향 |
|---|---|
| Voice ID를 계정과 1:1로 묶을 것인가? | 아니오. Person Profile을 중간 계층으로 둔다. |
| Voice ID를 Vital Face ID와 1:1로 묶을 것인가? | 아니오. 사용자 승인 기반 link 관계로 둔다. |
| 계정 표시 이름을 사용자 identity로 쓸 것인가? | 아니오. display name 후보로만 사용한다. |
| 건강 이력 조회를 voice만으로 허용할 것인가? | linked/verified + confidence high + 단일 화자 조건에서만 제한 허용한다. |
| Google 계정은 무엇을 의미하는가? | 외부 서비스 권한 provider이며 voice/face를 대체하지 않는다. |
| 0.5초 지연을 모든 기능에 감수할 것인가? | 아니오. 민감/개인화 기능에만 blocking 적용한다. |
9. 다음 문서/구현 반영점
- Speaker Context Contract에
person_id,linked_identity_state,consent_scope후보를 추가 검토한다. - Speaker Memory Management는
speaker_id뿐 아니라person_id기준 memory scope를 함께 다뤄야 한다. - TaskManager Integration은 side-effect gate 외에 personal data access gate를 추가해야 한다.
- Privacy And Safety은 voiceprint뿐 아니라 vital history, external account scope까지 포함해야 한다.
- Implementation Roadmap은
identity link티켓을 별도 phase로 추가해야 한다.