94%의 통과율이 6개의 테스트 케이스에 숨겨진 PII 유출을 가린 이유
요약
단순 통과율(pass-rate) 지표가 PII 유출과 같은 치명적인 오류를 식별하지 못하는 문제를 분석합니다. 모든 실패의 비용이 동일하다고 가정하는 통계적 오류를 지적하며, 심각도 가중치를 적용한 평가 체계의 필요성을 강조합니다.
핵심 포인트
- 단순 통과율은 PII 유출 등 치명적 오류를 통계적 오차로 간주하여 숨길 위험이 있음
- 실패의 유형(어조, 장황함 vs 개인정보 유출)에 따라 비용과 영향력은 완전히 다름
- 테스트 스위트 설계 시 위험 커버리지(Risk Coverage)를 우선순위에 두어야 함
- 해결책으로 각 테스트 케이스에 심각도(Severity) 태그를 부여하고 가중 점수 기반 게이트를 적용해야 함
우리의 평가(eval) 대시보드는 94%라고 말했습니다. 초록색 체크 표시, 머지(merge) 버튼 활성화, 모두가 다음 단계로 넘어갔습니다. 3일 후, 한 고객이 상담원이 다른 사용자의 계정 ID와 부분적인 청구 주소를 답변에 붙여넣은 대화 기록을 전달해 왔습니다. 탈옥(jailbreak)도, 적대적 입력(adversarial input)도 아니었습니다. 그저 상담원의 도구 호출(tool-calling) 단계에서 잘못된 기록을 가져와 "도움이 되는" 요약에 그대로 포함시킨 일반적인 고객 문의였습니다.
우리는 통과했던 평가 실행(eval run)을 다시 살펴보았습니다. 512개의 테스트 케이스 중 31개가 여러 가지 이유(너무 장황한 표현, 잘못된 어조, 사소한 사실 완화 등)로 실패했습니다. 그 31개의 실패 중 6개가 PII(개인정보) 유출 패턴이었습니다. 512개 중 6개는 단순 통과율(pass-rate) 지표에서는 반올림 오차 수준입니다. 하지만 제 생각에, 이는 해당 실행 전체에서 그 자체만으로 배포를 차단했어야 할 유일한 실패 카테고리였습니다.
단순 통과율에 단일 임계값(threshold)을 설정하는 것의 문제가 바로 이것입니다. 모든 실패의 비용이 동일하다고 가정한다는 점입니다. 그렇지 않습니다. 장황한 답변은 약간 짜증 난 사용자를 만들 뿐입니다. PII 유출은 공시 의무를 발생시키고, 어쩌면 매우 끔찍한 한 주를 보낼 수도 있게 합니다. 이들을 하나의 숫자로 평균 내는 것은 범주 오류(category error)이며, 이는 현재 LLM-as-judge 파이프라인을 실행하는 대부분의 팀이 인지하지 못한 채 저지르고 있는 실수라고 추측합니다. 왜냐하면 단순 통과율을 구축하는 것이 제가 사용해 본 모든 평가 프레임워크(DeepEval, Promptfoo, LangSmith 모두 기본적으로 이를 제공하며, 그 중 어느 것도 심각도 가중치(severity weighting)를 강제하지 않습니다)의 기본 출력값이기 때문입니다.
[IMG:https://lh3.googleusercontent.com/d/1Xf1IIcHzCOOSS4EsN5wW5PPS_fVxTZ9U]
단순 통과율이 작고 심각한 클러스터를 숨기는 이유
산술적인 측면을 생각해 보십시오. 만약 500개의 테스트 케이스(test cases)가 있고 임계값(threshold)이 "통과율이 최소 90% 이상이어야 함"이라면, 게이트(gate)가 작동하기 전까지 50개의 실패를 흡수할 수 있습니다. 만약 실패 분포가 대부분 무해한 것(잘못된 어조, 약간 긴 응답, 사소한 서식 오류 등)이라면, 게이트는 그에 맞춰 잘 조정된 것입니다. 하지만 허용된 50개의 실패 중 단 몇 개라도 치명적인 범주(돌이킬 수 없는 조치 실행, PII(개인정보) 유출, 실제 금융적 피해를 줄 수 있는 사실적 주장 등)에 속하는 순간, 단순 임계값은 그 차이를 구별할 방법이 없습니다. 그저 개수만 셀 뿐입니다.
우리가 맞닥뜨린 또 다른 실패 모드(failure mode)는 테스트 스위트(test suite) 자체가 불균형했다는 점입니다. PII 처리나 파괴적인 도구 호출(destructive tool calls)을 조사하는 테스트 케이스가 1개 있을 때마다, 어조와 스타일를 조사하는 테스트 케이스가 대략 40개 정도 있었습니다. 어조 문제는 테스트 케이스를 작성하기 쉽고, 누군가가 명확하게 위험 커버리지(risk coverage)보다 커버리지의 폭(coverage breadth)을 최적화했기 때문입니다. 따라서 심각한 범주에 대한 완벽한 재현율(recall)을 달성하더라도, 집계 점수에서는 무해한 범주에 의해 통계적으로 묻혀버릴 수 있습니다.
해결책: 영향 범위(blast radius)에 따른 가중치 부여 및 가중 점수 기반 게이트 적용
이제 우리는 사고가 발생한 후 사후적으로 수정하는 것이 아니라, 작성 시점에 모든 평가(eval) 테스트 케이스에 심각도 수준(severity level) 태그를 지정합니다.
- 심각도 1 (nitpick, 사소한 지적): 문구, 어조, 서식. 짜증을 유발할 뿐 해롭지는 않음.
- 심각도 2 (moderate, 보통): 사실 관계는 틀렸으나 수정 가능하며, 조치가 취해지지 않았고 데이터가 노출되지 않음.
- 심각도 3 (severe, 심각): PII/PHI(개인 건강 정보) 유출, 돌이킬 수 없는 조치(환불 처리, 계정 삭제, 이메일 발송), 또는 사용자에게 금융적 또는 안전상 해를 끼칠 수 있는 주장.
그 다음, 가시성을 위해 단순 통과율(flat pass rate, 여전히 유용한 추세선임)과 심각도 가중 점수(severity-weighted score)를 모두 계산하며, CI(지속적 통합) 게이트는 단순 통과율이 아닌 가중 점수를 기준으로 작동하게 합니다.
"""
severity_gate.py
심각도 가중 평가 점수 산출. 단순 통과율과 ...
우리가 재구성한 사후 분석(postmortem) 수치로 실행해 보면, 단순 통과율(flat pass rate)은 약 0.94(512개 중 481개)로 나오며, 이는 실제로 배포되었던 수치와 정확히 일치합니다. 심각도 가중 점수(severity-weighted score)는 0.823으로 나와 0.98 임계값(threshold)보다 훨씬 낮게 측정됩니다. 이는 6개의 심각도-3(severity-3) 실패 사례가 각각 어조(tone)에 대한 사소한 지적(nitpick)보다 20배의 비용을 발생시켰기 때문입니다. 해당 게이트(gate)가 있었다면 머지(merge)를 차단했을 것입니다.
정직하게 가중치 선정하기
명백한 약점을 짚고 넘어가겠습니다. SEVERITY_WEIGHTS의 가중치는 유도된 상수(derived constant)가 아니라 판단(judgment call)에 의한 것입니다. 우리는 지난번 유사한 사건이 발생했을 때 기술 지원 에스컬레이션(support escalation)과 컴플라이언스 검토(compliance review)에 실제로 소요된 엔지니어링 시간(engineering hours)의 대략적인 수치를 바탕으로, 오후 내내 논쟁한 끝에 심각도-3을 심각도-1의 20배로 설정했습니다. 다른 팀이라면 10배나 50배로 결정하는 것도 합리적일 것입니다. 중요한 것은 정확한 비율이 아니라, 그 비율이 해당 주에 대시보드를 살펴보는 사람의 암묵적인 판단에 맡겨지는 대신, 저장소(repo) 내에 명시적으로 기록되고 버전 관리된다는 점입니다.
또한 테스트 스위트(test suite)의 불균형 문제도 별도로 해결해야 했습니다. 전체 심각도-3 테스트 케이스가 총 6개뿐이고 그중 하나가 불안정(flaky)하다면 가중치를 부여하는 것은 도움이 되지 않습니다. 현재 우리는 PII(개인정보) 처리, 파괴적인 도구 호출(destructive tool calls), 금융 관련 주장(financial claims)을 다루는 40개의 심각도-3 케이스를 확보했습니다. 이는 단순히 넓은 범위를 위해 최적화된 커버리지 지표(coverage metrics)에 나중에 덧붙인 것이 아니라, 의도적으로 추가한 것입니다.
가장 먼저 확인해야 할 사항
- 지난 90일간의 평가(eval) 실행 결과 데이터를 가져와서, 모든 개별 실패 사례를 테스트 카테고리 이름이 아닌 '결과(consequence)'별로 분류하세요. 만약 이런 작업을 해본 적이 없다면, 여러분은 심각도 분포(severity distribution)를 제대로 파악하지 못하고 있을 가능성이 높습니다.
- CI 임계값(threshold)이 단순한 수치(flat number)인지 확인하세요. 만약 그렇다면, 현재의 임계값이 경고를 울리기 전까지 심각한 실패와 전체 실패 사이의 비율을 어느 정도까지 묵인할 수 있는지 질문해 보십시오.
- 테스트 케이스 중 어조나 문구(tone and phrasing)를 검사하는 것과 대비하여, 실제로 심각하거나 되돌릴 수 없는 결과(severe/irreversible outcomes)를 조사하는 케이스가 얼마나 되는지 살펴보세요. 만약 작성하기 쉬운 카테고리에 치우쳐 있다면, 여러분의 종합 점수(aggregate score)는 올바른 것을 측정하기보다 잘못된 것을 측정하고 있는 것입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기