프로젝트 문제 해결

화자 분리(Speaker Diarization) 설계: STT와는 다른 문제

AI아키텍트 2026. 7. 30. 14:16

회의록 제품에서 가장 자주 오해되는 지점 하나는, "음성 인식만 좋으면 화자 구분도 자연스럽게 따라온다"는 가정입니다.

실제로는 그렇지 않습니다. 무엇을 말했는지를 맞히는 문제와 누가 언제 말했는지를 맞히는 문제는 같은 원음에서 출발할 수 있지만, 최적화 목표·출력·평가 지표가 다르며 대개 별도 모듈로 구현되고, 다른 방식으로 실패합니다. 두 결과를 하나의 자막으로 합치려면 별도의 정렬(alignment) 단계까지 필요합니다.

이 글은 실시간 STT를 이미 갖춘 시스템에 화자 정보를 붙일 때, 화자 분리(Speaker Diarization)를 하나의 독립된 설계 대상으로 다루는 방법을 정리합니다. 그리고 순수 diarization에 그치지 않고, 익명 화자 라벨을 실제 참석자에 연결하는 화자 귀속(attribution) 과 그에 따르는 프라이버시·다운스트림 활용까지 범위에 포함합니다. 필자는 WebRTC 기반 서버 녹화와 화자별 WebSocket 자막, Faster-Whisper STT(CPU 및 NVIDIA DGX Spark 환경에서 측정)로 양방향 음성·화자별 자막·참가자별 서버 녹화 파일까지 이어지는 실시간 파이프라인을 개발·상용화 검증했으며, 그 과정에서 얻은 설계 관점을 공유합니다.

실시간 STT 자체의 설계(리샘플링, Partial·Final 자막 상태, 환각 억제)는 별도 글에서 다뤘습니다: 실시간 STT 설계. 회의 음성을 RAG까지 연결하는 전체 흐름을 다룬 글(회의 음성에서 RAG까지)에서 "STT ≠ 화자분리"라고 짧게 언급했는데, 이 글은 그 문장을 설계 수준으로 확장한 것입니다. STT 파이프라인은 재설명하지 않습니다.

먼저 용어 세 개를 분리하는 것에서 시작합니다.

1. 세 가지 문제를 먼저 분리한다: STT · Diarization · Speaker Identification

한 문장으로 들으면 비슷해 보이는 세 작업은 목적이 완전히 다릅니다.

작업 답하는 질문 출력 필요한 사전 정보
음성 인식 (STT, Speech-to-Text) 무엇을 말했나 텍스트 + 단어/세그먼트 타임스탬프 불필요
화자 분리 (Diarization) 누가(익명 라벨) 언제 말했나 화자 라벨이 붙은 시간 구간 불필요
음향 기반 화자 식별 (Speaker Identification) 그 익명 화자가 실제로 누구인가 실명/사용자 ID로의 매핑 등록 음성·성문 템플릿 등 enrollment 정보 필요
메타데이터 기반 참석자 귀속 (Attribution) 그 익명 화자를 어느 참석자로 볼 것인가 참석자 후보로의 매핑 인증된 세션·트랙 소유권 및 참석자 명단 필요

핵심 차이는 네 번째 열입니다. 특히 "실제로 누구인가"를 목소리로 판별하는 것(음향 기반 식별)과 세션 소유권·명단으로 후보를 좁히는 것(메타데이터 기반 귀속)은 근거가 전혀 다릅니다. 참석자 명단은 후보 집합을 제한할 뿐, 특정 음성이 누구인지 판별하지 못합니다.

  • STT는 음향 입력을 텍스트 토큰으로 변환하며, 구현은 전통적인 음향·언어 모델 결합 방식부터 end-to-end 모델까지 다양합니다. 어느 쪽이든 화자 정보는 원래 관심사가 아닙니다.
  • Diarization은 목소리의 음향적 특징만으로 몇 명이, 어느 구간을 말했는지 구분합니다. 이때 나오는 라벨은 Speaker A, Speaker B 같은 익명 라벨입니다. 모델은 "이 목소리가 김 아무개다"라고 말하지 못합니다. 그저 "구간 1·3·5는 같은 사람, 구간 2·4는 다른 사람"이라고 말할 뿐입니다.
  • Speaker Identification은 그 익명 화자를 실제 신원에 연결합니다. 이건 등록된 성문(voiceprint)이나 회의 참석자 명단 같은 외부 정보가 있어야 가능합니다.

이 구분이 설계에서 중요한 이유는, 많은 요구사항이 실제로는 서로 다른 작업을 섞어서 말하기 때문입니다. "화자별로 자막 보여줘"는 Diarization이면 되지만, "발언자 실명으로 자막 보여줘"는 Diarization 결과에 음향 기반 Identification 또는 신뢰 가능한 세션·트랙 기반 참석자 귀속을 결합해야 합니다. 참가자별 인증 트랙이 신뢰 가능한 환경이라면 음향 Identification 없이 메타데이터 귀속만으로 실명을 표시할 수도 있습니다. 뒤(9장)에서 다시 다룹니다.

한 가지 더 구분해 둘 것이 있습니다. 위 표의 "화자 식별"은 실무에서 서로 다른 세 가지 근거로 이뤄지며, 이 글은 이 셋을 분리해서 다룹니다.

  • 음향 기반 화자 식별: 사전 등록된 성문(voiceprint)과 음성을 비교해 신원을 추정합니다.
  • 메타데이터 기반 참석자 귀속: 인증된 세션·트랙의 소유자 정보(누가 어느 스트림을 소유하는가)를 근거로 발화를 참석자에 연결합니다. 목소리가 아니라 네트워크·세션 소유권을 근거로 삼습니다.
  • 사용자 확인: 위 두 자동 근거가 만든 제안을 사람이 최종 확정합니다.

이 셋은 신뢰 근거와 오류 특성이 서로 다르므로 뒤에서 별개로 취급합니다.

2. 왜 "STT가 좋으면 화자도 따라온다"가 틀린가

Diarization과 STT가 다른 문제라는 걸 가장 빠르게 이해하는 방법은, 각 작업이 무엇을 최적화하는가를 보는 것입니다.

  • ASR(STT)의 학습 목표는 화자 신원이 아니라 발화 내용이므로, 화자 구분에 필요한 정보가 출력 계약에 보존된다고 기대할 수 없습니다. (참고로 Faster-Whisper가 기반으로 하는 Whisper는 전통적인 "음향 모델 + 언어 모델" 분리 구조가 아니라 end-to-end encoder-decoder Transformer입니다.)
  • 반대로 전형적인 음향 기반 Diarization은 발화 의미보다 목소리의 개인차에 집중합니다(어휘 정보를 이용한 보정이나 ASR과의 결합 모델도 있습니다). 같은 문장을 두 사람이 말하면 STT 출력은 같지만 Diarization 출력은 달라야 합니다.

