컨텍스트 윈도우가 커지면서 몇 년 전에는 존재하지 않았던 설계 질문이 생겨났습니다. 모델이 한 번에 100페이지를 읽을 수 있다면, 여전히 검색(retrieval)이 필요할까요?
때로는 그렇지 않습니다. 하지만 대개는 그렇습니다. 이 글에서는 Claude에게 문서를 제공하는 세 가지 방법(stuff, cache, retrieve)을 최소한의 Python 코드로 안내하고 비용을 비교하는 방법을 간략하게 설명합니다. 여기에 있는 코드는 Anthropic 문서에서 작성된 스케치일 뿐 테스트된 라이브러리가 아니므로, 어떤 것을 복사하기 전에 현재 문서를 참조하여 매개변수 이름과 가격을 확인하세요.
토큰 개수 세기부터 시작하기
어떤 접근 방식을 선택하기 전에, 실제 자료의 크기가 얼마나 되는지 알아내는 것이 중요합니다. SDK를 사용하면 요청을 실행하지 않고도 토큰 수를 셀 수 있습니다:
import anthropic
client = anthropic.Anthropic()
...
만약 그 숫자가 모델의 컨텍스트 윈도우에 비해 작은 비율이라면, 긴 컨텍스트가 활용 가능합니다. 만약 한계치에 가깝거나 코퍼스(corpus) 자체가 훨씬 더 크다면, 검색(retrieval)만이 유일한 현실적인 선택지입니다.
옵션 1: 모든 것을 프롬프트에 넣고 캐싱하기 (put it all in the prompt, and cache it)
핸드북, 제품 사양서, 계약 템플릿처럼 여러 요청에서 공유되는 안정적인 문서 세트의 경우, 전체 내용을 매번 전송하고 이를 캐싱하도록 표시할 수 있습니다. 그러면 반복되는 요청은 전체 비용을 다시 지불하는 대신 처리된 접두사(prefix)를 재사용합니다.
response = client.messages.create(
model="claude-sonnet-5-5",
max_tokens=500,
...
캐싱을 성공적으로 구현하는 세 가지 습관이 있습니다:
- 안정적인 콘텐츠를 먼저, 변경되는 콘텐츠를 나중에 배치하세요. 캐시는 접두사(prefix)를 기준으로 일치합니다. 상단 근처에 타임스탬프나 사용자 이름을 넣으면 이 기능을 무력화시킵니다.
- 사용량 필드를 확인하세요. 두 번째 호출 및 그 이후의 호출에서
cache_read_input_tokens 값이 커져야 합니다. 만약 이 값이 0으로 유지된다면, 접두사 중 어떤 것이 변경되고 있다는 의미입니다.
- 한계를 파악하세요. 캐싱이 적용되기 전에 최소한의 접두사 길이가 필요하며, 사용되지 않으면 짧은 시간 후에 캐시 항목이 만료됩니다. 둘 다 모델마다 다르므로 문서를 확인해야 합니다.
옵션 2: 청킹 및 검색 (chunk and retrieve)
코퍼스(corpus)가 크거나, 자주 변경되거나, 사용자별 권한을 준수해야 하는 경우, 검색 증강 생성(Retrieval-Augmented Generation)이 더 적합합니다. 문서를 청크(chunk)로 분할하고, 각 질문에 중요한 몇 가지 정보만 찾아내어 그것들만 전송합니다.
단락을 유지하고 작은 중복(overlap)을 추가하는 간단한 청커입니다:
def chunk(text, max_chars=3000, overlap=300):
paragraphs = text.split("\n\n")
chunks, current = [], ""
...
그런 다음 검색 및 프롬프트 조립이 이루어집니다. 여기서 embed는 사용자가 사용하는 임베딩 모델(embedding model)을 의미하며, 이는 별도의 선택 사항입니다:
import numpy as np
def top_chunks(question, chunks, chunk_vectors, k=5):
...
검색(Retrieval)은 자체적인 실패 모드(failure mode)를 가지고 있습니다. 적절한 청크가 상위 5개에 순위가 매겨지지 않을 수 있으며, 여러 섹션에 걸쳐 있는 답변이 잘릴 수 있습니다. 구축하는 데만 시간을 할애하지 말고, 평가하는 데 시간을 배정하세요.
대략적인 비용 비교
가격은 변하므로 구체적인 금액을 제시하지 않겠습니다. 이 헬퍼 함수는 사용자가 직접 숫자를 입력하도록 되어 있습니다. 쓰기(write) 및 읽기(read) 배율기는 캐시된 입력이 일반 입력에 비해 어떻게 청구되는지를 설명하므로, 현재의 가격 페이지에서 가져가세요:
def monthly_input_cost(
doc_tokens, calls_per_month, price_per_mtok,
cache_write_mult=None, cache_read_mult=None,
...
사용자 자신의 문서 크기와 질문 볼륨에 대해 실행한 후, 각 호출마다 몇천 개의 토큰만 전송하는 검색 경로와 비교하세요. 두 가지 주의사항이 있습니다. 캐싱 항목은 만료되므로, 트래픽이 적은 앱의 경우 이 단순화된 함수가 가정하는 것보다 더 자주 캐시를 재작성할 것입니다. 그리고 검색에는 토큰 외의 비용이 있습니다: 임베딩(embeddings), 벡터 스토어(vector store), 인덱스를 최신 상태로 유지하기 위한 엔지니어링 시간입니다.
제가 선택하는 방법
| 상황 | 저는 ~에 기울일 것입니다 |
|---|
| 작고 안정적인 코퍼스, 많은 질문 | 캐싱을 이용한 긴 컨텍스트 |
| ... | |
| 어떤 것을 선택하든, 자체 질문으로 테스트하세요. 모델은 매우 긴 입력 내부에 묻힌 세부 사항을 놓칠 수 있으며, 알려진 답변이 있는 실제 질문의 작은 테스트 세트가 어떤 벤치마크(benchmark)보다 더 많은 정보를 제공할 것입니다. | |
로깅해야 할 것
어떤 접근 방식을 사용하든, 호출(call)마다 다음 사항들을 기록해야 합니다: 입력 토큰(input tokens), 읽고 쓰인 캐시된 토큰(cached tokens read and written), 출력 토큰(output tokens), 지연 시간(latency), 그리고 포함된 청크 또는 문서가 무엇인지. 비용이나 품질이 변동할 때, 이 필드들이 그 이유를 알려줄 것입니다.
저는 Claude 컨텍스트 윈도우 제한 및 비용 효율적 패턴 (Claude context window limits and cost-smart patterns)에서 창 크기(window sizes)와 비용 패턴에 대해 더 깊이 다루었습니다.
단일 프롬프트에 넣어보려고 시도했던 가장 큰 문서 세트의 크기는 어느 정도였으며, 그것이 잘 유지되었나요? 어떤 것이 효과가 있었는지 듣고 싶습니다.
저는 AI Hive의 AI 구현 전문가(AI Implementation Specialist)인 Darius Tran이며, 기업 팀을 위해 AI 에이전트(AI agents)를 프로덕션 환경에 도입하는 작업을 하고 있습니다.