가장 단순한 RAG — BM25 검색 경로 연결

발화 → 검색 → 문서 ID 목록. 리랭킹·생성 없이 검색만 붙인다.

허브 아웃바운드 포트 RetrievalPort 를 구현하는 첫 스포크다.

# apps/hub/app/ports/output/retrieval_port.py
class RetrievalPort(ABC):
    @abstractmethod
    async def retrieve(self, utterance: str, top_k: int = 5) -> list[RetrievedDoc]: ...

2026-08-26 정정: 이 티켓은 원래 RetrievalPredictor Protocol(def · list[str] 반환)을 적고 있었으나, fastapi/ 아키텍처 통합으로 접점이 hub 아웃바운드 포트 하나로 바뀌었다 (ABC · async · list[RetrievedDoc] 반환). 스포크당 계약 1개 — docs/architecture.md §1.

지금은 Ports(retrieval=None) 이라 하네스가 “측정 불가 — 모듈 미구현”으로 보고한다. 이 티켓이 끝나면 처음으로 실제 숫자가 나온다.

범위 밖 (의도적으로 미룸)

리랭킹(4주차) · 생성(6주차) · 하이브리드 검색(4주차) · 트리거 판정(3주차)

완료 조건

ai/apps/retrieval/ 에 구현체가 있고, evaluation.harness.Ports(retrieval=...) 에 꽂으면 Recall@5·MRR 이 계산된다. .importlinter 다섯 목록에 retrieval 등록 + 계약 5종 통과.


2026-08-27 완료 (류준)

첫 실측치가 나왔다. 이 프로젝트에서 처음으로 “측정 불가 — 모듈 미구현” 이 아닌 숫자다.

지표 목표(6.1절)
Recall@5 0.857 (12/14) ≥0.70 (오류 없음)
MRR 0.702 ≥0.55

이 값은 잠정이다. 공식 기준선은 3주차 골든셋 150건 재측정이고, dbeval_run/eval_result 기록과 6.1절 지표 표 반영은 w2-baseline 의 몫이다.

만든 것

파일 역할
ai/apps/retrieval/adapter/outbound/es_bm25_retriever.py RetrievalPort 구현체. BM25(nori) 단독
scripts/run_eval.py 평가 쪽 합성 루트 — 스포크를 포트에 꽂는다
ai/tests/test_eval_wiring.py 배선 테스트 (apps/ 밖)

scripts/run_eval.py 가 따로 있는 이유: evaluationretrieval 을 직접 import 하면 .importlinter 의 module-independence 계약이 깨진다. 두 모듈의 접점은 hub 포트(추상)뿐이고 구체 구현을 꽂는 일은 두 모듈 밖에서 해야 한다 — server/main.py 가 요청 경로에 대해 하는 일을 평가 경로에 대해 한다. 처음에 배선 테스트를 retrieval/tests/ 에 뒀다가 계약이 깨져서 ai/tests/ 로 옮겼다(ai/pytest.initestpathstests 추가).

못 맞힌 2건 — 원인이 보인다

MISS GS-001 정답 FIN-TERM-2.2  상위=['FIN-MANUAL-2.1', 'DASAN-MANUAL-4.1', 'HLT-MANUAL-1.4']
MISS GS-019 정답 SHOP-TERM-4.4 상위=['HLT-MANUAL-1.4', 'DASAN-MANUAL-1.4', 'SHOP-MANUAL-1.1']

둘 다 정답이 TERM 인데 MANUAL 문서가 자리를 채웠다. 그리고 금융·쇼핑 질의인데 DASAN·HLT 문서가 상위에 올라왔다 — 도메인 필터를 안 걸었기 때문이다. RetrievalPort.retrieve(utterance, top_k) 시그니처에 도메인이 없어 하네스가 넘겨줄 방법이 없다.

→ B-0 라우팅을 실제로 태우려면 포트 시그니처를 바꿔야 하고 그건 server/ 소관이다. 어댑터 생성자에 domain= 을 임시 통로로 열어 뒀고, 필터가 실제로 듣는 것은 integration 테스트로 확인했다. 미결 항목에 올렸다.

그 밖에 확인한 것

검증

cd ai && pytest 96개 통과(53 → 68 → 82 → 96), pytest -m integration 9건 통과(실제 ES 9.5.1), 구조 계약 3종 KEPT.