AMD 라벨링 / Supervised 파이프라인 · 가이드
DOC v1 --:--:--
INTERNAL ENGINEERING GUIDE

AMD 라벨링 / Supervised 파이프라인 가이드

자체 AMD(Answering Machine Detection)를 상용 수준으로 고도화하기 위한 라벨 데이터 수집 · 저장 · 검수 · 데이터셋 구축 전 과정을 정리한 운영 문서입니다. 핵심 원칙은 상담사 최소 개입 — 라벨링을 업무 부담이 아닌 예외 신고로 설계했습니다.

supervised labeling MinIO S3 · 버킷 tad PII = HMAC-SHA256 log-mel + CNN → ONNX
PHILOSOPHY
1. 개요 · 설계 철학
왜 자체 라벨이 필요한가, 그리고 라벨을 어떻게 "공짜로" 모으는가

자체 AMD를 상용 솔루션 수준으로 끌어올리려면 우리 환경(국내 통신사 컬러링 · 안내멘트 · 음성사서함 · 무응답)에서 직접 수집한 라벨 데이터가 필수입니다. 외부 데이터셋만으로는 국내 ARS/컬러링 특성을 충분히 커버할 수 없습니다.

그래서 운영 구조 자체를 supervised(상담사 확인) 라벨 수집기로 만들었습니다. 단, 핵심 제약은 현장 부담 제로화입니다. 하루 수백 통을 처리하는 상담사에게 매 콜 분류를 시키면 라벨 노가다가 되어 데이터 품질도, 상담 품질도 망가집니다.

CORE PRINCIPLE

상담사 화면의 라벨 기능은 "분류 도구"가 아니라 "예외 신고 장치"입니다.

기본값 = 무입력 = 자동 확정. 상담사는 "AMD가 사람이라며 연결했는데 실제로는 기계였다" 싶을 때만 단 한 번 개입합니다.

모든 콜의 오디오와 AMD 판정은 통화 종료 시 자동으로 라벨에 기록됩니다(implicit). 상담사 개입은 이 자동 라벨을 정정(explicit)하는 용도로만 쓰이며, 세부 분류는 LLM 자동 QA(DeepSeek/TCM)가 담당합니다.

AGENT WORKFLOW · TAD CLIENT
2. 상담사 워크플로
상담사가 실제로 보고 누르는 것 (대부분의 콜에서: 아무것도 안 누름)

통화가 종료되면 모든 콜의 녹음 오디오 + AMD 판정이 상담사 개입 없이 자동으로 라벨에 기록됩니다. 상담사 화면에 추가 UI가 뜨는 경우는 단 하나입니다.

언제 버튼이 뜨는가

사람으로 연결된 콜만 발신/통화 카드 안에 슬림 바가 나타납니다. 기계로 판정된 콜(음성사서함 · 안내 · 컬러링 · 무응답)은 상담사 화면에 버튼이 뜨지 않고 implicit 자동 저장됩니다 — 세부 분류는 LLM 자동 QA(DeepSeek/TCM) 몫.

상담사 화면 슬림 바 (사람 연결 콜)
✅ 사람 연결 — 기본 '사람 맞음' 저장됨. 아니었으면 → N ↩ 되돌리기

※ 위는 화면 미리보기입니다(비활성). 실제 동작은 TAD 클라에서.

동작 규칙
  • 기본값 = 사람 맞음: 사람으로 연결된 콜은 입력이 없으면 자동으로 human 라벨로 확정됩니다.
  • [✗ 사람 아님] / N 단축키: "사람이라고 연결했는데 실제론 기계였다" 싶을 때만 한 번 누릅니다 → coarse 라벨 not_human으로 정정.
  • [↩ 되돌리기]: 잘못 눌렀으면 즉시 원복.
  • 자동 확정 타이밍: 30초 경과 또는 다음 콜 시작 시 현재 라벨이 확정됩니다.
한 줄 요약

상담사가 하는 일은 사실상 "AMD가 사람이라며 연결했는데 기계였을 때 N 한 번"이 전부입니다. 그 외에는 평소대로 상담만 하면 라벨은 알아서 쌓입니다.

