개념
전수 검수는 왜 불가능한가
앞 레슨에서 데이터 품질을 무엇으로 재는지 봤다. 이제 현실적인 질문이 남는다. 그 측정을 실제로 어떻게 수행하는가?
숫자를 대보면 문제가 분명해진다. 문서 10만 건짜리 학습데이터셋이 있고, 한 건을 사람이 검토하는 데 3분이 걸린다고 하자.
100,000건 × 3분 = 300,000분 = 5,000시간
1인 하루 8시간 기준 → 625 인일 → 1명이 하면 약 2년 반
10명을 투입해도 약 3개월그리고 데이터셋은 한 번 만들고 끝이 아니다. 매달 갱신된다면 이 비용이 매달 발생한다. 전수 검수는 자원의 문제가 아니라 구조의 문제다.
그렇다고 검수를 건너뛰면 앞 레슨에서 본 문제가 그대로 하류로 흘러간다. 잘못된 레이블, 학습·평가셋 누출, 편중된 분포. 그래서 필요한 것이 모든 것을 다 보되, 모든 것을 같은 비용으로 보지는 않는 구조 다.
파이프라인의 기본 발상 — 값싼 검증을 앞에 둔다
이 문제의 해법은 QA에게 이미 익숙한 형태다. 모듈 11의 자동화 피라미드, 모듈 14의 품질 게이트 가 쓰는 것과 같은 발상이다.
값싸고 빠른 검증을 앞에 두고, 거기서 걸러진 것만 비싼 검증으로 보낸다.
단위 테스트가 통과해야 통합 테스트를 돌리고, 정적 분석이 통과해야 빌드를 하는 것과 같다. 데이터 검증에서는 이 구조가 4단계 모듈 로 구현된다. 실제로 KT가 사내 학습데이터에 적용해 공개한 파이프라인이 이 형태를 취한다.
원천 데이터
│
┌───▼──────────────────────────────┐
│ M1 데이터 정합성 검증 │ 물리적·구조적 무결성
│ (파일·스키마·타입·인코딩) │ → 게이트 1
└───┬──────────────────────────────┘
│ 통과분만
┌───▼──────────────────────────────┐
│ M2 데이터 유효성 검증 │ 논리 규칙·관계 무결성
│ (값 범위·참조·조합·중복) │ → 게이트 2
└───┬──────────────────────────────┘
│ 통과분만
┌───▼──────────────────────────────┐
│ M3 데이터 정성 검증 │ 내용의 적절성·정확성
│ 대표성 표본 추출 │
│ 다중 LLM 앙상블 교차 검증 │
│ HITL 최종 판정 │ → 게이트 3
└───┬──────────────────────────────┘
│
┌───▼──────────────────────────────┐
│ M4 데이터 품질 리포터 │ 심사 항목별 준수율 요약
│ (근거 자산화·이력 축적) │
└──────────────────────────────────┘각 단계를 순서대로 보자.
M1 — 정합성 검증: 형태가 맞는가
첫 관문은 물리적·구조적 무결성 이다. 내용의 옳고 그름은 보지 않는다. "이 데이터가 애초에 읽을 수 있는 형태인가"만 본다.
| 검사 유형 | 예 |
|---|---|
| 파일 수준 | 파일 존재, 크기 0 아님, 확장자·실제 포맷 일치, 인코딩(UTF-8) |
| 스키마 수준 | 필수 필드 존재, 필드명 일치, 계층 구조 깊이 |
| 타입 수준 | 숫자 필드에 문자열이 들어있지 않은가, 날짜 형식 |
| 쌍 수준 | 원본 파일과 레이블 파일이 1:1로 대응하는가 |
이 단계의 특징은 판정이 완전히 결정적 이라는 것이다. 앞 레슨에서 다룬 원칙에 따라, 여기서는 준수율 100%(오류 0건) 를 요구하는 것이 합리적이다. 필수 필드가 빠진 레코드를 "5%까지는 봐준다"고 할 이유가 없다.
실무에서 가장 자주 잡히는 것은 의외로 인코딩과 형식 혼재다. 여러 출처에서
모은 데이터를 합칠 때 한 출처만 CP949거나, 날짜가 2026-09-04와
2026/09/04로 섞인다. 이런 것들은 모델 학습 단계에서는 조용히 통과하고
서비스 단계에서 이상하게 터진다.
M2 — 유효성 검증: 값이 규칙에 맞는가
형태가 맞아도 값이 말이 안 될 수 있다. M2는 논리 규칙과 관계 무결성 을 본다.
| 검사 유형 | 예 |
|---|---|
| 값 범위 | 나이가 음수, 확률이 1을 넘음, 좌표가 지구 밖 |
| 열거값 | 카테고리 필드에 정의되지 않은 값 |
| 조합 규칙 | 종료일이 시작일보다 앞섬, 상태가 '완료'인데 완료시각이 비어 있음 |
| 참조 무결성 | 레이블이 가리키는 클래스 ID가 클래스 정의에 없음 |
| 유일성 | 완전 중복 레코드, 동일 해시 파일 |
| 누출 | 학습셋과 평가셋에 같은 항목이 존재 |
M1과 M2를 나누는 이유 는 실패했을 때 취할 행동이 다르기 때문이다. M1 실패는 대개 수집·변환 파이프라인의 버그이고, M2 실패는 데이터 생성 규칙이나 원천 시스템의 문제다. 고칠 사람도 고칠 곳도 다르다. 한 덩어리로 묶어두면 "뭐가 문제인지"를 매번 다시 분류해야 한다.
M2도 판정이 결정적이므로 준수율 100%가 기준이 된다. 다만 예외가 하나 있다 — 근사 중복 처럼 임계값이 필요한 항목은 M2에 두더라도 통계 기준으로 다뤄야 한다. 앞 레슨 과제 3에서 겪은 그 애매함이 여기서 실제 설계 결정이 된다.
M3 — 정성 검증: 내용이 맞는가
여기서부터가 진짜 문제다. "이 요약이 원문을 왜곡하지 않았는가", "이 레이블이 이미지와 실제로 맞는가" 같은 질문은 규칙으로 판정할 수 없다. 그리고 앞에서 계산했듯 사람이 전수로 볼 수도 없다.
해법은 세 겹으로 짜인다.
1. 대표성 있는 표본 추출
전수 대신 표본을 본다. 여기서 중요한 것은 무작위가 아니라 대표성 이다. 단순 무작위 추출은 다수 클래스에 쏠린 표본을 만들어, 정작 문제가 많은 소수 구간을 놓친다. 실무에서 쓰는 방식은 대개 셋을 섞는다.
- 층화 추출 — 클래스·출처·기간별로 비율을 맞춰 뽑는다
- 위험 기반 가중 — M2에서 경고가 났던 구간, 신규 출처, 이력이 나쁜 작업자의 결과물에 더 많은 표본을 배정한다 (모듈 4의 리스크 기반 테스트가 여기서 그대로 쓰인다)
- 경계 표본 — 길이가 극단적으로 짧거나 긴 항목, 특수문자 비율이 높은 항목처럼 분포의 가장자리
2. 다중 LLM 앙상블 교차 검증
표본을 LLM에게 판정시킨다. 그런데 레슨 5에서 배웠듯 LLM의 판정은 비결정적이고, 모델마다 편향의 방향이 다르다. 그래서 한 모델의 판정을 그대로 믿지 않는다.
표본 1건
├─ 판정자 A (모델 α, 프롬프트 P1) → 통과
├─ 판정자 B (모델 β, 프롬프트 P1) → 통과
└─ 판정자 C (모델 α, 프롬프트 P2) → 불합격
↓
합의 실패 → HITL 큐로 에스컬레이션판정이 일치하면 그대로 채택하고, 갈리면 사람에게 넘긴다. 이 구조의 장점은 "LLM이 얼마나 정확한가"라는 답하기 어려운 질문을 "LLM들이 얼마나 일치하는가"라는 측정 가능한 질문 으로 바꾼다는 데 있다. 불일치율 자체가 그 검증 항목의 난이도 지표가 된다.
3. HITL(Human-in-the-Loop) 최종 판정
사람은 전수를 보지 않고, 앙상블이 갈린 것과 불합격으로 판정된 것만 본다. 이 설계의 효과가 파이프라인 전체의 존재 이유다.
전체 100,000건
→ M1·M2 자동 통과/차단
→ M3 표본 추출 (예: 3,000건)
→ LLM 앙상블 판정
→ 사람이 실제로 보는 것: 합의 실패 + 불합격 (예: 700건 내외)
사람이 보는 비율 ≈ 1% 미만실제 사례에서도 검토 대상을 전체의 1% 미만으로 줄여 인력을 90% 이상 절감한 것으로 보고된다. 중요한 것은 줄인 만큼 놓쳤는가 인데, 이 구조에서는 놓칠 위험이 가장 큰 항목들이 오히려 사람에게 우선 배정된다.
정성 검증의 통과 기준은 M1·M2와 달라야 한다. 사람끼리도 판단이 갈리는 영역이므로 100%는 달성 불가능한 기준이다. 통과율 95% 이상 같은 통계적 기준을 쓰고, 그 임계값의 근거를 문서에 남긴다.
M4 — 리포터: 검증을 자산으로 바꾼다
마지막 단계는 결과를 심사 항목별 준수율 로 요약하고 기록하는 일이다. 이게 왜 별도 모듈일 만큼 중요한가?
- 인증·심사 대응 — 앞 레슨에서 본 DQ인증의 심사 항목에 우리 검증 결과가 매핑돼 있으면, 인증 준비가 정리 작업으로 끝난다.
- 추세 관찰 — 이번 데이터셋의 준수율이 지난번보다 떨어졌다면, 원천 시스템이나 수집 절차에 변화가 있었다는 신호다. 단발 판정보다 추세가 더 많은 것을 말해준다.
- 의사결정 근거 — "이 데이터셋을 써도 됩니까"에 대한 답이 문서로 남는다.
- 재현성 — 어떤 버전의 데이터를, 어떤 버전의 검증 규칙으로, 언제 검사했는지가 기록된다. 모듈 25에서 본 성적서의 사고방식과 같다.
M4가 없으면 파이프라인은 매번 다시 돌려야 하는 일회용 스크립트 로 남는다. 있으면 검증 자체가 조직의 자산이 된다.
설계 원칙 넷 — 이 구조를 지탱하는 것
파이프라인의 모듈 구성보다 오래 남는 것은 설계 원칙이다. 네 가지를 기억해두면 다른 도메인에서도 같은 구조를 만들 수 있다.
1. 단계적 게이트 — 비용이 낮은 검증을 먼저
앞에서 본 그대로다. LLM 호출은 규칙 검사보다 수백 배 비싸다. 형식이 깨진 데이터를 LLM에게 보내는 것은 순수한 낭비다.
2. 설정과 로직의 분리 — Config-driven
새 데이터셋이 들어올 때마다 코드를 고쳐야 한다면 파이프라인은 확장되지 않는다. 무엇을 검사할지는 설정 파일에, 어떻게 검사할지는 코드에 둔다.
# dataset-news-summary.yaml
dataset: news-summary-2026Q3
source: s3://datasets/news-summary/2026q3/
m1_integrity:
required_fields: [doc_id, title, body, summary, source_url]
encoding: utf-8
pair_check:
left: body
right: summary
threshold: 1.0 # 준수율 100% — 무관용
m2_validity:
rules:
- id: body_min_length
field: body
op: min_length
value: 200
- id: summary_ratio
expr: "len(summary) / len(body) < 0.5"
- id: no_leakage
type: cross_split_duplicate
compare_with: eval_set
method: minhash
similarity: 0.9
threshold: 1.0
m3_qualitative:
sampling:
method: stratified
strata: [source_domain, body_length_bucket]
size: 3000
risk_weight:
new_source: 2.0
m2_warned: 3.0
judges:
- model: model-a
prompt: prompts/summary_faithfulness_v3.md
- model: model-b
prompt: prompts/summary_faithfulness_v3.md
- model: model-a
prompt: prompts/summary_faithfulness_v3_reversed.md
consensus: majority
escalate_on: [disagreement, fail]
threshold: 0.95 # 통과율 95% — 통계적 기준설정만 새로 쓰면 새 데이터셋에 적용된다는 것이 이 구조의 핵심 이득이다. 코드 수정 없이 확장 가능 하다는 것은 곧 데이터 담당자가 직접 검증 조건을 조정할 수 있다는 뜻이기도 하다.
3. 검증기의 플러그인화
각 검사는 독립된 단위 모듈 로 만든다. 인터페이스를 하나로 고정하면 새 검사를 추가하는 비용이 거의 0이 된다.
from dataclasses import dataclass
@dataclass
class ValidationResult:
rule_id: str
passed: int
failed: int
samples: list # 실패 사례 몇 건 — 리포트에 그대로 실린다
@property
def compliance(self) -> float:
total = self.passed + self.failed
return 1.0 if total == 0 else self.passed / total
class Validator:
"""모든 검증기가 따르는 계약."""
rule_id: str
stage: str # "m1" | "m2" | "m3"
def validate(self, records, config) -> ValidationResult:
raise NotImplementedError
class RequiredFieldsValidator(Validator):
rule_id = "m1.required_fields"
stage = "m1"
def validate(self, records, config):
required = config["required_fields"]
passed, failed, samples = 0, 0, []
for r in records:
missing = [f for f in required if not r.get(f)]
if missing:
failed += 1
if len(samples) < 20:
samples.append((r.get("doc_id"), missing))
else:
passed += 1
return ValidationResult(self.rule_id, passed, failed, samples)이 계약이 주는 이득은 테스트에서도 나온다. 검증기 자체가 단위 테스트 대상 이 된다. 모듈 10에서 배운 것이 그대로 적용된다 — 검증 로직에 버그가 있으면 데이터 품질 지표 전체가 거짓말이 되므로, 검증기야말로 테스트가 필요하다.
4. 정량과 정성의 상호 보완
규칙은 놓치지 않지만 얕고, 판단은 깊지만 비싸고 흔들린다. 어느 한쪽만으로는 안 된다.
| 규칙 기반(M1·M2) | 판단 기반(M3) | |
|---|---|---|
| 잡아내는 것 | 형식·구조·논리 위반 | 내용의 부정확·부적절·왜곡 |
| 놓치는 것 | "형식은 완벽한데 내용이 틀린" 데이터 | 전수를 못 보므로 표본 밖의 것 |
| 비용 | 매우 낮음 | 높음 |
| 판정 안정성 | 결정적 | 확률적 |
| 통과 기준 | 100% | 95% 등 임계값 |
실제로 이 조합이 잡아내는 결함 중에는 어느 한쪽만으로는 원리적으로 발견 불가능한 것 들이 있다. 예를 들어 변환 과정에서 정상 데이터 일부가 조용히 소실된 경우 — 남은 데이터는 형식이 완벽하므로 규칙 검사는 통과하고, 표본 검사에서도 개별 항목은 멀쩡해 보인다. 이건 건수 대조(M2의 관계 무결성)와 분포 비교 를 함께 봐야 드러난다.
검증 항목을 인증 항목에 매핑해둔다
마지막으로 실무에서 가장 값을 하는 습관 하나. 각 검증기를 앞 레슨에서 본 인증·표준의 심사 항목에 미리 매핑해두는 것 이다.
| 검증기 | 파이프라인 단계 | 대응하는 품질 특성 | 관련 표준·심사 항목 |
|---|---|---|---|
| 필수 필드 존재 | M1 | 완전성 | ISO/IEC 25024 완전성 측정량 |
| 인코딩·포맷 일치 | M1 | 준수성 | DQ 구조 심사 |
| 값 범위·열거값 | M2 | 정확성·일관성 | ISO/IEC 25024 |
| 학습·평가 누출 | M2 | 유일성 | ISO/IEC 5259-2 계열 |
| 클래스 분포 균형 | M2 | 대표성 | ISO/IEC 5259-2 계열 |
| 요약 충실성(LLM) | M3 | 정확성 | 비정형 내용 심사 |
| 레이블 일관성(LLM+HITL) | M3 | 일관성 | 비정형 내용 심사 |
| 준수율 리포트 | M4 | (관리 체계) | ISO 8000-61/62 |
이 표가 있으면 인증 준비가 "무엇을 새로 해야 하나"가 아니라 "이미 있는 것 중 무엇을 제출하나" 의 문제가 된다. 모듈 25 레슨 7에서 반복해서 나온 그 원칙이다 — 평소에 굴려두면 정리 작업, 아니면 창작 작업.
실무에서 왜 필요한가
AI 기능을 개발하는 조직에서 QA가 모델 평가만 담당하면 할 수 있는 일이 좁다. 평가 결과가 나빠도 원인을 짚지 못하고, 개선 제안이 "프롬프트를 바꿔보자"에서 멈춘다. 데이터 검증 파이프라인을 다룰 줄 알면 그 위치가 바뀐다 — 문제의 상류를 짚고, 개선의 근거를 제시할 수 있다.
파이프라인 설계 능력 자체가 QA의 핵심 역량이기도 하다. 여기서 쓴 기법은 전부 앞 모듈에서 배운 것들이다. 게이트 설계(모듈 14), 리스크 기반 우선순위 (모듈 4), 표본과 통계(레슨 5), 플러그인 구조와 단위 테스트(모듈 10), 그리고 근거의 문서화(모듈 25). 새로운 것을 배운다기보다, 이미 아는 것을 데이터라는 대상에 적용하는 일 이다.
조직 관점에서는 비용 구조가 바뀐다. 전수 검수는 데이터가 늘어나면 인력이 비례해 늘어야 하지만, 이 구조는 자동 검증이 규모를 흡수하고 사람은 판단이 필요한 부분에만 투입 된다. 데이터가 두 배가 돼도 사람 검토량은 두 배가 되지 않는다.