두 작업이 다른 방식으로 실패한다는 점도 결정적입니다.

상황 STT 영향 Diarization 영향
두 사람이 동시에 말함(overlap) 텍스트가 섞이거나 한쪽만 인식 한 구간에 두 화자가 겹쳐 라벨링 난이도 급상승
아주 짧은 맞장구("네", "그렇죠") 인식될 수 있으나 짧은 길이·문맥 부족으로 누락 가능 임베딩 표본이 부족해 라벨 흔들림
비슷한 음색의 두 사람 텍스트 정확도 영향 적음 두 사람을 한 화자로 합칠 위험
배경 소음/에코 오탈자·환각 잘못된 화자 경계, 화자 수 오판

결론은 명확합니다. STT 정확도를 높이는 것만으로 화자 오류가 자동으로 해소되지는 않습니다(VAD·잡음·타임스탬프 오차처럼 공통 원인이 있고 두 작업을 묶은 결합 모델도 있지만, 최적화 목표가 다르므로 화자 오류는 별도로 남습니다). 화자 분리는 별도 예산·별도 검증·별도 품질 지표로 다뤄야 하는 문제입니다.

3. 표준 오프라인 파이프라인: VAD → 임베딩 → 클러스터링 → 라벨링

가장 이해하기 쉬운 형태는 파일이 모두 준비된 뒤 실행하는 오프라인(배치) 파이프라인입니다. 실시간 설계를 이야기하기 전에, 기준선을 여기서 잡습니다.

아래는 전형적인 모듈형 diarization의 개념도이며, 특정 버전의 실제 내부 단계를 그대로 표현한 것이 아니라는 점을 먼저 밝혀 둡니다. 예컨대 pyannote.audio는 버전에 따라 클러스터링 방식(예: VBx)과 출력이 달라지며, 3.0부터는 segmentation 모델이 겹침 발화(Overlapped Speech)를 함께 다루는 등 예전의 독립 단계들이 diarization 내부로 통합되어 아래 모듈 경계와 그대로 대응하지 않습니다.

Audio (mono, 16kHz)
  → VAD (Voice Activity Detection)         # 말/비말 구간 판정
  → Segmentation / Speaker Change Detection # 화자 전환 후보 경계
  → Speaker Embedding (화자 벡터)           # 각 구간을 고차원 벡터로
  → Clustering (군집화)                     # 벡터를 화자별로 묶음
  → Segment Labeling                        # Speaker A / B / C 라벨 부여
  → (선택) Overlapped Speech Detection       # 겹침 구간 별도 처리

각 단계의 역할은 다음과 같습니다.

단계 하는 일 대표적 실패
VAD 침묵·소음을 걸러 말이 있는 구간만 남김 소음을 말로 오인(false alarm), 작은 말 놓침(missed)
화자 임베딩 구간을 음색·발화 스타일 벡터로 변환 짧은 구간에서 벡터 불안정
클러스터링 벡터 간 유사도로 화자 수와 소속 결정 화자 수 과소/과대, 유사 음색 병합
세그먼트 라벨링 군집을 시간 구간에 매핑 경계 근처 잘못된 소속

여기서 나오는 라벨은 반복해 강조하듯 익명입니다. Speaker A가 회의마다 같은 사람을 뜻하지도 않습니다. 다음 회의의 Speaker A는 전혀 다른 사람일 수 있습니다.

임베딩과 클러스터링의 관계를 감으로 잡기 위한 개념적 예시(실제 수치·코드 아님):

# 개념적 예시 - 특정 구현/라이브러리에 종속되지 않은 설명용 의사코드
# start/end 는 초 단위 시각이라고 가정한다.
speech_regions = vad(audio)                          # 말/비말 구간만 판정

# VAD 구간 하나에도 여러 화자가 섞일 수 있으므로,
# 임베딩 전에 화자 전환 경계로 '화자 동질' 구간을 먼저 나눈다.
segments = segment_speakers(audio, speech_regions)   # 화자 동질 구간

embeddings = [embed(slice_by_time(audio, s.start, s.end))  # 각 구간 -> 화자 벡터
              for s in segments]

labels = cluster(embeddings,                # 유사한 벡터끼리 묶기
                 metric="cosine",
                 num_speakers=None)          # None = 화자 수 미상 -> 추정

diarization = [
    {"start": s.start, "end": s.end, "speaker": f"SPEAKER_{lab}"}
    for s, lab in zip(segments, labels)
]

VAD는 말/비말만 구분하므로, 한 VAD 구간 안에서 화자가 바뀔 수 있습니다. 화자 동질 구간으로 먼저 쪼갠 뒤 임베딩해야 여러 화자가 섞인 벡터가 나오지 않으며, 이 순서가 앞의 파이프라인 그림과도 일치합니다. (초 단위 시각을 배열로 슬라이싱하려면 샘플레이트 변환이 필요하므로, 의사코드에서는 slice_by_time으로 표현했습니다.) 그리고 num_speakers=None이 핵심입니다. 화자 수를 모른 채 데이터에서 추정해야 한다는 것, 이것이 4장에서 다룰 실시간 난이도의 뿌리입니다.

4. 오프라인과 온라인(스트리밍)은 다른 제품이다

위 파이프라인은 "파일 전체를 볼 수 있다"는 전제 위에 있습니다. 클러스터링은 전 구간의 임베딩을 모아놓고 전체 임베딩을 이용해 일관된 군집화를 수행합니다(모든 구현이 전역 최적해를 보장하지는 않습니다). 회의가 끝난 뒤 녹취록을 만드는 상황이라면 이 방식이 정확도 상 유리합니다.

실시간 자막은 전혀 다릅니다. 아직 오지 않은 미래 음성을 볼 수 없는 상태에서, 방금 들어온 몇 초의 오디오만 보고 화자를 즉시 결정해야 합니다.

관점 오프라인(배치) 온라인(스트리밍)
입력 전체 오디오 도착하는 청크(chunk)
화자 수 전역적으로 추정 진행 중 갱신, 새 화자 등장 가능
클러스터링 전체 임베딩 기반 일관 군집화 증분(incremental), 되돌리기 어려움
라벨 안정성 한 번에 확정 이후 근거로 라벨이 바뀔 수 있음
지연 관대 엄격(수백 ms~수 초)
재계산 자유 과거 라벨 변경은 UX 충격