DATA PIPELINE · MinIO S3 (bucket: tad)
3. 데이터 파이프라인
통화 종료 → 라벨 기록 → 오디오 직접 업로드 → 업로드 확인
전체 흐름
STEP 1
통화 종료
클라가 판정 · 메타와 함께
POST /api/amd/decision
STEP 2
서버: 라벨 기록
라벨 JSON을 S3에 기록 +
오디오용 presigned PUT URL 반환
STEP 3
오디오 직접 PUT
클라가 녹음 wav를 S3에
직접 PUT (서버 디스크 안 거침)
STEP 4
업로드 확인
POST /api/amd/uploaded
→ 라벨 audio.uploaded=true
왜 presigned 직접 업로드인가

오디오 wav가 서버 디스크를 경유하지 않고 클라이언트 → S3로 직접 전송되므로 서버 부하/디스크 사용이 없고, 라벨 메타와 오디오 객체가 분리되어도 decision_id로 결합됩니다.

정정(correction) 경로

상담사 또는 QA의 라벨 정정은 원본 라벨을 덮어쓰지 않습니다.

POST /api/amd/label/:decisionId
  # → amd/corrections/{id}/{ts}.json  (별도 객체)
  # 원본 라벨은 불변(immutable) — 전체 정정 이력이 감사추적으로 남음

최신 정정이 effective 라벨이 되며, export 단계에서 원본 + 정정을 병합해 최종 클래스를 산출합니다.

S3 키 레이아웃 (버킷 tad)
용도키 패턴
라벨amd/labels/YYYY/MM/DD/{decision_id}.json
오디오amd/audio/YYYY/MM/DD/{decision_id}.wav
정정amd/corrections/{decision_id}/{ts}.json
PII 처리

전화번호와 상담원 ID는 HMAC-SHA256 해시만 저장합니다 — number_hash, agent_id_hash. 원문은 저장하지 않습니다.

LABEL SCHEMA
라벨 JSON 스키마
amd/labels/.../{decision_id}.json 주요 필드
필드설명
schemaVersion스키마 버전 (호환성 관리)
decision_id콜 단위 고유 ID — 라벨·오디오·정정을 결합하는 키
amd{ verdict, confidence, decision_offset_ms, features } — 엔진 판정 결과 · 신뢰도 · 판정까지 걸린 오프셋 · 추출 피처
label{ class, method, usable, reason }method: implicit / explicit / qa
audio{ key, sampleRate, channels, durationMs, bytes, sha256, uploaded } — S3 키 · 포맷 · 무결성 해시 · 업로드 여부
meta{ device, appVersion, amdVersion, os, tz } — 수집 환경(드리프트 분석용)
qa_sampleQA 우선 검수 대상 여부 플래그 (아래 QA 섹션 참조)
serverReceivedAt서버 수신 시각 (ISO8601)
PII 관련 필드

전화번호·상담원ID는 스키마상 number_hash · agent_id_hash(HMAC-SHA256)로만 존재합니다.

CLASS TAXONOMY
4. 클래스 택소노미
학습용 8클래스 · 상담사 coarse · 제품 verdict 3종
학습 클래스 (8개)
human사람 voicemail_greeting음성사서함 인사말 voicemail_beep사서함 삐 신호 carrier_announcement통신사 안내멘트 ringback통화 연결음 coloring컬러링 fax_tone팩스 톤 silence_noise_unknown무음/잡음/불명
상담사 실시간 정정 (coarse)

상담사는 세부 8클래스를 고를 필요가 없습니다. 실시간 정정용 coarse 라벨은 하나뿐입니다.

not_human사람 아님

세부 분류(8클래스 중 어디인지)는 LLM 자동 QA(DeepSeek/TCM)가 확정합니다.

제품 verdict (3종)

엔진이 런타임에 내리는 판정은 3종입니다.

HUMAN
사람 — 상담사 연결
NOT_HUMAN
기계 — 다음 콜로
UNKNOWN
불명 — 보수적 처리
운영 목표

