Загружаем каталог…
Загружаем каталог…
이번 프로젝트에서는 Spring AI의 RAG 공식 문서를 대상으로 로컬 RAG 파이프라인을 구축하고, 검색 방법을 변경하면서 검색 성능이 어떻게 달라지는지 실험했다. 단순히 RAG를 구현하는 것에서 끝내지 않고, 문서 구조에 맞는 Chunking Dense Retrieval 기반 Baseline BM25 + Dense Retrieval Hybrid Search RRF k 값 변화 Embedding 모델 및 입력 방식 비교 Offline 실행 검증 검색 실패 가능성에 대한 진단 까지 단계적으로 확인했다. 이번 실험에서 사용한 Spring AI 공식 문서는 RAG의 기본 구조뿐 아니라 QuestionAnswerAdvisor, RetrievalAugmentationAdvisor, VectorStoreDocumentRetriever, RewriteQueryTransformer, MultiQueryExpander 등의 RAG 구성 요소를 계층적으로 설명하고 있어 실험용 기술 문서로 활용하기 적합했다. 프로젝트 목표 RAG(Retrieval-Augmented Generation)는 LLM이 질문에 대한 답변을 생성하기 전에 외부 문서에서 관련 정보를 검색하고, 검색된 내용을 LLM의 입력으로 활용하는 방식이다. 이번 프로젝트에서는 다음과 같은 로컬 RAG 구조를 구현했다. Spring AI 공식 문서 ↓ 문서 전처리 / Chunking ↓ BGE-M3 Embedding ↓ Qdrant Vector DB ↓ Dense Retrieval ↓ 검색 결과 ↓ Qwen2.5-7B-Instruct ↓ 최종 답변 또한 검색 성능을 정량적으로 비교하기 위해 Hit@3를 평가 지표로 사용했다. Hit@3는 질문에 대한 정답 문서가 검색 결과 상위 3개 안에 포함되었는지를 측정하는 지표이다. 문서 선정과 Chunking 2-1. 문서 선정 이번 실험에서는 Spring AI의 공식 RAG 문서를 사용했다. 문서는 다음과 같이 여러 단계의 제목 구조를 가지고 있다. Retrieval Augmented Generation ├─ Advisors │ ├─ QuestionAnswerAdvisor │ └─ RetrievalAugmentationAdvisor ├─ Naive RAG ├─ Advanced RAG ├─ Pre-Retrieval │ ├─ Query Transformation │ ├─ Query Expansion │ └─ ... ├─ Retrieval │ └─ Document Search ├─ Post-Retrieval └─ Generation 따라서 단순히 일정한 글자 수로 문서를 나누기보다는 문서의 Markdown 제목 구조를 유지하는 방식을 선택했다. 2-2. Chunking 전략 MarkdownHeaderTextSplitter를 사용하여 #, ##, ### 헤더를 기준으로 문서를 분할했다. headers_to_split_on = [ ("#", "문서"), ("##", "주제"), ("###", "세부주제") ] 이 방식의 장점은 각 Chunk가 어떤 주제에 속하는지를 Metadata로 유지할 수 있다는 것이다. 예를 들어, 주제 = Retrieval 세부주제 = VectorStoreDocumentRetriever 와 같이 문서의 계층 정보를 함께 보존할 수 있다. RAG에서는 검색된 Chunk 자체의 내용뿐 아니라 해당 내용이 문서의 어떤 영역에서 나온 것인지도 중요하기 때문에 문서 구조를 보존하는 방향으로 Chunking을 구성했다. 평가 질문 설계 검색 성능을 정량적으로 비교하기 위해 총 15개의 평가 질문을 구성했다. 질문은 크게 두 종류로 나누었다. Semantic Question 문서의 내용을 이해해야 답할 수 있는 질문이다. 예: Advanced RAG에서는 어떤 접근 방법을 사용하는가? Identifier Question 특정 기술 구성요소나 클래스명을 직접 찾는 질문이다. 예: QuestionAnswerAdvisor는 어떤 역할을 하는가? Identifier 질문에는 다음과 같은 기술 용어를 포함했다. QuestionAnswerAdvisor RetrievalAugmentationAdvisor VectorStoreDocumentRetriever RewriteQueryTransformer 이렇게 질문 유형을 구분한 이유는 단순한 의미 검색뿐 아니라 정확한 기술 식별자 검색 능력도 함께 평가하기 위해서이다. Baseline RAG 구축 Baseline에서는 BGE-M3 + Qdrant 기반 Dense Retrieval을 사용했다. Question ↓ BGE-M3 Embedding ↓ Qdrant Vector Search ↓ Top-3 Documents 검색된 결과 중 정답 Chunk가 Top-3 안에 포함되면 Hit로 판단했다. Baseline 결과 Hit@3 = 86.7% 15개의 평가 질문 중 정답 문서가 상위 3개 안에 포함되는 비율을 측정한 결과이다. 따라서 이후 모든 개선 실험에서는 이 값을 기준선으로 사용했다. 개선 실험 1 — Hybrid Search Dense Retrieval만 사용하는 경우 의미적으로 유사한 문서를 잘 찾을 수 있지만, 기술 문서에서는 클래스명이나 메서드명과 같은 정확한 문자열 검색도 중요하다. 이를 보완하기 위해 BM25를 추가했다. Question ├── Dense Retrieval │ └── BGE-M3 │ └── Lexical Retrieval └── BM25 ↓ RRF Fusion ↓ Top-K Dense Retrieval은 의미적 유사도를 활용하고, BM25는 단어의 등장 여부와 빈도를 활용한다. 두 검색 결과를 RRF(Reciprocal Rank Fusion) 방식으로 결합했다. 결과 실험 Hit@3 Baseline 대비 Baseline 86.7% +0.0%p Hybrid Search 86.7% +0.0%p Hybrid Search를 적용했지만 Hit@3에는 변화가 없었다. 개선 실험 2 — RRF k 값 비교 Hybrid Search에서는 Dense Retrieval과 BM25의 검색 결과를 RRF로 결합했다. RRF의 k 값을 변경하면서 결과가 달라지는지도 확인했다. RRF k Hit@3 Baseline 대비 10 86.7% +0.0%p 60 86.7% +0.0%p 100 86.7% +0.0%p 200 86.7% +0.0%p 모든 설정에서 동일한 결과가 나타났다. 따라서 이번 평가 데이터에서는 특정 RRF k 값이 다른 설정에 비해 더 좋은 결과를 만들었다고 판단할 수 없었다. Embedding 비교 — E5 Prefix 실험 추가로 BGE-M3와 다른 Embedding 모델인 E5를 사용하여 검색 결과를 비교했다. E5 계열 모델은 검색 상황에 따라 query와 passage에 구분된 입력 형식을 사용하는 방식이 일반적으로 사용된다. 이번 실험에서는 prefix 적용 여부를 비교했다. 실험 Hit@3 Baseline 대비 BGE-M3 86.7% +0.0%p E5 prefix 80.0% -6.7%p E5 no-prefix 86.7% +0.0%p E5에 prefix를 적용했을 때는 80.0%로 성능이 낮아졌지만, prefix를 제거하자 86.7%로 다시 증가했다. 이번 데이터에서는 E5 no-prefix가 BGE-M3와 동일한 Hit@3를 기록했다. 이를 통해 Embedding 모델을 변경할 때는 모델 자체뿐 아니라 실제 문서와 질문에 맞는 입력 방식도 함께 검증해야 한다는 점을 확인했다. Silent Failure 진단 검색 성능이 낮은 경우 단순히 모델의 성능 문제라고 판단하기 전에 문서 자체의 특성도 확인할 필요가 있다. 특히 긴 Section이 Embedding 모델의 입력 길이 제한 때문에 제대로 표현되지 않을 가능성을 확인했다. 긴 Section을 별도로 검색한 결과는 다음과 같았다. 긴 Section 검색 순위 : 1 Top-3 포함 여부 : True 이번 실험에서는 긴 Section이 검색 결과 1위에 위치했기 때문에 문서가 길다는 이유만으로 검색 실패가 발생했다고 보기는 어려웠다. 이와 같은 진단을 통해 검색 성능을 평가할 때 단순한 최종 점수뿐 아니라 실제 검색 결과와 문서 특성도 함께 확인할 필요가 있음을 확인했다. Offline 실행 검증 이번 프로젝트의 RAG 파이프라인은 외부 API에 의존하지 않고 로컬 모델을 사용하는 것을 목표로 했다. Embedding과 LLM을 로컬에서 실행한 후 Offline 환경을 가정하여 다음 설정으로 검증했다. import os os.environ["HF_HUB_OFFLINE"] = "1" os.environ["TRANSFORMERS_OFFLINE"] = "1" Offline 환경에서는 Hugging Face Hub에 접근하지 않고 로컬에 다운로드된 모델을 사용하도록 설정했다. 이를 통해 모델 다운로드가 필요한 환경과 실제 RAG 실행 환경을 분리할 수 있었다. 최종 결과 분석 전체 실험 결과를 정리하면 다음과 같다. 구분 변경 내용 Hit@3 Baseline 대비 Baseline BGE-M3 Dense Retrieval 86.7% +0.0%p 개선 1 Dense + BM25 Hybrid / RRF k=60 86.7% +0.0%p RRF 실험 Hybrid + RRF k=10 86.7% +0.0%p RRF 실험 Hybrid + RRF k=60 86.7% +0.0%p RRF 실험 Hybrid + RRF k=100 86.7% +0.0%p RRF 실험 Hybrid + RRF k=200 86.7% +0.0%p 추가 실험 E5 prefix 80.0% -6.7%p 추가 실험 E5 no-prefix 86.7% +0.0%p 이번 실험에서는 개선 기법을 적용했음에도 Baseline보다 높은 Hit@3를 얻지는 못했다. 특히 Hybrid Search와 RRF k 변경 실험에서 모두 동일한 86.7%가 나타났다. 이번 평가 질문은 Spring AI RAG 문서의 섹션명이나 기술 용어와 비교적 직접적으로 연결되어 있기 때문에 BGE-M3 Dense Retrieval만으로도 대부분의 정답 문서를 Top-3 안에서 찾을 수 있었던 것으로 해석할 수 있다. 따라서 BM25를 추가하거나 RRF의 k 값을 변경했지만 최종적인 Top-3 정답 포함 여부에는 변화가 발생하지 않았다. 또한 E5 prefix 실험에서는 오히려 Hit@3가 80.0%로 낮아졌다. prefix를 제거한 경우에는 86.7%로 회복되었다. 이번 결과를 통해 검색 시스템의 복잡도를 높이는 것이 항상 검색 성능 향상으로 이어지는 것은 아니라는 점을 확인할 수 있었다. Reflection 이번 프로젝트를 통해 RAG의 전체 구조를 직접 구현하면서 문서 전처리부터 검색, Vector DB, LLM 생성까지의 연결 과정을 확인할 수 있었다. 특히 Chunking 단계에서 문서의 내용을 단순히 일정한 길이로 나누는 것보다 원본 문서의 구조와 의미 단위를 고려하는 것이 중요하다는 점을 확인했다. 또한 Dense Retrieval에 BM25를 추가한 Hybrid Search가 항상 성능을 향상시키는 것은 아니었다. 이번 데이터에서는 Baseline의 검색 성능이 이미 높았기 때문에 Hybrid Search와 RRF k 변경이 최종 Hit@3에 영향을 주지 않았다. 반대로 E5 prefix 실험에서는 검색 성능이 낮아지는 결과도 확인했다. 이를 통해 RAG 시스템을 개선할 때는 새로운 기법을 무조건 추가하기보다 현재 문서의 특성, 질문 유형, 검색 실패 사례를 먼저 분석하고 그에 맞는 개선 방법을 선택해야 한다는 점을 배웠다. 또한 성능이 향상되지 않은 실험도 결과 자체를 기록하고 원인을 분석하면 의미 있는 실험이 될 수 있다는 점을 확인했다. 프로젝트 요약 이번 프로젝트에서는 Spring AI 공식 RAG 문서를 대상으로 로컬 RAG 시스템을 구축하고 검색 성능을 비교했다. 사용 기술 Document: Spring AI Retrieval Augmented Generation 공식 문서 Embedding: BGE-M3 Vector DB: Qdrant LLM: Qwen2.5-7B-Instruct Retrieval: Dense Retrieval Hybrid Search: BM25 + Dense Retrieval Fusion: RRF Evaluation: Hit@3 Offline Verification: Hugging Face Offline Mode 주요 결과 Baseline BGE-M3 86.7% Hybrid Search 86.7% RRF k=10 86.7% RRF k=60 86.7% RRF k=100 86.7% RRF k=200 86.7% E5 prefix 80.0% E5 no-prefix 86.7% 이번 프로젝트의 핵심은 단순히 높은 검색 점수를 만드는 것이 아니라, 동일한 평가 기준에서 여러 RAG 검색 전략을 실험하고 그 결과를 분석하는 과정에 있었다. 특히 기존의 Java/Spring 개발 경험과 연결되는 Spring AI 문서를 직접 RAG 대상으로 활용하면서, 기존 백엔드 개발 경험을 RAG 및 LLM 애플리케이션 개발 학습으로 확장해 보는 것을 목표로 했다.
То, что RADAR обнаружил и классифицировал для этой возможности. Это опубликованный источником текст, а не подтверждение, что предложение ещё действует.
로컬 문서로 RAG 구축하고 검색 성능 개선 실험하기. 이번 프로젝트에서는 Spring AI의 RAG 공식 문서를 대상으로 로컬 RAG 파이프라인을 구축하고, 검색 방법을 변경하면서 검색 성능이 어떻게 달라지는지 실험했다. 단순히 RAG를 구현하는 것에서 끝내지 않고, 문서 구조에 맞는 Chunking Dense Retrieval 기반 Baseline BM25 + Dense Retrieval Hybrid Search RRF k 값 변화 Embedding 모델 및 입력 방식 비교 Offline 실행 검증 검색 실패 가능성에 대한 진단 까지 단계적으로 확인했다. 이번 실험에서 사용한 Spring AI 공식 문서는 RAG의 기본 구조뿐 아니라 QuestionAnswerAdvisor,…
Открыть источник