즉, 오프라인 Diarization과 온라인 Diarization은 같은 목적의 다른 제품입니다. 오프라인에서 잘 되던 구성을 그대로 스트리밍에 옮기면, 정확도가 아니라 라벨 일관성지연에서 먼저 무너집니다.

실무 설계 원칙은 다음과 같습니다.

  • 실시간에는 "지금 확정할 수 있는 것"과 "나중에 정리할 것"을 분리합니다. 화자별 자막을 실시간으로 보여주되, 최종 화자 라벨은 회의 종료 후 오프라인 재처리로 정합성을 맞추는 2단(two-pass) 구조가 안전합니다.
  • 회의가 끝난 뒤 저장·요약·검색에 쓰는 화자 정보는 실시간 라벨이 아니라 오프라인 재처리 결과를 정본으로 삼는 편이 낫습니다.

5. STT와 Diarization의 정렬(alignment): 두 시간축을 병합하기

STT와 Diarization은 각각 시간 구간을 출력합니다. 문제는 두 시간축이 정확히 겹치지 않는다는 점입니다.

  • STT는 단어/세그먼트 타임스탬프를 냅니다: [t0, t1] "우리가 이번 주에".
  • Diarization은 화자 구간을 냅니다: [t0', t1'] SPEAKER_A.

정렬을 논하기 전에 전제부터 못박아야 합니다. 두 시간축을 합치려면 STT와 Diarization이 같은 시간 기준 위에 있어야 합니다. 구체적으로는 같은 clock origin, 동일 sample index 기준, 리샘플링으로 생기는 지연, 버퍼 오프셋, 장시간 진행에서 누적되는 clock drift를 모두 맞춰야 합니다. 이 기준이 어긋나면 아래의 겹침 계산 자체가 틀린 값 위에서 이뤄지므로, 정렬 규칙보다 시간 기준 정합이 먼저입니다.

두 결과를 합쳐 "누가 무엇을 말했나"를 만들려면, 각 단어(또는 세그먼트)를 겹치는 화자 구간에 배정해야 합니다. 실용적인 기본 규칙(휴리스틱)은 시간 겹침(overlap) 최대 화자에 배정하는 것입니다. 다만 이것이 유일하거나 표준적인 방법은 아닙니다. 단어 단위 배정, exclusive diarization, word-level speaker attribution 같은 대안이 있고, 모듈 간 타임스탬프 오차가 speaker-attributed ASR 성능을 크게 떨어뜨릴 수 있다는 연구도 있습니다.

STT 세그먼트:   |----- "이번 분기 목표는" -----|
Diar 구간 A:  |-------- SPEAKER_A --------|
Diar 구간 B:                        |--- SPEAKER_B ---|

배정: 세그먼트와 A의 겹침 > B의 겹침  ->  SPEAKER_A

정렬 결과의 내부 권장 계약 예시(외부 표준이 아니라 팀 내부에서 정해 두는 형태)를 하나 정의해 두면 다운스트림이 편해집니다. 아래 계약은 바로 뒤에서 설명할 두 신뢰도 분리(diarizationConfidence/identityMappingConfidence)와 겹침 다중 화자 표현을 처음부터 반영합니다.

{
  "segments": [
    {
      "start": 12.30,
      "end": 15.80,
      "text": "이번 분기 목표는 재계약률 개선입니다",
      "speakers": [
        {
          "label": "SPEAKER_A",
          "diarizationConfidence": "high",
          "identityMappingConfidence": null
        }
      ],
      "overlap": false
    },
    {
      "start": 15.60,
      "end": 16.10,
      "text": "네 동의합니다",
      "speakers": [
        {
          "label": "SPEAKER_A",
          "diarizationConfidence": "low",
          "identityMappingConfidence": null
        },
        {
          "label": "SPEAKER_B",
          "diarizationConfidence": "low",
          "identityMappingConfidence": null
        }
      ],
      "overlap": true
    }
  ]
}

speakers를 배열로 둔 이유는 겹침 구간에서 한 시간대에 두 화자가 존재할 수 있기 때문입니다. 화자를 하나만 담는 계약이면 겹침을 검출하고도 두 번째 화자를 보존할 수 없습니다. 신뢰도 값을 high/medium/low 등급으로 쓸 경우, 이 값이 무엇으로 계산됐고(모델 확률·임베딩 거리·규칙 등급) 어떻게 보정됐는지를 별도 메타데이터로 정의해야 소비자가 모델 확률처럼 오해하지 않습니다.

정렬에서 실제로 어려운 지점은 세 가지입니다.

  1. 경계 어긋남: STT 세그먼트 하나가 두 화자 구간에 걸칠 수 있습니다. 이때 세그먼트를 쪼갤지, 다수 겹침 화자로 통째 배정할지 규칙이 필요합니다. 문장 경계만으로 나누면 한 문장 안에서 화자가 바뀐 경우 잘못된 화자 귀속이 그대로 남습니다. 따라서 단어 타임스탬프를 이용해 화자 전환 경계 근처에서 먼저 분할한 뒤, 가독성을 위한 문장 경계 규칙을 적용하는 순서가 안전합니다.
  2. 겹치는 발화(overlap): 두 사람이 동시에 말하면 한 시간대에 두 화자가 존재합니다. 단일 채널에서는 완벽히 분리하기 어렵고, 최소한 "겹침 구간"이라는 표식(overlap: true)과 겹친 화자 목록(위 계약의 speakers 배열)을 남겨 사람이 검수할 수 있게 해야 합니다. 참고로 Diarization은 "누가 언제 말했는지"를 라벨링하는 작업이지, 혼합된 음성을 실제 별도 신호로 갈라내는 음원 분리(speech separation)와는 다릅니다. 겹침 구간을 두 화자로 라벨링하는 것과 두 음성을 실제로 분리해 각각 STT에 넣는 것은 별개의 문제입니다.
  3. 짧은 발화 차례(speaker turn): "네", "그렇죠" 같은 0.3~0.5초 맞장구는 화자 임베딩 표본이 부족해 라벨이 흔들립니다. 이런 세그먼트는 diarizationConfidence를 낮게 표시하는 것이 정직합니다.

위 계약이 신뢰도를 하나로 뭉뚱그리지 않고 성격이 다른 두 값으로 나눈 이유는 다음과 같습니다.

  • diarizationConfidence: 이 구간이 같은 화자 군집에 속한다는 확신(순수 diarization 품질).
  • identityMappingConfidence: 그 익명 화자가 특정 실제 참석자라는 매핑이 맞다는 확신(귀속 품질). 매핑이 아직 없으면 null입니다.

두 값이 뒤섞이면 "군집은 확실하지만 실명은 불확실"한 흔한 상황을 표현할 수 없습니다.

6. 서버 녹화 구조에서 얻는 이점: 화자별 스트림 분리

