Field Log · Entry

근거 충분성 판정: Self-RAG·CRAG·FLARE로 재검색하기 (5/10)

질문의 evidence requirement와 source span ledger를 비교해 충분, 부분 충족, 무관, 모순, 오래됨으로 판정하고 query rewrite·다른 source·확인 질문·안전 종료로 교정하는 RAG loop

오늘의 결론

  • 검색 문서가 질문과 관련 있다는 것과 답에 필요한 근거가 모두 있다는 것은 다릅니다.
  • 질문을 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월 정책이 없으므로 “짧아졌는가”를 비교할 수 없습니다. 현재 예외는 알지만 과거 예외가 없어 “바뀌었는가”도 판단할 수 없습니다.

Evidence requirement와 source span ledger를 비교해 corrective action을 선택하는 RAG 근거 충분성 loop

그림 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
AMBIGUOUSrequirement 자체가 확정되지 않음사용자에게 critical slot 질문
UNAUTHORIZED필요한 source 접근 불가권한을 확대하지 않고 안전 종료·escalate
UNANSWERABLEcorpus에 근거가 없다는 평가모른다고 답하거나 범위 안내

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를 고르지 않습니다.

확인 순서:

  1. 같은 entity와 scope인가?
  2. effective date와 revision이 다른가?
  3. 공식 policy와 설명용 FAQ 중 authority가 다른가?
  4. source가 revoked·superseded됐는가?
  5. 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로 본다.

스스로 확인하기

  1. 관련성이 높은 문서 세 개가 있어도 충분하지 않을 수 있는 이유는 무엇인가?
  2. Evidence requirement를 chunk ID가 아니라 source span과 연결하면 어떤 실험이 쉬워지는가?
  3. PARTIALIRRELEVANT은 다음 retrieval action이 어떻게 달라야 하는가?
  4. 외부 웹 검색 fallback에 별도 policy가 필요한 이유는 무엇인가?
  5. 여러분의 RAG가 재검색을 멈추는 no-progress 조건은 무엇인가?

다음 글에서는 현재 run의 state, 과거 사건, 안정된 사실, 재사용할 절차를 구분해 working·episodic·semantic·procedural memory의 저장·검색·갱신·망각 정책을 설계합니다.

참고자료