이 글은 사용자 질의를 시멘틱 벡터로 변환해 생성된 답을 미리 캐쉬에 저장해 놓고, 다음 유사 질의 시 관련 캐쉬 답변을 리턴하는 시맨틱 캐쉬 RAG 가속 방법을 알아본다.
pgVector 기반 RAG 캐쉬 개념도
시맨틱 캐쉬 필요성
LLM(대규모 언어 모델) 및 RAG(검색 증강 생성) 기반 애플리케이션은 종종 지연 시간(latency), 비용, 그리고 중복 연산의 문제에 직면한다. 사용자의 질의가 표현 방식만 약간 다를 뿐 의미론적으로 동일하더라도, 임베딩 생성, 문서 검색, LLM 호출에 이르는 전체 파이프라인이 매번 실행되는 경향이 있다. 이러한 방식은 특히 다수의 사용자가 유사한 질문을 반복할 때 비용 및 효율성 측면에서 비효율적이다. 전통적인 캐싱(traditional caching) 기법은 이러한 시나리오에서 제한적인 효용성을 보인다. 이는 기존 캐시가 텍스트의 정확한 일치(exact match)를 기반으로 작동하기 때문에, "파이썬이란 무엇인가?"와 "파이썬에 대해 설명해줘"와 같은 질의를 서로 무관한 요청으로 처리하기 때문이다.
이러한 문제를 해결하기 위해 시맨틱 캐시(Semantic Cache)가 도입되었다. 시맨틱 캐시는 이전에 처리된 질의와 그 응답을 저장하되, 원시 텍스트(raw text) 대신 질의의 의미론적 내용을 비교한다. 각 질의는 해당 의미를 포착하는 벡터 임베딩(vector embedding)으로 변환된다. 새로운 질의가 입력되면, 시스템은 캐시 내에서 가장 유사한 임베딩을 검색한다. 이때 코사인 유사도(cosine similarity)나 유클리드 거리(Euclidean distance)와 같은 벡터 공간 측정 기준이 사용된다. 만약 사전에 정의된 임계값(threshold) 이상의 근접한 일치 항목(cache hit)이 발견되면, 캐시된 결과가 즉시 반환된다. 일치 항목이 없는 경우(cache miss), 해당 요청은 LLM으로 전달되며, 새로 생성된 질의-응답 쌍이 캐시에 추가된다.
이 접근 방식은 특히 리소스 집약적인 문서 검색 및 생성 과정이 포함된 RAG 시스템, 그리고 사용자가 유사한 질문을 자주 반복하거나 재구성하는 챗봇 및 지식 보조 시스템에서 높은 가치를 지닌다. 그러나 실시간 주식 시세와 같이 데이터가 급격하게 변화하는 환경이나, 코드 생성 또는 형식적인 텍스트 매칭과 같이 구문의 정확성이 절대적으로 중요한 상황에는 적합하지 않다. 요컨대, 시맨틱 캐시는 사용자와 모델 사이의 지능형 계층(intelligent layer)으로 작동하여, 의미 있는 결과를 재사용하고 LLM 호출을 줄이며 응답 시간을 획기적으로 개선하는 역할을 수행한다.
시맨틱 캐쉬 구현 도구
RAG 애플리케이션에 시맨틱 캐시를 구현하기 위한 주요 도구는 다음과 같다.
저장소 및 캐시 역할로 PostgreSQL과 pgvector 확장이 사용될 수 있다. pgvector는 표준 SQL 데이터베이스를 벡터 저장소(vector store)로 기능하게 하여, 정형 데이터와 시맨틱 임베딩을 단일 시스템 내에서 효율적으로 관리하고 SQL 쿼리를 통해 직접 유사성 검색을 수행할 수 있게 한다. 캐시 테이블은 질의 텍스트, 해당 임베딩 벡터, 그리고 모델의 응답을 저장한다.
텍스트 생성을 위한 LLM으로는 LLaMA 기반 모델(예: llama3.2:1b 등)을 사용할 수 있다. 이 LLM은 캐시 미스(cache miss)가 발생했을 때, 즉 벡터 저장소에서 의미론적으로 유사한 질문이 발견되지 않았을 경우에만 호출된다.
시맨틱 캐시의 핵심인 임베딩 생성을 위해서는 별도의 경량 임베딩 모델(예: all-MiniLM-L6-v2)이 사용된다. 이 모델은 텍스트를 생성하는 것이 아니라, pgvector에 저장되고 비교될 의미의 수치적 벡터 표현(numerical vector representation)을 생성하는 역할만 담당한다. 이러한 경량 모델은 빠른 속도와 낮은 메모리 점유율로 인해, 메인 LLM을 호출하기 전 신속한 유사성 검사에 이상적이다.
전체 구성 요소를 통합하고 API를 제공하기 위해 FastAPI를 사용한 파이썬 서비스가 구축된다. 이 서비스는 REST API를 통해 사용자 질의를 수신하고, 입력 텍스트에 대한 임베딩을 생성하며, PostgreSQL의 시맨틱 캐시를 검색한다. 캐시 히트 시 캐시된 응답을 반환하고, 캐시 미스 시 LLaMA 모델을 질의한 후 새로운 질의-응답 쌍을 캐시에 저장하는 로직을 관장한다.
챗봇의 구현은 명확한 책임을 가진 모듈식 구성 요소로 설계된다. 영속성 계층(Persistence Layer)인 VectorDatabase는 pgvector를 활용하여 질의 임베딩, 응답, 메타데이터를 저장하고 코사인 거리를 기반으로 유사성 검색을 수행한다. EmbeddingService는 sentence-transformers 라이브러리(예: MiniLM)를 사용하여 사용자 텍스트를 수치적 벡터 표현으로 변환한다.
이 구성 요소는 모든 요청의 첫 단계에서 작동하며, 데이터베이스 스키마와 일관된 벡터 차원을 보장한다. LLMService는 LLaMA와 같은 메인 LLM을 호출하여 텍스트 생성을 처리한다. 이 서비스는 오직 캐시 미스가 발생했을 때만 활성화된다.
CacheService는 이러한 서비스들을 조율하는 핵심 오케스트레이션 계층이다. 이 모듈은 벡터 저장소에서 의미론적으로 유사한 임베딩을 확인하고, 유사도가 정의된 임계값을 초과하면 캐시된 응답을 반환한다. 캐시 미스 시에는 LLMService로 폴백(fallback)하고, 반환된 새로운 응답을 VectorDatabase에 업데이트하는 캐싱 로직 전체를 캡슐화한다.
마지막으로 Chat API는 FastAPI를 통해 사용자 대면 인터페이스를 제공하며, /chat과 같은 엔드포인트를 노출하여 전체 캐싱 및 생성 흐름을 트리거한다.
시맨틱 캐쉬 운영 고려사항
시맨틱 캐시 시스템의 운영에서 중요한 고려사항은 캐시 무효화(cache invalidation) 전략과 유사성 임계값(similarity threshold)의 정밀한 조정이다. 정보가 자주 변경되는 도메인에서는 캐시에 저장된 응답이 오래된 정보(stale data)가 될 위험이 있다. 이를 해결하기 위해 TTL(Time-To-Live)을 설정하여 일정 시간 후 캐시 항목을 자동 만료시키거나, 원본 데이터 소스가 업데이트될 때마다 연관된 캐시 항목을 능동적으로 제거하는 이벤트 기반 무효화 기법이 요구된다. 또한, 유사성 임계값 설정은 시스템의 민감도(sensitivity)와 특이도(specificity) 간의 균형(trade-off)을 결정한다.
임계값이 너무 낮으면(유사성 요구 수준이 낮으면) 의미론적으로 관련 없는 질의에 대해서도 캐시가 반환되어(False Positives) 부정확한 응답을 초래할 수 있다. 반대로 임계값이 너무 높으면(유사성 요구 수준이 높으면) 의미가 동일함에도 표현이 약간 다른 질의들을 캐시 미스로 처리하여(False Negatives) 캐시 효율성이 저하된다. 따라서 이 임계값은 실제 사용자 질의 데이터를 기반으로 한 지속적인 평가와 파인튜닝(fine-tuning)을 통해 최적화되어야 한다.
마무리
전통적인 캐싱이 LLM 질의에 실패하는 이유(상이한 표현, 동일한 의미)를 분석하고, 벡터 임베딩을 활용하여 의미론적 유사성을 기반으로 질의를 매칭하는 시맨틱 캐싱의 원리가 도입되었다.
아키텍처는 pgvector 기반의 VectorDatabase, 텍스트를 벡터로 변환하는 EmbeddingService, 캐시 미스 시에만 작동하는 LLMService, 그리고 전체 로직을 조율하는 CacheService 계층 및 FastAPI 기반의 API 엔드포인트로 구성된 모듈식 시스템으로 구현될 수 있다. 이러한 아키텍처는 높은 지연 시간과 비용을 유발하는 LLM 서비스를 빠르고 효율적인 프로덕션급 대화형 시스템으로 전환시킬 수 있는 잠재력을 보여준다.
레퍼런스