여기서 아키텍처가 크게 도움이 됩니다. 필자의 구성은 WebRTC로 참가자 음성을 받아 미디어 서버에서 참가자별 스트림(트랙)을 분리해 참가자별 서버 녹화 파일로 남깁니다. (미디어 서버 구현에 따라 녹화 파일은 재생·후처리에 앞서 표준 컨테이너로 변환이 필요한 구현 종속 형식일 수 있습니다.)

이 구조에서는 회의 참가자 각자가 자기 클라이언트에서 자기 마이크로 말합니다. 즉, 어느 스트림이 어느 참가자의 인증된 세션에 속하는지 네트워크 계층에서 이미 알고 있습니다. 정확히 말하면 네트워크 계층이 아는 것은 "실제 발화자가 누구인가"가 아니라 오디오 소스의 소유 세션입니다. 이것은 단일 마이크(한 방에 여러 사람)로 녹음한 뒤 목소리만으로 화자를 나눠야 하는 상황과 근본적으로 다릅니다.

[단일 채널 회의]
한 방 · 한 마이크 -> 목소리로만 화자 추정 -> 순수 Diarization 문제(어려움)

[참가자별 스트림 회의]
참가자 A 스트림 --\
참가자 B 스트림 ---> 스트림 = 오디오 소스/세션 경계의 강한 사전 정보(prior)
참가자 C 스트림 --/

정리하면:

  • 참가자별 스트림이 분리되어 있으면, "누가 언제 말했나"의 상당 부분은 스트림(세션) 소유권으로 이미 결정됩니다. 순수 음향 클러스터링의 부담이 크게 줄어듭니다.
  • 다만 스트림 = 참석자 세션은 성립해도 스트림 = 실제 발화자가 항상 성립하지는 않습니다. 한 스트림 안에 여러 사람이 들어오는 경우(한 노트북 앞에 두 명), 스피커로 새어 들어온 상대방 소리, 배경 발화, 가상 오디오 입력 등이 있기 때문입니다. 또 동일 참가자가 여러 기기로 접속하는 경우도 있어, 이런 상황에서는 여전히 Diarization이 필요합니다.
  • 크로스 트랙 누설도 함께 다뤄야 합니다. 참가자 A의 목소리가 B의 스피커를 거쳐 B의 마이크로 되돌아 들어오면, 같은 발화가 여러 트랙에 중복으로 잡힙니다. 이를 그대로 두면 한 사람이 두 화자로 보이거나 발화가 이중 계상됩니다. AEC(음향 에코 제거), 트랙 간 상관(cross-channel correlation) 분석, 중복 세그먼트 제거 정책이 필요합니다.
  • 트랙 간 시간 정합도 전제입니다. 5장은 STT와 diarization의 시간축을 맞추는 문제를 다뤘지만, 참가자별 녹화 파일·트랙끼리도 시작 오프셋과 clock drift가 다를 수 있으므로, 트랙을 하나의 타임라인으로 합치기 전에 이 오프셋·drift를 먼저 맞춰야 합니다.
  • 음향 Diarization은 스트림 내부의 화자 변경을 감지할 수는 있지만, 등록된 성문이 없으면 스트림 소유자의 실제 신원을 "검증"하지는 못합니다. 스트림 소유권이 알려주는 것은 신원이 아니라 세션 소유 관계라는 점을 잊지 말아야 합니다. (참고로 목소리로 신원을 대조하는 화자 검증(Speaker Verification)은 diarization·identification과도 별개의 작업이므로, 여기서 말하는 "검증"을 신원 검증으로 오해하면 안 됩니다.)
  • 따라서 실전 설계는 "스트림 기반 세션 경계"를 1차 근거로 쓰고, 음향 기반 Diarization을 보조 수단으로 결합하는 하이브리드가 현실적입니다. 이때 음향 diarization의 역할은 스트림 내부의 다중 화자 혼입, 화자 전환, 그리고 스트림 소유권과 음향 군집 사이의 불일치를 탐지하는 것이지, 실제 신원을 검증하는 것이 아닙니다.

이 하이브리드는 뒤에서 다룰 참석자 매핑(9장)에서도 큰 이점을 줍니다. 스트림 소유자의 세션 정보가 곧 참석자 후보이기 때문입니다.

7. 실시간 스트리밍 화자 분리의 네 가지 난제

스트림 분리로 많은 부담을 덜더라도, 순수 스트리밍 Diarization이 필요한 경우(단일 채널 유입, 한 스트림 다수 화자)를 위해 스트리밍 난제를 정리합니다.

7-1. 화자 수 미상

시작 시점에 몇 명이 말할지 알 수 없습니다. 회의 중간에 새 참석자가 발언을 시작할 수도 있습니다. 스트리밍 시스템은 "지금까지 본 화자 수"를 유지하면서 새 화자 등장을 감지해야 합니다.

7-2. 지연(latency)

정확도를 높이려면 긴 오디오를 봐야 하지만, 실시간 자막은 짧은 청크로 즉시 결정해야 합니다. 청크를 짧게 잡으면 지연은 줄지만 임베딩 표본이 부족해 화자 판단이 흔들립니다. 지연과 정확도의 트레이드오프가 여기서 가장 날카롭습니다.

7-3. 라벨 일관성(같은 화자 = 같은 라벨)

가장 UX를 해치는 문제입니다. 같은 사람이 회의 내내 SPEAKER_A로 유지돼야 하는데, 스트리밍 클러스터링이 중간에 SPEAKER_C로 새로 잡아버리면 자막에서 같은 사람이 두 사람처럼 보입니다. 화자별 임베딩 프로토타입(중심 벡터)을 세션 동안 유지하고, 새 청크를 기존 프로토타입과 먼저 대조하는 접근이 필요합니다.

7-4. 재연결(reconnect)

실시간 스트림은 끊어졌다 다시 붙습니다. 재연결 시 화자 상태(프로토타입, 라벨 매핑)를 복원하지 못하면 라벨이 초기화됩니다. 세션 키에 화자 상태를 묶어, 재연결 후에도 라벨을 이어가도록 설계해야 합니다.

네 난제를 상태로 요약하면 다음과 같습니다. 아래는 실제 API 계약이 아니라 설명용 개략 JSON으로, 일부 값은 필드의 의미를 설명하는 문자열로 채웠습니다.

{
  "sessionId": "opaque-session-id",
  "speakerState": {
    "knownSpeakers": ["SPEAKER_A", "SPEAKER_B"],
    "prototypes": "화자별 중심 임베딩(세션 유지)",
    "lastUpdatedAt": "streaming-clock",
    "reconnectPolicy": "resume-from-session-key",
    "stateTtlSeconds": 3600
  }
}

