LLM과의 대화가 길어질수록 한 가지 문제가 반드시 찾아옵니다. 모델이 한 번에 처리할 수 있는 텍스트 양, 즉 컨텍스트 윈도우가 가득 차는 것입니다. 윈도우가 넘치면 가장 오래된 내용부터 잘려 나가고, 모델은 앞서 나눈 중요한 맥락을 잃습니다. 단순히 컨텍스트를 크게 늘리면 해결될 것 같지만, 비용은 토큰 수에 비례해 증가하고, 긴 컨텍스트에서 모델의 집중력(중간 토큰 손실 문제)이 떨어진다는 현실적 제약이 있습니다. 슬라이딩 윈도우, 요약 압축, 선택적 보존, 외부 메모리 연동처럼 서로 다른 전략의 트레이드오프를 이해하고 상황에 맞게 조합하는 것이 실무의 핵심입니다.
컨텍스트 윈도우란 무엇인가
컨텍스트 윈도우(Context Window)는 LLM이 한 번의 추론에서 참조할 수 있는 최대 토큰 수입니다. 시스템 프롬프트, 대화 이력, 사용자의 현재 질문, 모델이 생성한 응답까지 이 안에 모두 들어가야 합니다. 윈도우를 초과하면 API가 오류를 반환하거나, 오래된 내용을 자동으로 잘라 냅니다. 어느 쪽이든 모델은 잘려 나간 내용을 볼 수 없습니다.
중요한 구분이 있습니다. 컨텍스트 윈도우 전체 크기와 실제로 사용 가능한 크기는 다릅니다. 고정 비용으로 항상 들어가는 시스템 프롬프트와 도구 정의 토큰을 제외하면 대화에 쓸 수 있는 공간이 줄어듭니다. 예를 들어 윈도우가 128k 토큰이라도 시스템 프롬프트가 8k를 차지하면 실제 대화 가용 공간은 120k입니다. 여기에 응답 예약(max_tokens)까지 빼면 실질 입력 가용 공간은 더 좁아집니다.
| 모델 | 컨텍스트 윈도우 | 한국어 약 1만 자 환산 | 비고 |
|---|---|---|---|
| Claude Opus 4 / Sonnet 4 | 200,000 토큰 | 약 66페이지 분량 | 프롬프트 캐싱 지원 |
| GPT-4o | 128,000 토큰 | 약 42페이지 분량 | 자동 프롬프트 캐싱 지원 |
| Gemini 2.0 Flash | 1,048,576 토큰 (1M) | 약 350페이지 분량 | Context Caching API 별도 제공 |
| Gemini 2.5 Pro | 1,048,576 토큰 (1M) | 약 350페이지 분량 | 최대 출력 65,536 토큰 |
| GPT-4o mini | 128,000 토큰 | 약 42페이지 분량 | 저비용 옵션 |
토큰 수는 언어마다 다릅니다. 영어는 단어 하나가 대략 1~2 토큰인 반면, 한국어는 형태소 분리 방식에 따라 한 어절이 2~5 토큰이 되는 경우가 많습니다. 실제 서비스에서는 같은 내용을 한국어로 쓰면 영어보다 토큰이 1.5~2배 더 소모된다고 예상하고 설계하는 것이 안전합니다.
왜 컨텍스트를 무한정 늘릴 수 없는가
모델 컨텍스트가 점점 커지고 있는데 왜 관리가 필요할까요? 비용과 품질 두 측면에서 현실적 제약이 있기 때문입니다.
비용 측면에서 입력 토큰 요금은 컨텍스트 길이에 정비례합니다. 10턴짜리 대화를 매번 처음부터 통째로 보내면 11번째 요청의 입력 비용은 1번째 요청의 11배입니다. 1,000번의 대화 세션이 있다면 토큰 누적 비용은 급격히 불어납니다. 프롬프트 캐싱이 이를 부분적으로 완화하지만, 캐시가 적중하지 않는 새 내용의 비용은 그대로입니다.
품질 측면에서 “Lost in the Middle” 현상이 알려져 있습니다. Liu et al.(2023, TACL)의 연구에서 확인된 것처럼, 컨텍스트가 매우 길어지면 모델은 입력의 앞부분과 끝부분에 집중하고, 중간에 있는 정보를 간과하는 경향이 있습니다. 즉 컨텍스트가 길다고 해서 모든 내용을 동등하게 참조하지 않습니다. 중요한 정보를 중간에 두면 놓칠 수 있습니다.
긴 컨텍스트 = 높은 품질이 아닙니다.
컨텍스트를 가득 채우는 것보다, 현재 작업에 실제로 필요한 정보만 선별해 넣는 것이 대부분의 상황에서 더 좋은 응답을 만들어 냅니다. 무한정 쌓는 전략보다 선별과 압축 전략이 품질과 비용 양쪽에서 유리합니다.
세 가지 핵심 전략 비교
긴 대화를 관리하는 접근법은 크게 세 가지입니다. 어느 것이 절대적으로 우월한 것은 없으며 서비스 특성에 따라 조합해 사용합니다.
1. 슬라이딩 윈도우
가장 단순한 방법입니다. 최근 N개의 메시지 또는 최근 K 토큰만 유지하고 그 이전은 버립니다. 구현이 쉽고 컨텍스트 길이가 예측 가능하지만, 잘려 나간 초반 대화의 맥락이 영구히 사라집니다. 서비스 도메인에 따라 치명적 문제가 될 수도, 문제가 안 될 수도 있습니다. 고객 지원 챗봇처럼 “현재 문제 해결”에 집중하는 경우에는 비교적 잘 작동합니다.
2. 요약 압축
대화 이력의 오래된 부분을 LLM으로 요약해 짧은 텍스트로 대체합니다. 맥락의 핵심은 유지하면서 토큰 수를 줄일 수 있습니다. LangChain의 ConversationSummaryMemory가 이 방식의 대표적 구현입니다. 단점은 요약 자체에 추가 API 호출이 필요하고, 요약 품질에 따라 세부 정보가 손실된다는 것입니다. 또한 요약 시점에 컨텍스트가 교체되면 프롬프트 캐시가 깨집니다.
3. 선택적 보존
모든 메시지를 동등하게 취급하지 않고, 중요도 점수를 부여해 높은 점수의 메시지만 선택적으로 유지합니다. MemGPT(Packer et al., 2023)에서 제안된 계층적 메모리 구조가 이 방향의 연구 대표입니다. 구현이 복잡하지만, 슬라이딩 윈도우나 단순 요약보다 정보 손실을 최소화할 수 있습니다.
| 전략 | 구현 난이도 | 정보 보존 | 비용 | 적합 상황 |
|---|---|---|---|---|
| 슬라이딩 윈도우 | 낮음 | 낮음 (오래된 맥락 소실) | 낮음 | 단기 세션, 현재 맥락 중심 서비스 |
| 요약 압축 | 중간 | 중간 (핵심 유지, 세부 손실) | 중간 (요약 API 호출 추가) | 장기 대화, 맥락 연속성 필요 서비스 |
| 선택적 보존 | 높음 | 높음 (중요 메시지 선별 유지) | 중간~높음 | 복잡한 멀티턴, 사용자 선호 추적 |
| 외부 메모리 연동 | 높음 | 매우 높음 (무제한 외부 저장) | 높음 (벡터 DB 인프라 추가) | 영구 메모리, 대규모 지식 베이스 |
중요 메시지 스코어링
선택적 보존 전략의 핵심은 어떤 메시지를 살릴지 결정하는 스코어링 로직입니다. 실무에서 사용하는 스코어링 기준은 다음과 같습니다.
시간 가중치는 최근 메시지일수록 높은 점수를 부여합니다. 가장 단순하고 직관적인 기준이지만 중요한 초반 합의나 핵심 정보가 희생될 수 있습니다. 명시적 중요도 마킹은 사용자가 “이것을 기억해줘”처럼 직접 중요도를 표시하거나, 시스템이 특정 패턴(이름, 날짜, 결정 사항 등)을 감지해 높은 점수를 부여합니다. 참조 빈도는 이후 대화에서 자주 언급된 내용일수록 높은 점수를 부여합니다. 실제로는 이 세 가지를 가중 합산한 복합 점수를 사용합니다.
# 단순 스코어링 예시 (개념 코드)
def score_message(msg, current_turn, total_turns):
# 시간 가중치: 최근일수록 높음
recency = msg.turn_index / total_turns # 0.0~1.0
# 명시적 중요도: 사용자가 "기억해줘" 등 표시 시 가중
explicit = 1.5 if msg.is_marked_important else 1.0
# 참조 빈도: 이후 메시지에서 인용된 횟수
ref_score = min(msg.reference_count * 0.2, 1.0)
return (recency * 0.5 + ref_score * 0.3) * explicit
# 컨텍스트 조립: 점수 상위 N개 + 최근 K개는 항상 포함
preserved = sorted(history, key=score_message, reverse=True)[:n_top]
recent = history[-k_recent:]
context = deduplicate(preserved + recent)외부 메모리(벡터 DB) 연동
컨텍스트 윈도우는 본질적으로 단기 메모리입니다. 대화가 세션을 넘어서거나, 수백·수천 건의 과거 상호작용을 참조해야 할 때는 외부 장기 메모리가 필요합니다. 이 역할을 벡터 데이터베이스가 담당합니다.
동작 방식은 다음과 같습니다. 대화의 각 메시지(또는 요약된 블록)를 임베딩 모델로 벡터화해 벡터 DB에 저장합니다. 새 사용자 입력이 들어오면 그것도 벡터화해, 저장된 벡터들과 유사도 검색을 수행합니다. 가장 유사한 과거 맥락 N개를 검색해 현재 컨텍스트에 삽입합니다. 이 방식을 RAG(Retrieval-Augmented Generation)의 대화 메모리 응용이라고 볼 수 있습니다.
# 외부 메모리 연동 흐름 (개념 코드)
# 1. 대화 저장
def save_to_memory(message, session_id):
embedding = embed(message.content) # 임베딩 생성
vector_db.upsert(
id=message.id,
vector=embedding,
metadata={"session": session_id, "role": message.role,
"timestamp": message.ts, "content": message.content}
)
# 2. 관련 기억 검색
def retrieve_relevant_memory(query, session_id, top_k=5):
query_vec = embed(query)
results = vector_db.query(
vector=query_vec,
filter={"session": session_id}, # 세션 범위 필터
top_k=top_k
)
return [r.metadata["content"] for r in results]
# 3. 컨텍스트 조립
memory_snippets = retrieve_relevant_memory(user_input, session_id)
augmented_context = "n".join(["[과거 대화 참고]"] + memory_snippets)
final_prompt = system_prompt + augmented_context + recent_messages벡터 DB 선택 기준
대화 메모리에 사용할 벡터 DB를 선택할 때 고려할 기준은 다음과 같습니다. 규모가 작은 프로토타입에는 Chroma(로컬 파일 기반, 설치 간단)나 FAISS(Meta 오픈소스, 인메모리 고속 검색)가 적합합니다. 운영 서비스로 전환할 때는 Pinecone(관리형 서비스, 확장성 우수), Weaviate(오픈소스, 하이브리드 검색 지원), Qdrant(Rust 기반, 낮은 레이턴시)를 검토합니다. 이미 PostgreSQL을 사용 중이라면 pgvector 확장으로 추가 인프라 없이 벡터 검색을 시작할 수 있습니다.
토큰 계산 도구와 측정 방법
컨텍스트를 관리하려면 먼저 현재 몇 토큰을 사용하고 있는지 알아야 합니다. 직접 측정하지 않으면 윈도우 초과가 예상치 못한 시점에 발생합니다.
# tiktoken (OpenAI 모델용 공식 토크나이저)
import tiktoken
enc = tiktoken.encoding_for_model("gpt-4o")
token_count = len(enc.encode(text))
# Anthropic Claude 토큰 카운팅 API
response = client.messages.count_tokens(
model="claude-opus-4-5",
system=system_prompt,
messages=messages
)
print(response.input_tokens) # 실제 API 청구 기준과 동일
# 간이 추정 (언어 무관 빠른 추정)
# 영어: 글자 수 / 4 ≈ 토큰 수
# 한국어: 글자 수 / 2 ≈ 토큰 수 (형태소 복잡도 반영)Anthropic은 Claude API에서 count_tokens 엔드포인트를 별도로 제공합니다. 실제 API 호출 전에 토큰 수를 확인할 수 있어 윈도우 초과 방지와 비용 예산 관리에 유용합니다. OpenAI는 tiktoken 라이브러리로 로컬에서 토큰 수를 계산할 수 있으며, API 응답의 usage.prompt_tokens로 실제 청구 기준을 사후 확인할 수 있습니다.
비용 vs 품질 트레이드오프
컨텍스트 관리 전략을 선택할 때 비용과 품질은 항상 반비례하는 긴장 관계에 있습니다. 모든 맥락을 완벽하게 유지하면 비용이 선형이 아닌 가속도로 증가하고, 너무 공격적으로 압축하면 모델이 중요한 맥락을 놓쳐 응답 품질이 떨어집니다.
실무에서 이 균형을 잡는 방법은 서비스 시나리오별로 허용 가능한 정보 손실 수준을 먼저 정의하는 것입니다. 고객 지원처럼 “현재 문제만 해결하면 되는” 시나리오는 슬라이딩 윈도우로 충분합니다. 개인화 코칭이나 장기 프로젝트 어시스턴트처럼 “수 주간의 히스토리가 중요한” 시나리오는 외부 메모리 연동이 필요합니다. 대부분의 서비스는 그 중간 어딘가이며, 요약 압축과 선택적 보존을 조합해 사용합니다.
| 서비스 유형 | 권장 전략 | 예상 비용 절감 | 주의 포인트 |
|---|---|---|---|
| 단발성 질의응답 | 슬라이딩 윈도우 (최근 3~5턴) | 70~90% | 초반 맥락 필요 여부 확인 |
| 세션 내 멀티턴 대화 | 요약 압축 (20턴 초과 시 작동) | 40~60% | 요약 주기와 캐시 적중률 균형 |
| 장기 프로젝트 어시스턴트 | 선택적 보존 + 외부 메모리 | 50~70% | 벡터 DB 인프라 비용 추가 발생 |
| RAG 기반 문서 QA | 검색 메모리 (전체 이력 저장, 필요 시 검색) | 60~80% | 검색 품질이 전체 품질 결정 |
구현 체크리스트
컨텍스트 관리 시스템을 처음 구축하거나 기존 시스템을 개선할 때 아래 항목을 순서대로 점검합니다.
- 현재 서비스의 평균 대화 턴 수와 턴당 평균 토큰 수를 측정한다. 이것이 전략 선택의 기준이 된다
- 컨텍스트 윈도우 사용률 모니터링을 먼저 추가한다. 실제로 문제가 발생하고 있는지 데이터 없이 최적화하지 않는다
- 프롬프트 캐싱을 먼저 적용한다. 구현 비용 없이 고정 컨텍스트(시스템 프롬프트, 도구 정의) 비용을 즉시 절감할 수 있다
- 슬라이딩 윈도우 임계값을 설정한다. 컨텍스트가 윈도우의 80%를 초과하면 트리거되도록 구현한다
- 요약 압축을 추가할 경우 요약 품질을 주기적으로 검사한다. 자동 요약이 핵심 정보를 누락하는지 샘플링한다
- 토큰 카운팅을 API 호출 전에 수행해 윈도우 초과를 사전에 차단하는 가드를 구현한다
- 외부 메모리를 도입할 경우 임베딩 모델과 벡터 DB를 서비스 언어(한국어)에 맞게 선택하고, 검색 품질을 평가 셋으로 검증한다
- 각 전략의 효과를 응답 품질 지표(인간 평가 또는 LLM 자동 평가)와 비용 지표로 함께 측정해 최적 균형점을 찾는다
자주 묻는 질문
- 컨텍스트 윈도우가 초과되면 어떤 일이 생기나요?
- API가 오류(context_length_exceeded 등)를 반환하거나, 설정에 따라 오래된 메시지가 자동으로 잘립니다. 어느 쪽이든 모델은 잘려 나간 내용을 참조할 수 없습니다. 자동 절단은 조용히 일어나므로 모니터링 없이는 품질 저하를 인지하지 못할 수 있습니다.
- Gemini의 1M 토큰 컨텍스트를 쓰면 관리가 필요 없지 않나요?
- 필요합니다. 1M 토큰 입력에 대한 비용은 매우 크고, Lost in the Middle 현상은 컨텍스트가 길수록 심화됩니다. 실제로 모든 정보가 동등하게 참조되지 않으므로, 필요한 정보를 선별해 넣는 것이 1M을 가득 채우는 것보다 응답 품질과 비용 모두에서 유리한 경우가 많습니다.
- 요약 압축 시 어떤 모델로 요약하는 것이 좋나요?
- 요약 자체는 복잡한 추론이 필요 없으므로 저비용 소형 모델(GPT-4o mini, Claude Haiku, Gemini Flash)로도 충분합니다. 비용과 지연을 최소화하면서 핵심 내용을 보존하는 간결한 요약을 생성하도록 프롬프트를 구성합니다. 단, 도메인 특화 전문 용어가 많은 경우 요약 품질을 별도로 검증해야 합니다.
- 벡터 DB 없이도 외부 메모리를 구현할 수 있나요?
- 소규모에서는 가능합니다. 대화 내용을 키워드 기반으로 인덱싱해 파일이나 SQL DB에 저장하고, 검색 시 키워드 매칭으로 관련 내용을 가져오는 방식입니다. 단, 의미 기반 유사도 검색이 안 되므로 다른 표현으로 같은 개념을 물어볼 때 검색이 실패할 수 있습니다. 수백 건 이상의 기록이 필요하다면 벡터 DB로 전환을 권장합니다.
- 프롬프트 캐싱과 컨텍스트 압축을 함께 쓸 수 있나요?
- 함께 쓸 수 있지만 충돌에 주의해야 합니다. 요약 압축은 대화 이력을 교체하므로 그 지점부터 캐시가 깨집니다. 최선의 조합은 고정 컨텍스트(시스템 프롬프트, 도구 정의)는 캐싱으로 처리하고, 가변 대화 이력은 압축 전략으로 관리하는 것입니다. 요약 주기를 너무 자주 하면 캐시 적중률이 떨어지므로 균형을 조정해야 합니다.
모델별 컨텍스트 윈도우 크기와 토큰 가격은 2026년 기준이며 자주 업데이트되므로, 적용 전 Anthropic 공식 문서의 컨텍스트 윈도우 항목에서 최신 값을 확인하세요.
이 글은 Anthropic Claude, OpenAI GPT-4o, Google Gemini의 공개 API 문서, Packer et al.(2023) MemGPT 논문(arXiv:2310.08560), Liu et al.(2023) “Lost in the Middle” 연구(TACL), LangChain 공식 문서 등 공개된 자료를 기반으로 작성되었습니다. 모델별 컨텍스트 윈도우 크기와 가격은 자주 업데이트되므로 적용 시점에 각 제공사의 공식 문서를 확인하시기 바랍니다. 벡터 DB 성능 수치는 환경에 따라 크게 달라집니다.