검색은 맞는데 답이 틀릴 때, RAG 인용 검증부터 확인하세요

RAG 인용 검증

RAG를 도입하면 환각이 저절로 사라진다고 생각하는 분들이 많은데요, 실제로는 검색기가 정확한 문서를 가져와도 답변 단계에서 왜곡되는 경우가 흔합니다. 이럴 때 필요한 게 바로 RAG 인용 검증입니다. 검색된 근거 문서와 모델이 실제로 인용한 문장이 일치하는지 별도로 확인하는 절차인데요, 이 글에서는 근거 인용을 강제하는 프롬프트 설계부터 인용 검증을 코드로 자동화하는 방법까지 구체적으로 다룹니다.

왜 검색 결과는 맞는데 답변은 틀릴까요?

RAG(Retrieval-Augmented Generation)는 질문과 관련된 문서를 먼저 검색하고, 그 문서를 근거 삼아 답을 생성하는 구조입니다. 원 논문인 Facebook AI의 “Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks”에서도 검색과 생성을 분리한 이유를 지식 집약적 작업의 정확도를 높이기 위해서라고 설명하고 있습니다. 이 논문은 arxiv.org에 공개된 원문에서 확인할 수 있어요.

문제는 검색기가 정확한 청크를 가져와도, 생성 모델이 그 내용을 그대로 쓰지 않고 사전학습 때 익힌 파라미터 지식과 섞어버릴 때 생깁니다. 예를 들어 사내 규정 문서에서 “환불은 7일 이내”라는 문장을 정확히 검색했는데, 답변에는 “환불은 14일 이내이며 배송비도 지원됩니다”처럼 없는 내용이 붙는 식입니다. 이런 현상을 일반적으로 인공지능 환각이라고 부르는데, 관련 개념은 위키백과의 인공지능 환각 문서에도 정리돼 있습니다. 즉 검색 정확도와 생성 충실도는 서로 다른 지표라서, 둘 다 따로 점검해야 합니다.

근거 인용을 강제하는 프롬프트와 출력 구조

가장 먼저 손댈 부분은 프롬프트입니다. “참고 문서를 바탕으로 답하세요” 정도로는 부족하고, 답변 형식 자체에 인용 필드를 강제하는 편이 효과적입니다. 아래는 실제로 자주 쓰이는 구조화 프롬프트 예시입니다.

system_prompt = """
아래 컨텍스트에 있는 내용만 근거로 답변하세요.
반드시 JSON으로만 응답하고, 각 주장마다 근거가 된 chunk_id와
원문 인용구(quote)를 포함하세요.
컨텍스트에 없는 내용이면 "answer": "확인 불가"로 답하세요.

출력 형식:
{
  "answer": "답변 내용",
  "citations": [
    {"chunk_id": "doc_003", "quote": "환불은 7일 이내 가능합니다"}
  ]
}
"""

AI가 문서를 검색해 인용 출처를 검증하는 개념 이미지

이렇게 answer와 citations를 강제로 분리해두면, 뒤에서 살펴볼 검증 코드가 citations에 적힌 quote를 실제 chunk_id 원문과 대조할 수 있습니다. 다만 모델이 JSON 형식을 어기는 경우도 있어서, function calling이나 구조화 출력(Structured Outputs) 기능을 지원하는 모델에서는 그쪽을 쓰는 편이 파싱 실패율을 줄여줍니다.

인용 검증 코드로 출처-문장 일치를 확인해 보세요

프롬프트로 인용을 강제해도, 모델이 quote 자체를 살짝 바꿔 쓰는 경우가 있습니다. 이걸 걸러내려면 인용된 문장과 원본 청크를 문자열 유사도로 대조하면 됩니다. difflib은 파이썬 표준 라이브러리라 별도 설치 없이 바로 쓸 수 있어요.

from difflib import SequenceMatcher

def verify_citation(quote: str, chunk_text: str, threshold: float = 0.8) -> bool:
    ratio = SequenceMatcher(None, quote, chunk_text).ratio()
    return ratio >= threshold

# 예시
chunk_003 = "본 서비스의 환불은 결제일로부터 7일 이내에만 가능합니다."
cited_quote = "환불은 7일 이내 가능합니다"

print(verify_citation(cited_quote, chunk_003))
# 출력: True (유사도 약 0.83)

cited_quote_wrong = "환불은 14일 이내이며 배송비도 지원됩니다"
print(verify_citation(cited_quote_wrong, chunk_003))
# 출력: False (유사도 약 0.4)

