# Eval v0.2 Baseline Analysis — 2026-05-23

> Parent PR: PR-Eval-V0_2-Baseline-Analysis
> Eval set: `tests/search_eval/queries.yaml` (v0.2, 51 case)
> Raw: `tests/search_eval/baselines/v0_2_baseline_2026-05-23.json`
> Branch: `feat/eval-v0-2-baseline-analysis` (HEAD-1: 725a4e1 PR-1 Schema-Harness)

## 측정 환경

| 항목 | 값 |
|---|---|
| corpus_size | 21,385 documents (deleted_at IS NULL) |
| embedding | BAAI/bge-m3 |
| reranker | BAAI/bge-reranker-v2-m3 |
| search_mode | hybrid (server default fusion + rerank) |
| eval cases | 51 (graded=46, failure_expected=5) |
| latency p50 / p95 | 528 ms / 1,664 ms |
| config.yaml sha256 prefix | 97ae77b4e1dfbbc6 |

## 1. 카테고리별 점수표

| Category | n | Recall@10 | NDCG@10 | graded NDCG@10 | Recall@10 (g≥2) | Recall@10 (g≥3) |
|---|---:|---:|---:|---:|---:|---:|
| **standards** | 11 | 0.91 | 0.85 | **0.87** | 1.00 | 1.00 |
| **english_only** | 9 | 0.78 | 0.71 | **0.78** | 0.83 | 0.89 |
| **exam** | 7 | 0.57 | 0.62 | **0.74** | 0.64 | **1.00** |
| **korean_only** | 9 | 0.55 | 0.47 | **0.51** | 0.57 | 0.56 |
| **mixed** | 10 | 0.38 | 0.36 | **0.39** | 0.38 | 0.40 |
| **ocr_derived** | 0 | — | — | — | — | — |
| **failure_expected** | 5 | failure precision = **0/5 (0.00)** |

### 언어별

| Language | n | Recall@10 | graded NDCG@10 |
|---|---:|---:|---:|
| en | 9 | 0.78 | 0.78 |
| ko | 27 | 0.70 | 0.72 |
| mixed | 10 | 0.38 | 0.39 |

## 2. 약점 식별 (top 3)

### 2.1 mixed (crosslingual) — graded NDCG **0.39**

가장 큰 weakness. 10 case 모두 한국어↔영어 cross-lingual.
- top-3 hit 0.90 자체는 높음 → "정답 후보가 top-10 안에 들지만 양언어 관련 doc 을 골고루 못 잡음"
- Recall (g≥2) 0.38, (g≥3) 0.40 — multi-doc relevant set 의 일부만 회수
- 예: cl_006 ("pressure vessel Korean industrial safety regulation", 영문 query → 한국 법령 + 영문 책 둘 다 정답) 같은 case 가 한쪽 언어만 회수

**추정 root cause**:
- bge-m3 multilingual 능력 한계 (특히 한국어↔영어 간 의미 align)
- 동일 의미의 ko/en doc 가 embedding 공간에서 분리 → fusion 후에도 한쪽 언어 dominance
- chunk language metadata 활용 부재 (필터 X, weighted X)

### 2.2 korean_only (natural language ko) — graded NDCG **0.51**

자연어 한국어 query 약함. 9 case 중 standards (exact_keyword) 만 보면 0.87, natural language 위주의 nl_*/news_*/misc_* 에서 점수 하락.
- Recall (g≥3) 0.56 — top-3 강제 정답조차 절반만 회수
- top3_hit 0.78 — direct match 도 22% miss

**추정 root cause**:
- query rewrite/expansion 부재 (자연어 의역 매핑 약함)
- bge-m3 한국어 chunk embedding 품질 (특히 도메인 용어)
- "유해화학물질을 다루는 회사가 지켜야 할 안전 의무" 같은 query 의 키워드 추출 약함

### 2.3 failure_expected — precision **0/5 (0.00)**

5 case 모두 "결과 0건 expected" 였으나 DS 가 무관 결과를 반환.
- confidence/score threshold 미적용
- 예: "초전도 안전 관리법" → 산안법 같은 무관 doc 반환

**추정 root cause**:
- search confidence score < 0.5 차단 로직 부재 ([[project_phase3_5_guardrails]] 의 B1/B2 미배포 또는 threshold 너무 낮음)
- reranker score 자체는 정상 동작이나 cutoff 정책 없음

## 3. Embedding-sensitive failure pattern (Phase 2A 입력)

peppy-hugging-nest Phase 2A 의 식별 카테고리 4개:

| 패턴 | 본 baseline 신호 | 우선순위 |
|---|---|---|
| **candidate recall@k** | exam Recall@10 0.57 vs MRR 0.89 — top-3 안엔 정답이 있으나 grade 2 보조 정답을 못 잡음 (10 슬롯 안에 후보 부재) | M |
| **crosslingual miss** | mixed 0.39 graded NDCG, 동일 의미 ko/en doc 분리 — **TOP weakness** | **H** |
| **Korean-English mismatch** | korean_only natural language 0.51, 한자/영문 fallback 표현 매칭 약함 (cl_005 "asme_code해설" 매칭은 OK 였으나 자연어 의역 약함) | H |
| **OCR-derived chunk miss** | **NOT_MEASURED** — OCR 식별 컬럼 부재 (TBD-O FAILED) | 보류 |