재연결 상태는 무한정 유지하지 말고 TTL을 두어 세션 종료 시 삭제하며, 저장·전송 시 암호화하는 것이 좋습니다(10장).

8. 화자 라벨 상태 모델: 잠정과 확정을 분리한다

실시간 STT에서 Partial·Final을 분리하듯, 화자 라벨도 잠정과 확정을 분리하면 UX와 데이터 신뢰도가 함께 좋아집니다.

상태 의미 UI 취급
잠정(tentative) 방금 결정, 이후 바뀔 수 있음 흐리게/보정 가능 표시
확정(committed) 세션 내 안정, 재처리 전 최종 정상 표기
정본(canonical) 회의 후 오프라인 재처리 결과 저장·검색의 기준

이 세 층을 두면, 실시간에는 잠정 라벨을 빠르게 보여주면서도 나중 근거로 라벨을 조정하는 것이 "버그"가 아니라 "설계된 동작"이 됩니다. 그리고 저장·요약·검색에는 정본만 쓰므로 다운스트림이 잠정 라벨의 흔들림에 오염되지 않습니다.

9. 화자 ↔ 참석자 매핑: 익명 라벨을 실명으로

SPEAKER_A는 사람에게 의미가 없습니다. 회의록으로 쓰려면 결국 "김 팀장", "박 매니저"(모두 가상 예시)처럼 실제 참석자에 연결돼야 합니다. 여기서 1장에서 구분한 세 가지 근거를 정확히 나눠 쓰는 것이 중요합니다. 아래 두 가지는 음향 기반 화자 식별(등록 성문과 음성 비교)이 아니라 메타데이터 기반 참석자 귀속에 해당합니다. 즉 목소리로 신원을 증명하는 것이 아니라, 세션 소유권과 명단으로 후보를 좁히는 방식입니다.

  1. 스트림(세션) 소유권: 화자별 스트림 구조에서는 스트림 = 참석자 세션이므로, 대부분의 매핑 후보가 자동으로 결정됩니다. 다만 이는 세션 소유권일 뿐 목소리로 검증된 신원은 아닙니다(6장).
  2. 참석자 명단: 회의 초대/입장 정보로 후보 집합을 좁힙니다. "이 회의엔 3명이 있고 목록은 이렇다"는 정보만으로도 잘못된 매핑을 크게 줄입니다. 다만 명단은 후보를 좁혀 줄 뿐, 특정 발화자가 그중 누구인지 그 자체로 증명하지는 못합니다.

세 번째 근거인 사용자 확인은 이 자동 제안을 사람이 최종 확정하는 단계로, 아래에서 상태 모델로 다룹니다. 목소리 자체로 신원을 확정하고 싶다면 별도로 사전 등록된 성문을 이용한 음향 기반 화자 식별이 필요하며, 이는 프라이버시 부담이 큰 별개의 기능입니다(10장). 아래 매핑 계약의 source 필드는 이 서로 다른 근거들(메타데이터 기반 세션 소유권, 음향 기반 성문 비교, 사용자 확인)을 구분해 기록하기 위한 것입니다.

중요한 설계 결정은, 이 매핑을 자동 확정하지 않고 확인 상태(confirmation state)를 두는 것입니다. 필자의 시스템도 "자동으로 붙인 화자"와 "사용자가 확인한 실제 참석자 매핑"을 구분합니다.

{
  "meetingId": "opaque-meeting-id",
  "mappings": [
    {
      "speakerLabel": "SPEAKER_A",
      "attendeeId": "opaque-attendee-id",
      "source": "stream-ownership",
      "state": "confirmed",
      "mappingVersion": 3,
      "confirmedBy": "opaque-user-id",
      "confirmedAt": "2026-07-30T10:20:30+09:00",
      "updatedAt": "2026-07-30T10:20:30+09:00"
    },
    {
      "speakerLabel": "SPEAKER_B",
      "attendeeId": "opaque-attendee-id-candidate",
      "source": "voiceprint-match",
      "state": "suggested",
      "mappingVersion": 1,
      "confirmedBy": null,
      "confirmedAt": null,
      "updatedAt": "2026-07-30T10:19:05+09:00"
    }
  ]
}

두 번째 매핑의 sourcevoiceprint-match인 점에 주의해야 합니다. 특정 참석자(attendeeId)를 후보로 제안하려면 그 근거가 있어야 합니다. 사전 등록된 성문과 비교한 음향 기반 식별 결과여야 참석자를 제안할 수 있고, 등록 성문 없이 순수 diarization만 수행했다면 SPEAKER_B라는 익명 라벨만 남길 뿐 attendeeId를 제안할 수 없습니다. source에는 이 근거(예: stream-ownership, voiceprint-match, manual)를 명시해, 매핑이 세션 소유권에서 왔는지 목소리 비교에서 왔는지 사람이 확인했는지 구분되게 합니다. mappingVersion·confirmedAt·updatedAt을 함께 두는 이유는 아래 "책임 추적"과 15장의 정정 전파에서 어느 버전의 매핑이 쓰였는지 추적하기 위해서입니다.

statesuggested(자동 제안)와 confirmed(사용자 확인)로 나누는 이유는 세 가지입니다.

  • 오류 흡수: 자동 매핑은 틀릴 수 있습니다. 확정 전 상태를 두면 틀린 매핑이 곧바로 정본 데이터로 흘러가지 않습니다.
  • 책임 추적: 누가 언제 확인했는지 남기면, 잘못된 매핑에 대한 이의 제기와 정정이 추적 가능해집니다.
  • 개인정보·권한: 실명을 붙이는 순간 개인정보가 됩니다. 확정 행위를 권한 있는 사용자로 제한하고 기록을 남겨야 합니다(10장).

10. 목소리와 성문 정보의 개인정보 처리: 권한과 프라이버시

화자 식별은 본질적으로 목소리를 사람에게 연결하는 작업입니다. 다만 "목소리는 무조건 개인정보(또는 민감정보)"라고 단정하기보다, 목적과 식별 가능성에 따라 성격을 구분하는 편이 정확합니다. 한국 개인정보 보호법 시행령 제18조는 민감정보의 하나로 "개인의 신체적·생리적·행동적 특징에 관한 정보로서 특정 개인을 알아볼 목적으로 일정한 기술적 수단을 통해 생성한 정보"를 규정합니다. 이 기준에 비추면 다음을 구분해 다뤄야 합니다.

  • 원음(raw audio)·일반 음성 특징: 그 자체로는 개인정보일 수 있으나, 반드시 민감정보(생체인식정보)로 취급되는 것은 아닙니다.
  • 식별용 성문(voiceprint) 템플릿: 특정 개인을 알아볼 목적으로 기술적으로 생성한 경우, 민감정보(생체인식정보)에 해당할 수 있습니다. 가장 보수적으로 취급하는 것이 안전합니다.

