Files
hyungi_document_server/reports/phase_2a_embedding_decision_2026-05-23.md
hyungi 3092e3009d feat(eval): Phase 2A Diagnose Phase 3+4 — dispatcher + 3 측정 + decision (H3 bge-m3 유지)
phase-2a-embedding-diagnose.md v4 § 6 (dispatcher) + § 7 Phase 3 (51 case 측정) + § 7 Phase 4 (decision)
Round 2 review: round-2-review-mighty-starfish.md (R2-2 + R2-B1 페어 invariant + slug-based resolve)

코드 변경:
- app/services/search/retrieval_service.py:
  - CANDIDATE_BACKEND_MAP allowlist (baseline / cand_me5_large_inst / cand_snowflake_l_v2)
  - _resolve_backend(slug) → docs_table/chunks_table/embed_endpoint or None
  - _embed_query_via_tei() — candidate TEI 엔드포인트 호출 (cache 미사용)
  - _VALID_DOCS_TABLE + _VALID_CHUNKS_TABLE regex (R2-B1 2단계 gate)
  - _search_vector_docs / _search_vector_chunks: docs_table/chunks_table + snapshot_*_id_max 파라미터
  - search_vector + search_vector_multilingual: embedding_backend + snapshot_*_id_max 파라미터 + dispatch log
- app/services/search/search_pipeline.py: run_search() 시그니처 + 4 search_vector* 호출 threading
- app/api/search.py: 3 Query parameter + ValueError → HTTP 400 (allowed list 응답)
- tests/search_eval/run_eval.py: --embedding-backend + --snapshot-doc-id-max + --snapshot-chunk-id-max
  + call_search/call_search_full/evaluate threading + main 3 asyncio.run threading

측정 산출물 (51 case, scored=46, failure=5):
- reports/v0_2_phase2a_baseline_snapshot_2026-05-23.csv (snapshot filter 적용 production path)
- reports/v0_2_phase2a_me5_large_inst_2026-05-23.csv
- reports/v0_2_phase2a_snowflake_l_v2_2026-05-23.csv
- tests/search_eval/baselines/v0_2_phase2a_{baseline_snapshot,me5_large_inst,snowflake_l_v2}_2026-05-23.json (3개)

결과:
| Candidate                          | NDCG | Δ vs baseline | mixed | korean_only | p50 ms |
|------------------------------------|-----:|--------------:|------:|------------:|-------:|
| bge-m3 (baseline snapshot)         | 0.659| —             | 0.39  | 0.51        | 464    |
| cand_me5_large_inst                | 0.477| -0.182        | 0.17  | 0.47        | 194    |
| cand_snowflake_l_v2                | 0.616| -0.043        | 0.35  | 0.52        | 254    |

Decision (H3): bge-m3 유지. 둘 다 net 회귀.
- mE5-large-instruct: 전 카테고리 회귀 (-0.182). prefix 미적용 변수 — 별 PR PR-2A-mE5-Prefix-Retry 후보.
- snowflake_l_v2: 가벼운 회귀 (-0.043). korean_only +0.01 미세 개선 신호.
- korean_only/mixed 약점 보완은 Phase 2B (Reranker) 또는 Phase 2Q (Query rewrite) 권고.

Decision report: reports/phase_2a_embedding_decision_2026-05-23.md (§ 1~8 포함, Closure gate 16 항목 모두 PASS).

후속 PR 백로그:
- PR-2A-mE5-Prefix-Retry (별 PR)
- PR-2A-Extended-Bge-Mgemma2 (별 PR, v3 결정)
- PR-2A-Cloud-Embedding-Scaffold-1 (Cohere/Voyage scaffold-only, 선택)
- PR-Search-Query-Rewrite-1 (Phase 2Q)
- PR-Search-Reranker-V2-Diagnose (Phase 2B)
- PR-2A-Chunks-Cand-Cleanup-1 (1주 후 cand 테이블 DROP)

production 영향:
- documents / document_chunks 컬럼/row 변경 0
- config.yaml 변경 0 (ollama bge-m3 unchanged)
- 추가된 endpoint = query parameter opt-in (미지정 시 production path 회귀 0)
- smoke 4건 PASS (baseline / baseline+snapshot / cand_me5 / cand_invalid → HTTP 400)
- dispatch log 박제 verify (snapshot_doc/chunk_id_max 박제)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 06:55:13 +00:00

