~/ai-dev.md
AI_DEV

RAG 인용은 왜 링크 목록이 아니라 근거 계약일까

10분 읽기·2026.07.10·출처 5·00
오늘의 질문

AI 답변에 출처 링크를 붙였는데도 왜 사용자는 여전히 이 말이 어디서 나온 거지라고 느낄까?

ai-dev.md
RAG citation contract

RAG 인용은 왜 링크 목록이 아니라 근거 계약일까

1. 왜 지금 봐야 하나

RAG를 붙인 AI 기능에서 흔한 착각이 있다. “검색 결과를 프롬프트에 넣었고, 답변 아래에 링크도 붙였으니 grounded response가 됐다”는 생각이다. 실제 운영에서는 그렇지 않다. 사용자가 필요한 것은 단순한 링크 목록이 아니라 각 주장(claim)이 어떤 근거 단위(source unit)에 의해 지지되는지 확인할 수 있는 계약이다.

최근 공식 문서 흐름도 이 방향을 보여준다. OpenAI의 Citation Formatting 가이드는 신뢰할 수 있는 citation system이 “무엇을 인용할 수 있는지, 자료를 어떻게 표현할지, 모델이 어떤 형식으로 인용할지, 결과를 어떻게 파싱하고 검증할지”를 모두 포함한다고 설명한다. Gemini File Search 문서는 파일을 chunk, embedding, index, retrieval로 처리하고 모델 출력에 file_citation annotation을 붙여 출처를 돌려준다. Google Cloud의 Check grounding API는 답변 후보를 facts와 비교해 전체 support score, claim-level citation, claim-level support score를 반환한다고 설명한다.

여기서 중요한 변화는 “RAG를 했는가?”가 아니라 “답변의 주장과 근거를 추적 가능한 구조로 연결했는가?”다. 오늘은 RAG 인용을 화면 장식이 아니라 시스템 계약으로 보는 법을 정리한다.

2. 핵심 개념

RAG citation을 설계할 때 먼저 분리해야 하는 세 가지가 있다.

첫째, retrieved chunk다. 검색기가 가져온 텍스트 조각이다. 이것은 “모델에게 참고하라고 준 후보”이지, 아직 답변의 특정 문장을 지지한다고 증명된 근거는 아니다. 검색 결과가 10개 들어갔어도 모델이 그중 1개만 사용했을 수도 있고, 아무 것도 제대로 사용하지 않았을 수도 있다.

둘째, citable unit이다. 사용자가 검증할 수 있도록 안정적인 ID를 붙인 근거 단위다. OpenAI 가이드는 document, block/chunk, line range 같은 granularity를 구분하고, 많은 시스템에서는 block-level citation이 line-level보다 모델이 재현하기 쉽고 document-level보다 유용하다고 설명한다. 핵심은 같은 내용이 실행마다 다른 ID를 갖지 않도록 source ID를 안정적으로 관리하는 것이다.

셋째, claim-to-source mapping이다. 답변의 “문장 또는 주장”이 어떤 citable unit에 의해 지지되는지 연결하는 단계다. Google Cloud Check grounding 문서는 완전한 grounding을 “answer candidate의 모든 claim이 주어진 facts 중 하나 이상에 의해 지지되는 것”으로 설명한다. 부분적으로 맞는 문장도 전체 claim이 틀리면 ungrounded가 될 수 있다. 예를 들어 “타이타닉은 제임스 카메론이 감독했고 1975년에 개봉했다”는 문장은 감독은 맞아도 연도가 틀리므로 근거 있는 claim으로 보기 어렵다.

따라서 RAG citation은 “검색된 문서 URL을 마지막에 나열하기”가 아니다. 더 정확히는 다음 계약이다.

답변에 포함된 검증 가능한 각 주장은, 사전에 정의한 인용 가능 단위의 안정 ID와 연결되어야 하며, 렌더링 전 파싱·검증 가능해야 한다.

3. 최신 이슈와 연결