설계 시 최소한 다음을 고려합니다.

항목 권장 기준
실명 매핑 권한 회의 소유자/관리자 등 명시적 권한자로 제한
처리 근거 분리 녹음 원음 처리 근거와 식별용 성문 생성 근거를 나눠 확보. 민감정보(생체인식정보)에 해당하면 일반 개인정보 동의와 별도의 요건이 필요할 수 있음
고지·동의 구분 회의 녹음 고지·동의와, 식별용 성문 등록 동의는 별개 사안으로 취급
성문 등록 사전 동의 없이 화자 식별용 성문을 축적하지 않음
익명 라벨 기본 확인 전에는 SPEAKER_A 등 익명 라벨 유지
저장 범위 임베딩은 세션/회의 범위로 한정, 목적 외 재사용 금지
보유·삭제 보유기간 또는 처리 목적 달성 시 관련 법령에 따른 예외(법정 보존 등)를 제외하고 파기하며, 정보주체의 열람·정정·삭제 요구를 처리할 절차를 둠
제3자·위탁·국외 이전 외부 STT·클라우드·모델 API를 쓴다면 제3자 제공, 처리위탁, 국외 이전 여부를 검토
보호 조치 저장·전송 암호화와 접근 통제로 성문·임베딩을 보호
학습 재사용 금지 화자 식별용 데이터를 동의 없이 모델 학습에 재사용하지 않음
감사 로그 매핑 확정·변경을 사용자·시각과 함께 기록

한 가지 더 분명히 해 둘 것은, 화자 식별(Identification)은 인증(authentication)이 아니라는 점입니다. 성문 유사도만으로 계정 인증이나 권한 부여를 해서는 안 됩니다. 재생 공격(replay)과 합성 음성 위험이 있어, 목소리 일치는 "이 발화가 등록된 화자와 비슷하다"는 신호일 뿐 신원 증명이 아닙니다.

즉, "정확히 누구인지 자동으로 다 붙여주는 것"이 항상 좋은 제품은 아닙니다. 잘못된 자동 실명 매핑은 오히려 신뢰와 법적 리스크를 동시에 키웁니다. 익명 라벨을 기본값으로 두고, 실명 연결은 사람이 확인하는 흐름이 안전한 기본형입니다. (구체적 법적 판단은 관할·처리 목적에 따라 달라지므로, 실제 서비스에서는 법무 검토를 거쳐야 합니다.)

11. 품질을 어떻게 측정하나: DER의 개념과 한계

화자 분리 품질의 사실상 표준 지표는 화자 분리 오류율(DER, Diarization Error Rate)입니다. DER은 "누가 언제 말했나"를 정답(reference)과 비교해 세 종류의 오류 시간을 합산합니다.

DER = (Missed Speech + False Alarm + Speaker Confusion) / Total Reference Speaker-Time

여기서 분모는 단순한 발화 총량이 아니라 평가 대상 구간에서의 정답 화자 발화 시간(reference speaker-time)입니다. 겹침 포함 여부에 따라 한 시점이 여러 화자 시간으로 계산될 수 있어, 분모 자체가 평가 프로토콜에 따라 달라집니다.

오류 항목 의미 대표 원인
놓친 말(Missed Speech) 정답엔 말이 있는데 시스템이 비말로 판정 작은 목소리, 겹침 구간의 한쪽
오검출(False Alarm) 정답엔 말이 없는데 말로 판정 배경 소음·비말음
화자 혼동(Speaker Confusion) 말은 맞게 잡았으나 화자를 틀림 유사 음색, 경계 근처

DER 해석에서 실무자가 알아야 할 것은, DER 값 하나가 아니라 평가 프로토콜과 함께 읽어야 한다는 점입니다.

  • DER은 100%를 넘을 수 있습니다. 이는 단순히 "겹침이 많아서"가 아니라, DER의 분자가 세 오류 시간의 합이기 때문입니다. False Alarm이 더해지고 겹침 구간의 speaker-time을 계산하는 방식(overlap 포함 여부 등 평가 프로토콜)에 따라, 분자가 기준 발화 시간(Total Speech)보다 커질 수 있습니다.
  • 평가에서 화자 전환 경계 주변의 짧은 구간(collar)을 제외하고 채점하는 경우가 있으나, 항상 적용되는 것은 아닙니다. 예컨대 pyannote.metrics의 현재 기본값은 collar=0.0, skip_overlap=False입니다(즉 기본적으로 collar 없이 겹침을 포함해 채점). 또 도구마다 collar=0.25가 "전체 250ms"인지 "경계 앞뒤 각각 250ms"인지 해석이 다를 수 있으므로, 수치를 인용할 때는 scorer 정의를 반드시 명시해야 합니다.
  • 따라서 DER 값을 공유할 때는 scorer 버전, collar 값, overlap 포함 여부, 화자 수 제공(oracle) 여부를 함께 기록해야 재현·비교가 가능합니다.

또한 DER 하나로 제품 품질을 다 말할 수는 없습니다. 실무에서는 다음 지표를 함께 봅니다.

지표 무엇을 보나
DER 전체 화자 분리 오류(놓침·오검출·혼동)의 시간 비율
Speaker-attributed ASR 지표 (SA-WER, SD-CER, cpWER 등) "누가 말했나"까지 반영한 인식 정확도(귀속 오류 포함) — 지표마다 계산법이 다르므로 사용 scorer와 정의를 명시
화자 수 오류 실제 화자 수 대비 추정 오차, 과분할·과병합 비율(클러스터링 실패 원인 진단)
겹침 검출 성능 동시 발화 구간을 얼마나 잡아내는가
실시간 지연 잠정 라벨 지연(tentative latency), 확정 라벨 지연(commit latency), 오프라인 정본 완료 시간을 구분해 측정
라벨 변경률 잠정 라벨이 나중에 바뀌는 빈도(UX 안정성)
사용자 수정률 사람이 자동 라벨·매핑을 고치는 비율

이 글에서는 조직·데이터마다 편차가 크므로 구체적 수치는 제시하지 않습니다. 중요한 것은 DER을 STT 정확도와 별개의 지표로 추적하고, 특히 화자 혼동(Speaker Confusion)을 사용자 체감 품질의 핵심으로 본다는 점입니다. 혼동은 자막을 "불완전"하게 만드는 게 아니라 "오해를 유발"하게 만들기 때문입니다.

12. 정확도는 정성적으로만 말한다: 한계 공개

