2년간 50개의 RAG 시스템을 만들며 배운 것들
게시일: 2025년 10월 24일 | 원문 작성일: 2025년 10월 23일 | 출처: Reddit r/LocalLLaMA | 원문 보기
핵심 요약
유럽과 미국의 여러 스타트업에서 ML 엔지니어로 일하면서 발견한 진실: RAG 데모와 실제 프로덕트 사이의 간극은 거의 항상 같은 문제에서 비롯됩니다. 사람들이 여전히 naive한 검색 방식을 쓰고 있다는 거죠.
실제로 작동하는 제품을 만들고 싶다면:
- 기본적인
sim(BiEncoder(q), BiEncoder(d))셋업에서 벗어나야 해요 - 이건 정밀도, 뉘앙스, 복잡한 쿼리에서 실패합니다 - Retriever-Reranker가 프로덕션에서 정밀도를 높이는 표준 방식입니다
- Query Transformer는 잘못된 사용자 쿼리를 고치는 비싼 방법이에요
- Graph RAG는 다른 문제(구조화된 데이터)를 해결하는 거고, 대부분의 경우 집중력을 분산시키는 요소입니다
표기법 정리
• q, d: 쿼리, 문서
• BiEncoder(x): Bi-encoder 모델 (예: SBERT), 벡터를 독립적으로 계산
• CrossEncoder(q, d): Cross-encoder 모델, 관련성 점수를 조인트로 계산
• sim(v1, v2): 코사인 유사도
• S_naive = sim(BiEncoder(q), BiEncoder(d))
1. Retriever-Reranker (정밀도 스택)
이게 프로덕션 정확도로 가는 가장 믿을 만한 경로예요. 리콜 문제와 정밀도 문제를 분리합니다.
작동 방식
Stage 1 (Retriever): 빠르고 높은 리콜의 하이브리드 검색(RRF)을 사용해서 Top-K 후보를 가져옵니다.
RRF_Score(d) = SUM( 1 / (k + rank_r(d)) ) for r in { bm25, vector }
Stage 2 (Reranker): Top-K만 느리지만 더 정확한 CrossEncoder(q, d)로 재점수화합니다.
✅ 장점
정밀도를 해결하는 올바른 방법이에요. CrossEncoder(q, d)는 S_naive보다 본질적으로 더 강력하고, 부정 표현과 뉘앙스를 처리할 수 있는 유일하게 신뢰할 만한 방법입니다.
⚠️ 단점
두 번째 네트워크 호출의 레이턴시는 사소하고 예측 가능한 비용이에요. 하지만 정확도 향상이 엄청나게 크니까요.
Turbopuffer와 ZeroEntropy를 사용한 좋은 구현이 있어요. (참고로 이게 지금까지 제일 좋은 결과를 줬는데, 다양한 변형을 찾을 수 있습니다)
2. Query Transformer (리콜 스택)
이 패턴은 쿼리 q가 문제라고 가정해요. 검색 전에 LLM을 사용해서 q를 정제합니다.
작동 방식
LLM이 n개의 쿼리 변형 { q_1, …, q_n } (Multi-Query)을 생성하거나, 검색에 사용할 가상의 문서 d_hypo (HyDE)를 만듭니다.
Search Vector = BiEncoder(d_hypo)
✅ 장점
모호하거나 의미적으로 매치가 안 되는 사용자 입력에서 오는 나쁜 리콜을 고칠 수 있어요.
⚠️ 단점
검색이 시작되기도 전에 비싸고 느린 LLM 호출을 추가합니다.
3. Graph RAG (연결 스택)
명시적이고 구조화된 관계에 초점을 맞춘 다른 패러다임이에요.
작동 방식
벡터 유사도를 버리고 그래프 쿼리 언어를 사용합니다.
MATCH (e:Engineer)-[:WORKS_AT]->(c:Company) RETURN e.name
✅ 장점
벡터 검색이 본질적으로 할 수 없는 복잡한 멀티홉 질문에 답할 수 있어요.
⚠️ 단점
대부분의 경우 집중력을 분산시키는 요소예요. 엄청난 사전 데이터 모델링 병목(ETL, 스키마 정의)이 필요합니다. 경직되고, 비싸고, RAG의 주된 목적인 비구조화 데이터를 다루는 것에 반하죠.
세 가지 패턴 비교
| 패턴 | 해결하는 문제 | 레이턴시 | 프로덕션 준비도 | 사용 시기 |
|---|---|---|---|---|
| Retriever-Reranker | 정밀도 | 중간 (2단계 처리) | ⭐⭐⭐⭐⭐ | 기본으로 사용 |
| Query Transformer | 리콜 (나쁜 쿼리) | 느림 (LLM 호출) | ⭐⭐⭐ | 사용자 쿼리가 일관성 없을 때 |
| Graph RAG | 구조화된 관계 | 빠름 (그래프 쿼리) | ⭐⭐ | 구조화된 데이터가 이미 있을 때만 |
결론: 무엇을 써야 할까?
명확하게 정리하면:
- Setup 1 (Retriever-Reranker)는 정밀도를 고치는 프로덕션 표준이에요.
- Setup 2 (Query-Transformer)는 나쁜 사용자 쿼리를 고치는 비싼 방법입니다.
- Setup 3 (Graph RAG)는 다른 문제(구조화된 데이터)를 해결하는 거고, 대부분의 경우 집중력을 분산시키는 요소예요.
실제 프로덕트를 배포하고 싶다면: Retriever-Reranker로 시작하세요. 이게 가장 신뢰할 수 있고, 검증된 방법입니다. Query Transformer는 특정 상황에서만, Graph RAG는 정말 필요할 때만 고려하면 됩니다.
참고: 이 글은 유럽과 미국의 여러 스타트업에서 ML 엔지니어로 일한 경험을 가진 개발자가 Reddit r/LocalLLaMA에 게시한 글을 번역하고 요약한 것입니다.
원문: https://reddit.com/r/LocalLLaMA/comments/1odv090/i_built_50_rags_in_2_years_here_are_the/
생성: Claude (Anthropic)