RAG 연습 (6) — 키워드를 바꿔 점수가 올랐는데 그게 함정이었다
RAG 연습 (5)에서 코퍼스를 추가했더니 평균이 0.694까지 올랐습니다. Ragas 0.70 기준선 바로 아래라 마지막 한 발만 더 가면 통과인 상황. 그런데 그 마지막 한 발에서 함정에 빠질 뻔했습니다.
키워드를 바꿨더니 점수가 올랐다
코퍼스를 추가한 뒤에도 두 항목이 50% 미만으로 남아 있었습니다. 하나는 “번들 계약 수행의무 구별”(K-IFRS 1115호 제27조), 다른 하나는 “본인/대리인 구분”(B34~B38)이었습니다.
본인/대리인 항목 답변을 까보니 “본인”, “대리인”은 들어 있는데 골든셋이 정한 키워드 “총액”, “순액”, “주된 책임”이 빠져 있었습니다.
그래서 키워드를 [“본인”, “대리인”, “통제권”, “책임”]으로 바꿨습니다. 점수가 올라갔습니다.
올리고 나서 의문이 들었습니다. “이거 오버피팅 아닌가?” — 맞았습니다. 정확히는 criterion contamination(평가 기준 오염)입니다. 일반적인 오버피팅이 “모델이 훈련 데이터에 과도하게 맞춰지는 것”이라면 여기는 방향이 반대입니다. 평가 기준이 모델 출력에 끌려갑니다.
Criterion contamination이 무서운 건 점수가 올라가기 때문
평가 지표는 “정답이 무엇인가”를 정의하는 도구입니다. 키워드는 “이 질문에 올바른 답변이라면 이 용어들이 들어가야 한다”는 기준입니다.
LLM이 “통제권”이라고 말한다고 해서 정답 기준을 “통제권”으로 바꿔 버리면 평가가 시스템 출력을 따라가는 꼴이 됩니다. 측정자가 측정 대상에게 끌려가는 구조입니다.
“총액”·”순액”은 K-IFRS B34~B38에서 본인/대리인 판단의 회계적 결론입니다. 본인이면 총액 인식, 대리인이면 순액 인식. 이게 빠진 답변은 회계 기준 입장에서 완전하지 않습니다. 시스템이 그 용어를 안 쓴다고 기준을 내리면, 다음 번에 더 부실한 답변이 나와도 점수는 좋게 찍힙니다.
criterion contamination이 무서운 이유는 점수가 떨어지지 않는다는 데 있습니다. 잘못된 방향으로 가는데 계기판이 정상이라고 가리킵니다.
두 루프를 분리한다
점수를 올리는 길이 두 가지입니다.
1
2
A. 평가 기준을 시스템 출력에 맞춘다 ← criterion contamination
B. 시스템 출력이 평가 기준을 충족하도록 시스템을 고친다 ← 정석
다만 평가 기준 자체를 손보는 게 정당한 경우도 있습니다 — 측정 도구에 버그가 있을 때입니다. 그래서 작업을 두 루프로 나눠 둡니다.
평가 품질 루프 — 측정 도구를 올바르게 만드는 작업. 측정 버그를 잡습니다. 예를 들어 답변엔 “27조”인데 키워드는 “제27조”라 불일치하면 같은 조문을 표기 차이로 놓치는 거니 키워드 정규화가 정답입니다. 답변엔 “동일한 금액, 벤더, 날짜”라 적혔는데 키워드는 “동일 금액”·”동일 벤더”·”동일 날짜”로 조사 차이만 있다면 keyword_score에서 공백 처리를 손보는 게 맞습니다. 질문 자체가 “구분 기준은?”인데 키워드엔 “총액/순액”(결과)이 들어 있으면 질문이 결과를 묻지 않으니 질문 쪽을 바꿔야 합니다.
시스템 성능 루프 — RAG 파이프라인을 개선하는 작업. 코퍼스에 없어서 LLM이 훈련 데이터로 답을 채우면 코퍼스를 추가합니다. 올바른 청크가 코퍼스엔 있는데 엉뚱한 청크가 위로 올라오면 검색을 튜닝합니다. LLM이 컨텍스트를 무시하면 프롬프트를 강화합니다.
두 루프 중 어느 쪽인지 가르는 질문
점수가 낮게 나오면 먼저 물어봅니다. “시스템이 틀린 건가, 측정이 틀린 건가?”
| 답변 품질 | 점수 | 원인 | 처리 |
|---|---|---|---|
| 맞는 답 | 낮음 | 측정 버그 | 평가 품질 루프 |
| 틀린 답 | 낮음 | 시스템 갭 | 시스템 성능 루프 |
| 맞는 답 | 높음 | 정상 | 없음 |
| 틀린 답 | 높음 | criterion contamination | 주의 신호 |
가장 위험한 칸은 “틀린 답인데 점수가 높다”입니다. 키워드를 답변에 맞춰 바꾸면 정확히 이 칸이 만들어집니다.
이번에 실제로 분리한 케이스
평가 품질 루프로 처리:
- 번들 계약 수행의무 구별 질문 — 키워드 “제27조”를 “27조”로. 답변이 “27조”로 표기했는데 같은 조문이라 측정 버그.
- 중복 거래 탐지 질문 — 키워드 “동일 금액”·”동일 벤더”·”동일 날짜”를 “금액”·”벤더”·”날짜”로. 답변이 “동일한 금액, 벤더, 날짜”로 적혔는데 조사 차이로 불일치. 측정 설계 문제.
- 본인/대리인 구분 질문 — 질문을 “구분 기준은?”에서 “구분 기준과 수익 인식 방법은?”으로 수정. 원 질문은 결과(총액/순액)를 묻지 않아서 키워드와 어긋나 있었습니다.
keyword_score공백 정규화 — “주된 책임”과 “주된책임”을 같게 처리.
시스템 성능 루프로 처리:
- 번들 계약 수행의무 구별 검색 오류 — 제35조(over-time) 문서가 제27조 자리에 검색돼 올라왔습니다. 제27조 문서에 “번들 계약 HW+SaaS” 맥락을 추가하고 구버전 청크를 DB에서 제거.
아직 남은 시스템 갭:
- 비업무 시간대 거래 탐지 — “00:00”, “06:00” 같은 구체 시간 표현이 답변에 없음. 관련 문서는 있는데 LLM이 추상적으로만 요약합니다. 프롬프트 또는 청크 형태를 손봐야 합니다.
처음에 본인·대리인 질문 키워드를 “통제권”으로 바꾼 건 위 분류 어디에도 안 들어갑니다. 답변이 “통제권”을 말한다고 해서 골든셋이 “통제권”을 받아주는 건 측정이 시스템에 끌려간 것이지, 측정 버그를 고친 게 아닙니다. 그래서 그 변경은 되돌렸습니다.
두 루프를 섞으면 생기는 일
측정 버그를 시스템 갭으로 착각하면 쓸데없는 코퍼스를 넣고 프롬프트를 흔듭니다. 반대로 시스템 갭을 측정 버그로 착각하면 진짜 문제를 방치합니다. 그리고 가장 나쁜 건 criterion contamination — 점수가 오르는데 시스템은 나빠지는 방향이라도 계기판으로는 알 수가 없습니다.
분리해서 관리하면 각 루프에 명확한 종료 조건이 생깁니다. 평가 품질 루프는 측정 버그가 없고 질문·키워드·정답 셋이 일관될 때 끝납니다. 시스템 성능 루프는 올바른 평가에서 점수가 목표에 도달할 때 끝납니다.
점수가 낮을 때 먼저 물어야 할 건 “시스템이 틀린 건가, 측정이 틀린 건가”. 답에 따라 다른 루프를 돌려야 합니다.
(클로드 코드의 도움을 받았습니다.)