품질 지표를 다뤘으니 한계도 정직하게 명시합니다. 화자 분리는 다음 조건에서 눈에 띄게 어려워집니다.

  • 겹치는 발화: 단일 채널에서 두 사람이 동시에 말하면 완전 분리가 어렵습니다.
  • 소음·에코·원거리 마이크: VAD와 임베딩이 함께 흔들립니다.
  • 유사 음색: 비슷한 목소리(예: 같은 성별·연령대의 두 사람)를 하나로 합칠 위험.
  • 아주 짧은 발화: 임베딩 표본 부족으로 라벨 불안정.
  • 채널·기기 변화: 같은 사람이 다른 기기로 접속하면 음색 특성이 달라질 수 있음.

이런 한계 때문에, 화자 분리는 "완전 자동"이 목표가 아니라 사람 검수를 전제로 한 초안 생성으로 설계하는 편이 현실적입니다. 다만 "항상 사람 검수"를 모든 경우에 적용할 필요는 없습니다. 단일 채널 diarization, 낮은 신뢰도 구간, 실제 신원 귀속, 중요한 결정·업무 추출은 사람 검수를 전제로 하되, 인증된 참가자별 트랙에서 세션 소유자를 표시하는 것처럼 근거가 강한 경우까지 모두 수동 검수로 묶으면 과도합니다. 화자별 자막을 초안으로 제시하고, 사용자가 화자 라벨을 손쉽게 정정·병합·분리할 수 있는 UI를 함께 두는 것이 품질 체감을 좌우합니다.

13. 정확도를 정직하게 표기하는 자막 스키마

자동 화자 라벨의 불확실성을 UI가 감출 것이 아니라 드러내야 검수 효율이 올라갑니다. 자막 세그먼트에 신뢰도와 검수 상태를 함께 실어 보내는 것을 권장합니다.

{
  "transcriptionState": "final",
  "speakerState": "tentative",
  "start": 42.10,
  "end": 45.30,
  "text": "다음 주까지 초안 공유하겠습니다",
  "speaker": {
    "label": "SPEAKER_A",
    "attendeeId": null,
    "displayName": null,
    "mappingState": "suggested",
    "diarizationConfidence": "high",
    "identityMappingConfidence": null
  },
  "overlap": {
    "detected": false,
    "speakerLabels": ["SPEAKER_A"]
  },
  "needsReview": true,
  "reviewReasons": ["unconfirmed-identity"]
}
  • transcriptionStatespeakerState를 분리한 이유는, STT 텍스트는 이미 final이어도 화자 매핑은 아직 잠정(tentative)일 수 있기 때문입니다. 하나의 type: "final"로 뭉치면 무엇이 확정인지 모호해집니다.
  • displayName은 확정 매핑 전에는 null로 두고 익명 라벨을 노출하며, identityMappingConfidence도 매핑 전이므로 null입니다.
  • needsReview를 켤 때는 반드시 reviewReasons에 사유를 남깁니다. 위 예시는 diarization 자체는 확실하지만(diarizationConfidence: "high") 실명 매핑이 확정되지 않았으므로(unconfirmed-identity) 검수가 필요합니다. 즉 신뢰도가 낮거나(low-confidence) 겹침(overlapped-speech)이 아니어도 미확정 신원만으로 검수 대상이 될 수 있으며, 사유를 기록하면 예시와 설명이 어긋나지 않습니다.
  • overlap은 검출 여부와 겹친 화자 목록을 함께 담아, 겹침 구간에서도 두 번째 화자를 잃지 않습니다.
  • 이 표식은 다운스트림(요약·검색)에서도 화자 신뢰도가 낮은 문장을 다르게 다루는 근거가 됩니다.

14. 저장: 화자 정보를 어떤 형태로 남길 것인가

실시간 자막은 휘발적이지만, 회의록·검색·요약을 위해서는 화자 정보가 붙은 세그먼트를 안정적으로 저장해야 합니다. 저장의 정본은 8장에서 말한 정본(canonical) 상태, 즉 회의 후 재처리 결과를 씁니다.

권장 저장 단위는 "화자·시간 정보가 붙은 세그먼트"이며, 여기에 회의/파일 출처를 함께 묶습니다.

{
  "meetingId": "opaque-meeting-id",
  "sourceId": "opaque-source-id",
  "segmentId": "opaque-segment-id",
  "start": 42.10,
  "end": 45.30,
  "speaker": {
    "speakerEntityId": "opaque-speaker-entity-id",
    "label": "SPEAKER_A",
    "attendeeId": "opaque-attendee-id",
    "mappingState": "confirmed",
    "mappingVersion": 3
  },
  "text": "다음 주까지 초안 공유하겠습니다",
  "provenance": {
    "diarization": "offline-repass",
    "reviewedBy": "opaque-user-id",
    "modelVersion": "diarizer-x.y",
    "pipelineParams": "opaque-param-set-id",
    "runId": "opaque-run-id",
    "processedAt": "2026-07-30T11:00:00+09:00",
    "inputHash": "sha256:..."
  }
}

핵심은 출처(provenance)를 함께 저장하는 것입니다. 이 화자 라벨이 자동 제안인지 사람이 확인한 것인지, 실시간 잠정 결과인지 오프라인 재처리 정본인지가 남아야, 나중에 요약·검색이 그 신뢰도를 반영할 수 있습니다. 여기에 모델·파이프라인 버전, 파라미터, run ID, 처리 시각, 입력 해시까지 provenance에 남기면 같은 입력을 재처리했을 때 결과를 재현·비교할 수 있습니다. 표시용 SPEAKER_A 라벨과 별개로 변경에 견디는 내부 식별자 speakerEntityId를 두고, 라벨·실명은 매핑 테이블에서 관리하면 라벨이 바뀌어도 다운스트림 참조가 깨지지 않습니다.

15. 다운스트림: RAG·요약·업무 추출에서 화자를 쓰는 법

화자 정보가 붙은 세그먼트는 다운스트림에서 세 가지 가치를 만듭니다. 전체 회의→RAG 흐름은 별도 글에서 다뤘으므로, 여기서는 화자 정보가 더하는 부분만 정리합니다.

  1. 출처 = 회의·시간·화자: 검색 답변에 "언제, 어느 회의에서, 누가 말했다"까지 붙일 수 있습니다. "그 결정을 누가 했지?"에 답하려면 화자가 출처의 일부여야 합니다.
  2. 요약의 발화자 귀속: "A가 다음 주까지 초안 공유"처럼 결정·업무를 발화자에 귀속하려면 화자 라벨이 필요합니다. 단, 화자 신뢰도가 낮은(13장 needsReview) 세그먼트는 요약에서 실명 귀속을 보류하는 것이 안전합니다.
  3. 업무 추출의 담당자 후보: "다음 주까지 초안 공유하겠습니다"라는 발화의 화자는 그 업무의 담당자 후보가 됩니다. 다만 자동 배정이 아니라 제안으로 두고, 승인 흐름을 거치는 것이 원칙입니다.