threshold는 문서 성격에 따라 조정이 필요합니다. 법률·계약서처럼 문장이 거의 그대로 나와야 하는 경우 0.85 이상으로 높이고, 요약형 인용을 허용하는 FAQ 봇이라면 0.6~0.7 정도로 낮추는 식입니다. 아래는 지금까지 나온 방법을 정리한 비교표입니다.

방법 원리 장점 한계
프롬프트 강제 인용 출력 형식에 citation 필드 강제 구현이 쉽고 비용 추가 없음 모델이 형식을 어기거나 quote를 왜곡할 수 있음
문자열 유사도 대조 difflib 등으로 quote-원문 매칭 빠르고 저렴함, 오프라인 배치 가능 의역·paraphrase에 취약
LLM-as-judge (RAGAS 등) 별도 모델이 답변의 근거 충실도 채점 의미 수준 판단 가능 추가 LLM 호출 비용·지연 발생

RAGAS·TruLens로 인용 신뢰도를 점수화하는 방법

RAG 파이프라인 인용 검증 코드를 작성하는 개발자

문자열 대조만으로는 의역된 인용을 놓치기 쉬워서, 의미 수준까지 보려면 평가 프레임워크를 쓰는 게 낫습니다. ragas 라이브러리는 faithfulness라는 지표로 답변의 각 주장이 검색된 컨텍스트에서 실제로 지지되는지를 별도 LLM으로 채점합니다. 자세한 지표 정의는 공식 문서에서 확인할 수 있어요.

from ragas import evaluate
from ragas.metrics import faithfulness, context_precision
from datasets import Dataset

data = {
    "question": ["환불 기한은 얼마인가요?"],
    "answer": ["환불은 7일 이내 가능합니다"],
    "contexts": [["본 서비스의 환불은 결제일로부터 7일 이내에만 가능합니다."]],
}

dataset = Dataset.from_dict(data)
result = evaluate(dataset, metrics=[faithfulness, context_precision])
print(result)
# 예시 출력: {'faithfulness': 1.0000, 'context_precision': 1.0000}

TruLens도 비슷하게 Groundedness라는 피드백 함수로 답변이 컨텍스트에 얼마나 근거하는지 점수화합니다. 다만 이런 방식은 채점용 LLM 호출이 추가로 들어가서, 실시간 서비스보다는 배치 평가나 QA 샘플 20~50건을 뽑아 정기적으로 돌리는 오프라인 검증에 더 적합합니다.

이 방법이 통하지 않을 때가 있을까요?

문자열 유사도 검증은 표나 숫자가 섞인 문서에서 잘 안 맞습니다. “매출 12억 원”과 “매출액 1,200,000,000원”은 의미가 같아도 문자열 유사도는 낮게 나오기 때문입니다. 이런 데이터가 많다면 임베딩 기반 유사도(코사인 유사도)로 바꾸는 게 낫습니다.

LLM-as-judge 방식도 완벽하진 않습니다. 채점하는 모델 자체가 판단을 잘못 내리는 경우가 있고, 특히 채점 모델과 답변 생성 모델이 같은 계열일 때 서로의 오류를 눈감아주는 경향이 보고되기도 합니다. 그리고 인용이 원문과 정확히 일치한다고 해서 답변 전체가 맞다는 보장도 없습니다. 문맥의 일부만 떼어와 앞뒤 조건을 빼먹으면, 인용은 진짜인데 답은 오해를 부르는 경우가 생깁니다. 그래서 자동 검증 결과를 100% 신뢰하기보다, 일정 비율은 사람이 직접 원문과 대조하는 절차를 남겨두는 편이 안전합니다.

인용 검증까지 마쳐야 RAG 파이프라인이 끝납니다

정리하면, 검색이 맞아도 생성 단계에서 왜곡될 수 있기 때문에 근거 인용을 강제하는 프롬프트와 인용 검증 로직은 별개로 갖춰야 합니다. 오늘 바로 해볼 수 있는 다음 단계는 두 가지입니다. 먼저 프롬프트에 citations 필드를 추가해 quote와 chunk_id를 강제로 받아보세요. 그다음 difflib 같은 간단한 도구로 quote와 원문을 대조하는 함수를 붙이고, 샘플 질문 20개 정도를 ragas의 faithfulness 지표로 돌려보면 지금 파이프라인의 인용 신뢰도가 어느 수준인지 숫자로 확인할 수 있습니다.

PDF RAG 파싱, 표만 나오면 답이 깨지는 이유

Leave a Comment