큰 컨텍스트 창을 믿지 마라: 100k 토큰 임계점과 실무 대응 전략
도입: 200만 토큰이라는 숫자에 속지 마라
벤더들이 "컨텍스트 창 1M, 2M" 하고 광고하는 걸 보면, 이제 RAG 파이프라인에서 청킹 같은 거 신경 안 써도 되는 거 아닌가 싶은 생각이 든다. 그냥 문서 통째로 다 때려넣으면 알아서 잘 답해주겠지, 라고. 실무에서 한 번이라도 긴 세션을 굴려본 사람이라면 그게 착각이라는 걸 안다.
핵심은 간단하다. 광고되는 컨텍스트 창 크기 = 실제로 모델이 똑똑하게 쓸 수 있는 범위가 아니다. 원문(큰 컨텍스트 창을 신뢰하지 마라)에서 짚는 건 컨텍스트 창이 두 구간으로 나뉜다는 점이다. 모델이 예리하게 작동하는 "스마트 구간"과, 앞에서 한 지시를 슬슬 까먹기 시작하는 "둔한 구간". 그 경계가 대략 100k 토큰 부근이라는 얘기다.
이게 왜 지금 중요하냐면, 요즘 코딩 에이전트(Claude Code, Cursor 등)는 토큰을 미친 듯이 소모한다. 파일 몇 개 읽고, 긴 디버깅 세션 한 번 돌리고, 테스트 전체 한 번 실행하면 100k는 우습게 넘긴다. 즉 우리가 일상적으로 굴리는 작업이 자기도 모르게 "둔한 구간"에 진입한다는 거다.
핵심: 100k 임계점과 둔한 구간의 정체
스마트 구간 vs 둔한 구간
비유를 하나 들자면, 회의에 들어가서 처음 10분은 다들 집중해서 안건을 또렷이 기억한다. 그런데 두 시간짜리 회의가 끝나갈 무렵엔 "아 그래서 아까 그 결정이 뭐였죠?" 하는 사람이 나온다. LLM도 비슷하다. 컨텍스트 창 앞쪽 일부 청크는 또렷하게 처리하지만, 창을 채워나갈수록 주의력이 분산되면서 성능이 점진적으로 떨어진다.
원문에서 인용하는 RULER 벤치마크와 Chroma의 context rot 보고서가 이걸 데이터로 보여준다. 요지는 유효 컨텍스트(effective context)는 광고된 숫자의 일부에 불과하고, 창을 채울수록 성능이 떨어진다는 것. 단, 원문에서도 명시하듯 이 연구들은 2024~2025년 자료라 최신 Claude 모델에 그대로 적용된다고 보긴 어렵다. 모델 버전마다 어텐션 구조와 장기 컨텍스트 학습량이 다르기 때문이다. 그래서 "100k"라는 숫자도 절대값이라기보단 경험적 가이드라인으로 받아들이는 게 맞다.
왜 잊어버리는가 — Attention 관점
Transformer의 self-attention은 입력 토큰 전부에 대해 서로의 관련도를 계산한다. 토큰이 N개면 attention 계산은 대략 N² 스케일로 늘어난다. 문제는 토큰이 많아질수록 "지금 이 작업에 진짜 중요한 토큰"에 쏠려야 할 주의력이, 관련 없는 수많은 토큰들과 나눠 가지게 된다는 점이다.
원문 HN 댓글 중에 이걸 잘 짚은 게 있다. "컨텍스트 창 안에서 어떤 것이 자주 등장하면, 설령 틀린 것이어도 가중치가 생긴다." 즉 디버깅 세션에서 실패한 접근법이 컨텍스트에 계속 쌓이면, 모델이 그 실패한 접근을 자꾸 다시 시도하는 현상이 생긴다. 절대적인 컨텍스트 크기보다 창 안에 찌꺼기와 잘못된 방향 지시가 쌓여서 정작 중요한 내용을 덮어버리는 것이 더 큰 문제라는 지적이다. 이거 실무에서 정말 자주 겪는다.
실무 관점: 어디서 터지고, 어떻게 막는가
흔한 함정 1 — 코딩 에이전트가 둔한 구간에서 압축을 시작한다
Claude Code의 auto-compact가 대표적이다. 세션이 길어지면 기록을 요약하고 새로 시작하는 기능인데, 함정은 이미 둔한 구간에 들어간 다음에 작동한다는 점이다. 게다가 요약을 만드는 모델 자체가 이미 성능이 저하된 상태다. 멍청해진 모델이 만든 요약을 들고 다음 세션을 시작하니, 인계 품질이 떨어진다.
실제로 긴 세션에서 이런 메시지를 만나게 된다:
Context low (8% remaining) · Run /compact to compact & continue
이게 뜨기 전에 이미 작업 품질이 떨어지고 있었다는 게 핵심이다. 그리고 도구 호출이 실패하기 시작하면 이런 것도 본다(에이전트/하네스마다 메시지는 다르다):
Error: Input is too long for requested model.
prompt token count (215431) exceeds the maximum (200000)
이 에러를 만났다면 이미 한참 전부터 모델이 흐리멍덩해진 상태로 작업하고 있었다고 봐야 한다.
흔한 함정 2 — "메모리 시스템"이 오히려 모델을 멍청하게 만든다
원문 댓글에서 강하게 동의가 모인 지점이다. "모델에는 메모리가 있는 게 아니라 컨텍스트만 있다." 관련 없는 사실을 메모리랍시고 컨텍스트에 계속 밀어 넣으면, 정작 현재 문제에 쓸 컨텍스트가 줄어든다. 방해가 적을수록 결과가 좋아진다는 것.
한 댓글은 이런 웃픈 상황도 공유한다 — Opus가 메모리에 뭔가 계속 써놓긴 하는데, 정작 같은 실수를 반복하기 전에 그 메모리를 확인하는 걸 까먹는다. 그래서 "메모리 확인하라고 기억해!"가 또 메모리로 저장된다. 잘 작동하는 시스템이 아니라는 거다.
대응 전략 1 — written artifact로 정보를 세션 밖에 빼라
가장 실용적인 처방은 자동 요약에 기대지 말고, 사람이 직접 쓴 명세(spec)를 다음 세션에 인계하는 것이다. 직접 쓴 명세는 자동 요약보다 신호가 강하다. 무엇이 중요한지 사람이 직접 결정했기 때문이다.
예를 들어 작업 시작 전에 이런 식으로 PRD나 계획을 Markdown으로 남기고 저장소에 커밋한다:
# 작업 명세: 결제 모듈 리팩토링
## 목표
- PaymentService의 동기 호출을 비동기 큐 기반으로 전환
## 이미 시도했고 실패한 접근 (다시 하지 말 것)
- Redis Pub/Sub 직접 사용 → at-least-once 보장 안 됨
- 트랜잭션 내부에서 큐 발행 → 롤백 시 유령 메시지 발생
## 확정된 방향
- Transactional Outbox 패턴 사용
- 편집 대상: src/payment/outbox.ts, src/payment/PaymentService.ts
## 체크리스트
- [ ] Outbox 테이블 마이그레이션
- [ ] Outbox poller 구현
- [ ] 기존 동기 호출 제거
핵심은 "실패한 접근" 섹션이다. 이걸 명시해두면 새 세션에서 모델이 같은 실패를 반복하는 걸 막는다. 이게 원문에서 말하는 breadcrumb(빵부스러기) 접근이다 — 다음 세션이나 다음 사람이 깔끔하게 이어받을 산출물을 남기는 것.
대응 전략 2 — 메인 스레드는 조율만, 무거운 작업은 하위 에이전트로
원문 댓글 중 가장 인사이트 있던 기법이다. 사용자와의 최상위 대화 스레드에서는 도구 호출을 막고, 토큰을 잡아먹는 작업(파일 읽기, 데이터 수집, 테스트 실행)은 하위 에이전트의 재귀 호출 안에서만 돌린 뒤 요약된 결과만 메인 스레드로 반환하는 방식이다.
이렇게 하면 하위 에이전트가 5천만 토큰을 태워도 루트 대화 스레드는 10만 토큰도 안 건드릴 수 있다. 100만 LOC 코드베이스에서도 메인 대화는 스마트 구간에 계속 머무른다. 개념을 의사코드로 표현하면:
# 안티패턴: 모든 걸 평면 컨텍스트에 다 들고 다님
main_context = []
main_context += read_file("a.ts") # +20k 토큰
main_context += read_file("b.ts") # +30k 토큰
main_context += run_tests() # +50k 토큰
# → 메인 스레드가 순식간에 둔한 구간으로
# 권장: 메인은 조율, 무거운 작업은 격리
def main_agent(task):
# 도구 호출 금지. sub_agent 결과 요약만 받음
summary = sub_agent(task="b.ts 분석 후 핵심만 보고")
# summary는 2~3k 토큰. 메인은 스마트 구간 유지
return decide_next_step(summary)
Claude Code에서는 이걸 부분적으로 자동으로 한다. "컨텍스트 많이 먹겠다" 싶은 휴리스틱이 작동하면 하위 에이전트(subagent)로 넘기는 식이다. 데이터 수집·집계를 하위 에이전트에 던지고 요약만 꺼내오는 패턴을 자주 볼 수 있다.
다만 트레이드오프도 있다. 원문 댓글에서 솔직하게 짚듯 재귀 깊이 1을 넘어서면 실제 성능 이득을 보기 어렵다. 외부의 기호적 재귀는 최전선 모델이 학습한 대상이 아닌 듯하다는 관찰이다. 그리고 하위 에이전트가 매번 "부트스트랩"하는 재작업 비용이 든다. 그래도 거대한 평면 컨텍스트를 들고 다니는 것보단 훨씬 효율적이라는 게 중론이다.
RAG 파이프라인이라면
RAG 운영자 입장에서 시사점은 분명하다. "컨텍스트 창 커졌으니 청킹/리랭킹 대충 해도 된다"는 유혹을 거부해야 한다. 검색해온 청크를 무작정 많이 넣을수록, 관련 없는 청크가 정작 중요한 청크의 주의력을 빼앗는다. top_k를 늘리는 게 항상 정답이 아니다. 리랭커로 정말 관련 높은 소수의 청크만 추리고, 컨텍스트를 예산처럼 다루는 게 맞다. 도움이 되는 부분은 앞쪽 일부 청크라고 가정하고 설계하는 편이 안전하다.
정리: 무엇을 봐야 하는가
한 줄 요약: 컨텍스트 창 크기는 마케팅 숫자에 가깝다. 실제로 봐야 할 건 "유효 컨텍스트를 스마트 구간 안에 유지하는 워크플로"다.
- 코딩 에이전트를 굴리는 사람: 긴 세션을 무작정 이어가지 말고, 작업 단위마다 직접 쓴 명세(특히 "실패한 접근" 기록)를 남기고 새 세션으로 인계하라. auto-compact는 보험이지 전략이 아니다.
- RAG 파이프라인 운영자: 컨텍스트 창이 커졌다고 청킹/리랭킹을 느슨하게 하지 마라. top_k는 신중하게. 관련 없는 청크는 노이즈다.
- 에이전트 설계자: 메인 대화는 조율자로, 토큰 먹는 작업은 하위 에이전트로 격리하라. 단 재귀 깊이는 1로 제한하는 게 현실적이다.
마지막으로 균형을 위해 덧붙이면 — 원문 댓글에는 "최신 Opus(예: 4.8)에서는 50만 토큰을 편하게 넘긴 세션도 있었다"는 반론도 있다. 모델 버전, 하네스, 작업 종류에 따라 체감 임계점은 크게 다르다. 그러니 "100k"를 신앙처럼 외우지 말고, 본인 환경에서 어느 지점부터 회상 실수가 시작되는지 직접 로깅해서 감을 잡는 것이 가장 확실하다. 결국 컨텍스트 엔지니어링은 아직 다들 숙련도만 다른 땜장이 단계라는 자조 섞인 댓글이, 어쩌면 가장 정직한 현실 인식일지도 모른다.