## 변경 사항
### app/services/search/retrieval_service.py
- **_QUERY_EMBED_CACHE**: 모듈 레벨 LRU (maxsize=500, TTL=24h)
- sha256(text|bge-m3) 키. fixed query 재호출 시 vector_ms 절반 감소.
- **_get_query_embedding(client, text)**: cache-first helper. 기존 search_vector()도 이를 사용하도록 교체.
- **search_vector_multilingual(session, normalized_queries, limit)**: 신규
- normalized_queries 각 언어별 embedding 병렬 생성 (cache hit 활용)
- 각 embedding에 대해 docs+chunks hybrid retrieval 병렬
- weight 기반 score 누적 merge (lang_weight 이미 1.0 정규화)
- match_reason에 "ml_ko+en" 등 언어 병합 표시
- 호출 조건 문서화 — cache hit + analyzer_tier=analyzed 시에만
### app/api/search.py
- use_multilingual 결정 로직:
- analyzer_cache_hit == True
- analyzer_tier == "analyzed" (confidence >= 0.85)
- normalized_queries >= 2 (다언어 버전 실제 존재)
- 위 3조건 모두 만족할 때만 search_vector_multilingual 호출
- 그 외 모든 경로 (cache miss, low conf, single lang)는 기존 search_vector 그대로 사용 (회귀 0 보장)
- notes에 `multilingual langs=[ko, en, ...]` 기록
## 기대 효과
- crosslingual_ko_en NDCG 0.53 → 0.65+ (Phase 2 목표)
- 기존 경로 완전 불변 → 회귀 0
- Phase 2.1 async 구조와 결합해 "cache hit일 때만 활성" 조건 준수
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>