OpenAI의 hallucination 연구 글은 왜 이 계약이 필요한지 평가 관점에서 설명한다. 이 글은 언어 모델이 모르는 것을 인정하기보다 그럴듯하게 추측하도록 평가가 보상할 때 hallucination이 남는다고 말한다. 특히 정확도만 보는 평가에서는 “모른다”고 말하는 것보다 찍어서 맞힐 가능성이 있는 답변이 더 유리할 수 있다. 실제 서비스에서는 이런 성향이 치명적이다. 사용자는 “틀릴 수 있음”을 알고 싶은데, 모델은 종종 자신 있게 답한다.

Citation은 이 문제를 완전히 해결하지 못한다. 모델은 그럴듯한 인용을 붙일 수도 있고, 실제로는 해당 source가 claim을 지지하지 않을 수도 있다. 그래서 citation은 두 단계로 봐야 한다.

  1. 생성 단계의 citation formatting: 모델이 안정적인 source ID를 정해진 마커 형식으로 출력하게 한다.
  2. 검증 단계의 grounding check: 출력된 claim이 제공된 facts에 의해 실제로 지지되는지 검사한다.

Gemini File Search 같은 관리형 도구는 retrieval과 annotation을 제품 수준에서 제공한다. 하지만 이것도 “운영 판단”을 대신해주지는 않는다. 문서에는 File Search store가 persistent embedding container이고, raw files는 48시간 후 삭제되지만 imported/indexed data는 수동 삭제 또는 모델 deprecation 전까지 유지된다고 설명된다. 또한 retrieved document tokens는 일반 context token으로 과금된다. 즉 개발자는 citation 품질뿐 아니라 저장 수명, 삭제 정책, 비용, latency까지 함께 설계해야 한다.

Anthropic의 Contextual Retrieval 글도 같은 지점을 보완한다. chunk를 너무 작게 자르면 원문 맥락이 사라져 검색 실패가 늘 수 있다. Anthropic은 chunk-specific context를 붙이는 Contextual Embeddings와 Contextual BM25가 retrieval failure rate를 줄이고, reranking까지 더하면 더 개선된다고 보고했다. 이 말은 citation 품질도 retrieval 품질의 영향을 받는다는 뜻이다. 잘못 가져온 chunk 위에 아무리 예쁜 citation format을 붙여도 좋은 근거 계약이 되지 않는다.

4. 개발자 관점 해석

개발자가 RAG citation을 설계할 때 가장 많이 하는 실수는 UI부터 정하는 것이다. “답변 옆에 작은 숫자 링크를 붙이자”는 결정은 마지막 단계다. 먼저 데이터 모델과 실패 모드를 정해야 한다.

첫 번째 실패 모드는 source ID 불안정성이다. 검색 결과 배열의 index를 그대로 source1, source2로 쓰면, 같은 문서도 실행마다 다른 번호를 받는다. 사용자가 북마크한 인용, 로그에 남은 citation, 나중에 재검증할 trace가 서로 맞지 않을 수 있다. 가능하면 문서 ID, chunk ID, 버전, locator를 분리해서 저장해야 한다.

두 번째 실패 모드는 locator를 모델에게 너무 많이 맡기는 것이다. OpenAI 가이드는 source ID와 locator를 구분하고, 모델은 source ID를 내보내고 시스템이 locator를 resolve/render하는 방식을 권장한다. line range까지 모델이 직접 맞히게 하면 formatting error와 off-by-one 문제가 늘어난다. 특히 한국어처럼 UTF-8 byte와 화면 글자 수가 다른 텍스트에서는 Google Cloud 문서가 지적하듯 byte offset과 character offset 차이도 조심해야 한다.

세 번째 실패 모드는 retrieval citation과 grounding citation을 혼동하는 것이다. 검색기가 가져온 chunk는 후보이고, claim-level support는 검증 결과다. 운영 시스템에서는 둘을 다른 필드로 남기는 편이 좋다. 예를 들면 retrieved_source_ids, emitted_citation_ids, verified_claims, unsupported_claims를 분리한다.

네 번째 실패 모드는 인용 없는 문장을 허용하는 정책 부재다. 모든 문장이 citation을 가져야 하는 것은 아니다. “아래는 요약입니다” 같은 담화 문장은 grounding check가 필요 없을 수 있다. 반대로 숫자, 날짜, 정책, 법률, 계정 상태, 가격, 장애 원인처럼 사용자가 의사결정에 쓰는 문장은 citation 없이는 위험하다. Google Cloud Check grounding의 grounding-check-required 같은 개념을 내부 정책으로도 가져올 수 있다.