6.8 KiB
Raw Permalink Blame History

Phase 2A Embedding Decision Report (2026-05-23)

Parent: phase-2a-embedding-diagnose.md v4

Round 2 review: round-2-review-mighty-starfish.md 채택

본 보고서 = Phase 4 산출물. Decision Tree H1~H4 중 권고 1개 + 후속 PR 후보.

1. Summary

Value
baseline (bge-m3, snapshot 범위) NDCG@10 (graded) 0.659 / mixed 0.39 / korean_only 0.51 / failure 0/5 / p50 464ms / p95 1582ms
baseline rebaseline (snapshot filter 적용) 위와 동일 (snapshot 범위 = corpus 전부와 거의 동일, 측정 가능 확인)
후보 2종 측정 완료 me5_large_inst (mE5-instruct), snowflake_l_v2 (Snowflake Arctic L v2.0)
이관 (별 PR) bge_mgemma2 (9B FP16 → 16GB GPU OOM risk → PR-2A-Extended-Bge-Mgemma2)
폐기 ko_me5 (HF 401 Unauthorized)

2. 후보별 Δ NDCG (vs baseline rebaseline)

Candidate overall NDCG Δ overall mixed Δ mixed korean_only Δ korean standards english_only exam failure p50 ms p95 ms
bge-m3 snapshot rebaseline 0.659 0.39 0.51 0.87 0.78 0.74 0/5 464 1582
mE5-large-instruct 0.477 -0.182 0.17 -0.22 0.47 -0.04 0.54 0.63 0.62 0/5 194 1348
snowflake-arctic-embed-l-v2.0 0.616 -0.043 0.35 -0.04 0.52 +0.01 0.87 0.74 0.56 0/5 254 1412

관찰:

  • mE5-large-instruct: 전 카테고리 큰 회귀. Δ -0.182 overall. mixed 절반 회귀 (0.39 → 0.17). standards 도 큰 회귀 (0.87 → 0.54). 단 latency p50 270ms 단축 (mE5 의 512 context = 적은 compute).
  • snowflake_l_v2: 가벼운 회귀 (Δ -0.043). standards / korean_only 거의 동일. mixed 약간 회귀. exam 명확 회귀 (-0.18). latency p50 210ms 단축.

ambiguous note (LLM 단독 결정, feedback_user_block_minimize):

  • mE5-instruct 는 query input 에 Instruct: <task>\nQuery: <query> prefix 권장 (intfloat 모델 카드). 본 PR 측정은 plain query → prefix 효과 미반영. prefix 적용 시 +0.05~0.15 회복 가능성 있으나 측정 외 — 별 PR 후보 PR-2A-mE5-Prefix-Retry.
  • snowflake_l_v2 의 한국어 specific 벤치마크 공개 부재. 본 측정 = 사실상 한국어 specific 첫 audit. korean_only +0.01 미세 개선 신호 있으나 통계적 의미 없음 (n=9, 0.51 vs 0.52).

3. Latency 영향

  • mE5 (512 ctx): p50 464 → 194 (270ms), p95 1582 → 1348 (234ms). 빠름.
  • snowflake (8192 ctx): p50 464 → 254 (210ms), p95 1582 → 1412 (170ms). 빠름.
  • 둘 다 baseline 보다 빠르지만 quality 회귀. trade-off favor quality (feedback_quant_expectation_not_hard_gate 룰, 정량 hard gate 없으나 +0 NDCG 회복 시 latency 30% 단축 가치는 별 평가).

4. Decision (H3 — bge-m3 유지)

H1 swap 권고 H2 query rewrite 보완 H3 bge-m3 유지 ( 선택) H4 latency 회귀
조건 mixed + korean_only 둘 다 명확 개선 korean_only 만 개선 / mixed 미개선 모든 후보 bge-m3 대비 개선 없음 latency p95 ≥ 3000ms
결과 둘 다 회귀 korean_only 미세 개선 (+0.01) 만, mixed 회귀 확정 둘 다 baseline 보다 빠름

최종 권고: bge-m3 유지 (Apply PR 진입 안 함).

