## 결과 요약 Phase 1.3 baseline vs Phase 2 final A/B (평가셋 v0.1, 23 쿼리): - Recall@10: 0.730 → 0.737 (+0.007) - NDCG@10: 0.663 → 0.668 (+0.005) - Top-3 hit: 0.900 → 0.900 (0) - p95 latency: 171ms → 256ms (+85) - news_crosslingual NDCG: 0.27 → 0.37 (+0.10 ✓) - exact_keyword / natural_language_ko: 완전 유지 (회귀 0) ## Phase 2 게이트: 2/6 통과 ✓ news_crosslingual NDCG ≥ 0.30 ✓ latency p95 < 400ms ❌ Recall@10 ≥ 0.78 (0.737) ❌ Top-3 hit ≥ 0.93 (0.900) ❌ crosslingual_ko_en NDCG ≥ 0.65 (0.53, bge-m3 한계) ❌ 평가셋 v0.2 작성 (후속) ## 핵심 성과 (게이트 미달이지만 견고한 기반) 1. QueryAnalyzer async-only 아키텍처 (retrieval 차단 0) 2. semaphore concurrency=1 (MLX single-inference queue 폭발 방지) 3. multilingual narrowing (news/global 한정 → 회귀 0 + news 개선) 4. soft_filter boost 보수적 설정 (0.01, domain only) 5. prewarm 15개 → cache hit rate 70%+ ## infra_inventory.md soft lock 준수 - config.yaml / Ollama / compose restart 변경 0 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
126 lines
5.5 KiB
Markdown
126 lines
5.5 KiB
Markdown
# Phase 2 최종 측정 보고서
|
||
|
||
**측정일**: 2026-04-08
|
||
**대상**: Document Server 검색 v2, Phase 2.1~2.3 통합
|
||
**평가셋**: `tests/search_eval/queries.yaml` v0.1 (23 쿼리, 8 카테고리)
|
||
**인프라 기준**: `memory/infra_inventory.md` (2026-04-08 실측)
|
||
|
||
## A/B 결과
|
||
|
||
| metric | Phase 1.3 baseline (A) | Phase 2 final (B) | Δ |
|
||
|---|---|---|---|
|
||
| Recall@10 | 0.730 | **0.737** | +0.007 ✓ |
|
||
| MRR@10 | 0.795 | 0.797 | +0.002 |
|
||
| NDCG@10 | 0.663 | **0.668** | +0.005 ✓ |
|
||
| Top-3 hit | 0.900 | 0.900 | 0 |
|
||
| Latency p50 | 114 ms | 109 ms | -5 |
|
||
| Latency p95 | 171 ms | **256 ms** | +85 |
|
||
|
||
## 카테고리별
|
||
|
||
| category | A NDCG | B NDCG | Δ | 비고 |
|
||
|---|---|---|---|---|
|
||
| exact_keyword | 0.96 | 0.96 | 0 | 회귀 0 ✓ |
|
||
| natural_language_ko | 0.73 | 0.73 | 0 | 회귀 0 ✓ (narrowed multilingual 덕) |
|
||
| crosslingual_ko_en | 0.53 | 0.53 | 0 | bge-m3 한계 — multilingual 효과 0 |
|
||
| **news_crosslingual** | 0.27 | **0.37** | **+0.10** | 개선 ✓ |
|
||
| news_ko | 0.36 | 0.37 | +0.01 | 미세 |
|
||
| news_en | 0.00 | 0.00 | 0 | 여전히 0 |
|
||
| news_fr | 0.46 | 0.46 | 0 | |
|
||
| other_domain | 0.88 | 0.88 | 0 | |
|
||
|
||
## Phase 2 게이트 검증
|
||
|
||
| 게이트 | 목표 | 실제 | 상태 |
|
||
|---|---|---|---|
|
||
| Recall@10 | ≥ 0.78 | 0.737 | ❌ (-0.043) |
|
||
| Top-3 hit | ≥ 0.93 | 0.900 | ❌ (-0.030) |
|
||
| crosslingual_ko_en NDCG | ≥ 0.65 | 0.53 | ❌ (-0.12) |
|
||
| news_crosslingual NDCG | ≥ 0.30 | 0.37 | ✓ |
|
||
| latency p95 | < 400 ms | 256 ms | ✓ |
|
||
| 평가셋 v0.2 완료 | - | v0.1만 | ❌ (후속) |
|
||
|
||
**2/6 통과** — 목표 미달. 단 회귀 0 + 일부 영역 개선.
|
||
|
||
## Phase 2에서 실제로 달성한 것
|
||
|
||
### 1. 아키텍처 — QueryAnalyzer async-only 구조 확립
|
||
실측 기반 철학 수정 (memory `feedback_analyzer_async_only.md`):
|
||
- `query → retrieval (즉시)` + `→ analyzer (async) → cache`
|
||
- retrieval 경로에 LLM 동기 호출 0
|
||
- background semaphore=1 (MLX single-inference 큐 폭발 방지)
|
||
- prewarm 15개 startup 시 자동 실행
|
||
- cache hit rate 첫 사용자 요청부터 70%+
|
||
|
||
### 2. 실측 데이터 — MLX 한계
|
||
gemma-4-26b-a4b-it-8bit MLX:
|
||
- full prompt (prompt_tok=2406) → **10.5초**
|
||
- 축소 prompt (prompt_tok=802) → **7~11초**
|
||
- concurrency >1 시 → **timeout 폭발** (semaphore=1 필수)
|
||
- 결론: analyzer는 **즉시 쓸 수 없는 자원**
|
||
|
||
### 3. multilingual narrowing — domain별 효과 차등
|
||
- 전 도메인 multilingual: natural_language_ko **-0.10 악화** ❌
|
||
- `domain_hint == news OR language_scope == global` 한정: 회귀 0 + news_crosslingual **+0.10** ✓
|
||
- 룰: 한국어 법령 검색에 영어 번역 쿼리 섞으면 noise
|
||
|
||
### 4. soft_filter boost — 보수적 설정 필요
|
||
- 초기 0.03+0.02 → exact_keyword **-0.03 악화**
|
||
- 낮춰서 0.01 단일 domain only → 회귀 0
|
||
- 평가셋에 filter 쿼리가 없어 효과 직접 측정 불가 (v0.2 확장 후 재평가)
|
||
|
||
## Phase 2에서 달성하지 못한 것 + 이유
|
||
|
||
### Recall@10 / Top-3 hit 회복 (0.730 → 0.78+ 미달)
|
||
- baseline 대비 +0.007 미세 개선만
|
||
- 원인: **corpus 1022 docs로 noise 증가**. chunk 수 7129. bge-m3의 embedding 공간에서 상위 후보 밀도 높아짐
|
||
- 해결책: retrieval 단계 품질 (Phase 3 evidence extraction) 또는 embedding 모델 업그레이드
|
||
|
||
### crosslingual_ko_en NDCG 0.65+ 미달 (0.53 정체)
|
||
- multilingual translation이 효과 없음
|
||
- 원인: 현재 category 3개 쿼리 중 정답 doc이 영어 교재 (Industrial Safety and Health Management 등). bge-m3는 ko 쿼리로 이 영어 doc을 약 0.5~0.6 cosine으로 이미 찾음. translation 추가가 정보 증가 없음
|
||
- 실제 필요: **reranker가 crosslingual pair**를 더 잘 학습해야 함 → bge-reranker-v2-m3의 한계 영역
|
||
|
||
### 평가셋 v0.2 완전 작성
|
||
- 시간 제약 + 정답 doc_id 수동 라벨링 필요
|
||
- 후속 작업으로 분리
|
||
|
||
## Phase 2 기여 commits (시간순)
|
||
|
||
```
|
||
d28ef2f Phase 2.1 QueryAnalyzer + LRU cache + confidence 3-tier (초기)
|
||
c81b728 async-only 구조 전환 (철학 수정)
|
||
324537c LLM_TIMEOUT_MS 5000 → 15000 (실측 반영)
|
||
1e80d4c setup_logger 수정 (prewarm 로그 보이도록)
|
||
f5c3dea Phase 2.2 multilingual + query embed cache
|
||
21a78fb semaphore concurrency=1 + run_eval --analyze 파라미터
|
||
e595283 multilingual news/global 한정 narrowing
|
||
e91c199 Phase 2.3 soft_filter boost (초기)
|
||
01f144a soft_filter boost 약화 (0.01, doctype 제거)
|
||
```
|
||
|
||
## 다음 단계 선택지 (사용자 결정)
|
||
|
||
### A. Phase 2 종료 + Phase 3 진입 (권장)
|
||
- Phase 2 성과: 아키텍처 + 회귀 0 + news 영역 개선 + 실측 기반 철학 확립
|
||
- Recall/crosslingual 정체는 **Phase 2 범위 밖** — embedding/reranker 교체 혹은 Phase 3 evidence extraction으로 우회
|
||
- Phase 3 (evidence extraction + grounded synthesis + `/api/search/ask`) 착수
|
||
|
||
### B. Phase 2 iteration — embedding 실험
|
||
- bge-m3 → 다른 embedding (e.g., multilingual-e5-large-instruct, jina-embeddings-v3) 교체 실험
|
||
- 대규모 재인덱싱 필요 (1022 docs × chunks)
|
||
- 인프라 변경이므로 infra_inventory.md drift 발생
|
||
|
||
### C. Phase 2 iteration — 평가셋 v0.2 작성
|
||
- queries_v0.2.yaml 작성 (filter 쿼리 + graded relevance)
|
||
- 현재 Phase 2 코드의 filter 효과 측정
|
||
- 단, Recall/crosslingual 근본 해결은 아님
|
||
|
||
## Soft Lock 준수 확인 (infra_inventory.md)
|
||
|
||
- ✓ `config.yaml` 변경 없음 (GPU local override 그대로)
|
||
- ✓ `docker compose restart` 사용 안 함 (`up -d --build fastapi`만)
|
||
- ✓ Ollama 모델 pull/remove 없음 (bge-m3, exaone3.5 그대로)
|
||
- ✓ Reranker 모델 변경 없음 (TEI bge-reranker-v2-m3 그대로)
|
||
- ✓ Mac mini MLX 설정 변경 없음
|