
RAG의 비용 문제를 1/15로 절감하는 ― 「매번 검색하지 않는」 아키텍처 설계
요약
RAG 애플리케이션의 비용과 레이턴시 문제를 해결하기 위해 검색을 최소화하는 4계층 아키텍처를 제안합니다. 모든 쿼리에 풀 RAG를 실행하는 대신, 쿼리 분류와 사전 생성된 상정 질문 인덱스를 활용하여 비용을 최대 1/15까지 절감할 수 있습니다.
핵심 포인트
- 쿼리 분류기를 통해 검색이 불필요한 쿼리를 40~60% 선제 차단
- 상정 질문 인덱스를 구축하여 추론 시 LLM 호출 없이 답변 반환
- 정적 코퍼스 환경에서 비용과 레이턴시를 획기적으로 개선
- 의미 단위의 사전 생성 답변을 통한 캐시 히트율 극대화
서론
AI 에이전트 및 RAG 애플리케이션이 급속히 보급되는 한편, 운영 단계에 진입한 팀들로부터 공통적으로 들려오는 것은 비용과 레이턴시 (Latency) 문제입니다.
「쿼리마다 retrieve(검색) → 모든 결과를 컨텍스트(Context)에 투입 → LLM으로 생성」이라는 단순한 구성은 토큰 과금과 응답 시간이 선형적으로 증가합니다. 월 수만 건의 쿼리까지는 버틸 수 있어도, 10만, 100만 건으로 늘어나면 무시할 수 없는 금액이 됩니다.
캐시를 도입하는 것이 가장 먼저 떠오르는 해결책이지만, 원시 쿼리 (Raw Query) 단위로 캐시하면 대상이 너무 많아 히트율 (Hit Rate)이 늘어나지 않는다는 벽에 부딪힙니다.
본 기사에서는 이 문제에 대해 **「추론 시의 검색을 최소화하고, 계산을 오프라인으로 돌린다」**는 발상으로 설계한 4계층 아키텍처와 그 PoC 설계의 포인트를 소개합니다.
상정하는 전제
설계의 전제 조건에 따라 최적해는 달라집니다. 본 기사의 구성은 아래를 상정하고 있습니다.
코퍼스 (Corpus)가 거의 정적 (사내 매뉴얼, 제품 문서, 지식 베이스 등)
월간 쿼리 수가 10만~100만 단위
코퍼스 규모가 1만~10만 문서
비용 최우선 (레이턴시와 정확도도 중요하지만, 우선 비용을 낮추고 싶음)
빈번하게 업데이트되는 데이터 (뉴스, 채팅 로그 등)가 대상이라면 다른 접근 방식이 필요하다는 점에 주의하십시오.
설계의 핵심 발상
단순 RAG의 문제는 **「쿼리가 올 때마다 retrieve와 generate를 모두 풀 실행하고 있다」**는 점입니다.
하지만 자세히 관찰하면, 실제 운영에서는 다음과 같은 분포를 보이는 경우가 많습니다.
- 전체 쿼리의 40~60%는 LLM의 내부 지식만으로 대답 가능 (잡담, 일반 지식, 정형 인사)
- 나머지 대부분은 과거에 누군가가 물어봤던 것과 유사한 질문
- 정말로 「새롭고 복잡한」 쿼리는 전체의 5~15% 정도
즉, 모든 쿼리에 대해 풀 RAG를 실행하는 것은 과잉입니다.
따라서 쿼리의 성질에 따라 4개 계층으로 분류하여, 「무거운 처리에 도달하는 쿼리를 단계적으로 깎아 나가는」 아키텍처를 설계합니다.
4계층 아키텍처
[쿼리]
↓
[Layer 0: 쿼리 분류기]
...
Layer 0: 쿼리 분류기
들어온 쿼리를 경량 모델 (Haiku 클래스, 혹은 파인튜닝 (Fine-tuning) 된 소형 classifier)로 분류하여, 검색이 필요 없는 것을 여기서 걸러냅니다.
- 잡담·일반 지식·정형 인사 → 메인 LLM만으로 응답
- 문서 참조가 필요 → Layer 1로 이동
체감상, 사내 매뉴얼 계열의 유스케이스에서는 40~60%의 쿼리가 여기서 완결됩니다.
Layer 1: 상정 질문 인덱스 (본 구성의 핵심)
「대상이 너무 많아서 캐시가 효과가 없다」는 문제는 원시 쿼리로 캐시하고 있기 때문에 발생합니다. 발상을 전환합니다.
오프라인 측에서 할 일:
- 코퍼스를 의미 단위의 청크 (Chunk)로 분할
- 각 청크에서 「상정되는 질문」을 LLM으로 5~10개씩 생성
- 각 상정 질문에 대한 답변도 사전에 생성해 둠
- 상정 질문을 임베딩 벡터 (Embedding Vector)화하여 인덱스 구축
추론 시에 할 일:
- 사용자의 쿼리를 임베딩 벡터화
- 상정 질문 인덱스에서 근방 탐색 (Nearest Neighbor Search)
- 유사도가 임계치를 넘으면, 사전 생성된 답변을 그대로 반환
- 중간 정도의 유사도라면, Haiku로 가볍게 다시 써서 반환
포인트는 추론 시에 LLM 호출이 발생하지 않는다 (또는 극히 경량한 재작성만 수행한다)는 점입니다. 비용은 거의 임베딩 계산과 벡터 검색뿐입니다.
「대상이 너무 많아서 캐시할 수 없다」는 것은 원시 쿼리 단위로 생각하기 때문이며, 상정 질문이라는 의미 단위로 생각하면 코퍼스 크기에 대해 유한합니다.
Layer 2: 일반 RAG (Haiku + Prompt Caching)
Layer 1에서 대답할 수 없었던 쿼리는 일반적인 RAG 파이프라인으로 흘려보냅니다. 단, 아래 방법으로 비용을 줄입니다.
- 시스템 프롬프트와 빈출 문서를 Prompt Caching에 태움 (최대 90% 절감)
- 리랭커 (Reranker)로 상위 3개까지 압축
- 생성은 Haiku로도 충분한 경우가 많음
Layer 3: 풀 RAG (Sonnet)
Layer 2에서도 품질이 불충분하다고 판단된 복잡한 쿼리에 대해서만 Sonnet 클래스의 상위 모델을 사용합니다. 전체의 5~15% 정도입니다. 이 부분만큼은 사치스럽게 사용해도 좋다는 식의 결단입니다.
비용 산출
가령 월 100만 쿼리, Naive (단순) 구현 시 1쿼리당 0.05달러라고 가정하면, 월 50,000달러입니다.
이 4계층 구성이라면,
| Layer | 통과율 | 1쿼리 비용 | 월 비용 |
|---|---|---|---|
| Layer 0에서 완결 | 50% (50만) | 거의 제로 | ~수십 달러 |
| ... | 합계 | ~3,000달러 |
대략 1/15~1/20까지 떨어지는 계산입니다. 실제 분포에 따라 다르므로 실측이 필수적이지만, 자릿수 자체가 바뀝니다.
PoC 설계
이론만으로 진행하면 큰 코를 다칠 수 있으므로, 단계적으로 검증하는 PoC (Proof of Concept, 개념 증명) 설계를 소개합니다.
Phase 0: 평가 세트 준비 (가장 중요)
이 단계를 건너뛰면 PoC는 "어찌어찌 작동은 한다" 수준에서 끝나버립니다. 가장 먼저 해야 할 일은 코드를 짜는 것이 아니라 평가 설계입니다.
- 실제 쿼리 로그에서 200~500건 샘플링 (없다면 전문가에게 작성을 요청)
- 각 쿼리에 이상적인 답변 또는 정답 문서(Document)를 어노테이션 (Annotation)
- 난이도·타입별로 분류
평가 지표:
- 검색 정확도: Recall@k, MRR
- 답변 품질: LLM-as-Judge + 추출 인적 평가
- 비용: 1쿼리당 실비
- 레이턴시 (Latency): p50, p95
Phase 1: 베이스라인 구축
비교 대상이 없으면 개선 효과를 측정할 수 없습니다. Naive RAG를 최소한으로 구현하고, Phase 0의 평가 세트로 수치를 측정합니다.
Phase 2: 코퍼스 (Corpus) 전처리 파이프라인
이 부분이 가장 시간이 많이 걸립니다.
- 의미 단위 청킹 (Chunking): 구조(장·절·항)를 유지하고, 헤딩(Heading) 계층을 메타데이터에 삽입. 청크는 단독으로 읽어도 의미가 통하는 입도(300~800 토큰)로 설정
- 예상 질문 생성: 각 청크에 대해 Haiku로 5~10개의 질문을 생성. Batch API를 사용하여 50% 할인 적용
- 답변 사전 생성: 예상 질문에 대한 답변도 Batch로 생성하여 임베딩 (Embedding) 계산 및 인덱싱 (Indexing)
5만 청크라면 25~50만 개의 질문이 되지만, Haiku Batch API를 사용하면 수십 달러 정도로 해결됩니다.
Phase 3: 추론 파이프라인
4계층의 오케스트레이션 (Orchestration)을 구현합니다. 임계값 (Threshold)은 실측 기반으로 결정하는 것이 요령입니다. Phase 0의 평가 세트를 사용하여 각 임계값에서의 품질과 통과율을 플롯 (Plot)하여 결정합니다. 감으로 정하지 마세요.
Phase 4: 평가 및 개선
평가 세트를 모든 레이어에 통과시켜 레이어별 통과율과 품질을 분석합니다. 히트율(Hit rate)이 낮으면 질문 생성 프롬프트를 개선하고, 품질이 낮으면 임계값 조정이나 Reranker (재순위화 모델) 추가로 대응합니다.
PoC에서 빠지기 쉬운 함정
Python 스크래치로 PoC를 구성하는 것은 올바른 판단입니다. 하지만 그대로 클라우드 운영 환경으로 옮길 때 문제가 되는 포인트가 몇 가지 있습니다.
1. 벡터 DB의 선택 (가장 큰 함정)
로컬의 FAISS나 Chroma로 PoC를 구성하면, 운영 환경으로 이전할 때 동작이 달라집니다.
- 검색 알고리즘 차이: 로컬 FAISS는 Exact Search (전수 검색), 운영 환경의 대부분은 ANN (Approximate Nearest Neighbor, 근사 최근접 이웃) 방식입니다. 같은 쿼리에 대해 다른 결과가 반환될 수 있습니다.
- 레이턴시 (Latency): 로컬 수 ms → 운영 환경 수십~수백 ms
- 비용 구조: 로컬 제로 → 인스턴스 상시 가동 + 요청당 과금
대책: PoC 단계에서도 운영 후보와 동일한 벡터 DB를 Docker로 로컬에서 실행하십시오. Qdrant나 pgvector 정도가 다루기 쉽습니다.
2. 임베딩 모델의 API 차이
로컬에서는 sentence-transformers를 쓰고, 운영 환경에서는 Bedrock Titan Embed를 쓰는 패턴은 주의가 필요합니다.
- 차원(Dimension) 수가 다름 → 인덱스 재구축 필요
- 정규화(Normalization) 여부가 다름 → 유사도 점수의 절대값이 변하여 임계값이 무효화됨
- 다국어 성능이 다름 → 특정 언어 특유의 쿼리에서 성능 차이 발생
대책: PoC에서도 운영 환경에서 사용할 임베딩 API를 처음부터 사용하십시오. API 키만 있으면 호출할 수 있으므로 인프라 의존적이지 않습니다.
3. 배치 처리의 현실
"Haiku로 50만 개 질문 생성"을 로컬 asyncio로 단순하게 작성하면,
- 확실하게 레이트 리미트 (Rate Limit)에 걸림
- 재시도 (Retry) 및 지수 백오프 (Exponential Backoff)가 필요함
- 도중에 중단되면 전부 다시 시작해야 함
대책: PoC 단계부터 멱등성 (Idempotency) + 체크포인트 (Checkpointing)화 하여 작성할 것. 중간 결과물을 parquet / jsonl로 저장하여 재개 가능하게 만듦.
4. 비용 구조의 질적인 차이
로컬 PoC의 비용은 LLM API만의 선형 과금 (Linear Billing)이지만, 운영 환경에서는 다음과 같은 비용이 추가됩니다.
- 벡터 DB (Vector DB) 인스턴스 과금 (요청이 없어도 발생) - 스토리지 · 네트워크 이그레스 (Egress)
- Lambda / Cloud Run / ECS 실행 비용
- API Gateway / Load Balancer
- 로그 · 모니터링 (은근히 영향을 미침)
- VPC 엔드포인트 (Endpoint), NAT Gateway
월 10만 쿼리 규모라면, LLM 이외의 인프라 고정비만으로도 월 500~2000달러가 추가될 수 있습니다.
5. 레이턴시 (Latency)의 누적
로컬에서의 800ms가 운영 환경에서 1.5~2배가 되는 것은 드문 일이 아닙니다. 특히 Bedrock의 모델 제공 리전과 다른 리소스의 리전이 일치하지 않으면 교차 리전 (Cross-region) 통신이 발생하여 레이턴시가 추가됩니다.
6. 병행성 · 동시 실행
로컬에서 요청을 하나씩 처리할 때는 보이지 않는 문제:
- 벡터 DB (Vector DB)의 동시 접속 수 상한
- LLM API의 TPM (Tokens Per Minute) 상한
- Lambda 동시 실행 수
대책: Phase 4에서 간이 부하 테스트 (100 병렬로 에러율 측정)를 포함할 것.
PoC에서 지켜야 할 6가지 규칙
함정을 피하기 위한 실용적인 체크리스트입니다.
- 벡터 DB (Vector DB)는 운영 환경 후보와 동일한 것을 로컬 Docker에서 구동한다.
- 임베딩 (Embedding) API는 운영 환경에서 사용할 것을 처음부터 사용한다.
- LLM 프로바이더 추상화 레이어 (Abstraction Layer)를 만들어, Bedrock / Anthropic API를 교체 가능하게 만든다.
- 오프라인 작업은 멱등성 (Idempotency) + 중간 결과 영속화 방식으로 작성한다.
- 비용 산정 시 LLM 이외의 인프라 고정비를 별도로 계상한다.
- 부하 테스트를 평가 단계에 포함한다.
이를 준수하면, 운영 환경으로의 이관은 **"벡터 DB의 호스팅 위치와 Python 애플리케이션의 실행 환경을 선택하는 것"**에 가까운 상태가 됩니다.
요약
RAG의 비용 문제는 "캐시를 넣는 것"만으로는 근본적인 해결이 되지 않습니다. 발상을 다음과 같이 전환하는 것이 핵심입니다.
- 모든 쿼리에 풀 RAG (Full RAG)를 실행하는 것은 과잉 ― 쿼리를 분류하여 배분한다.
- 원문 쿼리(Raw Query)로 캐싱하는 것이 아니라, 의미 단위(예상 질문)로 캐싱한다 ― 계산을 오프라인으로 넘긴다.
- 추론 시의 LLM 호출을 최소화한다 ― 사전에 생성한 답변을 재사용한다.
정적 코퍼스 (Corpus)를 전제로 한다면, 이러한 발상으로 비용을 1/15~1/20까지 절감하는 것이 현실적으로 가능합니다.
그리고 PoC를 구성할 때는, 운영 환경 이관 시 재작성이 발생하지 않도록 벡터 DB · 임베딩 API · 추상화 레이어 이 세 가지 포인트만큼은 처음부터 운영 환경을 상정하여 선택할 것. 이것만으로도 로직 자산은 그대로 운영 환경으로 가져갈 수 있습니다.
AI 에이전트 시대에는 모델 선정이나 프롬프트 설계에 주목하기 쉽지만, 비용과 레이턴시를 결정하는 것은 아키텍처 설계입니다. "매번 검색하지 않는" 설계를 꼭 검토해 보시기 바랍니다.
Discussion

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기