Balanced Comparison Ranking
Balanced Comparison Ranking
문제(problem)
비교(comparison) 쿼리(예: “기관 A와 기관 B의 보안 요구사항 차이는?”)의 경우 기존 검색 컷은 단순한 전역 top-k 정렬이었다. 한 비교 대상의 어휘가 질문을 지배하거나 코퍼스의 chunk 수가 비대칭일 때, top-k 슬롯 전부가 단일 문서로 채워질 수 있다. 하위 영향:
- 검증기가
missing_comparison_doc/missing_comparison_entity를 표시하고 재시도를 유발한다(추가 latency). - 재시도도 실패하면(편향이 구조적이므로) 답변은 부분(partial) / 한쪽으로 치우친(one-sided) 비교가 된다.
접근(approach)
커버리지 인지(coverage-aware) top-k 컷을 query_type == "comparison" AND target_count >= 2 에 게이팅하여 점수 계산 후 retrieve() 내부에서 적용한다. 컷은:
- 비교 대상별로 점수가 가장 높은 chunk 를
min_per_target개 고른다. - 남은 슬롯을 전역 점수 정렬 후보로 채운다.
- 반환 리스트에서 점수 내림차순을 보존한다.
선택은 검증기가 근거를 보기 전에 일어나므로, 공정한 pool 은 허위 재시도를 줄이면서도 실제로 대상이 부재한 케이스는 여전히 보류(abstain)할 수 있게 한다.
select_supporting_evidence(entity 그룹화, 답변 시점에 사용)는 변경되지 않으며 하위 안전망 역할을 한다.
설정(configuration)
이 동작은 파이프라인 preset 에 부착된 comparison_balance 설정 번들로 게이팅된다:
DEFAULT_COMPARISON_BALANCE = {
"enabled": True,
"min_per_target": 1, # guaranteed slots per comparison target
"k_per_target": 3, # adaptive top_k per target
"headroom": 2, # extra slots beyond k_per_target * target_count
"max_top_k": 12, # absolute ceiling on adaptive top_k
}
agentic_full은 이 설정을 활성화한 채 출하된다.naive_baseline은 이 키를 포함하지 않는다 — 기준선 검색 경로는 변경되지 않는다.- 호출별 비활성화는
run_rag_query(..., comparison_balance={"enabled": False})로 한다.
활성화되고 target_count >= 2 일 때, make_plan 은 다음을 설정한다:
top_k = clamp(k_per_target * target_count + headroom, 6, max_top_k)
2개 대상의 경우: top_k = clamp(8, 6, 12) = 8. 3개 대상의 경우: top_k = clamp(11, 6, 12) = 11.
대상 식별(target identification)
comparison_targets_for_analysis(analysis) 에서:
analysis["matched_doc_ids"]항목이 2개 이상이면, balancing 은chunk.doc_id로 그룹화한다.- 그렇지 않고
analysis["entities"](매치된 기관)가 2개 이상이면, balancing 은chunk.agency로 그룹화한다. - 그 외에는 헬퍼가
scored[:top_k]와 동등한 no-op 이다.
doc_id 는 고유하므로 우선되며, agency fallback 은 분석기가 기관은 매치했으나 doc_id 는 매치하지 못한 케이스를 처리한다.
진단(diagnostics)
쿼리가 대상 2개 이상의 비교일 때마다, balancing 활성화 여부와 무관하게 plan dict 에 comparison_coverage 필드가 추가된다:
{
"comparison_coverage": {
"targets": ["asym-agency-a", "asym-agency-b"],
"target_field": "doc_id",
"before": {"asym-agency-a": 6, "asym-agency-b": 1},
"after": {"asym-agency-a": 7, "asym-agency-b": 1},
"balanced": true,
"min_per_target": 1
}
}
이는 diagnostics.filter_stage_attempts[].comparison_coverage 에도 표면화되어 stage 별 재시도를 디버깅할 수 있다.
Eval 지표(metric)
eval/run_eval.py 는 expected doc_id 가 2개 이상인 query_type == "comparison" 케이스마다 두 개의 커버리지 지표를 계산한다. 여전히 multi_doc 를 쓰는 구(舊) config 는 comparison slice 로 정규화된다:
comparison_target_recall=|expected_doc_ids ∩ evidence_doc_ids| / |expected_doc_ids|— 최종(FINAL) 근거(select_supporting_evidencetopic-grounding trim 이후)에 대해 측정. 검색 커버리지뿐 아니라 topic-grounding 실패에도 민감하다.comparison_pool_recall=|expected_doc_ids ∩ pool_doc_ids| / |expected_doc_ids|— balance 이후 검색 pool(plan.comparison_coverage.after에서 읽음)에 대해 측정. balancing 의 효과를 하위 검증기/topic trimming 으로부터 분리한다.
둘 다 metric_block 에서 평균값과 *_full_coverage_rate(recall == 1.0 인 비율)로 집계된다. 이들은 by_slice["comparison"] / by_query_type["comparison"] 와 by_hardcase_category["one_sided_comparison"](또는 해당 케이스가 있는 임의의 slice) 아래에 나타나므로 핵심 수치가 깔끔하게 유지된다.
comparison_pool_recall 은 balanced top-k 컷이 제 역할을 하는지에 대한 가장 깔끔한 신호이고, comparison_target_recall 은 balancing 과 topic grounding 둘 다에 의존하는 사용자 가시(user-visible) 답변 품질 신호다.
도움이 되는 경우
- 비대칭 어휘: 두 대상이 모두 관련 있음에도, 질문 표현이 한 대상의 도메인 용어와 매치된다. 예: “품질관리 관점에서 기관 A와 기관 B의 차이는?” (“품질관리” 는 기관 A 에 많고, 기관 B 는 “데이터 거버넌스” / “drift” 를 쓴다).
- 비대칭 chunk 수: 한 문서는 짧은 chunk 가 많고, 다른 문서는 적거나 / 긴 chunk 를 갖는다.
- 비대칭 metadata 신호 강도: 한 대상은 고신뢰 metadata 매치를 갖고, 다른 대상은 약한 fuzzy 매치만 갖는다.
도움이 되지 않는 경우
- 대상이 코퍼스에 실제로 부재: balancing 은 근거를 합성할 수 없다. 검증기는 여전히
missing_comparison_doc를 표시하고 답변은 보류한다.tests/test_fuzzy_retrieval.py::test_partial_comparison_keeps_supported_claims_and_missing_target로 고정된다. - single-doc 및 follow-up 쿼리:
query_type == "comparison" AND target_count >= 2게이트를 통한 명시적 no-op. - 실제로 한쪽으로 치우친 답변: 예: “기관 A의 …” — 이들은 비교 분기에 절대 도달하지 않는다.
비활성화 방법
- 호출별:
run_rag_query(..., comparison_balance={"enabled": False}). plan 은 관측성(observability)을 위해 여전히comparison_coverage를 기록한다. - 전역:
naive_baselinepreset 을 고른다. 기준선 preset 은comparison_balance키가 없으므로 balancing 이 구조적으로 꺼져 있다.
구현 포인터
rag_core.py::DEFAULT_COMPARISON_BALANCE— 기본 config.rag_core.py::comparison_targets_for_analysis— 대상 추출.rag_core.py::apply_comparison_balance— balanced 컷.rag_core.py::make_plan— adaptive top_k.rag_core.py::reassemble_parent_sections— hierarchical-mode 연결.rag_core.py::summarize_stage_attempt— stage 별 진단.eval/run_eval.py::score_case/metric_block— eval 지표.tests/test_fuzzy_retrieval.py::BalancedComparisonRerankTest— 커버리지 테스트.