로컬 RAG를 구축하고 싶으신가요?
(blog.yakkomajuri.com)- Skald는 데이터를 제3자에게 전송하지 않고 완전히 자체 호스팅 가능한 RAG 시스템을 목표로 개발됨
- RAG 구성요소는 벡터 데이터베이스, 임베딩 모델, LLM, 리랭커, 문서 파서로 나뉘며, 각 요소에 대해 오픈소스 대안을 제시
- Skald의 기본 로컬 스택은 Postgres+pgvector, Sentence Transformers, Docling, 사용자 지정 LLM으로 구성
- 벤치마크 결과, 클라우드 기반 모델(Voyage+Claude) 은 평균 9.45점, 완전 로컬 GPT-OSS 20B는 7.10~8.63점으로 평가됨
- 이 접근은 데이터 프라이버시를 유지하면서도 고성능 RAG 구축이 가능함을 보여줌
RAG 구성요소와 오픈소스 대안
- 기본 RAG는 벡터 데이터베이스, 임베딩 모델, LLM으로 구성되며, 추가적으로 리랭커와 문서 파서가 포함될 수 있음
- 각 구성요소는 SaaS 대신 로컬 대안으로 대체 가능
- 예시 표에서 제시된 대안
- Vector DB: Pinecone, Weaviate Cloud → Qdrant, Weaviate, Postgres+pgvector
- Embeddings: OpenAI, Cohere → Sentence Transformers, BGE, E5
- LLM: GPT, Claude → Llama, Mistral, GPT-OSS
- Reranker: Cohere → BGE Reranker, Sentence Transformers Cross-Encoder
- Document Parsing: Reducto → Docling
- Skald는 완전한 오픈소스 스택을 지향하며, 각 구성요소를 로컬에서 실행
Skald의 로컬 스택 구성
-
Vector DB: Postgres + pgvector 사용
- 기존 인프라에 통합 용이하며, 수십만 문서까지 처리 가능
-
Vector Embeddings: 기본값은 Sentence Transformers (all-MiniLM-L6-v2)
- 영어 전용, 속도와 검색 성능 균형
- bge-m3 모델(다국어 지원)도 테스트됨
-
LLM: 기본 제공 없음, 사용자가 직접 실행
- 테스트에서는 GPT-OSS 20B를 EC2에서 실행
- Reranker: 기본값은 Sentence Transformers Cross-Encoder, 다국어 모델로 bge-reranker-v2-m3 등도 사용 가능
- Document Parsing: Docling 사용, docling-serve로 실행
성능 및 배포 결과
- 전체 스택을 포함한 Skald 프로덕션 인스턴스 배포에 8분 소요
- Postgres, 임베딩·리랭킹 서비스, Docling 포함
- LLM은 별도 실행 (llama.cpp 사용)
- 테스트 데이터셋은 PostHog 웹사이트 콘텐츠(약 2000문서) 와 자체 제작 질의응답 세트로 구성
- 실험 설정
- Vector search topK=100, Reranking topK=50, Query rewriting=Off
- 평가 기준은 정확도 중심
벤치마크 결과 비교
-
Voyage + Claude (클라우드 구성)
- 평균 점수 9.45, 모든 답변 정확
-
Voyage + GPT-OSS 20B (부분 로컬)
- 평균 점수 9.18, 대부분 정확하나 일부 정보 누락
-
완전 로컬 + GPT-OSS 20B
-
기본 영어 모델(all-MiniLM-L6-v2 + ms-marco-MiniLM-L6-v2) : 평균 7.10
- 영어 질의에는 정확, 다국어·모호 질의·다문서 집계에서 약점
-
다국어 모델(bge-m3 + mmarco-mMiniLMv2-L12-H384-v1) : 평균 8.63
- 포르투갈어 질의 처리 성공, 다문서 집계 시 일부 누락
-
기본 영어 모델(all-MiniLM-L6-v2 + ms-marco-MiniLM-L6-v2) : 평균 7.10
- 주요 한계는 여러 문서에 흩어진 정보의 통합 처리
- 클라우드 모델은 고성능으로 이를 보완하지만, 로컬 환경에서는 추가 기법 필요
향후 계획
- Skald는 로컬 RAG 성능 향상 및 오픈소스 모델 벤치마크 공개를 계획
- 에어갭 환경에서 AI 도구를 운영해야 하는 기업을 위한 솔루션 제공 목표
- 참여 희망자는 GitHub(skaldlabs/skald) 또는 Slack 커뮤니티를 통해 협업 가능
Gemini :
네, RAG(Retrieval-Augmented Generation)에서 벡터 데이터베이스(Vector Database) 의 사용은 2020년 관련 논문이 처음 발표되면서부터 그 개념적인 토대가 마련되었습니다.
RAG는 기본적으로 검색(Retrieval) 과 생성(Generation) 을 결합하는 방식인데, 이 검색 단계에서 벡터 임베딩과 이를 효율적으로 저장하고 검색하는 벡터 데이터베이스가 필수적인 역할을 하게 됩니다.
💡 RAG와 벡터 DB의 시작점
RAG에서 벡터 DB가 필요하다는 아이디어는 다음의 주요 논문과 개념에서 출발했습니다.
- RAG의 탄생: Lewis et al. (2020) 논문
- 논문 제목: "Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks" (지식 집약적 자연어 처리 작업을 위한 검색 증강 생성)
- 핵심: 이 논문에서 RAG라는 용어와 프레임워크가 처음 제시되었습니다.
- Retriever의 역할: 논문에서 제안된 RAG 모델은 Retriever(검색기) 와 Generator(생성기) 로 구성됩니다. Retriever는 위키피디아와 같은 대규모 데이터셋에서 쿼리와 관련된 문서(latent documents) 를 검색합니다.
- 벡터 인덱스 사용: 이 초기 RAG 모델은 문서를 검색하기 위해 데이터셋에 벡터 인덱스(Vector Index) 를 사용하여 사전 학습된 검색기(pretrained retriever) 가 문서를 가져올 수 있도록 했습니다.
- 결론: RAG의 핵심 단계인 '검색' 이 쿼리 및 문서의 벡터 표현을 기반으로 유사성을 계산하여 이루어지기 때문에, 효율적인 검색을 위한 벡터 저장소(Vector Store) 또는 벡터 인덱스의 개념이 필수적으로 내포되었습니다.
- 벡터 임베딩과 유사도 검색
벡터 데이터베이스가 RAG의 필수 요소가 된 근본적인 이유는 다음과 같습니다.
- 임베딩(Embedding): RAG 시스템에서 외부 지식(문서, 텍스트)과 사용자의 쿼리(질문)는 모두 벡터(Vector) 라는 수학적 표현으로 변환됩니다. 이 벡터는 텍스트의 의미를 고차원 공간에 밀집된 숫자의 배열로 나타냅니다.
- 유사도 검색(Similarity Search): 벡터 공간에서 쿼리 벡터와 가장 가까운 거리에 있는 문서 벡터를 찾는 것이 곧 의미적으로 가장 유사한(Relevant) 문서를 찾는 것을 의미합니다.
- 벡터 DB의 역할: 벡터 데이터베이스는 이러한 수많은 문서 벡터들을 저장하고, 주어진 쿼리 벡터에 대해 가장 유사한 벡터를 빠르고 효율적으로 검색하기 위해 특화된 데이터베이스입니다. 따라서 RAG의 검색 성능을 극대화하는 데 필수적입니다.
요약: 벡터 DB가 필요한 이유
LLM이 학습하지 않은 최신/도메인 특정 지식에 접근하게 하려면, 단순히 키워드 매칭(전통적인 검색)이 아닌 의미적 유사성을 기반으로 정보를 찾아야 합니다. 벡터 DB는 이 의미적 유사성 기반 검색을 효율적으로 수행하기 위해 RAG 프레임워크에 자연스럽게 통합된 핵심 기술입니다.
Hacker News 의견
-
이런 시스템을 만들 때는 벡터 데이터베이스나 임베딩에 집착하지 말라는 조언을 하고 싶음
전체 텍스트 검색이나grep/rg같은 도구가 훨씬 빠르고 저렴하며, 인덱스를 유지할 필요도 없음
좋은 LLM에게 검색 도구를 주면 “dog OR canine” 같은 쿼리를 스스로 만들어내고 반복적으로 개선할 수 있음
게다가 이렇게 하면 청킹 문제를 해결할 필요도 없어짐- 브라우저에서 임베딩 기반(“semantic”)과 BM25 검색의 차이를 보여주는 작은 앱을 만들었음
Search Sensei에서 확인 가능함
처음 로드 시 약 50MB의 모델 가중치와 onnx runtime을 다운로드하지만 이후엔 원활히 작동함
예를 들어 BM25는 “j lo”와 “jlo”가 Jennifer Lopez를 의미한다는 걸 이해하지 못하지만, 임베딩 기반 검색은 이런 오타나 별칭을 잘 처리함
2016~2024년 뉴스 기사 1000개를 대상으로 검색을 수행함 -
Anthropic의 contextual retrieval 연구에 따르면, 임베딩 + BM25 조합이 가장 좋은 결과를 냈다고 함
하지만 BM25 단독 성능은 공개되지 않아 아쉬움
내 소규모 테스트에서는 쿼리 단어가 그대로 포함된 페이지를 임베딩이 놓치는 경우가 있었음 — 결국 Ctrl+F가 이김 - 내 경험상 semantic vs lexical 검색은 정밀도(precision)와 재현율(recall)의 트레이드오프로 이해하는 게 맞음
Lexical 검색은 정밀도가 높지만 재현율이 낮고, semantic 검색은 그 반대 지점에 위치함 - Google Maps에서 “billiards”를 검색했더니 수영장과 염소 관련 결과만 나오는 동의어 문제를 겪었음
“NOT” 연산자가 더 필요하다고 느낌. RAG에 대해서도 더 배우고 싶음 - 이런 방식으로 검색을 수행할 때 표준 프롬프트를 사용하는지 궁금함
일부 에이전트형 도구들이 자동으로 이런 쿼리를 만들어주는 걸 봤는데, 프롬프트로 유도된 건지 기본 동작인지는 모르겠음
- 브라우저에서 임베딩 기반(“semantic”)과 BM25 검색의 차이를 보여주는 작은 앱을 만들었음
-
성능이 떨어지는 이유 중 하나는 semantic chunking이 부족해서일 수 있음
문서 전체를 임베딩하면 여러 개념이 섞여 정확도가 떨어짐
Spacy 같은 도구로 의미 단위로 나누고, 각 청크가 문서 내에서 어떤 맥락에 있는지 추가한 뒤 임베딩해야 함
Anthropic의 contextual retrieval 접근법이 RAG 시스템에서 매우 효과적이었음
GPT OSS 20B 모델로 문맥 생성을 하면 됨- 작성자 아님이지만, 우리는 이미 semantic chunking을 하고 있음
여러 문서의 컨텍스트를 집계해야 하는 질문으로 테스트했기 때문에 오해가 있었던 듯함
- 작성자 아님이지만, 우리는 이미 semantic chunking을 하고 있음
-
왜 semantic 검색이 lexical 검색보다 우수하다고 전제하는지 의문임
2023년에 Tantivy(BM25)와 비교했을 때 결과 차이는 미미했음
약간의 재현율 향상이 있다고 해도, 그 복잡한 구조를 만들 가치가 있는지 모르겠음- 테스트 방식에 따라 다름
개발자 테스트에서는 90% 재현율이었지만 실제 사용자 테스트에서는 30% 수준으로 떨어졌음
사용자는 문서의 정확한 용어를 모르기 때문에 lexical 검색만으로는 부족했음
에이전트를 얹을 수도 있지만, 지연(latency) 이 커져 사용자 만족도가 떨어짐 - 앱의 성격에 따라 다름
Wanderfugl에서는 BM25 점수가 낮은 부분도 semantic 검색이 잘 찾아줌
결국 하이브리드 랭킹이 답일 수 있음 - “두 과학자 간의 대화” 같은 쿼리를 처리할 수 있다는 점이 장점임
결국 사용 사례 의존적임
- 테스트 방식에 따라 다름
-
이메일, Slack, GDrive, 코드, 위키 등 모든 데이터를 로컬 오프라인에서 질의할 수 있는 오픈소스 도구를 찾고 있음
직접 구축하거나 커스터마이징은 피하고 싶고, 좋은 기본값과 모델 추천이 있으면 좋겠음- 그래서 Nextcloud MCP 서버를 만들었음
GitHub 링크
기본적으로 CRUD를 지원하고, 벡터 검색을 활성화하면 문서나 노트를 임베딩함
Ollama와 OpenAI를 임베딩 제공자로 지원함
MCP 서버는 semantic + BM25(qdrant fusion) 검색을 모두 제공하고, MCP 샘플링을 통해 응답을 생성함
서버 자체가 답을 생성하지 않고, 어떤 LLM/MCP 클라이언트와도 연동 가능함
이 MCP sampling/RAG 패턴은 매우 강력하며, 다른 데이터 소스에도 일반화된 오픈소스 버전이 나올 가능성이 큼
- 그래서 Nextcloud MCP 서버를 만들었음
-
우리가 사용하는 도구는 haiku.rag임
개발자 친화적인 Python 코드와 pydantic-ai 기반 구조, 벤치마크와 고급 인용 기능을 제공함
깊은 리서치 에이전트를 지원하며, 장기적으로 유지되는 진짜 오픈소스 프로젝트임 -
기본 임베딩 모델로 Sentence Transformers (all-MiniLM-L6-v2) 를 사용 중인데, 영어 전용이라 독일어 RAG를 만들 때 문제가 될 수 있음을 깨달음
비영어 모델의 성능이 어떤지 궁금함-
MTEB 리더보드를 참고하면 됨
“Retrieval” 섹션의 RTEB Multilingual 또는 RTEB German 항목을 보면 됨
CPU 기반 셀프호스팅이라면 100M 파라미터 이하 모델로 필터링하는 게 좋음 - 많은 모델이 비영어권 언어에서 성능 저하를 보임
하지만 독일어는 비교적 학습 데이터가 많고, 다국어 모델도 충분히 존재함
특히 상용 API 기반 모델들은 대부분 다국어 지원임 - 우리도 예전에 다국어 임베딩 모델을 사용했었음
관련 논문은 Springer 링크 참고 가능함
-
MTEB 리더보드를 참고하면 됨
-
GPT-4 시절(8K context)에는 책 전체를 청크로 나눠 GPT-4에 넣어 관련 구절을 검색하는 스크립트를 만들었음
그땐 검색 한 번에 1달러 정도 들었지만, 지금은 훨씬 저렴해짐
Anthropic의 contextual retrieval 글에서도, 문서가 컨텍스트에 다 들어간다면 RAG 대신 그냥 넣는 게 낫다고 함
다만 컨텍스트가 길어지면 품질이 떨어지고, 비용과 속도도 문제임
지금은 책 전체를 컨텍스트에 넣어도 1센트 수준으로 가능함 -
RAG에서 가장 어려운 부분은 문서 파싱임
텍스트만 다루면 괜찮지만, 표나 다중 페이지 표, 차트, 목차, 각주 등이 있으면 정확도가 급격히 떨어짐
이를 개선하기 위해 RAPTOR 패턴처럼 LLM이 내용을 요약·질문하며 벡터 DB에 저장하는 접근이 있음
하지만 모든 경우에 통하는 범용 RAG 파이프라인은 여전히 어려운 과제임- 벡터 임베딩 초보로서, 표가 그렇게 복잡한 문제를 만든다는 걸 몰랐음
벡터 DB가 긴 텍스트 그룹과 표 형식 중 어느 쪽을 더 잘 처리하는지도 궁금함
- 벡터 임베딩 초보로서, 표가 그렇게 복잡한 문제를 만든다는 걸 몰랐음
-
전체 텍스트 검색을 RAG에 적용한 새로운 관점이 흥미로웠음
에이전트형 도구 루프와 퍼지 검색(fuzzy search) 처리 방식에 대한 통찰이 인상적이었음 -
이런 시스템의 평가용 데이터셋이 표준화되어 있는지 궁금함
문서와 질문 세트가 있어 특정 문서나 청크가 가장 관련성 높은 결과로 나와야 하는 식의 벤치마크가 있으면 좋겠음- 그런 용도로 haiku-rag 벤치마크와 평가 세트를 참고하면 됨