05. 보상하지 않는다는 문장을 놓친 보험 RAG 회고
보험 답변에서 가장 위험했던 오류는 모른다고 말하는 것이 아니었습니다. 약관에 “보상하지 않는다”고 적혀 있는데 보상받을 수 있다고 답하는 것이었습니다.
Insurance_PF를 시작할 때는 PDF를 잘 나누고 도메인 모델을 학습하면 보험 질의응답의 정확도가 높아질 것으로 생각했습니다. 실험을 끝내고 보니 전처리, 검색, 생성은 기본 조건일 뿐이었습니다. 실제로 필요한 것은 부정 조항과 계산 조건을 별도 위험으로 다루는 평가 구조였습니다.
실패를 세 종류로 다시 분류했다
처음에는 최종 답이 맞았는지만 확인했습니다. 이 방식으로는 어느 단계가 문제인지 알 수 없었습니다. 오답 사례를 다시 읽으며 실패를 세 종류로 나눴습니다.
표현이 달라 정답 조항을 찾지 못했다
“노트북 액정이 깨졌다”는 질문과 약관의 “휴대품 손해”는 의미상 연결되지만 token이 거의 겹치지 않습니다. “아내 차에 치였다”와 배우자 관련 면책 조항도 마찬가지입니다. BM25가 초기 FAQ에서는 높은 순위를 기록했지만, 생활어와 약관어가 다른 질문에는 약했습니다.
이 문제는 생성 모델을 바꿔도 해결되지 않는다. 정답 근거가 context에 들어오지 않았기 때문이다. paraphrase와 생활어를 포함한 평가셋으로 Dense, Hybrid, Reranker를 다시 비교해야 한다.
부정 조건을 찾고도 답의 방향을 뒤집었다
배우자 관계나 특정 사고 조건에서 약관은 보상 제외를 설명한다. 모델은 관련 문장을 보면서도 일반적인 보상 안내를 이어 갔다. “보상한다”와 “보상하지 않는다”의 한 단어 차이가 최종 판단을 뒤집었다.
이 실패는 검색 성공 여부만으로 발견할 수 없다. 답변이 근거의 긍정·부정 방향과 일치하는지 확인하는 entailment 평가가 필요하다. 면책, 예외, 단서 조항은 일반 FAQ보다 높은 가중치로 검사해야 한다.
계산을 언어 모델에 맡겨 금액이 틀렸다
장해 등급과 가입금액을 조합하는 질문에서 모델은 6,000만 원을 답했지만, 기록된 정답 계산은 2,400만 원이었다. 또 7급의 지급 배수와 5급의 한도를 잘못 적용한 사례가 남았다.
숫자를 문서에서 정확히 가져오는 것과 그 숫자로 올바르게 계산하는 것은 다른 능력이다. 검색 결과에 산식이 포함돼도 자유 생성만으로 계산하면 중간 오류를 찾기 어렵다. 계산 규칙을 구조화하고 결정적 함수로 처리한 뒤, 모델은 결과를 설명하는 역할만 맡기는 편이 안전하다.
검색 점수와 최종 답변 점수를 분리해야 했다
프로젝트 기록에는 50개 검색 평가가 두 형태로 남아 있다. 한 문서에는 48개 성공과 2개 Top-5 실패가 적혀 있고, 후속 비교표에는 Sparse Recall@5 1.0이 적혀 있다. 평가 대상, 정답 ID, 판정 코드 가운데 무엇이 달랐는지 현재 artifact만으로 확정할 수 없다.
그래서 두 수치를 평균 내거나 더 좋은 결과만 선택하지 않았다. 30개 공통 비교, 50개 후속 비교, 별도 failure report를 각각의 기록으로 취급했다. 이 프로젝트에서 확인된 것은 특정 평가셋에서 Sparse가 강했다는 점이지, 모든 보험 질문을 빠짐없이 검색했다는 뜻이 아니다.
학습 데이터 수 기록도 시점에 따라 달랐다. 데이터 파일, split, model checkpoint, 평가 script의 hash를 한 manifest에 남기지 않으면 같은 이름의 실험도 재현할 수 없다.
다시 만든다면 평가 계약부터 고정한다
후속 버전은 모델 교체보다 평가 단위를 먼저 정리한다.
- 문서와 질문 dataset에 version을 부여하고 정답 조항 ID를 고정한다.
- retrieval은 Recall@K, MRR, 실패 query로 평가한다.
- 생성은 인용 근거 일치, 부정 조건 보존, 숫자 일치로 나눠 평가한다.
- 근거가 없거나 충돌하면 답변을 유보하는 항목을 포함한다.
- 산식이 필요한 질문은 구조화된 계산 함수와 test case로 검증한다.
검색 쪽에서는 BM25를 버리기보다 exact term에 강한 장점을 유지한다. semantic mismatch 질문에만 Dense 후보를 합치고, 그 효과를 고정된 paraphrase set에서 검증한다. Reranker도 전체 query에 무조건 적용하지 않고 후보가 충돌하는 경우의 비용과 순위 개선을 함께 측정한다.
답변 쪽에서는 chunk ID와 조항 경로를 인용하게 한다. 부정 조항을 근거로 사용했는지 자동 검사하고, supporting context가 없으면 “확인할 근거가 부족하다”고 답하도록 평가한다. 보험 판단을 모델의 확신 표현에 맡기지 않는 구조가 필요하다.
이 프로젝트가 보여주는 것과 보여주지 못하는 것
이 프로젝트로 보여줄 수 있는 것은 다음과 같다.
- 11개 보험사 문서를 구조 기반으로 전처리하고 6,402개 검색 단위를 만든 과정
- 한국어 보험 FAQ에서 embedding, 토크나이저, Dense·Sparse·Hybrid를 비교한 근거
- QLoRA를 적용하고 Base, Fine-Tuned, RAG 답변을 구분해 관찰한 과정
- 성공 수치보다 실패 사례를 다시 분류해 다음 설계로 연결한 판단
반대로 production 수준의 보험 상담 정확도나 법률적 신뢰성을 입증한 프로젝트는 아니다. 검색 결과에는 서로 다른 평가 기록이 남아 있고, 생성 평가는 일부 정성 비교에 의존했다. 실제 고객 데이터나 운영 환경에서 검증하지도 않았다.
취업 포트폴리오로 이 프로젝트를 정리하며 강조하고 싶은 부분은 모델 이름이 아니다. 높은 검색 점수가 최종 답변의 안전성을 대신하지 못한다는 것을 확인했고, 오류를 검색·해석·계산 문제로 분리했다. 다음 실험의 우선순위를 성능 홍보가 아니라 재현 가능한 평가와 실패 방지 구조로 바꾼 것이 이 프로젝트의 결과다.