시맨틱 캐시는 "비밀번호를 어떻게 재설정하나요"라는 질문에 "로그인을 잊어버렸어요"에 대해 이미 생성해 둔 응답을 돌려준다. 둘이 같은 뜻이기 때문이다. 요청의 정확한 문자열을 매칭하는 대신, 요청을 임베딩하고 저장된 요청 중 임베딩이 충분히 가까운 것을 찾은 다음, 모델을 호출하지 않고 그 캐시된 답을 돌려준다. 잘 작동하면 모델 호출을 통째로 건너뛴다. 토큰도, 지연도, 비용도 없다. "충분히 가까운지"를 잘못 판단하면 사용자가 묻지 않은 질문에 자신 있는 답을 내놓게 된다.

핵심 재구성은 이렇다. 일반 캐시는 동일성으로 키를 잡지만 시맨틱 캐시는 유사도로 키를 잡고, 유사도는 사실이 아니라 우리가 설정하는 임계값이다. 그 임계값이 위험 표면 전체다. 느슨하게 잡으면 틀린 답을 내놓게 되고, 빡빡하게 잡으면 거의 아무것도 캐시하지 못한다. 시맨틱 캐시를 잘 운영하는 일은 전부 이 다이얼을 관리하는 일이다.

마법을 걷어낸 작동 방식

메커니즘은 세 단계다. 들어오는 요청을 Amazon Titan Text Embeddings나 Bedrock의 Cohere 같은 임베딩 모델로 벡터로 만든다. 벡터 스토어에서 이전에 본 요청 중 가장 가까운 것을 검색한다. 가장 가까운 이웃의 코사인 유사도가 임계값 이상이면 캐시된 응답을 돌려주고, 그렇지 않으면 모델을 호출한 다음 새 요청의 임베딩과 응답을 다음번을 위해 저장한다.

vec = embed(request)
hit = vector_store.nearest(vec)
if hit and hit.similarity >= THRESHOLD:
    return hit.cached_response      # no model call
answer = model.invoke(request)
vector_store.put(vec, answer)
return answer

벡터 스토어는 이미 운영 중인 무엇이든 될 수 있다. OpenSearch, pgvector를 쓰는 Aurora, 작은 핫셋을 위한 인메모리 인덱스도 좋다. 어려운 부분은 저장소가 아니다. THRESHOLD 값과 애초에 캐시에 무엇을 들여보낼지가 어렵다.

잘못된 히트 위험이 게임의 전부다

잘못된 히트란 두 요청이 임베딩 공간에서 가깝지만 서로 다른 답이 필요한 경우다. "EU 고객 환불 정책이 무엇인가요"와 "US 고객 환불 정책이 무엇인가요"는 벡터 공간에서 위험할 만큼 가까이 앉아 있을 수 있지만 서로 다른 응답을 요구한다. 느슨한 임계값은 US 사용자에게 EU 답변을 돌려주며, 그것도 모델이 전혀 개입하지 않았으므로 완전히 자신 있는 태도로 그렇게 한다.

이것은 그냥 모델 호출 비용만 드는 일반적인 캐시 미스보다 나쁘다. 잘못된 히트는 맞아 보이지만 틀린 답이라는 비용을 물린다. 그러니 임계값은 추측이 아니라 실제 트래픽에 맞춰 튜닝해야 하고, 빡빡한 쪽으로 편향되어야 한다. 미스는 저렴하지만 잘못된 히트는 지원 티켓이나 컴플라이언스 문제가 될 수 있다. 뭔가 중요한 것에 캐시를 맡기기 전에 레이블이 붙은 표본에서 잘못된 히트율을 측정하라.

캐시하지 말아야 할 것

시맨틱 캐싱은 안정적이고, 일반적이고, 공유된 지식에는 맞고 그 외에는 맞지 않는다. "데이터를 어떻게 내보내나요"에 대한 답은 모두에게 동일하므로 캐시하라. 누가 묻는지 또는 언제 묻는지에 따라 달라지는 것은 캐시하지 마라. 코드로 강제할 가치가 있는 원칙들이다.

  • 신원 경계를 넘어 캐시하지 마라. 캐시를 테넌트별로 키를 잡거나, 개인화된 것은 제외하라. 호출자를 무시하는 공유 캐시는 결국 한 고객의 답을 다른 고객에게 내놓게 된다.
  • 시간에 민감한 답은 캐시하지 마라. 잔액, 주문 상태, 재고는 우리 밑에서 계속 바뀐다. 여기서 오래된 히트는 갓 만들어진 버그다.
  • 검색이 필요 없는 것을 캐시하고, 검색이 많이 필요한 것은 캐시하지 마라. 답이 변하는 문서에 의존한다면, 최종 응답이 아니라 임베딩 조회를 캐시하라.

모두가 건너뛰는 부분, 무효화

컴퓨팅에서 가장 오래된 농담은 캐시 무효화가 두 가지 어려운 문제 중 하나라는 것이고, 시맨틱 캐시도 예외가 아니다. 근본적인 진실이 바뀌면, 즉 정책이 갱신되거나, 가격이 움직이거나, 문서가 수정되면, 옛 진실에 기댔던 캐시된 답은 모두 이제 틀린 답이 되고, 우리가 그것을 제거할 때까지 계속 서비스된다.

오래된 답이 스스로 만료되도록 항목에 충분히 짧은 TTL을 부여하고, 근본 진실을 바꾸는 이벤트에 연결된 명시적 삭제 경로를 추가하라. 새 정책 버전을 게시하면 옛 정책 위에 만들어진 캐시 조각을 무효화해야 한다. 무효화 경로가 없으면 시맨틱 캐시는 호출을 절약하는 것을 넘어서, 우리 제품을 조용히 어제의 사실에 고정시킨다.

결론

시맨틱 캐싱은 표현만 다를 뿐 같은 질문에 대해서는 비용과 지연 면에서 진짜 승리이며, 개인화되거나 시간에 민감하거나 변경될 수 있는 것에 대해서는 자충수다. 메커니즘은 사소하다. 임베딩, 검색, 임계값. 엔지니어링은 전적으로 임계값, 범위 규칙, 무효화 경로에 있다. 실제 레이블이 붙은 트래픽으로 임계값을 튜닝하고, 안정적인 공유 지식만 캐시하고, 진실을 움직이는 이벤트에서 무효화하라. 이 세 가지를 하면 캐시는 스스로 값을 한다. 건너뛰면 모델이 옳은 답을 낼 수 있었을 속도보다 더 빠르게 틀린 답을 내놓는다.

이어서 읽으면 좋은 글

부하 상태에서 벡터 스토어와 그 축출을 운영하는 플랫폼 측면은 ercan.cloud의 클라우드 현장 노트에서 다루고, 허브는 ercanermis.com에 있다.