**embedding 독립 추정 원인**:
- chunking 전략: window 14041 / paragraph 9897 / section 4801 / legal_article 1859 — legal_article (1859, 5.5%) 만 짧은 단위, 나머지는 큰 window 위주. 자연어 query 시 chunk 가 너무 길어 의미 dilute 가능
- query rewrite 부재: 자연어 → 키워드 변환 layer 없음
- reranker threshold: 정상 동작 but failure cutoff X
- metadata filter: language/country 미활용

## 4. 다른 가능한 원인 (embedding 독립)

| 원인 | 신호 | 비고 |
|---|---|---|
| **chunking 단위 too coarse** | window 14041 (≈50% chunks) | Phase 3 markdown 전환 시 chunk_type 재분포 필요 |
| **query rewrite 부재** | korean_only natural language 0.51 vs standards 0.87 — exact keyword 와 의역 query 큰 격차 | Phase 2Q (별 PR-Query-Rewrite) 후보 |
| **reranker threshold 부재** | failure_expected 0/5 | Phase 3.5 B1/B2 활성화 검토 또는 별 chore |
| **metadata filter 미활용** | mixed 카테고리 양언어 분리 가능했을 chance | language 가중치/필터 도입 검토 |

## 5. Phase 2 dispatch 권고

본 baseline 의 약점 분포 → Phase 2A~D 우선순위:

| Phase | 영역 | 권고 | 근거 |
|---|---|---|---|
| **2A Embedding (bge-m3)** | TOP — **즉시 진입** | mixed 0.39 / korean_only 0.51 — 두 약점 모두 embedding-sensitive. bge-m3 alternative (예: bge-m3-large, multilingual-e5-large, polyglot embedding) 점검 가치 高 |
| **2B Reranker** | M — 2A 이후 | 일반 NDCG 향상 + failure precision 동시 개선 가능. threshold cutoff 추가 검토 |
| **2C OCR-Marker Pipeline** | 보류 — **선행 chore 필요** | ocr_derived 0 case → 측정 불가. **별 chore: OCR 식별 컬럼 추가** (`documents.is_ocr_derived` 또는 `document_chunks.extraction_source`) 가 선행. 이후 ocr_derived 4 case 추가 후 측정 |
| **2D STT (Faster Whisper)** | 보류 — 본 평가셋 영역 외 | search eval 과 직접 측정 link 없음. 별 평가셋 (voice → 텍스트 정확도) 필요 |

**추천 즉시 액션**:
1. Phase 2A 별 plan 작성 — bge-m3 alternative 후보 3종 비교, 본 baseline json 대비 mixed/korean_only 점수 변화 측정
2. failure_expected 0/5 chore 별 PR — confidence threshold 활성화 ([[project_phase3_5_guardrails]] B1/B2 재검토)
3. OCR 식별 컬럼 추가 chore (Phase 2C 선행)

Query rewrite 는 본 4-Phase 외 후보 → Phase 2Q 또는 Search-PR 로 별도 분리 (korean_only 약점 해결 보조).

## 6. v0.1 회귀 (참고)

PR-1 (`725a4e1`) 의 v0.1 23 case 점수는 별도 박제 부재. 본 baseline 의 v0.1 binary 점수:
- Recall@10 0.646, MRR@10 0.724, NDCG@10 0.606, Top-3 0.891

기존 23 case 만 분리 측정 시 (legacy_category 가 있는 case) 동일 점수 회귀 여부는 후속 별 PR 또는 chore 에서 검증 (PR-1 baseline 박제 부재로 직접 회귀 비교 불가).

## 7. Closure 조건 ([[feedback_quant_expectation_not_hard_gate]])

- ✓ 51 case 작성 완료, id 중복 0
- ✓ baseline json + analysis md 박제
- ✓ 약점 카테고리 top 3 식별 (mixed / korean_only / failure_expected)
- ✓ embedding-sensitive failure pattern 4 카테고리 분류 (3 식별 + 1 NOT_MEASURED)
- ✓ Phase 2 dispatch 권고 (2A 우선, 2B M, 2C 선행 chore 필요, 2D 본 평가셋 외)
- ✓ 0.70 미달 항목 (mixed 0.39 / korean_only 0.51) 의 원인 분해 보고서 역할

**Phase 1 closure**.

## 다음 단계

본 PR closure 후:
- Phase 2A 별 plan 작성 (`~/.claude/plans/phase-2a-embedding-diagnose.md`)
- chore: OCR 식별 컬럼 추가 별 PR (`PR-Chore-OCR-Column-1`)
- chore: failure_expected confidence threshold 별 PR (`PR-Chore-Confidence-Cutoff-1`)
