Minseong Code Lab
← Projects
Bootcamp MissionRAG / LLM

연말정산 문서 RAG QA

연말정산 문서를 기반으로 한 RAG 질의응답 시스템 실험

게시 2026-07-10
PythonLangChainFAISSSentence-TransformersJupyter
Contents · 목차
  1. 무엇을 하는 미션인가
  2. 파이프라인
  3. 검색을 두 단계로 나눈 부분
  4. 문서 밖 답변을 막는 장치
  5. 결과와 한계

무엇을 하는 미션인가

연말정산 신고안내 PDF 한 권을 검색 가능한 형태로 만들고, 질문에 문서 근거로만 답하는 RAG 파이프라인을 노트북 하나로 구성한 개인 미션입니다. 팀 프로젝트인 RFP-AI와는 별개의 과제이고, 구현도 공유하지 않습니다.

입력은 PDF 한 건, 출력은 질문에 대한 한국어 답변입니다.

파이프라인

PDF 로딩 → 클리닝·페이지 필터링 → 청킹 → KoE5 임베딩 → FAISS → Query Decomposition → CrossEncoder Reranking → LlamaCpp 생성

청킹은 세 조건을 비교한 뒤 골랐습니다. 노트북 출력에 남은 결과입니다.

실험chunk_size / overlap청크 수평균 길이
A (채택)500 / 1001,066407자
B300 / 501,653251자
C1000 / 200598698자

임베딩은 nlpai-lab/KoE5, 벡터 저장은 FAISS이고 리트리버는 k=6입니다.

검색을 두 단계로 나눈 부분

질문을 그대로 던지지 않고 하위 질문 3개로 분해한 뒤, 그 결과를 CrossEncoder로 다시 추려 상위 4개만 컨텍스트에 넣습니다. 넓게 모으고 좁게 거르는 구성입니다.

# notebooks/mission14.ipynb — Cell 14 (발췌)
cross_encoder = HuggingFaceCrossEncoder(
    model_name="cross-encoder/mmarco-mMiniLMv2-L12-H384-v1"
)
reranker = CrossEncoderReranker(model=cross_encoder, top_n=4)

class DecompositionRetriever(BaseRetriever):
    def _get_relevant_documents(self, query, *, run_manager):
        return decomposition_retrieve(query)   # 하위 질문 3개로 각각 검색

compression_retriever = ContextualCompressionRetriever(
    base_compressor=reranker,
    base_retriever=DecompositionRetriever(),
)

문서 밖 답변을 막는 장치

프롬프트에 규칙과 few-shot 예시를 함께 넣었습니다. 두 번째 예시가 "모르면 모른다고 답하는" 경우를 일부러 보여줍니다.

# notebooks/mission14.ipynb — Cell 11 프롬프트 (발췌)
1. 반드시 아래 [참고 문서]에 있는 내용만 사용하여 한국어로 답변하세요.
2. [참고 문서]에 없는 내용은 절대 추가하지 마세요.
3. 확실하지 않은 내용은 "문서에서 찾을 수 없습니다"라고 답변하세요.

[예시 2]
질문: 2025년 연말정산 일정을 알려줘.
참고 문서: 이 책자는 2024년 귀속 연말정산 신고안내입니다.
답변: 문서에서 찾을 수 없습니다. 제공된 문서는 2024년 귀속 기준으로 …

생성은 로컬 GGUF 모델(Qwen2.5-7B-Instruct-Q5_K_M)을 LlamaCpp로 올려 씁니다. temperature=0.05로 낮춰 문서에서 벗어난 문장이 나올 여지를 줄였습니다.

결과와 한계

최종 셀에서 질문 10개를 돌려 답변과 생성된 하위 질문을 함께 출력합니다. 정답률이나 RAGAS 같은 정량 평가는 없습니다 — 눈으로 확인한 수준이고, 그 이상을 주장할 근거가 저장소에 없습니다.

  • 청킹 비교는 청크 수·길이까지만 봤고, 검색 품질로 A를 고른 근거는 남아 있지 않습니다
  • 필터링 조건(50자 미만 제거)에 걸린 청크는 0개였습니다 — 조건이 느슨했다는 뜻입니다
  • 이 미션에서 다룬 Query Decomposition과 Reranking은 이후 팀 프로젝트에서 다른 방식(BM25 Hybrid + RRF)으로 다시 다뤘습니다