근거:

  • mE5 -0.182 / snowflake -0.043 — 둘 다 net 회귀.
  • korean_only 약점 보완 도구로 embedding swap 보다 query rewrite (Phase 2Q) 또는 reranker 튜닝 (Phase 2B) 가 더 유망.
  • mE5 prefix retry 는 별 PR 로 분리 — diagnose 본 PR scope 외.

5. Apply / 보완 / 보류 권고

  • Apply (production embedding swap): 하지 않음.
  • 보완 (다른 트랙): Phase 2B (Reranker) 또는 Phase 2Q (Query rewrite) 우선 — korean_only / mixed 약점 다른 layer 에서 공략.
  • 보류 (Phase 2A-Extended): bge_mgemma2 (별 PR), mE5 prefix retry (별 PR), Cloud embedding (Cohere/Voyage) scaffold-only (별 PR).

6. 후보 cleanup 일정

  • 미선택 후보 4 테이블 (documents_cand_me5_large_inst / document_chunks_cand_me5_large_inst / documents_cand_snowflake_l_v2 / document_chunks_cand_snowflake_l_v2) = 1주 dormant 유지 (mE5 prefix retry / Phase 2Q 비교 baseline 사용 가능성).
  • 1주 후 별 chore PR-2A-Chunks-Cand-Cleanup-1 에서 DROP + 컨테이너 docker-compose.override 제거.

7. 후속 PR 후보 (백로그)

PR 가칭 trigger scope
PR-2A-mE5-Prefix-Retry 본 PR 결과 + ambiguous note mE5-instruct query prefix 적용 후 재측정. 페어 reindex 재실행 + 51 case 재측정. 본 PR 의 dispatcher 재사용 (CANDIDATE_BACKEND_MAP 에 신규 slug 추가).
PR-2A-Extended-Bge-Mgemma2 v3 short-list swap 결정 9B FP16 OOM 회피 (quantization int8 또는 sentence-transformers). 별 컨테이너 + reindex + 측정.
PR-2A-Cloud-Embedding-Scaffold-1 (선택) self-hosted 무개선 확정 Cohere / Voyage scaffold-only ([[feedback_scaffold_first_for_external_cost_pr]]). 실비 0.
PR-Search-Query-Rewrite-1 (Phase 2Q) korean_only / mixed 약점 보완 자연어 query → SQL/keyword 강화.
PR-Search-Reranker-V2-Diagnose (Phase 2B) korean_only / mixed 약점 보완 bge-reranker-v2-m3 swap 후보 측정.
PR-2A-Chunks-Cand-Cleanup-1 본 PR closure 후 1주 4 cand 테이블 DROP + 컨테이너 정리.

8. Closure gate verify (§ 8 본 plan)

  • G0-1 + G0-2 fixture 박제 (Phase 1 closure 시 commit 943ac5f)
  • snapshot json 박제 (v0_2_phase2a_snapshot_2026-05-23.json, commit a67df0a)
  • 2 후보 (me5_large_inst + snowflake_l_v2) 51 case 측정 완료 (overall.n = 46, 5 failure 제외)
  • baseline rebaseline 51 case 측정 완료 (snapshot filter 적용)
  • 후보별 baseline json 2개 + baseline_snapshot json 1개 박제
  • documents_cand_ row count = 21365 verify (2 후보 동일)
  • document_chunks_cand_ row count = 30605 verify (2 후보 동일)
  • baseline rebaseline 측정도 동일 snapshot_doc/chunk_id_max filter 통과 verify (dispatch log)
  • dispatcher 호출 시 unknown slug → HTTP 400 verify (smoke test cand_invalid 통과)
  • decision md 박제 (본 파일)
  • Apply 권고 1줄 작성 (H3)
  • production embedding (bge-m3 ollama) 변경 0 verify (docker compose ps, ollama list, config.yaml diff 0)
  • production documents row count + embedding 변경 0 verify
  • production document_chunks row count + content 변경 0 verify
  • 후보 cleanup 일정 명시 (1주 dormant → PR-2A-Chunks-Cand-Cleanup-1)
  • dispatch log audit (silent fallback 0, embedding_backend_unavailable 0, snapshot id 박제 verify)
  • DOCSRV_TOKEN 만료 사고 0 (3 측정 모두 15분 이내 완주)

Phase 2A Diagnose PR closure: PASS.