RAG 청크 메타데이터에 화자를 실을 때의 예시:

{
  "chunkId": "opaque-chunk-id",
  "text": "재계약률 개선을 이번 분기 최우선 목표로 결정했다.",
  "metadata": {
    "meetingId": "opaque-meeting-id",
    "timeRange": [720.0, 765.0],
    "speaker": "SPEAKER_A",
    "speakerDisplayName": null,
    "diarizationConfidence": "high",
    "identityMappingConfidence": null,
    "mappingVersion": 3,
    "type": "decision"
  }
}

speakerDisplayName은 확정 매핑 전에는 null이며(실명은 확정 시에만 채움), 신뢰도는 5장·13장과 동일하게 diarization과 identity mapping으로 나눠 싣습니다. mappingVersion을 함께 넣는 이유는 아래 정정 전파에서 이 청크가 어느 매핑 버전으로 만들어졌는지 추적하기 위해서입니다.

주의할 점: 화자 신뢰도가 낮은 세그먼트를 근거로 실명 귀속 답변을 내지 않도록 검색·생성 단계에서 필터를 두는 것이 좋습니다. 잘못된 실명 귀속은 요약의 신뢰를 가장 빠르게 무너뜨립니다.

한 가지 더 설계에 반드시 넣어야 할 것은 정정 전파(correction propagation) 흐름입니다. 화자 매핑은 사후에 바뀔 수 있습니다(사용자가 SPEAKER_A를 다른 참석자로 정정하거나, 오프라인 재처리가 라벨을 바꾸는 경우). 이때 이미 만들어 둔 다운스트림 산출물이 옛 라벨을 그대로 들고 있으면 데이터가 어긋납니다. 따라서 화자 라벨/매핑을 다운스트림 산출물의 의존 대상으로 명시하고, 매핑이 바뀌면 다음을 수행해야 합니다.

  • 요약: 해당 화자에 귀속된 결정·업무 문장을 재생성하거나 최소한 재검토 대상으로 표시.
  • 검색 인덱스: 해당 세그먼트에서 파생된 RAG 청크의 speaker/speakerDisplayName 메타데이터를 갱신(부분 재색인) 또는 무효화.
  • 업무 후보: 담당자 후보로 제안됐던 항목의 후보를 갱신하고, 이미 배정·승인된 건은 재확인 요청.

정정 전파는 멱등(idempotent)하게 설계해야 합니다. 같은 정정 이벤트가 중복 처리돼도 결과가 흔들리지 않아야 하고, 요약·인덱스 각각이 어느 mappingVersion으로 만들어졌는지 기록해 두면 "이미 반영된 정정인지"를 안전하게 판별할 수 있습니다. 정정 전파를 설계에 넣지 않으면, "실시간에는 라벨이 바뀔 수 있다"는 8장의 원칙이 다운스트림에서 조용히 깨집니다.

16. 설계 체크리스트

화자 분리를 하나의 독립 설계 대상으로 다룰 때 점검할 항목입니다.

영역 점검 질문
문제 분리 STT·Diarization·Identification을 별개 예산·지표로 다루는가
파이프라인 VAD·임베딩·클러스터링·라벨링 단계의 실패를 각각 정의했는가
오프라인/온라인 실시간 잠정 라벨과 오프라인 정본 라벨을 분리했는가
정렬 공통 시간 기준(clock·offset·drift)을 맞추고, 두 시간축 병합 규칙(겹침·경계·짧은 발화 차례)이 있는가
스트림 활용 화자별 스트림 소유권을 1차 근거로 쓰는가
크로스 트랙 트랙 간 누설·중복 발화 제거와 트랙 간 clock 동기화를 처리하는가
라벨 일관성 세션 내 같은 화자=같은 라벨을 유지하고 재연결을 복원하는가
매핑 확인 실명 매핑에 suggested/confirmed 상태와 권한을 두었는가
프라이버시 목소리를 개인정보로 취급하고 익명 라벨을 기본값으로 두는가
품질 DER을 STT와 별개로 추적하고 화자 혼동을 핵심 지표로 보는가
지표 버전 DER의 scorer·collar·overlap·oracle 조건과 모델/파이프라인 버전을 함께 기록하는가
검수 신뢰도·검수 상태를 자막에 노출해 사람 검수를 유도하는가
저장 정본 세그먼트에 출처(provenance)를 함께 남기는가
재현성 재처리 시 모델·파라미터·run ID·처리 시각·입력 해시를 provenance에 남기는가
정정 전파 매핑 변경이 요약·검색·업무 후보로 멱등하게 전파되는가
다운스트림 낮은 신뢰도 세그먼트의 실명 귀속을 필터링하는가

17. 정리

화자 분리는 음성 인식의 부산물이 아니라 독립된 문제입니다.

  • STT는 "무엇을", Diarization은 "누가 언제(익명)", Identification은 "실제로 누구인지"를 답합니다. 세 가지는 같은 원음을 입력으로 삼을 수 있지만, 필요한 보조 정보·출력 계약·최적화 목표·실패 양상이 다릅니다.
  • 오프라인과 온라인(스트리밍)은 같은 목적의 다른 제품이며, 실시간에서는 정확도보다 라벨 일관성과 지연이 먼저 문제가 됩니다.
  • 화자별 스트림 구조는 화자 경계에 강한 사전 정보를 주지만, 순수 음향 Diarization은 여전히 스트림 내부 다중 화자·화자 전환·소유권 불일치를 탐지하는 보조 수단으로 필요합니다(신원 검증 수단은 아닙니다).
  • 익명 라벨을 실명에 붙일 때는 확인 상태(suggested/confirmed)와 권한·프라이버시를 반드시 설계에 넣어야 합니다.
  • 품질은 DER로 추적하되 한계는 정직하게 공개하고, 사람 검수를 전제로 한 초안 생성으로 설계하는 것이 현실적입니다.
  • 다운스트림에서는 화자·시간·회의를 출처로 삼아 검색·요약·업무 추출의 신뢰도를 높이되, 낮은 신뢰도의 실명 귀속은 걸러야 합니다.

실시간 STT 설계는 이 글에서, 회의 음성을 RAG로 잇는 전체 흐름은 이 글에서 이어집니다.

참고 자료 (공식·공개 출처)

접근일: 2026-07-30 (버전 명시가 필요한 문서는 아래에 함께 표기).