feat(infra): 2노드 이관 P1-4 — rerank 프로토콜 스위치(tei|llamacpp)·OCR/STT 명시 게이트·413 재홈
- AIModelConfig.protocol 판별자 신설(기본 tei = 무회귀), llamacpp = /v1/rerank 요청·응답 스키마 정규화(ai/rerank_protocol.py 순수함수 + 단위테스트 4) - OCR_ENABLED/STT_ENABLED 명시 게이트 — GPU CUDA 서비스(Surya/faster-whisper) 폐기 대응, silent 아님(경고 로그 + extract_meta 터미널 기록) - DS Caddyfile request_body 100MB — 413 정책을 edge(home-caddy)에서 내부로 재홈 (DSM 리버스 프록시 전환 대비, upload.max_bytes 정합) - SSE X-Accel-Buffering는 기점검 결과 기구현(eid_chat)이라 무변경 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
"""rerank 프로토콜 정규화 단위 테스트 — 2노드 이관 P1-4 (llama.cpp /v1/rerank).
|
||||
|
||||
순수 함수(ai/rerank_protocol.py)만 대상 — HTTP/DB 의존 없음.
|
||||
실행: PYTHONPATH=app pytest tests/test_rerank_protocol.py
|
||||
"""
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from ai.rerank_protocol import normalize_llamacpp_rerank
|
||||
|
||||
FIXTURES = Path(__file__).parent / "fixtures"
|
||||
|
||||
|
||||
def test_normalize_llamacpp_shape_and_desc_sort():
|
||||
payload = {
|
||||
"model": "bge-reranker-v2-m3",
|
||||
"results": [
|
||||
{"index": 0, "relevance_score": 0.12},
|
||||
{"index": 1, "relevance_score": 2.21},
|
||||
{"index": 2, "relevance_score": -1.5},
|
||||
],
|
||||
}
|
||||
out = normalize_llamacpp_rerank(payload)
|
||||
# TEI 계약: [{"index","score"}] score 내림차순
|
||||
assert [r["index"] for r in out] == [1, 0, 2]
|
||||
assert all(set(r) == {"index", "score"} for r in out)
|
||||
assert out[0]["score"] == 2.21
|
||||
|
||||
|
||||
def test_normalize_llamacpp_missing_fields_skipped():
|
||||
payload = {
|
||||
"results": [
|
||||
{"index": 0}, # relevance_score 없음 → 버림
|
||||
{"relevance_score": 1.0}, # index 없음 → 버림
|
||||
{"index": 3, "relevance_score": 0.5},
|
||||
]
|
||||
}
|
||||
assert normalize_llamacpp_rerank(payload) == [{"index": 3, "score": 0.5}]
|
||||
|
||||
|
||||
def test_normalize_llamacpp_empty_and_absent_results():
|
||||
assert normalize_llamacpp_rerank({}) == []
|
||||
assert normalize_llamacpp_rerank({"results": []}) == []
|
||||
|
||||
|
||||
def test_tei_fixture_shape_is_already_contract():
|
||||
"""TEI 캡처 fixture(Phase 2B G0-1 spec 박제)의 실응답이 정규화 없이 계약 형태임을 확인."""
|
||||
doc = json.loads((FIXTURES / "tei_rerank_response.json").read_text())
|
||||
captured = doc["captured_responses"]["baseline_bge_v2_m3"]
|
||||
assert isinstance(captured, list) and captured
|
||||
assert {"index", "score"} <= set(captured[0])
|
||||
# spec 문자열도 계약과 일치 (score desc 정렬 포함)
|
||||
assert "index" in doc["response_shape"] and "score" in doc["response_shape"]
|
||||
Reference in New Issue
Block a user