JIT 검색과 신선 컨텍스트 전략
두 가지 정보 로딩 철학
섹션 제목: “두 가지 정보 로딩 철학”루프가 필요로 하는 정보를 컨텍스트에 올리는 방법은 크게 두 가지 철학으로 나뉜다.
사전 로딩(Pre-loading): 루프 시작 전에 필요할 것으로 예상되는 모든 정보를 컨텍스트에 미리 적재한다. RAG(검색 증강 생성)의 전통적 방식이 이에 해당한다. 쿼리가 들어오면 관련 문서를 검색해 컨텍스트에 추가하고 모델을 호출한다.
JIT 로딩(Just-In-Time Loading): 파일 경로, 문서 ID 같은 식별자(identifier) 만 컨텍스트에 유지하고, 실제 내용은 모델이 필요하다고 판단한 순간에 도구 호출로 가져온다.
이 두 방식의 차이는 단순한 구현 선택이 아니다. 컨텍스트 효율성과 정보 신선도에 근본적으로 다른 결과를 낳는다.
┌─────────────────────────────────────────────────────────────┐│ 사전 로딩 vs JIT 로딩 비교 │├────────────────┬───────────────────────┬────────────────────┤│ 특성 │ 사전 로딩 (Pre-load) │ JIT 로딩 │├────────────────┼───────────────────────┼────────────────────┤│ 컨텍스트 크기 │ 크다 (전체 로드) │ 작다 (식별자만) ││ 도구 호출 수 │ 적다 │ 많다 ││ 정보 신선도 │ 로드 시점 기준 │ 항상 최신 ││ 실패 지점 │ 불필요 정보 적재 │ 검색 실패 가능성 ││ 적합한 상황 │ 짧은 루프, 고정 문서 │ 긴 루프, 변하는 파일│└────────────────┴───────────────────────┴────────────────────┘JIT 검색: 식별자를 stable context로
섹션 제목: “JIT 검색: 식별자를 stable context로”JIT 검색의 핵심 아이디어는 컨텍스트에 내용이 아니라 주소를 저장하는 것이다. 파일의 전체 내용 대신 파일 경로를 저장하고, 필요할 때 read_file 도구로 가져온다. Anthropic의 컨텍스트 엔지니어링 가이드에서 이를 “파일 경로 등 식별자를 stable context로 유지하고 런타임에 로드”하는 방식으로 설명한다.
이 방식이 효과적인 이유가 있다. 파일 경로는 수십 토큰이지만 실제 파일 내용은 수천~수만 토큰이다. 루프가 10개의 소스 파일을 다룬다면, 사전 로딩 시 수만 토큰이 컨텍스트를 채우지만 JIT 방식에서는 경로 목록만 보관하다가 각 파일을 실제로 편집할 때만 읽는다.
# 개념 이해용 의사 코드이며 실제 API와 다를 수 있습니다.
# 사전 로딩 방식 (비효율)def preload_context(file_list: list[str]) -> list: messages = [] for path in file_list: content = read_file(path) # 모든 파일을 즉시 로드 messages.append({ "role": "user", "content": f"파일 {path}:\n{content}" # 수만 토큰 추가 }) return messages
# JIT 방식 (효율적)def jit_context(file_list: list[str]) -> list: # 식별자(경로)만 컨텍스트에 유지 — 수십 토큰 file_index = "\n".join(f"- {p}" for p in file_list) return [{ "role": "system", "content": f"작업 가능한 파일 목록:\n{file_index}\n\n필요할 때 read_file 도구로 내용을 가져오세요." }]
# 루프 내에서 모델이 read_file을 스스로 호출해 필요한 파일만 로드신선 컨텍스트(Fresh Context) 전략
섹션 제목: “신선 컨텍스트(Fresh Context) 전략”신선 컨텍스트 전략은 맥락 부패 문제를 압축(compaction)으로 해결하는 대신 원천 차단한다. 매 루프 이터레이션 또는 매 루프 사이클 시작 시 컨텍스트를 초기화하고, 지속할 정보만 안정적인 소스(파일)로부터 새로 주입한다.
Geoffrey Huntley가 “Ralph” 패턴으로 정리한 이 접근은 그 극단적 형태를 잘 보여준다.
while :; do cat PROMPT.md | claude-codedone이 한 줄짜리 루프는 다음을 함축한다.
- 매 이터레이션 컨텍스트 초기화. 이전 루프의 컨텍스트가 다음 루프로 이어지지 않는다.
- PROMPT.md가 stable context. 모든 중요한 지시, 목표, 상태가 PROMPT.md 파일에 담겨 있다.
- 모델은 매번 새 눈으로 작업을 본다. 이전 루프의 잘못된 추론이 누적되지 않는다.
# 개념 이해용 의사 코드이며 실제 API와 다를 수 있습니다.
def ralph_loop(prompt_file: str = "PROMPT.md"): """ 신선 컨텍스트 전략: 매 이터레이션마다 컨텍스트를 초기화. 맥락 부패가 누적될 수 없다. """ while True: # 매번 PROMPT.md에서 최신 지시 로드 (신선 컨텍스트) prompt = read_file(prompt_file)
# 컨텍스트는 이번 이터레이션에만 존재 messages = [{"role": "user", "content": prompt}] response = model.generate(messages)
# 결과를 파일 시스템에 반영 (코드 수정, 노트 작성 등) apply_response(response)
# 다음 이터레이션 조건 확인 if is_done(): break신선 컨텍스트 전략의 전제 조건
섹션 제목: “신선 컨텍스트 전략의 전제 조건”신선 컨텍스트 전략은 강력하지만 두 가지 전제가 필요하다.
첫째, 중요한 상태는 모두 외부 파일에 저장되어야 한다. 컨텍스트가 초기화되면 이전 이터레이션의 추론 과정은 사라진다. 다음 이터레이션에 필요한 정보는 NOTES.md, PROMPT.md, 또는 코드 파일 자체에 기록되어 있어야 한다. 이는 챕터 5-4에서 다룬 파일 기반 장기 메모리와 직결된다.
둘째, PROMPT.md(또는 안정적인 사양 파일)가 단일 진실 공급원이어야 한다. 매 이터레이션에 재주입되는 컨텍스트가 일관성 없거나 최신 상태가 아니면, 신선 컨텍스트의 장점이 사라진다.
| 전략 | 맥락 부패 | 정보 손실 위험 | 구현 복잡도 |
|---|---|---|---|
| 누적 컨텍스트 | 높음 | 낮음 | 낮음 |
| Compaction | 중간 | 중간 | 중간 |
| 신선 컨텍스트 | 없음 | 높음 (설계 잘못 시) | 중간 |
| JIT + 신선 컨텍스트 | 없음 | 낮음 (설계 잘 됐을 때) | 높음 |
언제 어느 전략을 쓸까
섹션 제목: “언제 어느 전략을 쓸까”두 전략은 배타적이지 않다. 실제 프로덕션 시스템은 보통 조합해서 쓴다.
- 단일 태스크, 짧은 루프: 누적 컨텍스트로 충분. JIT나 신선 컨텍스트 불필요.
- 복잡한 코딩 에이전트: JIT 파일 로딩 + compaction 조합. 파일 내용은 필요 시 로드, 오래된 도구 결과는 주기적 압축.
- 반복 실행 루프(Ralph 패턴): 신선 컨텍스트. PROMPT.md와 NOTES.md에 모든 상태 외부화.
- 멀티에이전트, 장기 연구: JIT 검색 + 외부 벡터 DB + 서브에이전트 격리.
Anthropic의 컨텍스트 엔지니어링 가이드는 “파일 경로 등 식별자를 컨텍스트에 유지하고, 실제 내용은 런타임에 로드”하는 JIT 패턴을 특히 코딩 에이전트에서 효과적인 전략으로 제시한다.
컨텍스트는 유한한 자원이다. 그 자원을 어떻게 채울지 — 무엇을 미리 올리고, 무엇을 필요할 때 꺼내고, 무엇을 이터레이션 간 유지할지 — 는 루프 엔지니어가 내려야 하는 핵심 설계 결정이다.
참고 자료
- Anthropic — Effective context engineering for AI agents — 접속 2026-06-30
- Geoffrey Huntley — Ralph Wiggum as a software engineer — 접속 2026-06-30
- Geoffrey Huntley — everything is a ralph loop — 접속 2026-06-30
- OpenAI — Unrolling the Codex agent loop — 접속 2026-06-30