엔터프라이즈 RAG의 가장 큰 위험: 맞은 것처럼 보이지만 틀린 답변
요약
엔터프라이즈 RAG 시스템에서 발생하는 '그럴듯하지만 틀린' 답변의 위험성을 경고합니다. 단순한 답변 생성을 넘어, 데이터 파싱 오류나 잘못된 범위 참조와 같은 미세한 오류를 추적하고 복구할 수 있는 파이프라인 구축의 중요성을 강조합니다.
핵심 포인트
- RAG의 핵심 문제는 단순 환각이 아닌 '그럴듯한 오답'임
- PDF 표 파싱 오류 및 잘못된 재무 범위 참조 주의 필요
- 실패를 추적 가능하고 복구 가능한 파이프라인 구축 필수
- 단순 생성보다 품질 개선의 반복 가능성이 중요함
대부분의 RAG 데모는 처음에는 인상적으로 느껴집니다.
문서를 업로드하고 질문을 던지면, 시스템이 인용구와 함께 유창한 답변을 반환합니다. 예를 들어:
2023년 Tesla의 자동차 매출은 얼마였나요?
시스템은 연례 보고서에서 구절을 검색(Retrieval)하고, 답변을 생성(Generation)하며, 출처를 첨부합니다.
그 시점에서는 시스템이 바로 사용 가능한 수준에 근접했다고 생각하기 쉽습니다.
하지만 저만의 재생 에너지 산업 RAG 에이전트를 구축한 후, 답변을 하는 것은 단지 첫 번째 단계일 뿐이라는 것을 깨달았습니다. 더 어려운 문제는 그 답변이 실제로 신뢰할 수 있는지 증명하는 것입니다.
엔터프라이즈 문서에서는 많은 실패 사례가 명백한 환각(Hallucination)으로 나타나지 않습니다. 대신 "거의 맞을 것 같은" 답변으로 나타납니다:
- 숫자는 존재하지만, 잘못된 재무 범위(Financial scope)에서 가져온 경우
- 답변은 맞지만, 인용구(Citation)가 실제로 이를 뒷받침하지 않는 경우
- PDF 표가 파싱(Parsing)되었으나, 지표(Metric)와 값이 어긋난 경우
- 올바른 근거가 검색되었으나, 순위(Rank)가 너무 낮게 매겨진 경우
- 하나의 잘못된 사례를 수정하면 다른 사례에서 퇴보(Regression)가 발생하는 경우
이것이 제가 기존 RAG 시스템 위에 '경험 + 복구 파이프라인 (Experience + Repair Pipeline)'을 추가한 이유입니다.
목표는 모델이 더 듣기 좋게 말하도록 만드는 것이 아니었습니다. 목표는 실패를 추적 가능하게(Traceable) 만들고, 복구(Repair)를 테스트 가능하게 하며, 품질 개선을 반복 가능하게(Repeatable) 만드는 것이었습니다.
기존 프로젝트
제 프로젝트의 첫 번째 버전은 재생 에너지 산업 연구 에이전트였습니다.
이 에이전트는 연례 보고서, 투자자 자료, 공개 문서에서 근거를 검색하여 전기차, 배터리, 에너지 저장 장치(ESS), 태양광 기업에 관한 연구 질문에 답변했습니다.
질문 예시는 다음과 같습니다:
- 2023년 Tesla의 자동차 매출은 얼마였나요?
- First Solar가 연례 보고서에서 공개한 재무 성과는 무엇인가요?
- LONGi Green Energy가 언급한 용량 확장 계획은 무엇인가요?
- CATL의 글로벌 에너지 저장 배터리 시장 점유율은 얼마였나요?
이 시스템은 이미 문서 수집(Ingestion), 청킹(Chunking), 임베딩(Embeddings), 하이브리드 검색(Hybrid retrieval), 재순위화(Reranking), 근거 인용(Evidence citation), 구조화된 재무 지표 추출(Structured financial metric extraction), 프론트엔드 워크플로, 그리고 Docker 배포를 지원하고 있었습니다.
하지만 첫 번째 버전이 작동하기 시작하자, 다른 종류의 문제가 나타나기 시작했습니다.
RAG (Retrieval-Augmented Generation) 시스템은 질문에 답변을 할 수 있으면서도 여전히 틀릴 수 있습니다.
실제 실패 사례: 숫자는 실제였으나, 범위(Scope)가 틀렸다
한 가지 나쁜 사례는 다음과 같았습니다:
2023년 CATL의 영업활동으로 인한 순현금흐름(net cash flow from operating activities)은 얼마였습니까?
시스템의 답변은 다음과 같았습니다:
9,282,612.44만 위안 (ten thousand RMB)
이것은 환각 (hallucination)된 숫자가 아니었습니다. 이 숫자는 실제로 CATL의 2023년 연례 보고서에 등장했으며, 영업활동으로 인한 순현금흐름과 관련이 있었습니다.
언뜻 보기에는 정확해 보였습니다.
하지만 제 평가 세트(evaluation set)의 골드 증거(gold evidence)는 다른 표, 즉 지배기업 현금흐름표(parent company cash flow statement)를 가리키고 있었습니다.
해당 증거에 대한 정답은 다음과 같았습니다:
5,647,457.04만 위안 (ten thousand RMB)
즉, 시스템이 숫자를 지어낸 것이 아니었습니다. 실제 숫자를 찾아냈지만, 잘못된 재무 범위(financial scope)에서 가져온 것이었습니다.
이러한 종류의 실패는 매우 위험합니다. 왜냐하면 전문적으로 보이기 때문입니다. 답변이 명백하게 틀린 것이 아니기 때문입니다. 정확한 표, 범위, 행(row), 그리고 인용(citation)을 확인했을 때만 문제를 인지할 수 있습니다.
또 다른 실패: 답변은 맞았으나, 인용(Citation)이 틀렸다
또 다른 사례는 다음과 같았습니다:
CATL에는 박사 및 석사 학위 연구원이 각각 몇 명입니까?
답변은 정확했습니다:
박사 연구원 361명 및 석사 연구원 3,913명.
하지만 인용(citation)은 실제 골드 증거(gold evidence) 대신 유사한 청크(chunks)들을 가리키고 있었습니다.
해당 청크들에도 “박사(PhD)”, “석사(master’s)”, “R&D 직원(R&D staff)”과 같은 단어들이 포함되어 있었습니다. 일부에는 관련 숫자도 들어 있었습니다. 하지만 그것들은 이 답변을 뒷받침하는 가장 직접적인 증거는 아니었습니다.
엔터프라이즈 RAG에서는 인용(citation)의 품질이 중요합니다.
사용자는 답변만을 필요로 하지 않습니다. 답변이 어디에서 왔는지 알아야 합니다.
그렇기 때문에 저는 인용 정확도(citation accuracy)를 단순히 있으면 좋은 기능(nice-to-have)이 아니라, 별도의 지표(metric)로 취급하기 시작했습니다.
실패 사례가 스스로를 설명하게 만들기
RAG 시스템이 실패할 때, 일반적인 워크플로(workflow)는 매우 수동적입니다.
잘못된 사례를 열고, 검색된 청크(retrieved chunks)를 조사하고, 무엇이 잘못되었는지 추측하고, 무언가를 변경한 뒤, 몇 가지 질문을 다시 실행하는 방식입니다.
몇 가지 사례에는 효과가 있을 수 있습니다. 하지만 확장성(scale)이 없습니다.
그래서 저는 경험(Experience) 레이어를 추가했습니다.
이 프로젝트에서 경험(experience)은 단순한 로그(log)가 아닙니다.
로그는 저에게 다음과 같은 정보를 알려줍니다:
입력값은 무엇이었는가?
출력값은 무엇이었는가?
무언가 충돌(crash)이 발생했는가?
경험(experience)은 저에게 다음과 같은 정보를 알려주어야 합니다:
이 케이스는 왜 실패했는가?
실패가 검색(retrieval), 재순위화(reranking), 답변 추출(answer extraction), 인용(citation), 또는 판단(judging) 단계 중 어디에서 발생했는가?
문제가 PDF 표 파싱(PDF table parsing)으로 인해 발생했는가?
...
각 실패 케이스는 다음과 같은 구조화된 정보로 변환됩니다:
root_cause (근본 원인)
root_cause_detail (근본 원인 상세)
diagnostics (진단)
...
제가 반복적으로 목격한 몇 가지 실패 유형은 다음과 같습니다:
table_line_break (표 줄바꿈)
duplicate_equivalent_chunk (중복된 동등 청크)
market_share (시장 점유율)
...
진단(diagnostics) 데이터에는 다음과 같은 상세 정보도 저장됩니다:
answer_numbers (답변 번호)
question_terms (질문 용어)
...
이를 통해 실패한 케이스는 고립된 버그에서 시스템이 추론(reason)할 수 있는 대상으로 변합니다.
복구 파이프라인(Repair Pipeline): 추측에 의한 RAG 수정을 중단하라
실패 케이스에 구조화된 설명이 갖춰지자, 저는 다음 단계인 복구 후보(repair candidates)를 구축했습니다.
복구 후보는 즉각적인 코드 변경이 아닙니다. 이는 반드시 테스트를 거쳐야 하는 제안된 수정안입니다.
루프는 다음과 같이 구성됩니다:
eval set (평가 세트)
→ failed cases (실패 케이스)
→ experience (경험)
...
제가 사용한 복구 후보에는 다음과 같은 것들이 포함되었습니다:
table_row_stitch (표 행 이어붙이기)
equivalent_citation_group (동등 인용 그룹)
...
시장 점유율 바인딩 (Market Share Binding)
시장 점유율 관련 질문은 종종 한 단락 안에 많은 백분율(percentage)을 포함하고 있습니다.
보고서에는 다음과 같은 내용이 언급될 수 있습니다:
- EV 배터리 시장 점유율
- 에너지 저장 장치(ESS) 배터리 시장 점유율
- 글로벌 시장 점유율
- 국내 시장 점유율
- 전년 대비 성장률
시스템은 단순히 근처에 있는 백분율을 선택해서는 안 됩니다.
이 케이스를 위해, 복구 후보는 다음과 같이 바인딩합니다:
subject (주체) + market (시장) + metric (지표) + value (값) + citation (인용)
따라서 값은 단순히 동일한 청크 내의 아무 백분율이 아니라, 요청된 주체 및 시장 맥락과 일치해야 합니다.
표 행 이어붙이기 (Table Row Stitching)
PDF 표는 종종 행을 분리해 버립니다.
사람은 다음과 같은 내용을 이해할 수 있습니다:
영업 활동으로 인한 순현금흐름
5,647,457.04
하지만 파서 (parser)는 지표와 값을 별개의 행으로 취급할 수 있습니다.
table_row_stitch 후보는 다음과 같이 결합하여 행을 재구성하려고 시도합니다:
테이블 제목
지표 행
값 행
...
이는 CATL 영업 현금 흐름 사례를 해결하는 데 도움이 되었습니다.
동등 인용 그룹 (Equivalent Citation Groups)
때때로 답변은 정답이지만, 인용된 청크 (chunk)가 정확한 골드 청크 (gold chunk)가 아닌 경우가 있습니다.
이는 청크 중첩 (chunk overlap), 중복된 테이블, 또는 인접한 페이지에 걸친 반복된 증거로 인해 발생할 수 있습니다.
그래서 저는 equivalent_citation_group을 추가했습니다.
인용된 청크와 골드 청크가 핵심 질문 용어와 핵심 답변 값을 공유한다면, 이들은 동등한 지원 증거로 취급될 수 있습니다.
CATL R&D 인력 사례의 경우, 다음을 모두 포함하는 청크:
PhD: 361
Master’s: 3,913
은 동일한 답변에 대한 동등한 증거로 그룹화될 수 있습니다.
리랭크 구절 힌트 (Rerank Phrase Hints)
때때로 올바른 증거가 검색되기는 하지만, 4위나 5위로 순위가 매겨지는 경우가 있습니다.
이 경우, 모델은 그보다 위에 순위가 매겨진 유사한 청크를 인용할 수 있습니다.
rerank_exact_phrase_hint는 질문 용어, 답변 값, 그리고 골드와 유사한 구절 (gold-like phrases)을 사용하여 더 관련성 높은 증거가 상위로 올라가도록 돕습니다.
수락 게이트 (The Acceptance Gate)
수정 후보 (repair candidates)는 단지 하나의 사례를 해결했다고 해서 수락되지 않습니다.
반드시 타겟 회귀 테스트 (targeted regression)를 통과해야 합니다.
수락 게이트는 다음을 확인합니다:
실패한 사례의 수가 감소했는가?
답변 정확도가 유지되거나 향상되었는가?
인용 정확도가 유지되거나 향상되었는가?
...
이 과정에서 실제 회귀 (regression) 문제가 발견되었습니다.
한 시점에서, 새로운 수정 후보 세트가 마지막 두 개의 잘못된 사례를 해결했지만, 이전에 해결되었던 세 개의 사례를 다시 실패하게 만들었습니다.
만약 제가 마지막 두 사례만 보았다면, 수정이 성공했다고 생각했을 것입니다.
하지만 수락 게이트는 이를 거부했습니다.
그 후, 저는 후보 병합 (candidate merging)을 추가했습니다. 과거에 수락된 후보들을 다시 회귀 테스트를 실행하기 전에 새로운 후보들과 병합하는 방식입니다.
후보 병합을 통해 다섯 개의 잘못된 사례가 모두 통과되었습니다.
1회 반복 결과
이번 라운드에서는 57개의 QA 사례를 평가했습니다.
여러 번의 반복 (iterations) 과정을 거친 후, 5개의 대표적인 실패 사례 (bad cases)가 남았습니다. 이 사례들은 시장 점유율 추출, PDF 표 줄 바꿈, 재무제표 범위, 인용 결합 (citation binding), 그리고 재순위화 (reranking) 문제를 포함하고 있었습니다.
수정 전:
5개의 타겟 실패 사례
5개 실패
답변 정확도: 60%
...
첫 번째 수정 후보 (repair candidate) 적용 후:
5개의 타겟 실패 사례
2개 실패
답변 정확도: 80%
...
남은 두 사례를 수정하고 이전의 후보들을 병합한 후:
5개의 타겟 실패 사례
0개 실패
답변 정확도: 100%
...
이것이 이제 전체 RAG 시스템이 100% 정확하다는 의미는 아닙니다.
이것은 이 특정 실패 사례 세트에 대해, 파이프라인 (pipeline)이 다음과 같은 작업을 수행할 수 있었음을 의미합니다:
실패 감지 (detect failures)
실패 원인 설명 (explain failures)
수정 후보 생성 (generate repair candidates)
...
이는 수동으로 몇 가지 질문을 던져보고 시스템이 "더 나아진 것 같다"라고 판단하는 것보다 훨씬 더 신뢰할 수 있는 방식입니다.
스케줄된 작업 (Scheduled Jobs)과 CI/CD가 이를 더 유용하게 만드는 이유
현재 이 파이프라인은 수동으로 실행할 수 있습니다.
더 유용한 방향은 이를 스케줄된 작업 (scheduled jobs) 및 CI/CD와 연결하는 것입니다.
엔터프라이즈 RAG 시스템은 정적이지 않습니다. 다음과 같은 상황이 발생할 때마다 품질이 변할 수 있습니다:
새로운 문서가 추가될 때
청크 (chunks)가 재구축될 때
임베딩 모델 (embedding models)이 변경될 때
...
각각의 변경 사항은 무언가를 조용히 망가뜨릴 수 있습니다.
새로운 청킹 (chunking) 전략은 재현율 (recall)을 높일 수 있지만 인용 정확도 (citation accuracy)를 해칠 수 있습니다.
프롬프트 (prompt) 업데이트는 답변을 더 유창하게 만들 수 있지만 근거 기반 (grounded) 성능을 떨어뜨릴 수 있습니다.
PDF 파서 (parser) 수정은 하나의 표 문제는 해결할 수 있지만 다른 표의 정렬을 어긋나게 할 수 있습니다.
재순위화기 (reranker) 변경은 어떤 쿼리 (query)에 대해서는 올바른 증거를 상단으로 올릴 수 있지만, 다른 쿼리에 대해서는 순위를 낮출 수 있습니다.
만약 '경험 + 수정 파이프라인 (Experience + Repair Pipeline)'이 스케줄된 작업이나 CI/CD에 연결된다면, 다음과 같은 작업을 자동으로 실행할 수 있습니다:
평가 (evaluation)
실패 경험 생성 (failure experience generation)
수정 후보 생성 (repair candidate generation)
...
RAG 엔지니어에게 이는 반복적인 부분 점검 (spot checking) 업무가 줄어듦을 의미합니다.
매번 변경 사항이 있을 때마다 몇 가지 질문을 반복해서 던지는 대신, 시스템이 다음과 같이 보고할 수 있습니다:
어떤 사례가 실패했는지
왜 실패했는지
어떤 수정 후보가 생성되었는지
...
이 파이프라인 (Pipeline)은 엔지니어를 대체하기 위한 것이 아닙니다. 반복적인 디버깅 (Debugging)을 줄이고 품질 검사 (Quality checks)를 반복 가능하게 만들기 위한 것입니다.
그러면 엔지니어는 다음과 같은 상위 수준의 결정에 집중할 수 있습니다:
이 수정 후보 (Repair candidate)를 수락해야 하는가?
이 실패는 데이터 파싱 (Data parsing), 검색 (Retrieval), 답변 추출 (Answer extraction), 또는 판단 (Judging) 중 무엇 때문에 발생했는가?
품질 게이트 (Quality gate)가 프로덕션 (Production)에 적용하기에 충분히 강력한가?
...
이는 전통적인 프롬프트 튜닝 (Prompt tuning)보다는 RAG QAOps에 더 가깝습니다.
나의 교훈 (My Takeaway)
나는 예전에 RAG를 다음과 같이 생각했습니다:
검색 (Retrieval) + 생성 (Generation)
이제 나는 엔터프라이즈 RAG가 다음과 같아야 한다고 생각합니다:
검색 (Retrieval)
+ 생성 (Generation)
+ 평가 (Evaluation)
...
어려운 부분은 모델이 답변하게 만드는 것이 아닙니다.
어려운 부분은 모든 답변에 대해 책임을 지게 (Accountable) 만드는 것입니다.
엔터프라이즈 문서 시나리오에서, 많은 실패는 명백한 환각 (Hallucination)이 아닙니다. 그것들은 미묘하게 "거의 맞을 뻔한" 답변들입니다:
숫자는 존재하지만, 재무 범위 (Financial scope)가 틀림.
답변은 맞지만, 인용 (Citation)이 틀림.
증거 (Evidence)는 검색되었으나, 순위 (Rank)가 너무 낮음.
...
이러한 문제들은 수동적인 샘플 검사 (Spot checks)만으로는 관리하기 어렵습니다.
그것이 바로 내가 엔터프라이즈 RAG에 경험 + 수정 파이프라인 (Experience + Repair Pipeline)이 필요하다고 믿는 이유입니다.
만약 RAG의 첫 번째 단계가 "답변할 수 있는가"이고, 두 번째 단계가 "평가될 수 있는가"라면, 세 번째 단계는 다음과 같아야 합니다:
스스로를 지속적으로 수정할 수 있어야 하며, 언제 자동 수정을 하지 말아야 할지를 알아야 한다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기