RAG
외부 문서에서 근거를 검색해 최신성, 출처, 권한 필터를 운영 로직으로 통제한다.
문서가 자주 바뀌고 답변 근거를 사용자나 감사 로그에 남겨야 할 때분류: Layer 12 - AI 시스템 & LLM 애플리케이션 | 선수지식: L12-10 (LLM API), L12-20 (Prompt), L12-30 (임베딩·벡터)
RAG(Retrieval-Augmented Generation)는 모델이 이미 알고 있는 고정 지식만으로 답하게 두지 않고, 외부 문서를 검색해 context에 붙인 뒤 답을 생성하게 하는 애플리케이션 패턴이다.
이름의 세 단어를 그대로 읽으면 된다.
핵심은 “검색을 붙이면 모델이 더 똑똑해진다”가 아니다. RAG의 핵심 철학은 지식의 원본을 모델 가중치 밖에 두고, 답변할 때마다 필요한 근거만 가져와 provenance(출처)와 freshness(최신성)를 운영 로직으로 통제하는 것이다.
LLM은 학습 시점까지의 패턴과 사실을 가중치 안에 압축해 둔다. 이 지식을 parametric knowledge라고 부른다. 사용자가 “현재 사내 휴가 정책”, “오늘 적용 중인 가격표”, “이 고객에게 허용된 계약 조항”을 묻는 순간 이 방식은 세 가지 벽에 부딪힌다.
| 벽 | 모델 고정 지식만 쓸 때 생기는 문제 | RAG가 줄이는 문제 |
|---|---|---|
| 최신성 | 모델 학습 이후 바뀐 사실을 모른다 | 원본 문서가 바뀌면 색인을 갱신해 다음 답변부터 반영한다 |
| 출처 | 답이 어느 문서에서 왔는지 되짚기 어렵다 | chunk ID, URL, version을 함께 반환해 인용과 감사를 가능하게 한다 |
| 권한 | 모델은 사용자별 문서 권한을 스스로 알지 못한다 | 검색 단계에서 tenant, ACL, version filter를 적용한다 |
| 수정 가능성 | 잘못된 지식을 고치려면 모델·prompt·데이터를 함께 의심하게 된다 | 원본 문서, 색인, 검색, 생성 중 어느 단계가 깨졌는지 분리해 본다 |
Lewis et al.의 2020년 RAG 논문은 모델의 parametric memory와 외부 문서 인덱스 같은 non-parametric memory를 결합했다. 여기서 non-parametric memory는 “지식이 모델 가중치에 박혀 있지 않고, 검색 가능한 외부 저장소에 남아 있다”는 뜻으로 이해하면 된다.
이 발상은 fine-tuning, 긴 prompt, 검색 없는 LLM 호출이 각각 잘 못 푸는 문제에서 나왔다.
RAG는 이 문제를 “모델을 계속 다시 학습시키자”가 아니라 지식과 생성 능력을 분리하자로 푼다. 지식은 문서·DB·검색 인덱스에 두고, 모델은 매 호출마다 가져온 근거를 읽어 답을 합성한다.
퀴즈
힌트: 검색과 생성은 서로 다른 실패 지점이다.
아니다. RAG는 모델이 참고할 근거를 제공하고 출처를 남길 수 있게 해 주지만, 검색된 문서가 틀렸거나 prompt가 근거 밖 생성을 허용하면 여전히 그럴듯한 오답이 나온다. 검색 실패와 생성 faithfulness(근거 충실도) 실패를 분리해서 봐야 한다.
RAG는 보통 두 개의 시간대로 나뉜다.
[색인 단계 — offline 또는 background]1. 원본 문서 수집2. 문서를 검색 가능한 chunk로 분할3. chunk를 embedding으로 변환4. vector store와 lexical index에 저장5. doc_id, version, source URL, tenant, ACL, updated_at metadata 저장
[질문 처리 단계 — online]6. 사용자 질문과 대화 맥락 정리7. 검색 query 생성8. 후보 문서 검색과 재정렬9. prompt에 근거 주입10. LLM 생성11. citation, refusal, 품질 gate 적용여기서 tenant는 여러 고객·조직의 데이터를 한 시스템에 담을 때의 격리 단위이고, ACL(Access Control List)은 사용자가 볼 수 있는 문서 권한 목록이다. updated_at은 최신성 판단에 쓰는 시간 metadata다. 이 셋은 검색 점수보다 먼저 적용되어야 한다. 권한 밖 문서를 검색한 뒤 마지막 응답에서만 숨기면, trace·reranker·prompt 안에는 이미 민감 문서가 들어간 상태가 된다.
flowchart TD
A["원본 문서"] --> B["Chunking"]
B --> C["Embedding"]
C --> D["Vector store / lexical index"]
D --> E["권한·버전·출처 metadata"]
F["사용자 질문"] --> G["Query transform"]
G --> H["Retrieval"]
E --> H
H --> I["Rerank / context packing"]
I --> J["Augmentation"]
J --> K["LLM generation"]
K --> L{"근거와 답변이 맞나?"}
L -->|yes| M["답변 + citation"]
L -->|no| N["재검색 또는 refusal"] RAG 품질은 LLM 호출 하나가 아니라 색인, 검색, context 구성, 생성, 검증이 이어진 파이프라인 품질이다.
처음 공부할 때는 많은 기법 이름보다 아래 네 질문을 먼저 잡는다.
아래처럼 사내 정책 문서가 있다고 하자.
doc_hr_v7 / section: annual_leave / updated_at: 2026-03-01 연차는 사용 1일 전까지 HR 포털에서 신청한다.
doc_hr_v8 / section: half_day / updated_at: 2026-06-15 반차는 사용 당일 오전 10시 전까지 신청할 수 있다. 단, 팀 승인 정책이 있는 조직은 전날 18시까지 신청한다.
doc_hr_v5 / section: half_day / updated_at: 2025-11-20 반차는 사용 1일 전까지 신청한다.사용자가 묻는다.
질문: "반차는 언제까지 신청해야 해?"검색 없는 LLM 호출은 “일반적으로 전날까지 신청합니다”처럼 답할 수 있다. 그 답이 자연스러워 보여도 현재 회사 정책과 맞는지는 알 수 없다.
RAG는 다르게 움직인다.
1. query rewrite: "반차 신청 마감 시간 사내 휴가 정책"
2. retrieval: doc_hr_v8 half_day chunk를 상위 후보로 찾음 doc_hr_v5는 old version이라 제외하거나 낮은 우선순위로 둠
3. augmentation: <documents> <doc id="doc_hr_v8#half_day" updated_at="2026-06-15"> 반차는 사용 당일 오전 10시 전까지 신청할 수 있다. 단, 팀 승인 정책이 있는 조직은 전날 18시까지 신청한다. </doc> </documents>
4. generation: "반차는 기본적으로 사용 당일 오전 10시 전까지 신청할 수 있습니다. 다만 팀 승인 정책이 있는 조직은 전날 18시까지 신청해야 합니다. [doc_hr_v8#half_day]"이 예제에서 RAG가 추가한 가치는 단순히 “문서를 붙였다”가 아니다.
doc_hr_v8처럼 어느 version의 문서를 근거로 삼았는지 남겼다.doc_hr_v5를 그대로 넣지 않도록 freshness와 version filter를 적용했다.Retrieval은 “질문과 관련 있는 문서를 찾는다”는 한 문장으로 끝나지만, 실제로는 여러 결정을 포함한다. 깊은 정의는 L12-30 임베딩과 벡터 운영 문서가 맡는다. 이 문서에서는 RAG 조립에 필요한 짧은 역할만 확인한다.
| 요소 | RAG에서의 역할 | 여기서 기억할 정도 |
|---|---|---|
| Chunking | 긴 문서를 검색 가능한 조각으로 나눈다 | 답변에 필요한 조건과 예외가 같은 chunk에 남아야 한다 |
| Vector store | embedding과 metadata를 함께 저장한다 | 검색 점수뿐 아니라 tenant, ACL, version filter가 중요하다 |
| Dense search | 의미가 비슷한 문서를 찾는다 | paraphrase에 강하지만 고유명사·코드·조항 번호를 놓칠 수 있다 |
| BM25 | 단어 일치와 희귀도를 보는 lexical ranking이다 | 정확한 문자열 단서에 강하다 |
| RRF | 여러 ranking을 안정적으로 합치는 방식이다 | dense와 BM25 결과를 섞을 때 자주 쓴다 |
| Reranker | 1차 후보를 query와 함께 다시 읽어 정렬한다 | recall을 확보한 뒤 precision을 회복한다 |
| Freshness | 원본 변경이 검색에 반영되는 상태다 | 오래된 chunk가 top-k에 남으면 답변도 오래된다 |
사용자 질문은 검색 query로 바로 쓰기 어려울 때가 많다. 대화형 질문은 짧고, 생략이 많고, 문서가 쓰는 용어와 다르다.
대화 맥락: user: "RAG 구조 알려줘" assistant: "검색, 보강, 생성으로 나뉩니다." user: "그럼 비용은?"
나쁜 검색어: "그럼 비용은?"
좋은 검색어: "RAG 시스템 비용 구성 검색 latency context token vector store 운영 비용"rewrite의 목표는 멋진 문장을 만드는 것이 아니라 독립적으로 검색 가능한 query를 만드는 것이다. 이전 turn을 통째로 붙이면 noise가 늘 수 있으므로 핵심 entity와 intent만 남긴다.
같은 의도를 여러 표현으로 바꿔 검색한다.
원본: "Python에서 비동기 처리"검색 1: "Python asyncio 사용법"검색 2: "Python async await 예제"검색 3: "Python coroutine 동시성"Multi-Query는 recall을 올리는 대신 후보가 많아진다. 그래서 보통 reranker나 dedupe와 같이 쓴다.
HyDE(Hypothetical Document Embeddings)는 LLM이 먼저 가상의 답변 문서를 만들고, 그 가상 문서를 embedding해 검색하는 방식이다. 질문보다 답변 형태의 문장이 실제 문서와 더 비슷할 때 도움이 된다.
질문: "RAG 어떻게 해?"가상 답변: "RAG는 문서를 chunking하고 embedding한 뒤 vector store에서..."검색: 가상 답변을 embedding해 관련 문서 검색반례도 기억해야 한다. 사용자가 이미 문서와 같은 용어로 질문했다면 HyDE는 추가 LLM 호출 비용과 latency만 늘릴 수 있다.
복합 질문은 여러 하위 질문으로 나눈다.
원본: "RAG와 fine-tune 중 어떤 게 비용과 최신성에 유리해?"
하위 질문: 1. RAG의 지식 갱신 방식은 무엇인가? 2. fine-tune의 지식 갱신 방식은 무엇인가? 3. 두 방식의 비용 구조는 어떤 항목으로 나뉘는가?분해는 multi-hop 질문에 좋지만, 단순 FAQ에는 과하다. “분해할수록 좋다”가 아니라 정답이 여러 근거 조각을 필요로 할 때만 쓴다.
RAG 장애를 볼 때 가장 먼저 나눌 질문은 이것이다.
정답 근거가 검색 결과 안에 있었나?이 분기를 하지 않으면 “모델이 나쁘다”, “vector DB가 나쁘다”, “prompt가 나쁘다”가 한 덩어리로 섞인다.
Augmentation은 검색 결과를 prompt에 “그냥 붙이는” 단계가 아니다. 모델이 어떤 텍스트를 질문으로, 어떤 텍스트를 근거로, 어떤 텍스트를 지시로 봐야 하는지 구획을 나누는 단계다.
<documents> <doc id="doc_hr_v8#half_day" source="/hr/leave-policy.md" updated_at="2026-06-15"> 반차는 사용 당일 오전 10시 전까지 신청할 수 있다. 단, 팀 승인 정책이 있는 조직은 전날 18시까지 신청한다. </doc> <doc id="doc_hr_v7#annual_leave" source="/hr/leave-policy.md" updated_at="2026-03-01"> 연차는 사용 1일 전까지 HR 포털에서 신청한다. </doc></documents>
<question>반차는 언제까지 신청해야 해?</question>
<instruction>documents에 근거해서만 답하라.답변에는 사용한 doc id를 대괄호로 인용하라.documents에 없는 내용은 추측하지 말고 "문서에서 찾을 수 없습니다"라고 답하라.</instruction>XML 자체가 정답은 아니다. Markdown heading, JSON wrapper, message role을 써도 된다. 중요한 것은 사용자 입력, 검색 문서, 시스템 지시, 출력 계약이 섞이지 않는 것이다.
검색 후보를 모두 넣으면 recall은 높아 보이지만 답변 품질은 떨어질 수 있다. 관련 없는 chunk가 많아질수록 모델이 잘못된 근거를 집거나, 중요한 근거가 긴 context 중간에 묻힌다.
안정적인 사고 순서는 다음과 같다.
retrieve: 넓게 후보를 가져온다. 예: top-50 또는 top-100rerank: 질문에 직접 답하는 후보를 위로 올린다.dedupe: 같은 문서·같은 문단의 중복 chunk를 줄인다.pack: 최종 context에는 답변에 필요한 5~7개 정도의 근거만 넣는다.cite: 각 근거의 doc_id, source, version을 남긴다.숫자는 절대 규칙이 아니라 토큰 예산을 계산하기 위한 감각이다. 예를 들어 평균 800토큰 chunk를 10개 넣으면 검색 context만 8,000토큰이다. 여기에 system prompt, 대화 history, 사용자 질문, 출력 형식 지시가 붙는다. RAG에서 top-k를 키우는 결정은 검색 품질뿐 아니라 input token, prefill latency, lost-in-the-middle 위험까지 함께 키운다.
p95는 100번 중 느린 쪽 5%에 걸리는 응답 시간을 보는 지표이고, prefill은 모델이 입력 token을 먼저 읽어 내부 상태를 채우는 단계다. 입력 context가 길어질수록 prefill 시간이 늘 수 있다.
작은 비용·latency 예제로 감을 잡아 보자.
질문 1개 처리: retrieval p95: 120ms rerank p95: 180ms 최종 context: 7 chunks * 800 tokens = 5,600 input tokens prompt/history/질문: 1,400 input tokens 예상 답변: 500 output tokens
대략적 병목: online latency ~= retrieval + rerank + LLM prefill(7,000 input tokens) + decode(500 output tokens) token 비용 ~= input 7,000 tokens + output 500 tokens 고정비 ~= vector store 저장량 + reindex worker + 평가 trace 저장이 계산은 vendor 가격표를 외우기 위한 것이 아니다. top-k를 7 -> 14로 올리면 단지 근거가 두 배가 되는 것이 아니라 input token, prefill latency, citation 검증 대상, lost-in-the-middle 위험도 같이 늘어난다는 점을 보는 것이다.
Liu et al.의 “Lost in the Middle” 연구는 긴 context에서 중간에 놓인 정보가 덜 활용될 수 있음을 보여준다. 그래서 RAG prompt는 중요한 근거를 무작위 순서로 붙이지 않는다.
Generation은 LLM이 검색된 문서를 읽고 사용자가 원하는 형식으로 답을 만드는 단계다. 여기서도 RAG는 자동 안전장치가 아니다. 모델은 documents에 없는 내용을 덧붙일 수 있고, 인용처럼 보이는 문자열을 만들어낼 수도 있다.
Faithfulness는 답변 문장이 검색된 근거에 의해 지지되는지를 보는 관점이다. “답이 질문에 친절한가”와 다르다. 답변이 친절해도 근거 밖 사실을 말하면 RAG에서는 실패다.
작은 반례를 보자.
검색 문서: "반차는 사용 당일 오전 10시 전까지 신청할 수 있다."
질문: "반차를 취소하려면 언제까지 해야 해?"
나쁜 답변: "반차 취소도 당일 오전 10시 전까지 가능합니다. [doc_hr_v8]"
왜 실패인가: 문서는 신청 마감만 말한다. 취소 마감은 근거가 없다.
좋은 답변: "제공된 문서는 반차 신청 마감만 설명하고, 취소 마감은 설명하지 않습니다. [doc_hr_v8]"이 반례가 RAG의 핵심 경계다. 검색된 문서가 관련 있어 보여도 질문에 필요한 속성을 실제로 담고 있는지는 별도로 확인해야 한다.
Citation은 답변 끝에 링크를 붙이는 UI 기능이 아니라, 운영에서 세 가지 기능을 한다.
따라서 citation은 문자열 생성만 믿지 않는 편이 좋다. 답변에 등장한 doc_id가 실제로 이번 retrieval 결과 안에 있었는지, 해당 사용자가 볼 권한이 있는지, 최신 version인지 후처리에서 확인한다.
RAG 제품에서 “모르겠습니다”는 실패가 아니라 안전한 성공일 수 있다. 검색 결과가 없거나, 관련도가 낮거나, 근거가 질문의 핵심 속성을 담고 있지 않으면 모델이 답을 만들지 않도록 해야 한다.
답변 정책: - documents에 직접 근거가 있으면 답한다. - 근거가 부분적이면 "문서에서 확인되는 범위"와 "확인되지 않는 범위"를 나눈다. - 근거가 없으면 추측하지 않고 추가 문서나 담당 부서를 안내한다.이 정책이 없으면 RAG는 “검색된 문서가 있으니 아무 답이나 해도 되는 시스템”이 된다.
RAG 이름은 계속 늘어나지만, 운영자가 볼 축은 단순하다.
| 변형 | 핵심 구조 | 적합한 상황 | 경계 |
|---|---|---|---|
| Naive RAG | query embedding → top-k → prompt | 작은 FAQ, PoC, 명확한 단일 문서 질문 | query mismatch, reranker 부재, stale data에 약함 |
| Advanced RAG | rewrite, hybrid, rerank, context packing | 많은 production QA의 시작 후보 | stage가 늘어 latency와 trace가 복잡해짐 |
| Modular RAG | 검색, 재정렬, 생성, 평가를 교체 가능한 단계로 분리 | 팀·도메인별 검색기와 평가기를 바꿔야 하는 플랫폼형 RAG | 추상화가 빨리 들어가면 단순 문제도 복잡해짐 |
| Corrective RAG | 검색 결과를 평가하고 재검색 또는 refusal | 잘못된 답변 피해가 큰 도메인 | judge 품질이 낮으면 불필요한 refusal이 늘어남 |
| Self-RAG | 모델이 검색 필요 여부와 답변 근거를 스스로 점검 | 질문 유형이 다양하고 검색 필요성이 매번 다른 서비스 | loop 비용과 latency를 제한해야 함 |
| GraphRAG | entity, relation, community summary를 검색 | ”전체 전략”, “조직 간 관계”처럼 단일 chunk에 답이 없는 질문 | 색인 비용과 entity 추출 품질 의존이 큼 |
| Agentic RAG | agent가 검색, DB, tool을 여러 번 호출 | multi-hop 조사, 업무 시스템 action이 이어지는 작업 | permission, tool budget, 재현성 관리가 어려움 |
운영 기본값은 대개 Advanced RAG까지 작게 쌓는 것이다. 처음부터 GraphRAG나 agentic loop를 붙이면 retrieval 문제인지 orchestration 문제인지 분리하기 어렵다.
1. 질문이 단일 문서·단일 문단에서 답이 나는가? yes -> Naive 또는 Advanced RAG no -> 2로
2. 여러 문서의 관계나 요약이 필요한가? yes -> GraphRAG 또는 hierarchical summary 검토 no -> 3으로
3. 검색 결과가 부족할 때 외부 검색·도구·DB 조회가 필요한가? yes -> Corrective RAG 또는 Agentic RAG no -> query decomposition + rerank부터 개선RAG는 모든 LLM 문제의 기본값이 아니다. 지식, 행동, 계산, 권한을 분리해서 본다.
외부 문서에서 근거를 검색해 최신성, 출처, 권한 필터를 운영 로직으로 통제한다.
문서가 자주 바뀌고 답변 근거를 사용자나 감사 로그에 남겨야 할 때관련 자료를 한 호출에 많이 넣고 모델이 직접 읽게 한다.
단발 분석이고 자료 묶음이 context window와 비용 예산 안에 들어갈 때새 지식보다 반복되는 형식, 말투, 분류 기준, 도메인 행동을 모델에 맞춘다.
지식 갱신은 느리지만 응답 스타일과 판단 습관을 일관되게 만들 때가격, 재고, 권한, 결제 상태처럼 정확한 시스템 값을 API나 DB에서 직접 조회한다.
문서 검색보다 현재 상태 조회가 본질이고, 답이 deterministic해야 할 때| 상황 | 먼저 볼 선택지 | 이유 |
|---|---|---|
| 정책·매뉴얼·FAQ가 자주 바뀐다 | RAG | 문서 교체와 재색인이 모델 재학습보다 작게 통제된다 |
| 답변마다 출처를 보여줘야 한다 | RAG | chunk ID와 source URL을 답변에 연결할 수 있다 |
| 사용자의 현재 잔액·재고·권한이 필요하다 | Tool lookup | 문서 검색이 아니라 실시간 상태 조회 문제다 |
| 말투·JSON 구조·분류 기준이 흔들린다 | Prompt, structured output, fine-tune | 지식보다 행동·형식 문제일 가능성이 크다 |
| 한 번 분석할 자료가 작고 고정돼 있다 | Long-context | 별도 색인과 freshness 파이프라인이 과할 수 있다 |
| corpus가 정리돼 있지 않다 | Corpus 정비 | 검색할 진실이 없으면 RAG는 오답을 더 그럴듯하게 포장한다 |
RAG 평가는 “답이 좋아 보인다”로 끝나면 안 된다. 최소 네 층으로 나눠 본다.
| 층 | 물어볼 질문 | 대표 지표 또는 관찰 |
|---|---|---|
| Retrieval | 정답 근거가 후보 안에 들어왔나? | Recall@k, Hit@k, MRR, NDCG |
| Context | 후보 중 실제로 prompt에 들어간 근거가 적절한가? | Context precision, 중복률, stale chunk 비율 |
| Generation | 답변 문장이 근거에 의해 지지되는가? | Faithfulness, citation validity, refusal correctness |
| Product | 사용자가 문제를 해결했나? | 사용자 피드백, escalation rate, task success, latency, cost |
MRR과 NDCG는 정답 문서가 후보 목록의 몇 번째에 오는지 보는 순위 품질 지표다. 처음에는 공식을 외우기보다 “정답이 후보 안에 있는가”와 “정답이 위쪽에 있는가”를 분리해서 본다고 이해하면 된다.
Gold dataset은 기대 답변, 필수 출처, 실패 사례를 사람이 검토하고 버전별로 관리하는 평가 데이터셋이다.
question: "반차는 언제까지 신청해야 해?"expected_answer: "기본은 당일 오전 10시 전, 팀 승인 조직은 전날 18시"required_sources: - doc_hr_v8#half_dayforbidden_sources: - doc_hr_v5#half_day좋은 gold case는 정답 문장만 갖고 있지 않다. 필수 source와 금지 source를 함께 둔다. 그래야 stale data, permission leak, citation hallucination을 잡을 수 있다.
1. 질문, 기대 답변, 필수 source를 가진 gold dataset을 만든다.2. retrieval만 먼저 실행해 정답 source가 후보 안에 들어오는지 본다.3. rerank와 context packing 후 prompt에 실제로 들어간 source를 기록한다.4. generation 결과의 문장과 citation을 대조한다.5. 실패를 retrieval, context, generation, product issue로 라벨링한다.6. prompt, chunking, retriever, reranker, corpus 변경 시 같은 set으로 회귀를 본다.공개 블로그나 도구 문서에서 제시하는 faithfulness threshold를 그대로 복사하지 않는다. 도메인, 답변 형식, 모델, judge 방식에 따라 점수 의미가 달라진다. 팀 기준은 현재 production baseline, 사용자 피해도, 사람 검수 샘플을 기준으로 잡고, 숫자는 “배포 gate”가 아니라 “회귀 감지 신호”로 먼저 다룬다.
처음 기준을 잡을 때는 작은 절차로 충분하다. 실패가 섞인 질문 30~50개를 뽑아 사람이 정답 source 있음, 답변 문장 근거 있음, 권한 위반 없음, 거절해야 할 때 거절함 네 칸으로 라벨링한다. 그다음 현재 시스템의 점수 분포를 baseline으로 저장하고, prompt나 retriever를 바꿀 때 같은 set에서 분포가 나빠지는지 본다. 기준선은 “faithfulness 0.8 이상이면 안전” 같은 보편 규칙이 아니라, 우리 도메인에서 사람이 확인한 샘플과 피해 비용에 붙어 있어야 한다.
Ragas, TruLens, DeepEval 같은 도구는 회귀 탐지에 유용하지만 정답 판정 그 자체는 아니다. 특히 표, 코드, 짧은 숫자 답변, 다국어 답변은 문장 분해와 entailment 판단이 흔들릴 수 있다.
자동 평가는 아래처럼 쓴다.
자동 평가만으로 “안전하다”고 결론내리지 않는다. RAG는 출처·권한·최신성이 제품 요구사항이므로 샘플 기반 사람 검수와 audit log가 필요하다.
Silent failure는 HTTP 200, latency 정상, 답변 형식 정상인데 내용이 틀린 상태다. RAG에서는 특히 위험하다. 자연어 답변이 매끄러우면 사용자가 오류를 늦게 발견하기 때문이다.
| 증상 | 보이는 현상 | 먼저 의심할 지점 | 복구 방향 |
|---|---|---|---|
| Stale data | 옛 정책이나 삭제된 문서를 인용한다 | freshness pipeline, version filter, reindex lag | changed event, embedding queue, old version cleanup 확인 |
| Permission leak | 다른 tenant나 권한 밖 문서가 답변에 섞인다 | metadata pre-filter, namespace, ACL join | 검색 전 필터 강제, response-stage 필터만 쓰지 않기 |
| Query mismatch | 사용자의 표현과 문서 표현이 달라 정답 chunk가 빠진다 | query rewrite, hybrid search, synonym, BM25 | rewrite와 hybrid를 추가하고 gold dataset recall을 측정 |
| Reranker 부재 | 정답이 후보에는 있지만 context 밖으로 밀린다 | rerank, top-k, context packing | retrieve 후보를 넓히고 rerank 후 최종 context를 줄임 |
| Context stuffing | 너무 많은 chunk를 넣어 답변이 흐려진다 | top-k 과다, dedupe 부재, lost-in-middle | 중복 제거, parent context, 중요한 근거 우선 배치 |
| Citation hallucination | 답변에 없는 doc id나 무관한 doc id가 붙는다 | generation prompt, post-validation | citation이 retrieval 결과에 존재하는지 검증 |
| Refusal 누락 | 근거가 없는데 답을 지어낸다 | instruction 약함, output policy 부재 | ”확인 범위”와 “문서에 없음” 응답을 명시 |
| Over-filtering | 권한·언어·날짜 필터가 정답까지 지운다 | 품질 필터와 보안 필터 혼합 | 보안 필터는 유지, 품질 필터는 fallback 규칙 분리 |
| Architecture overkill | 단순 FAQ에 agent loop나 GraphRAG가 붙어 느려진다 | 패턴 선택 과잉 | 단순 RAG baseline으로 돌아가 단계별 품질을 비교 |
둘 다 metadata filter에서 생기지만 방향이 반대다.
tenant_id, ACL, RBAC(Role-Based Access Control, 역할 기반 접근 제어) 같은 보안 필터는 완화 대상이 아니다. 후보 생성 전에 강제해야 한다.language, doc_type, updated_at 같은 품질 필터는 recall이 너무 낮을 때 완화할 수 있다.두 필터를 한 덩어리로 묶으면 위험하다. recall을 살리려고 조건을 풀다가 권한을 풀 수 있고, leak을 막으려고 조건을 강하게 하다가 정답 source까지 지울 수 있다.
상황: 사내 정책 RAG 챗봇에서 "답이 이상하다"는 사용자 피드백이 늘었다.
1단계: 검색 결과 확인 최근 실패 질문 50개를 뽑아 retrieval trace를 본다. 정답 source가 top-k 후보 안에 있었는지 확인한다.
trace 예시: query="반차 취소 마감" top_candidates=[doc_hr_v8#half_day, doc_hr_v7#annual_leave, doc_hr_v5#half_day] filtered_out=[doc_hr_private#exec_leave_acl_denied] packed_context=[doc_hr_v8#half_day] answer_citations=[doc_hr_v8#half_day]
2단계: 분기 A. 정답 source가 없다 -> chunking, query rewrite, hybrid, freshness, permission filter를 본다.
B. 정답 source는 후보에 있지만 prompt에 없다 -> reranker, dedupe, context packing, top-k 정책을 본다.
C. 정답 source가 prompt에 있는데 답이 틀렸다 -> generation prompt, citation validation, refusal rule을 본다.
3단계: 복구 retrieval 실패면 gold dataset recall을 기준으로 검색 파이프라인을 고친다. generation 실패면 "근거 밖 내용 금지", citation post-validation, refusal 예시를 보강한다. corpus 실패면 원본 문서 version, 삭제 문서, 권한 metadata부터 정리한다.
4단계: 회귀 방지 실패 case를 gold dataset에 추가한다. 다음 prompt, chunking, retriever 변경부터 같은 case를 자동 평가한다.여기서 중요한 점은 “LLM 모델을 바꿔 보자”가 첫 복구가 아니라는 것이다. RAG 품질 문제는 검색, context, 생성, corpus 중 하나의 문제일 수 있다. trace 없이 모델만 바꾸면 원인을 잃는다.
RAG는 LLM에만 있는 특수 마법이 아니라, 시스템에서 자주 보던 패턴의 조합이다.
| RAG 구성요소 | 일반 시스템 매핑 | 학습 포인트 |
|---|---|---|
| Retrieval | DB SELECT, search query, cache lookup | 필요한 근거 후보를 찾는다 |
| Augmentation | template rendering, dynamic config injection | 실행 시점 정보를 입력에 주입한다 |
| Generation | response synthesis, report rendering | 여러 근거를 사용자 답변으로 합성한다 |
| Citation | provenance tracking, audit trail | 결과가 어느 입력에서 왔는지 남긴다 |
| Faithfulness check | contract test, validation | 결과가 입력 계약을 위반하지 않는지 본다 |
| Freshness | cache invalidation, CDC(Change Data Capture), materialized view refresh | 원본 변경이 파생물에 반영됐는지 본다 |
이 매핑은 비유가 아니라 설계 점검표다. RAG를 만들 때도 “저장소는 무엇인가, invalidation은 어떻게 되는가, 권한 필터는 어디서 걸리는가, 결과 provenance는 남는가”를 묻는다.
엔지니어가 RAG를 운영할 때 특히 중요한 판단은 다음이다.
| 개념 A | 개념 B | 차이점 |
|---|---|---|
| RAG | Search UI | 검색 결과 목록을 보여주는 것이 아니라 답변 생성을 위해 근거를 주입한다 |
| Retrieval | Generation | 근거 후보를 찾는 단계 vs 근거를 답변으로 합성하는 단계 |
| Context recall | Faithfulness | 필요한 근거가 context에 들어왔는가 vs 답변이 그 근거에 묶였는가 |
| Citation | Faithfulness | 출처 ID가 붙었는가 vs 그 문장이 실제 출처로 지지되는가 |
| Query rewriting | Decomposition | 검색어를 독립적으로 고치는 것 vs 복합 질문을 하위 질문으로 나누는 것 |
| Multi-Query | HyDE | 여러 query 표현을 검색 vs 가상 답변을 만들어 검색 |
| Semantic search | Hybrid search | 의미 벡터만 사용 vs dense와 BM25 같은 lexical ranking을 함께 사용 |
| Reranker | Retriever | 후보를 처음 찾는 모델 vs 후보를 다시 읽고 순서를 고치는 모델 |
| RAG | Long-context | 필요한 근거를 검색해 넣음 vs 자료를 한 번에 많이 넣음 |
| RAG | Fine-tune | 외부 지식을 조회함 vs 모델 행동·형식·습관을 맞춤 |
| GraphRAG | Vector RAG | entity·관계·요약 그래프 사용 vs chunk embedding 중심 검색 |
| RAG | Tool lookup | 문서 근거 기반 답변 vs 시스템의 현재 상태를 직접 조회 |
최종 수정: 2026-07-09