GitHub ↗
CHAPTER 07 OF 10
🎯

Context Engineering — Karpathy's 4 Strategies

컨텍스트 엔지니어링 — Karpathy의 4전략

프롬프트 엔지니어링이 '무슨 말을 할 것인가'라면, 컨텍스트 엔지니어링은 '컨텍스트 창을 어떤 정보로 채울 것인가'다 — 이것이 모든 산업용 LLM 앱의 핵심 기술이다.

Context Engineering — Karpathy's 4 Strategies cheatsheet
🍌 NANO BANANA CHEATSHEET · CH 07

Overview

개관

Andrej Karpathy는 2025년 9월에 이렇게 말했다: "사람들은 '프롬프트'를 짧은 태스크 설명으로 생각한다. 하지만 모든 산업용 LLM 앱에서, 컨텍스트 창을 올바른 정보로 채우는 것이 다음 단계를 위한 섬세한 예술이자 과학이다."

LangChain은 이를 공식화해서 4가지 전략으로 정의했다: Write(작성), Select(선택), Compress(압축), Isolate(격리). 이 4가지 전략의 조합이 에이전트 성능을 결정한다.

동시에 중요한 경고가 있다: 컨텍스트가 길수록 좋은 게 아니다. 연구에 따르면 32,000 토큰 이후부터 모델 정확도가 하락하기 시작하고, 120,000 토큰 이후에는 심각한 'context rot'이 발생한다. 컨텍스트 엔지니어링은 '많이 넣는 것'이 아니라 '올바른 것을 전략적으로 넣는 것'이다.

🎯 Learning Goals
  • Write, Select, Compress, Isolate 4가지 컨텍스트 전략을 구분해서 설명할 수 있다
  • U-shaped attention curve가 CLAUDE.md 작성에 미치는 영향을 설명할 수 있다
  • Context rot가 무엇이고 왜 발생하는지 설명할 수 있다
  • Just-in-time retrieval 패턴을 설계하고 구현할 수 있다

Sections

본문

4가지 컨텍스트 전략

LangChain의 Lance Martin이 정형화한 4가지 전략:

전략 무엇을 하는가 도구
Write 지시, 메모리 엔트리, 구조화된 아티팩트 작성 CLAUDE.md, MEMORY.md, JSONL
Select 관련 컨텍스트 청크 선택해서 주입 RAG, Just-in-time retrieval, @import
Compress 토큰 낭비 줄이기 — 요약, 정리 autoDream, 압축 파이프라인
Isolate 무관한 컨텍스트를 별도 창에 격리 서브에이전트, 별도 세션

실전 조합 예시:

  • CLAUDE.md = Write 전략 (핵심 지침 작성)
  • @import = Select 전략 (필요한 문서만 선택적 로드)
  • autoDream = Compress 전략 (중복/오래된 내용 정리)
  • 서브에이전트 = Isolate 전략 (각기 다른 태스크를 깨끗한 컨텍스트로 격리)

U-shaped Attention Curve

LLM의 어텐션 분포는 U자 형태다 — 컨텍스트의 시작에 집중되고, 중간은 상대적으로 약하다.

실용적 함의:

CLAUDE.md의 핵심 규칙은 파일 시작과 끝에 배치: 중간에만 있으면 무시될 가능성이 높다 2.

시스템 프롬프트 구조 최적화:

시작 (고어텐션): Identity + Safety/Security 규칙
중간 (저어텐션): 일반 워크플로우, 스타일 가이드
끝 (고어텐션): 핵심 규칙 반복 + 리마인더

중요 정보는 절대 중간에만 두지 말 것: 세션이 길어지면 중간 내용이 압축에 의해 희석된다

양방향 제약 패턴: Bash(rm -rf *) 금지만 쓰는 것보다, '금지 + 왜 금지인지 + 대신 해야 할 것'을 함께 쓰면 에지 케이스에서도 올바른 판단을 한다.

Context Rot — 컨텍스트가 길수록 성능이 하락하는 현상

Context Rot = 컨텍스트가 길어질수록 LLM 정확도가 하락하는 현상.

실험 결과 (Databricks, Elastic 연구):

  • 관련 정보가 긴 컨텍스트 안에 묻힐 때 정확도 24.2% 하락 (관련 없는 토큰이 마스킹되었을 때도)
  • Llama 3.1 405B: 32,000 토큰부터 하락 시작
  • 120,000 토큰 이후: 심각한 성능 저하

어텐션 메커니즘의 한계: 이것은 공학적으로 완전히 해결할 수 없는 모델 아키텍처의 근본적 제약이다. 컨텍스트 선택과 압축이 선택사항이 아니라 필수인 이유.

토큰 예산 현실:

시스템 프롬프트:     1,500-6,000 토큰 (당신의 직접 제어)
도구 정의 (자동 주입): 5,000-15,000 토큰
컨텍스트 저하 시작:  ~80,000 토큰
심각한 저하:         ~120,000 토큰

