안녕하세요! 테디노트님의 RAG 비법노트 37일차 학습 기록입니다.
오늘은 어제(36일차)까지 배운 OpenAI 임베딩을 한 단계 발전시켜, 임베딩을 캐싱(Cache) 하는 방법을 실습했습니다.
RAG 파이프라인에서는 문서를 임베딩할 때마다 모델이 호출되기 때문에, 동일한 데이터를 여러 번 처리하면 비용과 시간이 낭비됩니다.
이를 해결하는 방법이 바로 CacheBackedEmbeddings 입니다.
1. CacheBackedEmbeddings란?
CacheBackedEmbeddings는 임베딩 결과를 저장해두었다가
같은 텍스트를 다시 임베딩할 때 모델을 재호출하지 않고 캐시된 결과를 사용하는 래퍼(wrapper) 클래스입니다.
즉, “이미 계산된 임베딩은 다시 계산하지 않는다”는 개념입니다.
이 방식은 특히 대량 문서 처리나 벡터 DB 구축 시 큰 효율을 가져옵니다.
2. 작동 원리
- 텍스트를 해시(hash)하여 캐시의 Key로 사용
- 해시된 Key와 임베딩 벡터를 Key-Value 저장소(ByteStore) 형태로 저장
- 다음에 같은 텍스트를 요청하면 → 모델 호출 대신 캐시에서 즉시 반환
핵심 초기화 함수는 다음과 같습니다. 👇
CacheBackedEmbeddings.from_bytes_store(
underlying_embeddings, # 실제 임베딩 모델 (예: OpenAIEmbeddings)
document_embedding_cache, # 캐시 저장소 (LocalFileStore, InMemoryByteStore 등)
namespace=embedding.model # 네임스페이스(중복 방지용)
)
💡 주의
다른 임베딩 모델을 동시에 쓸 때 충돌이 날 수 있으므로
namespace에는 보통 모델 이름(embedding.model)을 넣습니다.
3. LocalFileStore로 임베딩 캐싱 (영구 저장)
먼저, 로컬 디스크에 캐시를 저장하는 방식입니다.
한 번 생성된 임베딩은 ./cache/ 폴더에 저장되어, 다음 실행 시 재활용됩니다.
from langchain.storage import LocalFileStore
from langchain_openai import OpenAIEmbeddings
from langchain.embeddings import CacheBackedEmbeddings
from langchain_community.vectorstores.faiss import FAISS
# 1. 기본 임베딩 설정
embedding = OpenAIEmbeddings(model="text-embedding-3-small")
# 2. 로컬 저장소 설정
store = LocalFileStore("./cache/")
# 3. 캐시 지원 임베딩 객체 생성
cached_embedder = CacheBackedEmbeddings.from_bytes_store(
underlying_embeddings=embedding,
document_embedding_cache=store,
namespace=embedding.model
)
# 4. 캐시 키 확인
list(store.yield_keys())
이제 문서를 로드하고 분할한 뒤, FAISS 벡터 저장소를 생성해봅니다.
from langchain.document_loaders import TextLoader
from langchain_text_splitters import CharacterTextSplitter
# 문서 로드 및 분할
raw_documents = TextLoader("./data/appendix-keywords.txt").load()
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
documents = text_splitter.split_documents(raw_documents)
# 첫 번째 실행 (임베딩 계산 포함)
%time db = FAISS.from_documents(documents, cached_embedder)
# 두 번째 실행 (캐시 활용, 훨씬 빠름)
%time db2 = FAISS.from_documents(documents, cached_embedder)
실행 결과 비교 예시
첫 번째 실행: CPU times: user 100 ms, sys: 19.3 ms, total: 120 ms
Wall time: 1.32 s
두 번째 실행: CPU times: user 4.61 ms, sys: 2.18 ms, total: 6.79 ms
Wall time: 6.96 ms
📈 캐싱 덕분에 속도는 수십 배 빨라지고,
비용(OpenAI API 호출 수) 또한 크게 절감됩니다.
4. InMemoryByteStore로 임베딩 캐싱 (비영구 저장)
이번엔 메모리 기반 캐시를 사용해봅시다.
이 방식은 실행 중에만 데이터를 유지하며, 프로그램 종료 시 사라집니다.
from langchain.embeddings import CacheBackedEmbeddings
from langchain.storage import InMemoryByteStore
from langchain_openai import OpenAIEmbeddings
embedding = OpenAIEmbeddings(model="text-embedding-3-small")
store = InMemoryByteStore()
cached_embedder = CacheBackedEmbeddings.from_bytes_store(
embedding, store, namespace=embedding.model
)
💡 InMemoryByteStore
- 장점: 빠름, 임시 테스트용으로 적합
- 단점: 프로그램 종료 시 데이터 손실 (디스크 저장 아님)
Local vs InMemory 비교
| 구분 | 클래스 | 저장 위치 | 영구성 | 사용예시 |
| LocalFileStore | langchain.storage.LocalFileStore | 로컬 디스크(./cache/) | ✅ 영구 | RAG 서비스 구축 시 |
| InMemoryByteStore | langchain.storage.InMemoryByteStore | 메모리 내 | ❌ 비영구 | 실험, 테스트 환경 |
🧾 마무리
오늘은 CacheBackedEmbeddings를 활용하여 임베딩을 효율적으로 캐싱하는 방법을 학습했습니다.
💬 한 줄 요약
RAG의 성능을 높이는 가장 쉬운 최적화는 “이미 계산된 임베딩을 다시 계산하지 않는 것”이다.
읽어주셔서 감사합니다!