5. 내 프로젝트에 적용할 체크포인트

작은 팀이라면 다음 순서로 시작하면 된다.

  1. 인용 가능 단위를 정한다
    문서 전체, section, chunk, line range 중 무엇을 사용하지 결정한다. 처음에는 block/chunk 단위가 현실적이다.

  2. 안정 ID 규칙을 만든다
    예: doc_id, doc_version, chunk_id, source_url, updated_at을 저장한다. 검색 결과 순번만 ID로 쓰지 않는다.

  3. 모델 출력용 citation format을 고정한다
    커스텀 마크다운 링크를 즉흥적으로 만들게 하지 말고, 파싱 가능한 marker 또는 JSON field로 분리한다. structured output을 쓴다면 answer text와 citations 배열을 나누는 것도 방법이다.

  4. 렌더링 전 파싱한다
    citation marker가 문법에 맞는지, 존재하지 않는 source ID를 참조하지 않는지, citation이 code block 안에 들어가지 않았는지 확인한다.

  5. claim-level 샘플 검증을 한다
    모든 요청에 비싼 검증기를 붙이지 못하더라도, 고위험 도메인에서는 claim별 support score 또는 LLM judge/eval을 샘플링한다.

  6. unsupported policy를 정한다
    근거가 약한 문장은 삭제할지, “자료에서 확인되지 않음”으로 바꿀지, 사용자에게 clarification을 요청할지 미리 정한다.

  7. 로그를 남긴다
    trace에는 query, retrieved source IDs, emitted citations, dropped citations, unsupported claims, grounding score, final render IDs를 남긴다. 원문 전체를 저장하면 개인정보·저작권 문제가 생길 수 있으니 hash와 metadata 중심으로 시작한다.

6. 오늘 10분 액션

오늘은 코드보다 표 하나를 만든다. 현재 만들고 있거나 상상 중인 RAG 기능 하나를 고르고 아래를 채워보자.

항목내 시스템의 답
사용자가 검증해야 하는 claim 유형예: 가격, 정책, 오류 원인, API 사용법
citable unit예: chunk, paragraph, line range
안정 source ID 구성예: doc_id:version:chunk_id
모델이 출력할 citation 형식예: {cite: source_id} 또는 별도 citations 배열
렌더링 전 검증존재하지 않는 ID 차단, citation 없는 factual claim 표시
실패 시 정책답변 삭제, 불확실성 표시, 재검색, 사람 검토

이 표를 채우면 RAG citation이 링크 장식인지, 근거 계약인지 바로 드러난다.

7. 더 볼 자료

  • OpenAI Citation Formatting 가이드: citable unit, source ID, locator, parsing을 분리하는 실무 패턴을 확인하기 좋다.
  • Gemini File Search 문서: 관리형 RAG 도구가 chunking, embedding, indexing, annotation을 어떻게 묶는지 볼 수 있다.
  • Google Cloud Check grounding 문서: claim-level support score와 citation threshold를 운영 정책으로 바꾸는 데 도움이 된다.
  • OpenAI hallucination 연구 글: “모른다”와 “틀린 답”을 다르게 평가해야 하는 이유를 이해할 수 있다.
  • Anthropic Contextual Retrieval 글: citation 이전 단계인 retrieval 품질을 chunk context, BM25, rerank로 개선하는 관점을 준다.

중복 회피 메모

기존 ai_dev 글은 RAG의 recall/rerank, structured outputs, tool calling, agent trace, token counting, guardrail checkpoint를 다뤘다. 이번 글은 retrieval 성능 자체나 JSON schema 출력이 아니라, RAG 답변의 각 claim을 안정적인 citable unit과 연결하고 렌더링 전 검증하는 citation/grounding 계약에 집중한다.

오늘 10분 액션+5%

댓글 0

최신순 ▾
한 줄 남기기

혹시 이 글을 읽는 동료 개발자가 있다면, GitHub으로 로그인하고 한 줄 흔적을 남겨줘요. (스팸 방지용 로그인이에요)