Appearance
컨텍스트 격리와 오프로딩
이 장에서 얻는 것
- 서브에이전트 격리가 "왜" 메인 에이전트의 컨텍스트를 지켜주는지, 그리고 그 대가로 무엇을 지불하는지(토큰 배수, 동기화 비용)
- 파일시스템 오프로딩과 구조화 노트테이킹을 언제 compaction 대신 선택해야 하는지
- Anthropic의 initializer agent /
claude-progress.txt패턴을 우리 빌더 에이전트 설계에 어떻게 적용하는지 - 실무에서 자주 터지는 실패 모드와 이를 계측하는 SLI
왜 문제가 되는가
컨텍스트 윈도우는 유한하고, 토큰이 늘어날수록 모델의 attention이 관련 정보에 집중하기 어려워진다(이 현상 자체는 Context Rot에서 다룬다). 이 장과 Compaction과 요약은 같은 문제를 서로 다른 시점에서 다룬다.
- Compaction은 컨텍스트가 이미 차버린 뒤 압축한다 — 대화 기록을 요약해 재초기화하는 사후 처리다.
- 격리/오프로딩은 애초에 컨텍스트에 들어오지 않도록 막는다 — 정보를 별도의 컨텍스트 윈도우(서브에이전트)나 컨텍스트 바깥 저장소(파일시스템)에 두고, 필요한 결과물만 메인 스레드로 들여온다.
Anthropic의 엔지니어링 블로그는 이 구분을 명시적으로 제시한다. 서브에이전트는 "탐색을 위해 수만 토큰 이상을 쓰더라도, 압축되고 정제된 요약(보통 1,000~2,000 토큰)만 반환"하며, 이를 통해 "상세한 탐색 컨텍스트는 서브에이전트 내부에 격리된 채로 남고, 리드 에이전트는 결과를 종합·분석하는 데 집중"할 수 있다.[^ctx-eng] 즉 격리·오프로딩은 compaction이 처리해야 할 원본 트래픽의 양 자체를 줄이는 상류(upstream) 대책이고, compaction은 그래도 남은 것을 하류(downstream)에서 정리하는 대책이다. 둘은 대체재가 아니라 파이프라인의 서로 다른 단계다.
이 격리에는 대가가 있다. Anthropic이 공개한 멀티 에이전트 리서치 시스템 사례에서, 서브에이전트를 두는 멀티 에이전트 구성은 "표준 채팅 대비 약 15배 더 많은 토큰"을 사용했다.[^multi-agent] 성능 이득(내부 리서치 평가에서 단일 에이전트 대비 90.2% 개선)이 이 비용을 정당화했지만, 이는 "결과의 가치가 비용을 상회하는 고부가가치 작업"에 한정된 판단이었다는 점을 같은 글이 명시한다.[^multi-agent] 격리를 도입할 때마다 이 트레이드오프—토큰 비용 대 컨텍스트 청정도—를 재확인해야 한다. Part 1의 단일 vs 멀티 에이전트, 오케스트레이션 패턴이 "언제 서브에이전트를 쓸 것인가"라는 아키텍처 질문을 다루는 반면, 이 장은 "서브에이전트를 쓴다면 컨텍스트 경계를 어떻게 관리할 것인가"라는 좁은 질문에 집중한다.
또 하나의 근본 제약은 세션 경계다. 장기 실행(long-running) 에이전트는 한 컨텍스트 윈도우 안에서 작업을 끝낼 수 없고, "여러 세션에 걸쳐 작업해야 하며 각 새 세션은 이전에 무슨 일이 있었는지에 대한 기억이 전혀 없이 시작"한다.[^harness] 이 챕터의 오프로딩 논의는 서브에이전트 간 격리(공간적 분리)와, 세션 간 상태 브리징(시간적 분리)이라는 두 축을 함께 다룬다.
핵심 개념
1. 서브에이전트 컨텍스트 격리
각 서브에이전트는 독립된 컨텍스트 윈도우, 독립된 도구 세트, 독립된 탐색 궤적을 가진다. 리드 에이전트는 서브에이전트의 중간 사고 과정(도구 호출, 실패한 시도, 장황한 원본 검색 결과)을 보지 않고, 서브에이전트가 반환하는 압축된 요약만 받는다. 이것이 "격리"의 본질이다: 실패한 탐색이나 노이즈가 메인 스레드의 attention 예산을 갉아먹지 않는다.
이 패턴이 컨텍스트 관점에서 성립하려면 두 가지가 지켜져야 한다.
- 반환 계약(return contract): 서브에이전트가 무엇을 몇 토큰 이내로 반환해야 하는지 프롬프트에 명시한다. 계약이 없으면 서브에이전트가 원본 로그를 그대로 리드에게 넘겨 격리가 무의미해진다.
- 재현 불가능성 감수: 리드 에이전트는 서브에이전트가 왜 그 결론에 도달했는지 검증할 원본 근거가 없다. 디버깅 시 이 정보 손실이 병목이 될 수 있으므로, 서브에이전트 실행 로그는 별도로(파일 또는 트레이싱 시스템에) 보존해야 한다.
2. 파일시스템 오프로딩
컨텍스트에 전부 담는 대신, 상태를 파일시스템(또는 외부 저장소)에 쓰고 필요할 때만 읽어온다. Anthropic은 이를 "가벼운 식별자(파일 경로, 저장된 쿼리, 웹 링크 등)"를 컨텍스트에 유지하고 "런타임에 동적으로 데이터를 로드"하는 방식이라고 설명하며, 이는 "사람이 전체 말뭉치를 기억하는 대신 파일시스템을 활용하는 방식"을 그대로 반영한다고 말한다.[^ctx-eng]
이 패턴은 JIT 검색과 토큰 예산에서 다루는 "필요할 때 가져온다"는 원칙의 파일시스템 특화판이다. 폴더 계층, 네이밍 컨벤션, 타임스탬프 같은 메타데이터는 "에이전트가 정보를 언제 어떻게 활용해야 하는지"를 판단하는 신호로 작동한다.[^ctx-eng] 즉 오프로딩이 잘 되려면 파일 구조 자체가 "다음에 이걸 왜 읽어야 하는지"를 코딩해야 한다 — 무작위 이름의 스크래치 파일 더미는 오프로딩이 아니라 컨텍스트 부채의 이전일 뿐이다.
3. 구조화 노트테이킹
에이전트가 "컨텍스트 윈도우 바깥의 메모리에 주기적으로 노트를 기록하고, 이 노트를 이후 시점에 다시 컨텍스트로 불러오는" 패턴이다.[^ctx-eng] NOTES.md나 to-do 리스트가 대표적 구현이다. Anthropic이 예시로 든 포켓몬 플레이 에이전트는 이 방식으로 "수천 게임 스텝에 걸친 정확한 집계"와 "수시간짜리 트레이닝 시퀀스"를 자기 관리형 메모리로 추적했다.[^ctx-eng]
노트테이킹과 파일 오프로딩의 차이는 미묘하다. 오프로딩은 "이미 존재하는 대용량 데이터"를 컨텍스트 밖에 두는 것이고, 노트테이킹은 "에이전트 자신이 생성하는 진행 상태·판단·중간 결론"을 컨텍스트 밖에 적립하는 것이다. 전자는 검색(retrieval) 문제, 후자는 상태 관리(state management) 문제에 가깝다.
4. Initializer agent와 세션 간 상태 브리징
Anthropic의 "Effective harnesses for long-running agents"는 여러 컨텍스트 윈도우에 걸쳐 일관되게 진행하기 위한 2단 구조를 제시한다: "첫 실행 시 환경을 세팅하는 initializer agent"와 "매 세션마다 점진적 진행을 담당하며 다음 세션을 위한 명확한 산출물을 남기는 coding agent"다.[^harness]
initializer agent는 다음을 만든다.[^harness]
init.sh— 개발 서버 구동 등 환경 실행 방법을 정의하는 스크립트claude-progress.txt— 에이전트들이 지금까지 한 작업의 로그- 초기 git commit — 어떤 파일이 추가됐는지 보여주는 베이스라인
- 요구사항을 수백 개의 테스트 가능한 항목으로 확장한 JSON 기능 목록 — 한 예시에서는 "a user can open a new chat, type in a query, press enter, and see an AI response" 같은 종단간(end-to-end) 기능 서술 200개 이상으로 확장되었다.[^harness]
핵심 인사이트는 "새 컨텍스트 윈도우로 시작하는 에이전트가 작업 상태를 빠르게 이해할 방법을 찾는 것이었고, 이는 claude-progress.txt 파일과 git 히스토리의 조합으로 달성"되었다는 것이다.[^harness] 매 세션 끝에 coding agent는 "git commit과 진행 상황 업데이트를 작성"하도록 지시받으며, git commit은 단순 기록이 아니라 "모델이 잘못된 코드 변경을 되돌리고 작업 가능한 상태로 복구"하는 복구 지점(checkpoint)으로도 쓰인다.[^harness]
⚠️ 위 인용은 Anthropic 공식 엔지니어링 블로그(각주 참조)에 근거한다. 구체적 수치(기능 200개 이상 등)는 해당 글이 제시한 특정 예시 프로젝트에 한정된 것으로, 모든 프로젝트에 일반화되는 값이 아니다.
이 패턴과 빌더 에이전트 설계의 직결점: initializer agent가 요구사항을 구조화된 파일로 남겨 다음 세션이 그것을 읽고 시작하는 방식은, Part 11의 요구사항 대화에서 다루는 "대화형 요구사항 수집 → 요구사항 파일 작성" 흐름과 본질적으로 같은 문제를 푼다: 대화(또는 세션)가 끝나는 순간, 그 안에 있던 암묵적 맥락을 다음 컨텍스트 윈도우가 재구성할 수 있는 명시적 아티팩트로 응고시켜야 한다. 빌더 에이전트를 설계할 때는 요구사항 대화의 산출물을 claude-progress.txt와 동형(isomorphic)인 구조 — 사람도 diff로 리뷰할 수 있는 평문/JSON 파일, git으로 버전 관리되는 상태 — 로 남기는 것을 원칙으로 삼아야 한다.
5. Agentic search vs. pre-indexing
Anthropic은 업계 전반에서 사전 처리(pre-indexing) 대신 "에이전트가 도구로 직접 데이터를 조회하는" JIT(just-in-time) 전략으로의 이동을 관찰한다고 말한다.[^ctx-eng] 트레이드오프는 명확하다: "런타임 탐색은 사전 계산된 데이터를 조회하는 것보다 느리다."[^ctx-eng] 실무에서는 하이브리드가 흔하다 — 초기에 일부 데이터를 미리 가져와 두고, 나머지는 에이전트 재량으로 탐색하게 한다. 이 축의 세부 저지먼트는 JIT 검색과 토큰 예산에서 다룬다.
결정 표
| 상황 | 선택 | 이유 | 트레이드오프 |
|---|---|---|---|
| 여러 독립적인 대용량 탐색(코드베이스 검색, 웹 리서치 등)을 병렬로 수행해야 함 | 서브에이전트 격리 (orchestrator-worker) | 탐색 노이즈가 리드 에이전트 컨텍스트를 오염시키지 않음 | 토큰 사용량 최대 15배 증가[^multi-agent]; 서브에이전트 내부 추론 과정은 리드가 검증 불가 |
| 대용량 참조 데이터(문서, 로그, 대형 파일)를 반복 참조해야 함 | 파일시스템 오프로딩 + 가벼운 식별자만 컨텍스트에 유지 | 컨텍스트에 원본을 중복 적재하지 않음 | 파일 네이밍/구조 설계 비용, 읽기 시점의 지연 |
| 단일 세션 내 장시간 작업(수백~수천 스텝)에서 누적 집계·진행 상태 추적이 필요 | 구조화 노트테이킹 (NOTES.md, to-do 파일) | 컨텍스트 윈도우 크기와 무관하게 정확한 상태 유지 가능 | 노트 스키마가 부실하면 노트 자체가 노이즈원이 됨 |
| 세션이 여러 컨텍스트 윈도우(수 시간~수일)에 걸쳐 이어짐 | Initializer agent + claude-progress.txt + git 커밋 | 새 컨텍스트가 상태를 재구성하는 데 걸리는 시간 최소화[^harness] | 초기 세팅 오버헤드, 진행 파일 갱신을 빠뜨리면 다음 세션이 처음부터 재탐색 |
| 컨텍스트가 이미 임계치에 근접했고 위 격리 조치로도 부족함 | Compaction | 마지막 방어선으로 대화 자체를 압축 | 정보 손실 위험, 압축 프롬프트 튜닝 필요 |
| 조회 대상 데이터가 안정적이고 사전 스키마가 명확함 | Pre-indexing (사전 검색/사전 로드) | 런타임 탐색보다 빠름[^ctx-eng] | 데이터 변경 시 인덱스 동기화 비용 |
실패 모드
| 증상 | 근본 원인 | 확인 방법 | 해결 |
|---|---|---|---|
| 서브에이전트가 반환한 요약이 수만 토큰에 달해 리드 컨텍스트가 즉시 소진됨 | 서브에이전트 프롬프트에 반환 토큰 예산/형식 계약이 없음 | 서브에이전트 트레이스를 열어 반환 페이로드 크기를 직접 측정 | 서브에이전트 프롬프트에 "N토큰 이내로 요약" 등 명시적 반환 계약 추가 |
| 세션이 끝났는데 다음 세션이 처음부터 코드베이스를 다시 탐색함 | 진행 파일(claude-progress.txt 등) 갱신 없이 세션 종료, 또는 파일이 있어도 다음 세션이 읽지 않음 | 세션 종료 시 진행 파일의 마지막 수정 시각과 git log 타임스탬프 비교 | 세션 종료를 "커밋 + 진행 파일 업데이트"가 완료되어야 끝나는 것으로 하니스에서 강제 |
| 파일 오프로딩 도입 후에도 컨텍스트 사용량이 줄지 않음 | 컨텍스트에는 파일 경로만 남기기로 했지만 실제로는 파일 전체 내용을 매번 다시 읽어 컨텍스트에 붙여넣음 | 도구 호출 로그에서 동일 파일에 대한 반복 전체 읽기 빈도 확인 | 부분 읽기(라인 범위, grep 결과)로 전환, 읽은 내용에 대한 캐시/참조 유지 |
| 여러 서브에이전트가 같은 파일에 진행 상태를 동시에 기록해 상태가 덮어써짐 | 오프로딩 대상 파일에 대한 쓰기 동시성 제어가 없음 | 파일의 git 히스토리에서 짧은 시간 내 상충하는 diff 확인 | 파일별 소유권을 서브에이전트 하나로 한정하거나, append-only 로그 + 병합 단계 도입 |
| 노트 파일이 계속 커져서 오히려 다시 읽을 때 컨텍스트를 많이 잡아먹음 | 노트에 만료 정책이 없어 오래된 항목이 계속 누적 | 노트 파일 크기와 세션 수의 상관관계 확인 | 오래된/완료된 항목을 주기적으로 별도 아카이브 파일로 이동, 노트는 "현재 유효한 상태"만 유지 |
| initializer agent가 만든 요구사항 목록이 실제 구현 진행과 어긋남 | 요구사항 파일이 최초 1회만 작성되고 이후 갱신되지 않음(살아있는 문서가 아님) | 요구사항 JSON의 passes 필드 갱신 시점과 실제 커밋 시점 비교 | coding agent 프롬프트에 요구사항 파일 갱신을 세션 종료 체크리스트에 포함 |
안티패턴
- ❌ 서브에이전트에게 "조사해서 알려줘"라고만 지시하고 반환 형식을 정하지 않는다 → ✅ 반환 스키마와 토큰 상한을 프롬프트에 명시해 격리 경계를 실제로 강제한다.
- ❌ 모든 중간 상태를 매번 컨텍스트에 다시 붙여넣어 "최신 상태를 항상 모델에게 보여줘야 안전하다"고 가정한다 → ✅ 컨텍스트에는 식별자만 남기고, 필요한 시점에만 파일을 읽는다.
- ❌ 컨텍스트가 꽉 찰 때까지 기다렸다가 compaction으로 때운다 → ✅ 컨텍스트가 차오르기 전에 격리·오프로딩으로 애초에 유입량을 줄이고, compaction은 그래도 남는 잔여물에 대한 마지막 수단으로 둔다.
- ❌ 진행 파일(
claude-progress.txt등)을 사람이 읽기 좋은 산문으로만 쓰고 기계적으로 파싱 가능한 구조를 두지 않는다 → ✅ 사람 가독성과 기계 파싱성을 함께 만족하는 형식(예: 상단 구조화 요약 + 하단 자유 서술 로그)을 쓴다. - ❌ 서브에이전트 아키텍처를 "컨텍스트가 부족하니 일단 나눈다"는 이유로 도입한다 → ✅ 토큰 배수 비용(최대 15배[^multi-agent])을 감당할 만큼 작업의 가치가 큰지 먼저 판단한다.
계측 (SLI)
격리·오프로딩이 실제로 효과를 내는지는 다음 지표로 확인한다.
- 서브에이전트 반환 압축률: 서브에이전트 내부에서 소비한 토큰 대비 리드 에이전트로 반환된 토큰 비율. 낮을수록(예: Anthropic 예시의 1,000~2,000 토큰대[^ctx-eng]) 격리가 잘 작동한다는 신호.
- 세션 재탐색 비율: 새 세션 시작 후 첫 N개 도구 호출 중 "이전 세션에서 이미 확인했던 것과 동일한 조회"의 비율. 높으면 진행 파일/노트 오프로딩이 실효성이 없다는 신호.
- 컨텍스트 도달 전 격리 개입 비율: compaction이 트리거되기 전에 격리·오프로딩으로 처리된 토큰 유입량 비율. 이 비율이 낮으면 상류 대책 없이 하류(compaction)에만 의존하고 있다는 신호.
- 진행 파일 최신성(staleness): 진행 파일의 마지막 갱신 시각과 마지막 커밋 시각의 간격. 간격이 벌어질수록 다음 세션의 상태 재구성 신뢰도가 떨어진다.
- 파일 오프로딩 캐시 적중률: 동일 파일/청크에 대한 반복 요청 중 이미 컨텍스트에 있던 참조를 재사용한 비율 대 전체 다시 읽은 비율.
체크리스트
- [ ] 서브에이전트를 도입하기 전에, 예상 토큰 배수와 작업 가치를 비교했는가?
- [ ] 모든 서브에이전트 프롬프트에 반환 형식·토큰 상한이 명시되어 있는가?
- [ ] 서브에이전트의 원본 실행 로그가 (리드 컨텍스트에는 안 들어가더라도) 별도로 보존되어 디버깅 가능한가?
- [ ] 대용량 참조 데이터는 컨텍스트에 통째로 넣지 않고 경로/식별자로만 참조하는가?
- [ ] 세션이 여러 컨텍스트 윈도우에 걸칠 가능성이 있다면, initializer agent가
init.sh/진행 파일/git 베이스라인을 만드는가? - [ ] 매 세션 종료 시 진행 파일 갱신과 커밋이 하니스 차원에서 강제되는가?
- [ ] 노트/진행 파일에 오래된 항목을 정리하는 만료·아카이브 정책이 있는가?
- [ ] 격리·오프로딩으로도 컨텍스트가 임계치에 도달하는 경로에 대해 compaction이 후속 대책으로 준비되어 있는가?
- [ ] 빌더 에이전트의 요구사항 대화 산출물이 다음 세션(또는 다음 에이전트)이 재구성 가능한 명시적 파일 형태로 응고되는가? (요구사항 대화 참고)
참고
[^ctx-eng]: Anthropic, "Effective context engineering for AI agents", Anthropic Engineering Blog. [^harness]: Anthropic, "Effective harnesses for long-running agents", Anthropic Engineering Blog. [^multi-agent]: Anthropic, "How we built our multi-agent research system", Anthropic Engineering Blog (2025년 6월 13일 게시).
- Compaction과 요약 — 컨텍스트가 이미 꽉 찼을 때의 압축 전략
- Context Rot — 긴 컨텍스트가 모델 성능에 미치는 영향
- JIT 검색과 토큰 예산 — 오프로딩의 반대편에 있는 "언제 가져올 것인가" 판단
- 단일 vs 멀티 에이전트, 오케스트레이션 패턴 — 서브에이전트 아키텍처 자체의 설계 판단
- 요구사항 대화 — initializer agent 패턴이 빌더 에이전트 설계에 적용되는 지점