6장. RAG 의 원리와 로컬 모델로 옮기기
RAG 가 틀리는 자리
오픈북 시험에서도 틀릴 수 있습니다. 엉뚱한 쪽을 펼치거나, 찢어져 반만 남은 쪽을 보거나, 펼쳐 놓고도 안 보고 쓰거나, 답이 있는데도 없다고 넘어갈 때입니다.
네 카드가 RAG 가 틀리는 네 자리입니다. 앞의 둘은 검색과 조각 쪽의 문제이고, 뒤의 둘은 생성(모델과 프롬프트) 쪽의 문제입니다. 어느 자리에서 틀렸는지에 따라 고칠 곳이 다릅니다.
어디를 고칠까
| 실패 | 알아보는 법 | 고칠 곳 |
|---|---|---|
| 검색 실패 | 정답 조항이 위 k 개에 없다 | 검색(낱말 맞추기, 7장의 의미 검색), k |
| 조각 잘림 | 정답이 두 조각에 반씩 있다 | 나누는 법, 겹치기 |
| 근거 무시 | 정답 조항이 붙어 있는데 다른 숫자를 말한다 | 더 큰 모델, 프롬프트 |
| 지나친 거절 | 정답 조항이 붙어 있는데 "찾지 못했습니다" | 프롬프트의 문구, 모델 |
틀린 답을 나눠 세기
검색 결과와 답을 함께 남겨 두면, 틀린 답이 어느 자리의 실패인지 기계적으로 나눌 수 있습니다.
def where_failed(hit, result):
"""hit: 정답 조항이 위 k 개에 들었나. result: grade() 의 결과."""
if result in ("정답", "모름 맞음"):
return "맞음"
if not hit:
return "검색 실패"
return "지나친 거절" if result == "거절" else "근거 무시"
print(where_failed(False, "거절"), where_failed(True, "거절"), where_failed(True, "오답"))차례로 "검색 실패", "지나친 거절", "근거 무시"가 나옵니다. 검색이 정답 조항을 놓쳤다면 모델이 모른다고 한 것은 오히려 바른 행동입니다.
코드에 나오는 함수
| 코드 | 쉬운 뜻 |
|---|---|
hit | 정답 조항이 위 k 개 검색 결과 안에 들었는지를 True, False 로 적은 값이다 |
result in ("정답", "모름 맞음") | 채점 결과가 두 이름표 가운데 하나인지 본다 |
not hit | hit 가 False 일 때, 곧 검색이 정답 조항을 놓쳤을 때 True 다 |
이 코드가 뜻하는 것
자동차 정비소에서 고장 난 곳을 차례로 짚어 가는 일과 같습니다. 먼저 차가 잘 가는지 보고, 안 가면 연료(검색)가 들어왔는지 보고, 연료가 있는데도 안 가면 엔진(모델과 프롬프트) 쪽을 봅니다.
| 줄 | 하는 일 | 쉽게 말하면 |
|---|---|---|
if result in ("정답", "모름 맞음"): | 바르게 답했으면 "맞음"을 돌려준다 | 잘 가는 차는 손대지 않는다 |
if not hit: | 검색이 정답 조항을 못 찾았으면 "검색 실패"다 | 연료가 안 들어왔다 |
return "지나친 거절" if ... else "근거 무시" | 조항은 붙었는데 모른다고 했으면 지나친 거절, 다른 답을 했으면 근거 무시다 | 연료는 있는데 시동을 안 걸었나, 엉뚱한 길로 갔나 |
결과의 세 낱말은 세 경우를 차례로 넣은 것입니다. 검색이 놓친 거절은 "검색 실패", 검색이 맞힌 거절은 "지나친 거절", 검색이 맞혔는데 틀린 숫자를 말한 답은 "근거 무시"로 나뉩니다.
주의할 점
- 고치기 전에 먼저 셉니다. 실패의 대부분이 검색 실패인데 모델만 키우면 시간과 메모리만 듭니다.
- 문서 자체가 낡았거나 서로 맞지 않으면(한 곳에는 7일, 다른 곳에는 14일) 어떤 RAG 도 바르게 답하지 못합니다. 문서를 고치는 일도 RAG 의 일입니다.