ML 모델 없이 단 50줄의 Python 코드로 LLM 환각 탐지 재현율(Recall) 96% 달성하기
요약
추가적인 ML 모델 학습이나 GPU 없이, 4가지 통계적 신호를 활용하여 LLM의 환각을 탐지하는 효율적인 Python 구현 방법을 소개합니다. HaluEval 데이터셋 테스트 결과, 재현율 96%라는 높은 성능을 달성했습니다.
핵심 포인트
- 모델 없이 통계적 신호만으로 환각 탐지 가능
- 길이 비율, 미인지 단어, 중복도, 숫자 불일치 활용
- 연산 비용 절감 및 결과에 대한 해석 가능성 확보
- Soft flag 기준 재현율 0.96 달성
대부분의 환각 탐지 (Hallucination Detection) 접근 방식은 또 다른 모델을 학습시키라고 말합니다. 저는 그렇게 하고 싶지 않았습니다. 저는 네 가지 통계적 신호 (Statistical Signals), 결합 점수 (Combined Score), 그리고 조정 가능한 임계값 (Tunable Threshold)을 사용했습니다. 미세 조정 (Fine-tuning)도, GPU도, 외부 API도 필요 없었습니다. HaluEval 데이터셋의 실제 사례 10,000개를 대상으로 테스트했습니다.
Soft flag 결과: 정밀도 (Precision) 0.71, 재현율 (Recall) 0.96.
Strict flag 결과: 정밀도 (Precision) 1.00, 재현율 (Recall) 0.38.
작동 원리는 다음과 같습니다.
왜 단순히 모델을 사용하지 않는가?
SelfCheckGPT와 같은 접근 방식은 여러 번의 모델 샘플링과 상당한 연산 자원을 요구합니다. 하루에 수천 개의 답변을 점수화해야 할 때는 비용이 빠르게 불어납니다. 또한, 블랙박스 (Black Box) 위에 또 다른 블랙박스가 놓인 형태가 됩니다. 문제가 발생했을 때, 어느 계층에서 실패했는지 알 수 없습니다.
저는 모든 플래그 (Flag)에 대해 실제로 읽을 수 있는 이유가 있는 방식을 원했습니다.
핵심 아이디어
환각이 포함된 답변은 근거가 있는 (Grounded) 답변과 측정 가능한 방식으로 다르게 행동합니다. 이를 위해 모델은 필요하지 않습니다. 그저 올바른 요소들을 살펴보기만 하면 됩니다.
네 가지 신호가 대부분의 역할을 수행했습니다.
신호 1: 길이 비율 (Length Ratio)
모델이 정답을 모를 때, 내용을 채워 넣으려는 경향이 있습니다. 사실에 충실하기보다는 설득력 있게 들리기 위해 더 많은 텍스트를 생성합니다.
df['answer_len'] = df['answer'].str.split().str.len()
df['knowledge_len'] = df['knowledge'].str.split().str.len()
df['length_ratio'] = df['answer_len'] / df['knowledge_len']
평균 길이 비율: 환각 발생 0.22 vs 미발생 0.05
신호 2: 미인지 단어 비율 (Unknown Word Rate)
근거가 있는 답변은 출처에 가깝게 유지됩니다. 환각이 있는 답변은 참조 텍스트에 전혀 나타나지 않은 단어들을 도입합니다.
def unknown_word_rate(row):
knowledge_words = set(str(row['knowledge']).lower().split())
answer_words = set(str(row['answer']).lower().split())
...
평균 미인지 단어 비율: 환각 발생 0.46 vs 미발생 0.30
신호 3: 질문-답변 중복 (Question-Answer Overlap)
모델이 환각 (Hallucination)을 일으킬 때, 종종 질문을 그대로 되풀이하는 경향이 있습니다. 소스 (Source)에서 정보를 가져오는 대신, 답변에서 질문의 단어들을 반복합니다.
def question_answer_overlap(row):
question_words = set(str(row['question']).lower().split())
answer_words = set(str(row['answer']).lower().split())
...
평균 중복도: 환각 발생 0.39 vs 미발생 0.02
신호 4: 숫자 불일치 (Numeric Inconsistency)
숫자는 모델이 가장 자신 있게 환각을 일으키는 부분입니다. 일반적인 개념은 맞을 수 있지만, 날짜, 수량 또는 통계 수치가 틀릴 수 있습니다.
def numeric_inconsistency(row):
knowledge_nums = set(re.findall(r'\b\d+\b', str(row['knowledge'])))
answer_nums = set(re.findall(r'\b\d+\b', str(row['answer'])))
...
평균 숫자 불일치: 환각 발생 0.087 vs 미발생 0.0001
점수로 결합하기
각 신호가 임계값 (Threshold)을 넘으면 1점씩 기여합니다. 모든 답변은 0점에서 4점 사이의 점수를 받게 됩니다.
df['score'] = (
(df['length_ratio'] > 0.1).astype(int) +
(df['unknown_word_rate'] > 0.4).astype(int) +
...
환각이 발생하지 않은 답변은 0과 1에 밀집되어 있습니다. 환각이 발생한 답변은 2, 3, 4에 밀집되어 있습니다.
평균 점수: 환각 발생 2.18 vs 미발생 0.39
위험 허용 범위에 따른 두 가지 임계값
소프트 플래그 (Soft flag, 점수 >= 1): 정밀도 (Precision) 0.71, 재현율 (Recall) 0.96. 환각을 놓치는 비용이 오탐 (False alarm) 비용보다 클 때 사용하세요. 금융 서비스, 의료, 법률 분야를 생각하면 됩니다.
엄격한 플래그 (Strict flag, 점수 >= 3): 정밀도 (Precision) 1.00, 재현율 (Recall) 0.38. 검토 역량이 제한적이고 명백한 사례만 골라내고 싶을 때 사용하세요.
무엇도 재학습할 필요 없이 임계값을 조정할 수 있습니다. 이는 프로덕션 (Production) 환경에서 매우 중요합니다.
실제 적용하기
def score_answer(knowledge, question, answer):
knowledge_words = set(str(knowledge).lower().split())
answer_words = set(str(answer).lower().split())
...
밀리초(milliseconds) 단위로 실행됩니다. 로드할 모델도, GPU도, API 호출도 필요 없습니다. 모든 답변에 대해 점수와 개별 신호(signal) 값을 기록하세요. 시간이 지나면 이것이 여러분의 보정(calibration) 데이터셋이 됩니다.
실제 사례
환각 발생, 점수 3/4
질문: Zilpo Road로 연결되며 Midland Trail로도 알려진 미국의 고속도로는 무엇인가요? 답변: 사실 Midland Trail로 알려진 것은 US 60이 아니라 Zilpo Road입니다.
모델이 질문에 답하는 대신 출처를 회피하고 모순된 내용을 말했습니다. 탐지되었습니다.
환각 발생, 점수 3/4
질문: Dua Lipa의 데뷔 앨범에서 "New Rules"가 탄생했습니다 — 이 앨범은 몇 년도에 발매되었나요? 답변: 그 앨범은 2018년에 발매되었습니다.
정확한 연도는 2017년입니다. 확신에 차서 틀린 답변을 했으며, 숫자 플래그(numeric flag)가 이를 잡아냈습니다.
환각 아님, 점수 0/4
질문: 네덜란드-벨기에 시리즈인 "House of Anubis"는 무엇을 바탕으로 했으며 — 첫 방송은 몇 년도였나요? 답변: 2006년.
정확하고, 근거가 있으며, 한 단어로 구성되었습니다. 점수는 0점입니다.
알아두어야 할 한계점
이 방식은 비교할 수 있는 출처 지식(source knowledge)이 있는 경우에만 작동합니다. 검색 가능한 출처가 없는 개방형 생성(open-ended generation)에는 적용되지 않습니다. RAG 파이프라인(RAG pipelines) 및 QA 시스템에 가장 적합합니다.
이 방식은 의미론적 이해(semantic understanding)가 아닌 단어 수준의 매칭(word-level matching)을 사용합니다. 출처를 밀접하게 의역(paraphrase)한 환각은 통과될 수도 있습니다. 임계값(thresholds)은 HaluEval을 기준으로 조정되었으므로, 전문적인 도메인에서 작업하는 경우 먼저 자체 데이터로 재보정(recalibrate)하십시오.
소프트 플래그(soft flag)의 정밀도(Precision)가 0.71이라는 것은 플래그 10개 중 약 3개가 오탐(false alarm)임을 의미합니다. 이는 결함이 아니라 트레이드오프(tradeoff)입니다. 이를 모니터링하십시오.
마지막 생각
AI는 입력받은 것을 생성합니다. 출력이 검증되지 않는다면, 여러분은 무엇을 얻고 있는지 알 수 없을 것입니다. 이 프레임워크는 많은 인프라를 추가하지 않고도 점검을 시작할 수 있는 하나의 방법입니다.
GitHub 전체 코드: github.com/ritikade2/llm-hallucination-detector
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기