벡터 검색이 약한 질문을 재현한 뒤, Kiwi 형태소 토크나이저를 쓴 BM25와 벡터 검색을 EnsembleRetriever 의 가중 RRF로 합치고,
CrossEncoder 로 (질문, 후보) 쌍을 다시 채점해 줄을 세웁니다. 마지막으로 eval.py 가 평가 세트를 어떻게 채점하는지 봅니다. RRF 계산은 공식과 가상의 순위 예시로 보여 줍니다.
질문과 청크를 형태소로 쪼갠 뒤 겹치는 단어가 많고, 그 단어가 드물수록 점수를 높게 줍니다. TR-102 같은 기호에 강하고, "월차"처럼 문서에 없는 말로 물으면 아무것도 맞히지 못합니다.
질문과 청크를 따로 임베딩해 거리로 비교합니다. "월차"와 "연차"를 이어 주지만, 기호가 정확히 일치하는지는 보지 않습니다.
점수가 아니라 각 검색기 안에서의 순위를 가중치와 함께 더합니다. BM25 점수와 거리는 단위와 방향이 달라 그대로 더할 수 없기 때문입니다.
질문과 후보를 한 쌍으로 모델에 넣어 관련도 점수를 받습니다. 더 정확하지만 쌍마다 모델을 돌려야 해서 후보가 적을 때만 씁니다. 후보에 없는 청크는 올릴 수 없습니다.
VV-R 태그를 받는데 keep 에는 VV, VA 만 있어 t.tag in keep 을 통과하지 못합니다. 문서와 질문에서 똑같이 빠지므로 검색이 깨지지는 않지만 일부 동사·형용사는 BM25 단어 목록에 들어가지 않습니다. 포함하려면 t.tag.split("-")[0] in keep 처럼 비교합니다.hybrid.py 는 import 만 해도 실험이 전부 돕니다. 29행 이후의 비교·가중치 실험이 if __name__ == "__main__": 없이 모듈 수준에 있어, rerank_demo.py 의 from hybrid import hybrid 순간 출력이 먼저 찍히고 벡터 검색(임베딩 호출)도 그만큼 일어납니다.eval.py 는 eval_set.json 을 현재 폴더에서 찾습니다. 레포에서는 이 파일이 루트에 있으므로 day2_practice 안에서 실행하려면 복사해 둡니다. 거꾸로 루트에서 실행하면 ./chroma_db 가 루트를 가리켜 검색 결과가 비고 전부 실패로 채점될 수 있습니다.docs/ 를 다시 읽어 메모리에 만들고, 벡터 쪽은 예전에 저장한 chroma_db 입니다. 문서를 고치고 vectorstore.py 를 다시 돌리지 않으면 둘이 서로 다른 문서를 봅니다.rag_chain.py 와 eval.py 가 쓰는 검색기는 벡터 검색기(k=3)입니다. 하이브리드를 평가하려면 eval.py 의 retriever 자리를 hybrid 로 바꿔 다시 돌립니다.| 파일 | 하는 일 |
|---|---|
failures.py | 고유 기호, 청크 경계, 모호한 질문으로 벡터 검색만 돌려 약점을 재현. 모델 호출 없음 |
hybrid.py | Kiwi 토크나이저 + BM25, 벡터 검색기, EnsembleRetriever 결합과 가중치 실험. hybrid 객체를 내보냄 |
rerank_demo.py | 하이브리드 후보를 CrossEncoder("BAAI/bge-reranker-v2-m3") 로 다시 채점해 재랭킹 전후 순위를 비교 |
eval.py | eval_set.json 5문항을 검색 적중과 거절 문구로 자동 채점하고 4문항 기준으로 판정 |
eval_set.json (레포 루트) | 질문, 기대 출처, 유형(fact / paraphrase / no_answer)으로 된 평가 세트 |