실용적 규칙: 컨텍스트 창의 40-60%를 넘기 전에 적극적 압축이나 서브에이전트 격리를 시작하라.

Just-in-Time Retrieval 패턴

Just-in-Time Retrieval = 모든 것을 미리 로드하지 않고, 에이전트가 필요한 시점에 도구로 정보를 가져오는 패턴.

인간의 인지 방식을 모방한다: 모든 책을 암기하는 대신, 어떤 책이 어디 있는지 알고 필요할 때 꺼내 읽는다.

Sourcegraph 실험 결과:

  • 일반 검색 대신 코드 인식 검색: 파일 재현율 0.127 → 0.277 (2.2배)
  • Precision@5: 0.140 → 0.478 (3.4배)
  • 크로스파일 리팩토링: 96 도구 호출/84분 → 5 도구 호출/4.4분

구현 패턴:

# CLAUDE.md에서
## More Detail On-Demand
- DB 스키마: @agent_docs/db_schema.md  ← 필요할 때만 로드
- API 문서: @agent_docs/api_guide.md   ← 필요할 때만 로드
- 빌드 방법: @agent_docs/building.md  ← 필요할 때만 로드

가벼운 식별자 패턴: 파일 경로, 링크, ID를 미리 로드하고, 실제 내용은 도구(Read, WebFetch)로 온디맨드 로드. 컨텍스트를 'index'로 유지하고 'content'는 필요시 로드.

💡 Analogy · 비유
도서관 사서 vs. 암기 천재

컨텍스트 엔지니어링을 두 가지 접근법으로 비교해보자.

나쁜 접근 = 암기 천재 방식: 프로젝트와 관련된 모든 문서, 모든 API 레퍼런스, 모든 히스토리를 컨텍스트에 밀어넣는다. 초반에는 답이 좋다. 하지만 컨텍스트가 길어질수록 Context Rot이 발생하고 점점 엉뚱한 답을 한다.

좋은 접근 = 도서관 사서 방식: 모든 책의 위치를 알지만 전부 암기하지는 않는다. 필요한 것이 생기면 즉시 찾아온다. 컨텍스트에는 '어디에 있는지'(가벼운 식별자)만 두고, 내용은 필요할 때 가져온다. 컨텍스트가 깔끔하게 유지된다.

U-shaped Attention이란 도서관 입구(시작)와 출구(끝) 근처의 책은 잘 기억하지만, 중간 서가의 책은 덜 기억하는 것과 같다. 중요한 것은 입구와 출구 근처에 두어야 한다.

Just-in-Time Retrieval 패턴을 구현하는 컨텍스트 어시스턴트. CLAUDE.md에 포인터만 유지하고, 실제 내용은 필요할 때 로드한다.

python
#!/usr/bin/env python3
"""context-assistant.py — JIT Retrieval 패턴 구현"""
import os
from pathlib import Path

def calculate_context_health(session_tokens: int) -> dict:
    """현재 세션의 컨텍스트 상태를 평가"""
    total_budget = 200_000  # Claude 기본 컨텍스트 윈도우
    system_overhead = 10_000  # 도구 정의 + 시스템 프롬프트
    available = total_budget - system_overhead
    usage_pct = session_tokens / available * 100
    
    status = 'healthy'
    action = None
    
    if usage_pct > 60:
        status = 'warning'
        action = '서브에이전트로 새 태스크 격리 권장'
    if usage_pct > 80:
        status = 'critical'
        action = '즉시 새 세션 또는 서브에이전트로 전환'
    
    return {
        'usage_pct': round(usage_pct, 1),
        'status': status,
        'action': action,
        'tokens_used': session_tokens,
        'tokens_remaining': available - session_tokens
    }

def build_jit_index(project_dir: str = '.') -> str:
    """프로젝트 문서들에 대한 JIT 인덱스 생성 (CLAUDE.md용)"""
    docs_dir = Path(project_dir) / 'agent_docs'
    if not docs_dir.exists():
        return "# agent_docs/ 없음 — 디렉토리를 생성하고 문서를 추가하세요"
    
    index_lines = ["## More Detail On-Demand",
                   "Claude는 필요할 때만 이 파일들을 읽습니다. 모두 미리 로드하지 마세요.\n"]
    
    for md_file in sorted(docs_dir.glob('*.md')):
        line_count = len(md_file.read_text().split('\n'))
        # 파일명에서 설명 추론
        name = md_file.stem.replace('-', ' ').replace('_', ' ').title()
        rel_path = os.path.relpath(md_file, project_dir)
        index_lines.append(f"- {name}: @{rel_path} ({line_count}줄)")
    
    return '\n'.join(index_lines)

