Field Log · Entry
근거 충분성 판정: Self-RAG·CRAG·FLARE로 재검색하기 (5/10)
오늘의 결론
- 검색 문서가 질문과 관련 있다는 것과 답에 필요한 근거가 모두 있다는 것은 다릅니다.
- 질문을 evidence requirement로 분해하고 각 requirement를 source span에 연결해야 coverage를 계산할 수 있습니다.
- 충분성 판정은 relevance, support, coverage, consistency, freshness, authority를 분리해서 봅니다.
- 부족한 이유마다 query rewrite, 다른 retriever·source, 추가 읽기, 사용자 확인, 안전 종료가 달라집니다.
- Corrective loop에는 새 근거 증가량, 최대 시도, 시간·비용 budget을 이용한 stop rule이 필요합니다.
앞 글에서 Agent가 action 순서를 계획하고 관찰에 따라 다시 계획하는 방법을 배웠습니다. 하지만 언제 검색을 그만두고 답해야 할지는 아직 남아 있습니다.
다음 top-3 결과를 생각해 봅시다.
Q: 6월보다 현재 환불 기한이 짧아졌고, 예외 조건도 바뀌었는가?
D1: 현재 정책 — 기본 환불 기한 14일
D2: 현재 FAQ — 배송 지연 시 예외 가능
D3: 현재 정책 요약 — 기본 환불 기한 14일
세 문서 모두 관련 있어 보이고 score도 높을 수 있습니다. 그러나 6월 정책이 없으므로 “짧아졌는가”를 비교할 수 없습니다. 현재 예외는 알지만 과거 예외가 없어 “바뀌었는가”도 판단할 수 없습니다.
그림 1. 충분성 judge는 점수 하나로 끝나지 않는다. 어떤 requirement가 비었는지와 왜 비었는지를 기록해야 다음 retrieval action을 선택할 수 있다.
관련성, 충분성, 정답성은 서로 다르다
Relevance
문서가 질문 주제와 관련 있는가?
refund policy query ↔ refund policy document
Support
특정 evidence span이 특정 claim을 실제로 지지하는가?
Claim: 현재 기본 환불 기한은 14일이다.
Evidence: “구매일로부터 14일 이내...”
Coverage 또는 Sufficiency
답에 필요한 evidence requirement가 모두 채워졌는가?
R1 current base window ✓
R2 previous base window ✗
R3 current exceptions ✓
R4 previous exceptions ✗
Consistency
서로 모순되는 evidence가 있는가? 있다면 revision·scope·authority로 해소했는가?
Freshness
질문의 기준 시점에 맞는 revision인가?
Answer correctness
최종 answer가 질문에 맞고 evidence로 뒷받침되는가?
검색 score가 높아도 coverage가 낮을 수 있고, coverage가 높아도 생성 model이 잘못 요약할 수 있습니다. 단계를 분리해야 합니다.
질문을 Evidence requirement로 바꾸기
질문:
6월보다 현재 환불 기한이 짧아졌고 예외 조건도 바뀌었는가?
요구사항 graph:
{
"question_id": "q_1042",
"requirements": [
{
"id": "r1",
"description": "current default refund window",
"source_constraints": {
"policy": "refund",
"revision": "current",
"authority": "official"
},
"required": true
},
{
"id": "r2",
"description": "2026-06 default refund window",
"source_constraints": {
"policy": "refund",
"revision": "2026-06",
"authority": "official"
},
"required": true
},
{
"id": "r3",
"description": "current exception conditions",
"source_constraints": {
"revision": "current"
},
"required": true
},
{
"id": "r4",
"description": "2026-06 exception conditions",
"source_constraints": {
"revision": "2026-06"
},
"required": true
}
],
"relations": [
{"type": "COMPARE", "left": "r2", "right": "r1"},
{"type": "COMPARE", "left": "r4", "right": "r3"}
]
}
이 decomposition도 틀릴 수 있으므로 version과 provenance를 남깁니다. 중요한 것은 “문서 세 개”가 아니라 필요한 정보 slot 네 개를 추적한다는 점입니다.
Evidence ledger
검색 결과를 prompt 문자열로만 쌓지 않고 ledger에 저장합니다.
{
"evidence_id": "ev_017",
"source_id": "policy/refund",
"revision": "2026-07-01",
"span_id": "p3:l12-l18",
"content_hash": "sha256:...",
"authority": "official_policy",
"retrieved_at": "2026-07-16T04:20:00Z",
"access_scope": "tenant:acme",
"supports": [
{"requirement_id": "r1", "grade": "DIRECT", "score": 0.97}
],
"contradicts": [],
"trust": "untrusted_content",
"validation": {
"source_exists": true,
"revision_matches": true,
"span_verified": true
}
}
Ledger가 주는 이점:
- 같은 evidence 중복 검색 감지
- requirement별 coverage 계산
- citation validation
- contradiction 추적
- source revision 변경 감지
- 재실행 시 stable evidence reference
- model context 밖으로 밀려난 근거도 보존
충분성을 여섯 축으로 판정하기
1. Relevance
Evidence가 requirement의 주제를 다루는가?
2. Entailment 또는 Support
Evidence만 보고 claim을 지지할 수 있는가? 단순 단어 겹침이 아니라 의미 관계를 봅니다.
3. Coverage
필수 requirement 중 얼마나 채워졌는가?
coverage = covered_required / total_required
4. Consistency
동일 scope와 시점에서 충돌하는 evidence가 있는가?
5. Freshness
질문이 요구한 시점, effective date, revision을 만족하는가?
6. Authority
공식 정책, FAQ, 사용자 작성 note 중 어떤 source가 이 claim을 결정할 권위를 가지는가?
점수 예:
{
"verdict": "PARTIAL",
"coverage": 0.5,
"requirement_results": [
{"id": "r1", "status": "SUPPORTED", "evidence": ["ev_017"]},
{"id": "r2", "status": "MISSING", "evidence": []},
{"id": "r3", "status": "SUPPORTED", "evidence": ["ev_021"]},
{"id": "r4", "status": "MISSING", "evidence": []}
],
"contradictions": [],
"reason_codes": ["PREVIOUS_REVISION_MISSING"],
"recommended_action": "SEARCH_ARCHIVE_REVISION"
}
Verdict를 행동 가능한 상태로 만들기
| Verdict | 의미 | 기본 행동 |
|---|---|---|
| SUFFICIENT | 필수 requirement가 검증됨 | 답변 생성·citation 검사 |
| PARTIAL | 일부 requirement만 있음 | missing slot 중심 재검색 |
| IRRELEVANT | 결과가 requirement를 지지하지 않음 | query rewrite·retriever 변경 |
| CONTRADICTORY | 해결되지 않은 충돌 | authority·revision 확인, 양쪽 공개 |
| STALE | 시점이 맞지 않음 | 최신 source 또는 revision lookup |
| AMBIGUOUS | requirement 자체가 확정되지 않음 | 사용자에게 critical slot 질문 |
| UNAUTHORIZED | 필요한 source 접근 불가 | 권한을 확대하지 않고 안전 종료·escalate |
| UNANSWERABLE | corpus에 근거가 없다는 평가 | 모른다고 답하거나 범위 안내 |
LOW_SCORE 하나로 모든 실패를 묶으면 corrective action도 하나밖에 만들 수 없습니다.
Deterministic check를 먼저 한다
LLM judge 전에 코드로 확인할 수 있는 것을 검사합니다.
def deterministic_evidence_checks(requirement, evidence, runtime):
issues = []
if not runtime.acl.can_read(evidence.source_id):
issues.append("UNAUTHORIZED_SOURCE")
if not evidence.validation.source_exists:
issues.append("SOURCE_NOT_FOUND")
if requirement.source_constraints.get("revision") not in {
None,
evidence.revision,
"current",
}:
issues.append("REVISION_MISMATCH")
if not evidence.validation.span_verified:
issues.append("SPAN_NOT_VERIFIED")
if evidence.content_hash in runtime.revoked_content_hashes:
issues.append("REVOKED_CONTENT")
return issues
그 뒤에 semantic relevance와 support를 model이나 NLI evaluator로 봅니다.
source existence → ACL → revision/freshness → span integrity
→ semantic relevance → support → cross-evidence consistency
Judge에게 답을 쓰게 하지 않는다
Sufficiency evaluator의 출력은 verdict와 missing requirement여야 합니다.
나쁜 prompt 목표:
문서를 읽고 답을 만든 뒤 충분한지 알려 줘.
좋은 계약:
{
"task": "map evidence spans to requirement IDs",
"allowed_labels": [
"DIRECT_SUPPORT",
"PARTIAL_SUPPORT",
"CONTRADICTS",
"IRRELEVANT"
],
"must_quote_span_ids": true,
"must_not_generate_answer": true
}
같은 model을 사용해도 generation 역할과 judging 역할의 input·output·temperature·rubric을 분리합니다. 중요한 domain에서는 human-labeled calibration set으로 judge 오류를 측정합니다.
Threshold는 Calibration 결과다
relevance ≥ 0.7
support ≥ 0.8
coverage = 1.0
숫자 자체에는 보편적인 의미가 없습니다. 다음을 기준으로 threshold를 정합니다.
- human label과의 precision·recall
- false sufficient의 위험
- requirement 유형
- source authority
- 질문 risk tier
- route별 cost
정책 질문에서 잘못된 SUFFICIENT는 추가 검색보다 비쌀 수 있으므로 precision을 높게 잡습니다.
Self-RAG에서 가져올 아이디어
Self-RAG는 retrieval 필요성, passage relevance, response support 등을 reflection token으로 판단하며 retrieve·generate·critique를 조정하는 framework입니다.
Application harness에 옮길 수 있는 원리:
- retrieval을 항상 고정적으로 하지 않는다.
- 검색된 passage가 실제로 관련 있는지 평가한다.
- 생성 내용이 passage로 지지되는지 평가한다.
- quality preference에 따라 inference behavior를 조절한다.
논문의 special token을 그대로 구현하지 않아도 typed verdict와 state transition으로 같은 제어 문제를 표현할 수 있습니다.
NEED_RETRIEVAL → router/search
PASSAGE_RELEVANT → evidence ledger
CLAIM_SUPPORTED → citation validator
UTILITY → final selection
CRAG에서 가져올 아이디어
Corrective Retrieval Augmented Generation은 retrieval evaluator로 문서 품질을 판정하고, 잘못된 retrieval일 때 corrective action을 수행합니다. 또한 검색 결과에서 핵심 부분을 분해·재조합하고 외부 검색을 보완 source로 사용합니다.
실무 원리:
- evaluator verdict에 따라 경로를 나눈다.
- corpus retrieval이 약하면 다른 source를 사용할 수 있다.
- 긴 문서를 통째로 넣지 말고 관련 span을 선택한다.
- fallback source의 trust·privacy·freshness 정책을 별도로 둔다.
“내부 검색 실패 → 무조건 웹 검색”은 위험합니다. 비공개 질문을 외부 search query로 보내도 되는지, 외부 source를 답에 사용할 수 있는지 policy gate가 필요합니다.
FLARE에서 가져올 아이디어
FLARE는 긴 글을 생성하는 중 앞으로 쓸 내용을 예측하고, 낮은 confidence가 예상될 때 추가 retrieval을 수행하는 active retrieval 접근입니다.
실무 원리:
- retrieval은 답변 시작 전에 한 번만 일어나지 않아도 된다.
- section·claim 단위로 evidence gap을 탐지한다.
- 앞으로 필요한 evidence를 query로 바꾼다.
- 생성 도중 검색하더라도 전체 budget과 stop rule을 유지한다.
단, token confidence가 factual uncertainty의 완벽한 proxy는 아닙니다. claim template와 evidence coverage 같은 외부 signal을 함께 씁니다.
2026년 관점: Relevance만이 아니라 Diversity
DF-RAG은 reasoning-intensive QA에서 cosine relevance만 최적화하면 중복 context가 늘고 보완 근거가 빠질 수 있다는 문제를 다루며, query별 diversity를 조정합니다.
이 결과를 evidence ledger 관점으로 읽으면 다음과 같습니다.
같은 requirement를 지지하는 비슷한 chunk 5개
<
서로 다른 requirement를 채우는 보완 chunk 3개
중복 제거는 token 절약만이 아니라 requirement coverage 개선 수단입니다.
Corrective action을 Missing reason에 연결하기
Query rewrite
조건:
- query가 대명사·축약어로 모호함
- lexical mismatch
- requirement가 명확하지만 검색 표현이 약함
Decomposition
조건:
- comparison·multi-hop
- 여러 evidence group 필요
- 한 query에 entity와 relation이 과도하게 섞임
Alternate retriever
조건:
- exact code·ID를 dense가 놓침 → BM25/direct lookup
- paraphrase를 lexical이 놓침 → dense
- relation이 필요 → graph/text hybrid route
Alternate source
조건:
- 현재 corpus에 revision archive 없음
- authority source가 다른 system에 있음
Wider candidate pool 또는 diversity selection
조건:
- top result가 중복
- 필요한 aspect가 다양함
Ask user
조건:
- critical entity·time range·scope가 없음
- 검색으로 의도를 결정할 수 없음
Finish with uncertainty
조건:
- 허용된 source에서 필요한 근거를 찾지 못함
- budget 소진
- source 접근 권한 없음
- contradiction을 해소할 authority 없음
Bounded corrective loop
def corrective_loop(state, deps):
while True:
verdict = deps.judge.evaluate(
requirements=state.requirements,
ledger=state.evidence_ledger,
)
deps.trace.record_verdict(verdict)
if verdict.kind == "SUFFICIENT":
return state.to_answering(verdict)
if verdict.kind == "AMBIGUOUS":
return state.wait_for_user(verdict.missing_slots)
if verdict.kind in {"UNAUTHORIZED", "UNANSWERABLE"}:
return state.finish_uncertain(verdict.reason_codes)
stop = deps.stop_policy.check(state, verdict)
if stop:
return state.finish_uncertain(stop.reason_codes)
action = deps.corrector.propose(verdict, state)
prepared = deps.tool_gate.prepare(action, state)
observation = deps.executor.execute(prepared)
state = deps.reducer.add_observation(state, observation)
deps.checkpoints.save(state)
Judge, corrector, tool gate를 분리하면 evaluator가 직접 외부 search를 실행하지 않습니다.
No-progress를 수치로 잡기
재검색 전후 ledger 변화를 계산합니다.
Δrequirements = newly_covered_requirements
Δevidence = new_verified_spans
Δcontradictions = resolved - introduced
Stop 예:
def no_progress(history):
recent = history[-2:]
return (
len(recent) == 2
and all(x.new_covered_requirements == 0 for x in recent)
and all(x.new_verified_evidence == 0 for x in recent)
)
다음도 hard limit입니다.
- max corrective rounds
- max searches and reads
- max distinct query rewrites
- wall-clock deadline
- token·cost budget
- same query/source fingerprint repetition
Contradiction 처리
모순을 평균 내거나 더 높은 similarity score를 고르지 않습니다.
확인 순서:
- 같은 entity와 scope인가?
- effective date와 revision이 다른가?
- 공식 policy와 설명용 FAQ 중 authority가 다른가?
- source가 revoked·superseded됐는가?
- exception 조건 때문에 둘 다 참일 수 있는가?
Ledger 예:
{
"claim": "refund window is 14 days",
"support": ["ev_current_policy"],
"contradiction": ["ev_old_faq_30_days"],
"resolution": {
"status": "RESOLVED",
"reason": "FAQ revision predates current policy effective date",
"authority_evidence": "ev_current_policy"
}
}
해소할 수 없으면 양쪽을 citation과 함께 공개하고 단정하지 않습니다.
Unanswerable을 정상 결과로 학습시키기
Agent가 항상 답을 만들어야 한다고 평가하면 evaluator도 부족한 근거를 충분하다고 판정하는 방향으로 압력을 받습니다.
Unanswerable dataset에 포함할 유형:
- corpus 밖 질문
- 미래 사건
- 삭제·폐기된 source
- 권한 밖 source만 답을 가짐
- 서로 모순되고 authority가 없음
- critical user slot 누락
성공 조건:
unsupported factual claim = 0
uncertainty reason is correct
available partial evidence is cited
next safe action is useful
평가 Dataset
각 query에 answer만 두지 말고 evidence requirement를 label합니다.
{
"question": "6월보다 현재 환불 기한과 예외가 바뀌었는가?",
"requirements": [
{"id": "r1", "gold_spans": ["current_policy:..."]},
{"id": "r2", "gold_spans": ["june_policy:..."]},
{"id": "r3", "gold_spans": ["current_exception:..."]},
{"id": "r4", "gold_spans": ["june_exception:..."]}
],
"answerable": true,
"critical": ["r1", "r2", "r3", "r4"]
}
평가 지표:
- sufficiency precision: SUFFICIENT 판정 중 실제 충분한 비율
- sufficiency recall: 실제 충분한 경우를 놓치지 않은 비율
- requirement coverage
- false sufficient rate
- false unanswerable rate
- corrective success rate
- new evidence per corrective round
- contradiction resolution accuracy
- unsupported claim rate
- extra searches, latency, cost
High-risk RAG에서는 false sufficient를 가장 중요한 gate로 둘 수 있습니다.
흔한 실패 패턴
1. Top score를 충분성으로 사용
한 requirement에 매우 관련 높은 문서만 반복됩니다.
처방: requirement coverage와 diversity를 봅니다.
2. Answer model이 스스로 충분하다고 선언
답을 만들고 싶은 model의 bias와 평가가 결합됩니다.
처방: evidence mapping contract와 별도 calibration을 둡니다.
3. 낮은 점수면 같은 query를 반복
새 evidence 없이 비용만 늘어납니다.
처방: missing reason별 corrective action과 no-progress stop을 둡니다.
4. 외부 검색을 무조건 fallback
비공개 질문이 외부로 유출되거나 낮은 authority source가 섞입니다.
처방: source별 privacy·authority·citation policy를 둡니다.
5. Contradiction을 하나 버림
최신 revision이나 exception 차이를 놓칩니다.
처방: 양쪽 evidence와 resolution record를 유지합니다.
6. Unanswerable을 실패로 간주
없는 근거로 답을 채우게 됩니다.
처방: 안전한 불확실 응답을 정상 성공 class로 평가합니다.
Production 체크리스트
- relevance, support, coverage, consistency, freshness, authority를 분리한다.
- 질문을 versioned evidence requirement로 분해한다.
- evidence는 source·revision·span·hash·ACL과 함께 ledger에 저장한다.
- deterministic source·ACL·revision 검사를 먼저 한다.
- judge는 답변 대신 requirement-evidence mapping을 출력한다.
- threshold를 human-labeled calibration set으로 정한다.
- verdict마다 다른 corrective action이 있다.
- 외부 source 사용에 privacy·authority policy가 있다.
- contradiction resolution을 artifact로 남긴다.
- no-progress, round, search, time, cost hard limit가 있다.
- unanswerable을 정상 결과로 평가한다.
- false sufficient와 corrective cost를 release gate로 본다.
스스로 확인하기
- 관련성이 높은 문서 세 개가 있어도 충분하지 않을 수 있는 이유는 무엇인가?
- Evidence requirement를 chunk ID가 아니라 source span과 연결하면 어떤 실험이 쉬워지는가?
PARTIAL과IRRELEVANT은 다음 retrieval action이 어떻게 달라야 하는가?- 외부 웹 검색 fallback에 별도 policy가 필요한 이유는 무엇인가?
- 여러분의 RAG가 재검색을 멈추는 no-progress 조건은 무엇인가?
다음 글에서는 현재 run의 state, 과거 사건, 안정된 사실, 재사용할 절차를 구분해 working·episodic·semantic·procedural memory의 저장·검색·갱신·망각 정책을 설계합니다.
참고자료
- Self-RAG: Learning to Retrieve, Generate, and Critique through Self-Reflection
- Corrective Retrieval Augmented Generation
- Active Retrieval Augmented Generation
- Adaptive-RAG
- DF-RAG: Query-Aware Diversity for Retrieval-Augmented Generation
- RouteRAG: Efficient Retrieval-Augmented Generation from Text and Graph via Reinforcement Learning