내 RAG 앱이 계속 환각(Hallucination)을 일으켰던 이유와 해결 방법

몇 달 전, 저는 제가 만든 RAG 지원 봇을 시연했습니다. 봇은 동료에게 환불 정책이 30일이라고 말했습니다. 실제 저희 정책은 14일입니다. 봇은 망설이지 않았습니다. 불확실하다고 말하지도 않았습니다. 아주 자신만만하게 답변을 지어냈습니다.

RAG는 환각을 줄여야 합니다. 하지만 제 설정은 환각을 다른 곳으로 옮기기만 했습니다. 이 시스템을 디버깅하면서 다섯 가지 교훈을 얻었습니다.

  1. 고정된 글자 수로 청크(chunk)를 나누는 것을 멈추세요 저는 약간의 중첩(overlap)을 둔 1,000자 단위의 청크를 사용했습니다. 이것이 문제를 일으켰습니다. 하나의 청크에 배송 규칙과 반품 규칙이 섞이는 경우가 자주 발생했습니다. 모델은 이 서로 다른 섹션들을 섞어서 잘못된 답변 하나를 만들어냈습니다. 해결책: 시맨틱 청킹(semantic chunking)으로 전환했습니다. 제목과 단락을 기준으로 데이터를 나누었습니다. 이렇게 하면 관련 정보가 함께 유지됩니다.

  2. 유사도가 곧 관련성을 의미하지는 않습니다 제 리트리버(retriever)는 코사인 유사도(cosine similarity)를 기반으로 상위 3개의 청크를 가져왔습니다. 청크가 질문과 유사해 보일 수는 있지만, 정답을 포함하고 있지 않을 수도 있습니다. 모델은 컨텍스트에 있는 모든 것이 사실이라고 가정합니다. 해결책: 크로스 인코더(cross-encoder)를 사용하여 리랭킹(reranking) 단계를 추가했습니다. 또한 검색 점수(retrieval scores)를 로깅하기 시작했습니다. 이를 통해 시스템에 실제 답변이 부족한 시점을 파악할 수 있습니다.

  3. 모델에게 실패해도 괜찮다고 말해주세요 기존 프롬프트는 단순했습니다: "컨텍스트를 사용하여 질문에 답하세요." 컨텍스트가 없을 때 모델이 어떻게 해야 하는지에 대한 지침이 없었습니다. 모델은 빈틈을 추측으로 채웠습니다. 해결책: 구체적인 지침을 추가했습니다. "만약 컨텍스트에 답이 없다면, 모른다고 말하세요." 환각 현상이 즉시 줄어들었습니다.

  4. 검색 임계값(retrieval threshold)을 강제하세요 검색에 실패했을 때도 모델은 여전히 일반적인 지식을 사용했습니다. 프롬프트가 작동하기를 바랐지만, 희망은 전략이 아닙니다. 해결책: 엄격한 점수 임계값을 설정했습니다. 상위 검색 점수가 너무 낮으면 시스템이 중단됩니다. 모델이 추측하게 두는 대신 폴백(fallback) 메시지를 반환합니다.

  5. 성공뿐만 아니라 실패에 대해서도 테스트하세요 저는 문서에 포함되어 있다고 확신하는 쉬운 질문들만 테스트했습니다. 모호한 질의나 누락된 정보는 무시했습니다. 환각은 바로 그런 빈틈에서 발생합니다. 해결책: 함정 질문(trap questions)으로 구성된 평가 세트를 구축했습니다. 이는 정답이 시스템에 없는 경우를 말합니다. 저는 변경 사항을 적용할 때마다 이 테스트를 실행합니다.

RAG가 환각을 완전히 없애주지는 않습니다. 다만 환각을 제어 가능하게 만들어 줄 뿐입니다. 제 봇이 여전히 모든 것을 아는 것은 아닙니다. 하지만 이제는 불확실할 때 그렇다고 말합니다. 그것이 바로 도구를 실제로 사용할 수 있게 만듭니다.

Source: https://dev.to/pallavi_sharma_10c1a6f1da/why-my-rag-app-kept-hallucinating-and-how-i-fixed-it-3i10