
LLM 판정 점수를 신뢰할 수 있는가 — 채점자를 인간 없이 매주 테스트하는 메커니즘을 만들었다
요약
LLM-as-a-judge 방식의 신뢰성을 검증하기 위해 인간의 개입 없이 메타모픽 테스팅(Metamorphic Testing)을 활용하는 자동화 메커니즘을 소개합니다. 원문을 기계적으로 악화시킨 후 Judge의 식별력을 측정하여 품질 점수의 신뢰도를 확보하는 방법을 다룹니다.
핵심 포인트
- LLM Judge의 신뢰성을 위해 정답 라벨 대신 '원문 > 악화판' 관계를 이용한 검증 수행
- 악화판 생성 시 LLM 대신 기계적 변환을 사용하여 검증의 객관성 확보
- 메타모픽 테스팅 개념을 응용하여 정답 없이도 Judge의 식별력 측정 가능
- 평가 기준(간결함, 안전성 등)에 따라 불변 조건이 깨질 수 있는 함정 주의
LLM의 출력 품질을 다른 LLM(Judge)이 채점하게 한다. 이른바 LLM-as-a-judge 방식으로, 우리 프로덕트에서도 실제 트래픽을 매일 자동으로 채점하고 있다.
그러던 어느 날 깨달았다. 대시보드에 「품질 93/100」이라고 표시되어 있지만, 이 93이라는 숫자를 믿어도 좋다는 근거가 어디에도 없다는 것을. 만약 Judge가 고장 난다면, 품질 점수는 전부 깨끗한 거짓말이 된다. 채점 메커니즘을 만든 당사자로서 이는 상당히 찝찝한 일이다.
전형적인 답은 「사람의 채점과 대조하는 것」이다. 실제로 만들어 보았다. 사람이 몇 건을 채점하고 Judge와의 일치율을 산출한다. 작동은 했지만, 운용한 지 며칠 만에 문제가 명확해졌다. 사람(나)이 채점을 계속할 수 없다. 몇 건이라면 하겠지만, 매주는 불가능하다. 사용자에게 매주 채점 당번을 요구하는 프로덕트는 논외다.
그래서 인간의 개입 없이 Judge를 검증하는 방법을 고민하기로 했다. 이 기사는 그 구현에 관한 이야기다.
발상: 정답에 라벨을 붙이는 것이 아니라, 정답의 「관계」를 구축한다
막혀 있었던 지점은 「올바른 점수를 알기 위해서는 누군가가 채점할 수밖에 없다」라는 전제였다. 하지만 잘 생각해보면 절대적인 정답은 필요 없다.
실제로 수락된 응답이 있다고 가정하고, 그 복사본을 기계적으로 악화시킨다.
| 악화 방식 | 생성 방법 | 보장되는 열화 |
|---|---|---|
| 수치 변경 | 응답 중의 수치를 기계적 변환(×2+7) | 사실 정확성 |
| ... |
이때 「원문 > 악화판」이라는 순서는 만드는 방식으로부터 논리적으로 보장된다. 누구의 주관도 아니다. Judge에게 양쪽을 모두 채점하게 하여, 악화판을 제대로 낮게 채점할 수 있는지 확인하면 정답 라벨 없이도 Judge의 식별력을 측정할 수 있다.
소프트웨어 테스트 세계에서 메타모픽 테스팅 (Metamorphic Testing)이라고 불리는 개념을 응용한 것이다. LLM Judge의 평가에 사용하는 연구도 나오고 있지만, 내가 찾아본 범위 내에서는 이를 고객 계정별로 매주 자동으로 돌리는 제품은 아직 보이지 않았다.
중요한 설계 결정이 하나 있다. 악화판 생성에 LLM을 사용하지 않는다. LLM에게 「나쁜 응답을 만들어줘」라고 부탁하면, 이번에는 악화판의 품질이라는 새로운 검증 문제가 발생한다. 수치의 기계적 변환과 문장의 삭제는 결정적이며, 생성 오류가 구조적으로 발생하지 않는다.
판정 방법
원문과 악화판 한 세트를 동일한 평가 기준으로 채점하게 하는 시험을, 이 기사에서는 「프로브 (Probe)」라고 부른다. 스코어는 0..1로 정규화하여,
- 원문 − 악화판 ≥ 0.25 → 탐지 (1~5 스케일 환산 시 1점 차)
- 악화판 > 원문 → 역전 (명백한 실패)
- 그 외 → 간과
「안정성」도 측정하고 싶었지만, 여기서 한 번 실수했다. 당초에는 「같은 입력을 두 번 채점하여 편차를 본다」는 생각이었으나, 우리 Judge는 temperature 0으로 결정론적이기 때문에 재채점은 똑같은 답이 돌아올 뿐이라 무의미했다. 대신, 줄바꿈과 공백만 바꾼 동일 내용의 정렬판을 채점하게 하여 스코어가 움직이지 않는지 보고 있다. 의미를 바꾸지 않는 표층 변화에 대한 강건성(Robustness)이다.
함정 1: 불변 조건이 성립하지 않는 평가 기준이 있다
구현 후 리뷰를 돌렸더니 갑자기 본질적인 지적을 받았다.
「간결함」을 측정하는 기준에 문장 삭제를 적용하면, 삭제하는 편이 더 좋은 응답이 될 수 있다. 「안전성」 기준이라면, 무관한 응답으로 바꾸는 것이 오히려 안전한 쪽으로 치우칠 수 있다. 즉 「원문 > 악화판」이라는 불변 조건은 정확성·완전성·관련성 계통에서만 성립한다.
이를 간과하면 건전한 Judge가 「간과」 또는 「역전」 판정을 받아 신뢰도 숫자가 위양성(False Positive)으로 오염된다. 대상 평가 기준을 이름과 루브릭(Rubric)으로 판정하여, 간결함·톤·안전성 계통은 프로브 대상에서 제외했다. 보장할 수 없는 축은 「미측정」으로 표시하는 것이 부풀려진 숫자보다 정직하다.
함정 2: 주간 cron과 과금의 관계는 생각보다 허점이 많다
프로브는 Judge 호출, 즉 과금되는 LLM 호출을 동반하므로 주 1회·계정당 최대 5개 프로브로 제한하고 있다. 이 「주 1회」 관리가 리뷰에서 3번이나 수정하게 된 가장 큰 늪이었다.
허점 1: 전멸하면 기록이 남지 않아 매 tick 재시도한다. 「이번 주에 이미 프로브를 수행했는가」를 결과 테이블의 유무로 판정했기 때문에, Judge API가 다운되어 모든 프로브가 실패하면 기록이 0이 된다 → 15분 뒤의 cron이 다시 도전 → 실패 → 무한히 예산만 낭비된다. 실행 전에 원자적(Atomic)으로 「이번 주의 할당량」을 확보하는 claim 방식으로 변경했다.
INSERT INTO ops_kv (k, v, updated_at) VALUES (?, '1', datetime('now'))
ON CONFLICT(k) DO UPDATE SET updated_at = datetime('now')
WHERE ops_kv.updated_at < datetime('now', '-7 days')
...
허점 2: 마감 직전에 슬롯(Slot)만 확보하고 공회전하는 경우입니다. cron은 다른 처리와 시간 예산(Time budget)을 공유하므로, 선행 처리가 예산을 다 써버린 직후에 프로브(Probe) 차례가 오면, 슬롯은 확보했음에도 단 1건도 완수하지 못한 채 종료됩니다. 그러면 다음 1주일 동안 해당 계정은 프로브되지 않습니다. 프로덕션 투입 첫 번째 틱(Tick)에서 실제로 이 문제를 겪었습니다. 그래서 '남은 시간이 1회 프로브 분량에 미치지 않는다면 슬롯을 확보하지 않는다'로 변경했습니다.
허점 3: 반대로, 부분 실행 시마다 슬롯을 반환하면 연타(Spamming)가 발생한다는 점입니다. 허점 2의 대책으로 '0건으로 종료되면 슬롯을 해제한다'는 단순한 방식을 적용하면, 마감이 만성적으로 타이트한 환경에서는 '1회 호출하여 과금 → 슬롯 해제 → 15분 후 다시 1회 호출'의 루프가 성립됩니다. 결국, 과금을 동반하는 호출이 단 한 번이라도 진행되었다면 슬롯은 소비된 것으로 간주하고, 진행 전의 중단(Interruption)에 대해서만 해제한다는 선을 긋기로 했습니다.
과금, 재시도(Retry), 그리고 스로틀링(Throttling)이 얽힌 처리는 '실패했을 때 어떻게 되는가'를 성공 경로(Success path)보다 3배는 더 고민해야 한다는 것이 이번의 배움입니다.
함정 3: 고객 데이터를 외부로 내보내는 경로에 대한 동의는, 저장 시점이 아니라 전송 시점에 확인해야 한다
프로브는 고객의 실제 응답(평문 저장에 동의한 데이터)을 저지(Judge)에게 보냅니다. 처음에는 '평문이 저장되어 있음 = 동의 완료'라고 판단하여 실행했으나, 이 역시 리뷰 과정에서 제동이 걸렸습니다. 사용자가 평문 저장을 해제한 직후에는, 저장된 데이터가 삭제되기 전까지 동의가 없음에도 데이터만 남아 있는 시간이 존재합니다.
저장 여부를 전송 가능 여부의 근거로 삼아서는 안 됩니다. 전송 직전에 현재의 동의 상태를 매번 확인해야 합니다. 데이터를 외부 API로 내보내는 자동화 로직을 작성하는 사람이라면, 이러한 시간차(TOCTOU, Time-of-Check to Time-of-Use)를 사양(Specification)으로서 한 번쯤 의심해 보아야 합니다.
프로덕션 첫날, 갑자기 '역전' 현상이 나타났다
가장 흥미로웠던 부분은 여기입니다. 프로덕션에 투입한 첫 번째 주간 실행에서, 데모 환경의 저지가 수치를 조작하여 품질을 떨어뜨린 개악(Degradation) 버전을 원문보다 더 높게 채점했습니다. 교과서적인 역전 현상입니다. 다른 환경에서는 3회 프로브 전건 검출(식별률 100%)이었으므로, 저지의 개체 차이(정확히는 루브릭(Rubric)과 데이터의 궁합)가 제대로 수치로 나타난 셈입니다.
역전이나 미검출이 일정 비율을 넘어서면, 실패한 프로브의 원문과 개악 버전을 재료로 삼아 루브릭 수정안을 자동으로 초안 작성하여 사용자의 수신함에 넣어주는 단계까지 연결했습니다. 인간이 하는 일은 수정안을 승인할지 말지를 판단하는 것뿐입니다.
한계점도 명시해 둔다
단측 검정(One-sided test)입니다. '명확한 악화(Degradation)를 찾아낼 수 있는가'만을 측정할 수 있습니다. 모든 데이터에 낮은 점수를 매기는 방식의 고장은 검출할 수 없습니다(그 부분은 포맷 안정성과 향후 기대 출력(Expected output)과의 대조를 통해 보완할 예정입니다).
주관적 축은 검증할 수 없습니다. 톤(Tone)의 좋고 나쁨에 대해서는 '보증된 개악'을 만들어낼 수 없습니다.
프로브의 난이도 교정(Calibration)이 다음 과제입니다. 결정적인 개악은 인간이라면 한눈에 알 수 있는 수준이므로, 식별률이 포화 상태에 이르면 의미가 퇴색됩니다. 포화 시에는 LLM이 생성한 미묘한 개악 단계로 넘어갈 예정이지만, 이는 '개악의 품질' 문제로 다시 진입하는 것이기도 합니다.
검수하는 측을, 검수한다
코드를 작성한 AI가 '완료했습니다'라고 자기 보고하는 구조에서는 부정행위를 바로잡을 수 없습니다. AI 코딩 문맥에서 자주 언급되는 이야기입니다. 채점도 같은 구조입니다. 채점자를 배치하는 순간, '채점자가 옳은가'라는 한 단계 높은 문제가 발생하며, 그 부분을 인간의 정신력으로 메우는 설계는 지속될 수 없습니다.
정답을 모르더라도, 정답의 순서 관계(Ordinal relationship)라면 기계적으로 만들 수 있습니다. 이 점이 핵심입니다. 평가 파이프라인을 구축하고 있는 분들이라면, 라벨링(Labeling) 작업에 지치기 전에 한 번 시도해 보시기 바랍니다.
만들고 있는 것: Argosvix — LLM 호출을 기록하여 비용, 품질, 안전성을 AI가 감시하는 Observability 서비스입니다. 이 글의 메커니즘은 품질 채점의 신뢰성 검증으로서 프로덕션에서 작동하고 있습니다.
Discussion

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기