운영은 사람 recall 최우선(목표 98~99%)입니다. 사람을 기계로 오판해 끊는 것이 최악이므로, 애매하면 UNKNOWN을 허용해 사람을 놓치지 않는 방향으로 설계합니다.

QA · DATASET EXPORT
5. QA · 데이터셋 export
LLM 자동 세부분류 · 신뢰계층 · 학습용 manifest 생성
qa_sample 샘플링 규칙

qa_sample 플래그가 붙은 콜이 QA 우선 검수 대상입니다.

  • usable=false 전수: UNKNOWN · 저신뢰(low confidence) · 너무 짧은(too short) 콜은 모두 검수.
  • usable의 8% 랜덤: 정상 라벨도 8%를 랜덤 추출해 라벨 품질을 모니터링.
자동 세부 분류 — LLM 파이프라인 (사람이 듣지 않음)

모인 라벨(not_human · implicit · qa_sample)의 8클래스 세부 분류는 사람이 아니라 LLM이 자동으로 합니다. 사람은 저신뢰·불일치 건만 스팟체크합니다.

  • DeepSeekscripts/llm-classify.js: S3 라벨의 AMD features를 DeepSeek에 보내 8클래스 분류. 신뢰도 ≥0.8 자동수용(method:qa_llm), 미만은 amd/qa_pending 보류. 멱등·재시도. features만 전송 → 오디오·PII 국외 미전송
  • TCM — 통화 녹취 STT+LLM 풀분석: 같은 decision_idmethod:tcm correction을 써넣음(오디오+transcript 기반이라 더 정확). 연동은 TCM 연동 명세 참조.
  • 사람: 실시간 "✗ 사람 아님" 1클릭 + 저신뢰/불일치 스팟체크만. 일일이 듣지 않음.
라벨 신뢰계층 — 축 분리 (단순 서열이 아님)

출처마다 잘하는 축이 다릅니다. 단일 서열로 매기지 않고, export가 두 축을 분리해 처리합니다:

  • is_human (사람인가 · 이진): 상담사(그 통화에 직접 있었음) > TCM > implicit. → 상담사가 가장 강함(현장 관측).
  • 세부 8클래스 (어떤 기계인가): TCM(전체 오디오 STT+LLM) > 상담사(coarse) > DeepSeek(features) > implicit. → TCM이 가장 정확.

상담사 ↔ TCM이 사람/기계 판단에서 불일치하면 자동 채택하지 않고 needs_review 표시 + 학습 가중치 감쇠. 둘이 일치할 때가 가장 신뢰(gold). 사람도 급한 1클릭이라 휴먼에러 있음 · TCM은 STT오류 가능 → 일치가 진짜 신뢰

상황label_weight
상담사 + TCM 일치1.0 (gold)
TCM 단독 (세부분류)0.85
상담사 단독0.9
DeepSeek (features)0.35
implicit (AMD 원본)0.1
상담사 ↔ TCM 불일치 (재검수)0.3
데이터셋 export
node scripts/export-amd-dataset.js
  1. 라벨 + 정정 병합 → 신뢰계층(사람 > TCM > DeepSeek > implicit)으로 effective_class + source + weight 부여
  2. 오디오 객체 존재를 HEAD 요청으로 확인
  3. 학습용 JSONL manifest + source별 통계 출력
ROADMAP
6. 로드맵 (요약)
상세는 repo의 todo.md 참조
P0
라벨 캡처 완료
상담사 워크플로 · decision/uploaded/correction API · 슬림 바 UI.
P1
데이터 수집 · export 인프라 완료
MinIO S3 저장 · presigned 업로드 · export 스크립트. 데이터는 운영하며 누적 중.
P2
학습
log-mel + 소형 CNN. train/serve skew 방지를 위해 전처리를 ONNX에 내장.
P3
추론 통합
onnxruntime-node worker. 휴리스틱 + ML + 템플릿 하이브리드 + fallback.
P4
피드백 루프
model-manifest 배포 · 드리프트 감지 · 재학습 사이클.