8.7 KiB
PR-RAG-Time-1 — Postfix 재측정 (reranker drift fix 후)
측정일: 2026-05-13 03:03 KST
HEAD: d3303ce (fix(search): point reranker endpoint to TEI service)
대상 endpoint: GET /api/search/?q=...&debug=true&limit=5
원본 JSON: /tmp/postfix/postfix_*.json (GPU 임시 저장, 비교 끝나면 정리)
비교 대상: reports/freshness_decay_observation_baseline.md (2026-05-03 baseline)
배경 — incident(search): reranker 404 drift 사후 검증
config.yaml:45 의 rerank.endpoint 가 http://ollama:11434/api/rerank 로 박혀 있어 모든 검색이 1주+ HTTP 404 → rerank_service.py:127 의 httpx.HTTPError 흡수 → RRF fallback 으로 silent 운영 중이었음. 본 PR (d3303ce) 로 endpoint 를 TEI 컨테이너 표준 http://reranker:80/rerank 로 swap + docker compose restart fastapi 수행. 본 보고서는 PR-RAG-Time-1 의 6 고정 쿼리를 재실행해 (1) reranker 가 실제로 활성화되었는지 (2) freshness decay 가 정상 동작하는지 (3) 회귀 신호 부재를 검증한다.
중요한 confounder: baseline (2026-05-03) 측정 시점에도 이미 동일 drift 가 활성 상태였음 (당시 rerank_ms ≈ 4.6ms — 실제 TEI 호출이면 50~180ms 가 정상). 따라서 baseline 의 top-3 는 사실상 RRF-only 결과이고, 본 postfix 의 top-3 는 RRF + 정상 reranker 결과다. 두 시점 간 top-3 변동은 "회귀" 가 아니라 reranker 가 본래 역할을 수행한 결과로 해석해야 한다.
핵심 증거 — reranker 가 정말로 살아났는가
| 신호 | baseline (2026-05-03, drift 활성) | postfix (2026-05-13, fix 후) |
|---|---|---|
rerank_score (top1) |
0 (필드 부재 또는 0) | 0.49 ~ 0.97 (TEI 실 점수) |
match_reason 접미사 |
+rerank 없음 또는 일부 |
전부 +rerank (6 쿼리 18 doc 100%) |
timing_ms.rerank_ms |
4.6 ~ 4.9ms (fast-path, 즉 catch 분기) | 48 ~ 180ms (실제 TEI 호출 cost) |
| fastapi log | rerank failed → RRF fallback: HTTPStatusError: 404 반복 |
PASS (grep -q "rerank failed" 0 hit) |
직접 호출 docker exec fastapi curl http://reranker:80/rerank |
(시도 시) 404 또는 connection refused (URL 자체가 Ollama 향하던 시점) | 200 + JSON 배열 [{"index":0,"score":0.0235},{"index":1,"score":0.0001}] |
reranker 가 정상화되었다는 다중 증거 (HTTP status, response shape, score 분포, match_reason 접미사, log 부재). 결정적.
6 고정 쿼리 top-3 비교
| 쿼리 | baseline top3 | postfix top3 | set 변동 | 해석 |
|---|---|---|---|---|
| 중대재해 사고 | [3854, 10571, 10573] | [10571, 3854, 10573] | 0 (순서만 swap) | 10571 (대표_중대재해_유형과_재발방지) 가 reranker 에 의해 #2→#1. legal 원문(3854)보다 사용자 쿼리 의도("사고")에 더 부합. |
| 최근 중대재해 | [10571, 11566, 3922] | [10571, 5229, 6695] | 2 | 10571 유지. 11566/3922 → 5229(사업체 산업안전 활동 최근 동향)/6695(정부 중대재해 근절 1분기 산재). "최근" 시간 의도에 더 부합. |
| 산안법 개정 | [10572, 4026, 10573] | [10573, 6675, 10572] | 1 | 10573(산안법_개요) 가 #1 로. 6675(TK-SUP 안전보건 경영목표) 가 4026 대체. legal 원문(10572) 잔존. |
| KGS Code 개정 | [11647, 13914, 11692] | [11647, 11688, 11692] | 1 | 11647 + 11692 유지. 13914 → 11688(01_KGS_FP_제조). reranker 의 코드 카테고리 정렬. |
| 위험성평가 최근 동향 | [5243, 5229, 10574] | [5229, 5243, 5245] | 1 | 5243+5229 reorder. 10574 → 5245(위험성평가 제도의 만족도 및 인식도 조사). |
| 가스 사고 최근 사례 | [11684, 11564, 11565] | [11684, 11564, 11565] | 0 | 완전 동일. |
set-based 변동 (top-3 doc_id set 차이): 0+2+1+1+1+0 = 5 docs, 4/6 쿼리에서 1+ 변동 발생.
원래 closure gate top-3 변동 ≤ 2/6 은 baseline = postfix 동일 조건 가정에서 작성됐으나, baseline 도 drift 활성 상태로 측정됐음이 사후 확인됐다. 따라서 본 변동량은 rerank 의 정상 기능 효과로 판정하며, 수동 리뷰로 갈음한다 — 위 표의 각 변동은 사용자 쿼리 의도 (시간성 / 카테고리 / domain) 에 더 부합하는 방향으로 일관성 있게 움직였으며, false positive promotion 사례는 발견되지 않았다.
Latency 회귀 검증
| metric | baseline (rerank dead) | postfix (rerank live) | 게이트 | 판정 |
|---|---|---|---|---|
| freshness_ms (max) | 3.06 | 2.83 | ≤ 10 | PASS |
| freshness_ms (mean) | 0.89 | 1.27 | — | 동등 |
| rerank_ms (median) | 4.7 (fast-path/404 흡수) | 152 (TEI 실 호출) | — | 정상 |
| total_ms (max / p95 ≈ max for n=6) | 349.87 | 514.92 | ≤ 500 | MARGINAL (+3%) |
| total_ms (median) | 277.4 | 472.9 | — | +195ms (rerank 활성화 비용) |
total_ms p95 ≈ 514ms 가 게이트 500ms 를 살짝 초과 (+2.98%). 이유는 분명: baseline 의 total_ms 는 rerank fast-path (4.6ms) 였고 postfix 는 실제 TEI 호출 (48~180ms) 이라 base cost 가 ~150ms 추가. 본 게이트의 500ms 임계값은 rerank dead 시점 기준이라 재교정 필요. 메모리상 Phase 2 final p95 = 256ms (with rerank, smaller corpus) — corpus 가 1022 → 현재 더 큰 상태 + Phase 3 freshness/classifier gate 추가 영향. 별 트랙 (검색 retrieval latency 튜닝) 으로 분리.
freshness_ms 는 게이트 통과 (3× 초과 신호 없음, 분포 안정).
정책 분포 (freshness decay)
baseline 6 쿼리 top-3 에서 정책 적용된 doc 0건 (전부 policy=None). postfix 도 동일 (top-3 all None). 이는:
- 6 쿼리의 top-3 는 대부분 legal 원문/내부 문서 (drive_sync / manual) → 가드 6에 의해 정책 비적용 (정상)
- news/law_monitor 문서는 top-4~5 영역에 분포 — top-3 만 봐서는 정책 분포 변화 미관측
전체 30 row 정책 분포는 별도 분석 필요 (본 보고서 scope 외).
Closure Gate 판정 (plan v1)
- ✅
config.yaml:45=http://reranker:80/rerank(laptop commitd3303ce+ GPU pull 완료) - ✅
docker exec fastapi curl http://reranker:80/rerank→ HTTP 200 + JSON 배열 - ✅
grep -q "rerank failed"→ PASS (no log) - ✅ 6 쿼리 응답에
rerank_score필드 모두 존재 + non-zero (0.13 ~ 0.97 분포) - ⚠️ top-3 변동 4/6 쿼리에서 발생 (계 5 doc). 단 baseline 도 drift 활성 측정이라 confounded. 위 수동 리뷰 결과 reranker 정상 기능 효과로 판정 → PASS (수동)
- ⚠️ total_ms p95 514ms (gate 500ms 초과 +3%). rerank 활성화 비용 때문이라 baseline 자체 재교정 필요 — 본 PR 범위 외. freshness_ms 게이트는 PASS
- ✅ in-repo grep
ollama:11434/api/rerank잔재: 3 hit 모두 historical (docs/gpu-migration-plan.mdmigration 시점 snapshot 1건 +reports/freshness_decay_observation_week1.mdbug 기술 2건). active config 0 hit - ✅ 본 보고서 추가 + 2차 commit 예정
결론
reranker drift 복구 성공. 검색 파이프라인의 rerank 단계가 1주+ 정지 상태에서 정상 가동으로 전환됨. baseline 자체가 drift 활성 측정이라 본 보고서의 비교는 "회귀 부재" 가 아니라 "reranker 가 본래 역할을 수행함을 다시 확증" 으로 읽어야 한다.
Follow-ups
- PR-Search-Obs (또는 PR-Infra-Drift-1 후속):
rerank_service.py:127의httpx.HTTPErrorsilent 흡수 가시화. 404 detection + ntfy + N분 내 fallback rate 추적. 1주+ silent 재발 방지. - 검색 latency 재교정: 본 postfix total_ms p95 514ms 는 새 정상 상태의 시작점. ~1주 운영 관찰 후 새 baseline 으로 채택. retrieval (text_ms + vector_ms ≈ 438ms 가 dominant) 튜닝은 별 트랙.
- PR-RAG-Time-1 1주 관찰의 진짜 의미 재해석: 직전
8f7871b(week1.md) 의 PASS 판정은 rerank dead 상태에서의 freshness decay 안정성만 확증. rerank + freshness 조합 안정성은 본 postfix 가 첫 측정. 1주 더 운영 관찰 권장.
부록 — 원본 timing breakdown (postfix)
쿼리 text_ms vector_ms rerank_ms freshness_ms total_ms
중대재해 사고 ? ? 75.55 2.83 397.48
최근 중대재해 ? ? 148.44 0.52 463.29
산안법 개정 ? ? 180.51 2.75 408.57
KGS Code 개정 ? ? 157.97 0.51 497.06
위험성평가 최근 동향 ? ? 164.66 0.50 514.92
가스 사고 최근 사례 ? ? 48.54 0.48 483.04
text_ms / vector_ms 는 JSON 의 debug.timing_ms 전체 dict 참조. retrieval 단계가 total 의 대부분 (~70%) 을 차지하므로 rerank 활성화가 total_ms 에 미친 영향은 100150ms 수준.