def optimize_prompt_cache_structure(content_sections: list) -> list:
    """
    프롬프트 캐싱 최적화를 위한 섹션 순서 조정.
    정적 내용은 앞, 동적 내용은 뒤.
    """
    static = [s for s in content_sections if not s.get('dynamic', False)]
    dynamic = [s for s in content_sections if s.get('dynamic', False)]
    
    ordered = static + dynamic
    
    total_static_tokens = sum(s.get('estimated_tokens', 0) for s in static)
    total_dynamic_tokens = sum(s.get('estimated_tokens', 0) for s in dynamic)
    cached_savings = total_static_tokens * 0.90  # 캐시 히트 시 ~90% 비용 절감
    
    print(f"정적 컨텐츠: {total_static_tokens:,} 토큰 (캐싱 적용)")
    print(f"동적 컨텐츠: {total_dynamic_tokens:,} 토큰 (캐싱 불가)")
    print(f"예상 캐시 절감: {cached_savings:,.0f} 토큰/세션 (90% 히트 기준)")
    
    return ordered

if __name__ == '__main__':
    # 컨텍스트 상태 평가
    health = calculate_context_health(75_000)
    print("=== 컨텍스트 상태 ===")
    print(f"사용: {health['usage_pct']}% | 상태: {health['status']}")
    if health['action']:
        print(f"권장: {health['action']}")
    
    # JIT 인덱스 생성
    print("\n=== JIT 인덱스 (CLAUDE.md 추가용) ===")
    print(build_jit_index('.'))

calculate_context_health()로 현재 세션의 컨텍스트 사용량을 평가하고 60%/80% 임계값에서 경고한다. build_jit_index()는 agent_docs/ 디렉토리를 스캔해서 CLAUDE.md에 추가할 JIT 인덱스를 생성한다. optimize_prompt_cache_structure()는 프롬프트 캐싱 최적화를 위해 정적/동적 섹션을 분리한다.

🏭 현업에서의 평가
컨텍스트 엔지니어링을 이해하는 엔지니어와 그렇지 않은 엔지니어의 차이는 세션이 길어질수록 극명하게 드러난다. 전자는 에이전트가 신뢰할 수 있는 결과를 계속 내놓고, 후자는 에이전트가 점점 엉뚱한 것을 한다.

✅ 시니어가 보는 것

  • Just-in-time retrieval 패턴을 써서 컨텍스트를 최소화하는가
  • 컨텍스트 80% 이상 시 서브에이전트로 격리하는 패턴이 있는가
  • 시스템 프롬프트에서 U-shaped attention을 고려해서 중요 규칙을 처음과 끝에 배치하는가
  • 프롬프트 캐싱을 위해 정적 내용이 앞에 오도록 구조화하는가

⚠️ 레드 플래그

  • 세션 초기에 모든 문서를 한번에 컨텍스트에 로드
  • 32,000 토큰 이상인데도 서브에이전트 격리 없음
  • 중요 규칙이 시스템 프롬프트 중간에만 위치

🎤 예상 인터뷰 질문

  1. Context rot이 왜 어텐션 메커니즘의 근본적 한계인가? 완전히 해결할 수 없는 이유는?
  2. U-shaped attention curve가 CLAUDE.md 작성 방법에 어떤 영향을 미치는가?
  3. Sourcegraph 실험에서 코드 인식 JIT retrieval이 일반 검색보다 크로스파일 리팩토링에서 96 도구 호출을 5 도구 호출로 줄인 이유는?
숙달 vs 익숙함: 단순히 아는 사람은 컨텍스트 창이 크다는 것에 안심한다. 마스터한 사람은 50-80K 토큰에서 이미 Context Rot이 시작된다는 것을 알고, 적극적으로 Write/Select/Compress/Isolate 4전략을 조합해서 컨텍스트를 관리한다.

Key Takeaways

핵심 정리

4전략: W/S/C/I

Write(작성), Select(선택), Compress(압축), Isolate(격리) — 4전략 조합이 컨텍스트 엔지니어링의 전부다.

Context Rot은 실재한다

24.2% 정확도 하락. 32K 토큰부터 시작. 공학적으로 완전히 해결 불가 — 압축과 선택이 필수다.

U-shaped Attention

중요 규칙은 시스템 프롬프트의 처음과 끝에 배치하라. 중간은 어텐션이 낮다.

JIT Retrieval

모든 것을 미리 로드하는 대신, 가벼운 식별자(경로, ID)를 두고 내용은 온디맨드 로드.

Sourcegraph 증거

JIT Retrieval이 크로스파일 리팩토링을 96→5 도구 호출, 84→4.4분으로 단축시켰다.

60%/80% 임계값

컨텍스트 60% 시 서브에이전트 고려, 80% 시 즉시 새 세션 또는 서브에이전트.

정적 앞, 동적 뒤

프롬프트 캐싱 최적화: 시스템 프롬프트(정적)를 앞에, 대화 히스토리(동적)를 뒤에 배치하면 90% 비용 절감.

Karpathy의 정의

Context engineering = 컨텍스트 창을 다음 단계를 위한 올바른 정보로 채우는 섬세한 예술이자 과학.