본문으로 건너뛰기
24/3030개 중 24장

Context Engineering: 왜 당신의 agent는 40번째 턴에 더 멍청해질까

window의 2.6%만 채운 prompt에서 사실 하나를 세 줄 아래로 옮기자 retrieval이 84%에서 19%로 떨어졌습니다. 문제는 window가 아니었습니다.

이 페이지에서

다음은 같은 모델에 greedy decoding으로 288번 보낸 하나의 prompt입니다. 길이는 853 tokens입니다. 여기에는 25개의 지원 티켓 등록부 — 도시, queue, 우선순위, 담당자, 내선번호 — 와 질문 하나가 들어 있습니다. Marta Ferreira가 자신의 티켓에 대해 콜백을 받아야 합니다. 그 티켓의 직통 내선번호는 무엇인가요?

등록부는 매번 동일합니다. 모델도 매번 동일합니다. 바뀌는 것은 25개 줄 중 어느 줄에 정답이 들어 있는지뿐입니다.

정답 slot적중retrieval 비율95 % 구간
25개 중 1번째27/3284 %68–93 %
25개 중 4번째6/3219 %9–35 %
25개 중 7번째6/3219 %9–35 %
25개 중 10번째9/3228 %16–45 %
25개 중 13번째8/3225 %13–42 %
25개 중 16번째6/3219 %9–35 %
25개 중 19번째6/3219 %9–35 %
25개 중 22번째3/329 %3–24 %
25개 중 25번째7/3222 %11–39 %

각 행마다 32번의 trial, trial마다 다른 티켓, Wilson 구간은 제4장에서 가져왔습니다. 스무 번 중 열일곱 번으로는 무엇과 무엇도 제대로 구분할 수 없기 때문입니다.

첫 번째 slot은 **84 %**의 확률로 답이 맞습니다. 그 밖의 모든 위치는 9 %에서 28 % 사이에 있고, 그 여덟 개 구간은 모두 겹칩니다. 따라서 정직한 해석은 처음, 그리고 나머지 전부입니다. Liu 등은 U자형 — 양끝에서 높고 가운데에서 낮은 — 을 발견했지만, 여기서는 최신성 쪽 팔이 뚜렷하게 나타나지 않습니다. 마지막 slot의 22 %는 가운데 값들의 분포 안에 있습니다. 어느 분포 안에도 들어가지 않는 것은 slot 1에서 slot 4로 떨어지는 낙폭입니다. 세 줄.

이 모델의 context window는 32,768 tokens입니다. prompt는 그중 853개, **2.6 %**를 씁니다. 아무것도 넘치지 않았고, 아무것도 잘리지 않았고, 어떤 한계에도 도달하지 않았고, 경고도 나타나지 않았습니다. 모델은 자신에게 건네진 줄 하나를 찾지 못하게 되었습니다. 그 줄이 25개짜리 목록에서 세 칸 아래로 이동했기 때문입니다.

제16장은 context window의 가격을 매겼고, 백만 tokens를 갖고 있는 것은 그것을 사용하는 것이 아니라고 경고하며 여기로 이어졌습니다. 여기가 바로 그 지점입니다.

세부 정보 보기

이 장이 앞선 장들에서 필요로 하는 것.

  • **제9장**은 self-attention과 그 O(n2)O(n^2) 비용을 유도했습니다. 모든 token은 다른 모든 token에 attend하므로, 쌍별 관계의 수는 길이의 제곱에 따라 늘어납니다. 아래에서는 이 사실을 다시 유도하지 않고 사용합니다.
  • 제16장은 과금되는 다섯 개 token bucket을 세고, 대화의 비용이 제곱으로 증가함을 보였습니다. 이 장은 agent를 망가뜨리지 않고 그 문제에 대응하는 방법입니다.
  • **제18장**은 tool catalogue를 만들고, 20개의 tool이 선택 성능을 해치지는 않았지만 prompt를 여섯 배로 키웠다는 점을 측정했습니다. 여기에는 그 비용이 나옵니다.
  • **제19장**은 retrieval을 만들었습니다. 아래의 just-in-time retrieval은 그 장을 agent 자신의 history에 적용한 것입니다. chunking은 다시 설명하지 않습니다.
  • **제23장**은 harness를 만들었습니다. 이 장의 모든 것은 그 loop 안에서 실행되는 policy입니다. 그래서 TypeScript입니다. artefact는 tensor를 담은 notebook이 아니라 state를 들고 오래 살아가는 service입니다.

이름이 비슷한 두 가지 일

섹션 링크: 이름이 비슷한 두 가지 일

Anthropic은 2025년 9월에 선을 그었고, 두 문장은 나란히 놓여야 합니다. Prompt engineering은 "최적의 결과를 위해 LLM 지시문을 작성하고 구성하는 방법"입니다. Context engineering은 "LLM inference 중 최적의 tokens(정보) 집합을 선별하고 유지하기 위한 전략들의 집합이며, prompts 밖에서 그곳에 들어올 수 있는 다른 모든 정보까지 포함한다"입니다.1

실질적인 차이는 언제, 그리고 누가입니다. prompt는 사람이 한 번 작성하고 검토합니다. context는 매 호출마다, 아무도 보고 있지 않은 code가, 사람이 손으로 쓰지 않은 재료 — history 40턴, tool result 6개, retrieved passage 4개, 사용자 profile, JSON schema 12개 — 로 조립합니다. 제15장은 더 나은 instruction이 무엇을 사 주는지 측정했습니다. 이 장은 나머지 90퍼센트의 tokens, 저절로 도착하는 tokens에 관한 것입니다.

같은 문서는 이 모든 것이 소비하는 resource의 이름도 붙입니다. 모델에는 대량의 context를 parsing할 때 끌어다 쓰는 "attention budget"이 있습니다. "새로 도입되는 모든 token은 이 budget을 얼마간 고갈시킨다"고 합니다. 그리고 증상도 명명합니다. "context window 안의 tokens 수가 증가할수록, 모델이 그 context에서 정보를 정확히 recall하는 능력은 감소한다" — context rot입니다.1

마지막 문장은 behaviour에 관한 주장입니다. 그렇다면 확인할 수 있습니다. 이 페이지 맨 위의 표가 그 확인입니다.

제22장의 local endpoint를 향해 40줄 — CPU에서 Qwen2.5-0.5B-Instruct를 들고 chat-completions 형태로 말하는 작은 Python server입니다. 그래서 loop는 TypeScript에 남고 tensor는 port 너머에 남습니다.

position.tsTS
const DEPTHS = [0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1];

for (const d of DEPTHS) {
  const slot = Math.round(d * (N - 1));
  let hits = 0, other = 0;
  for (let t = 0; t < TRIALS; t++) {
    const recs = buildRecords(N, 1000 + t);          // 25 unique tickets
    const gold = recs[Math.floor(rng(7 + t)() * N)]; // a different one each trial
    const rest = recs.filter((x) => x.ticket !== gold.ticket).slice(0, N - 1);
    const lines = [...rest.slice(0, slot).map((x) => x.line),   
                   gold.line,                                   
                   ...rest.slice(slot).map((x) => x.line)];     
    const r = await complete(prompt(lines, ask(gold.owner)), { maxTokens: 12 });
    const said = /\d{4}/.exec(r.text)?.[0];
    if (said === String(gold.ext)) hits++;
    else if (said && recs.some((x) => String(x.ext) === said)) other++;
  }
}

other counter가 실망스러운 결과를 유용한 결과로 바꿉니다. 모델이 틀렸을 때, 그것은 길을 잃은 것일까요, 아니면 확신하는 것일까요?

답은 확신입니다. 첫 번째가 아닌 여덟 위치 전체에서, 205개의 오답 중 136개는 다른 티켓의 내선번호였습니다. 실제 네 자리 숫자이고, 형식도 맞으며, 잘못된 줄에서 읽어 온 값입니다. slot 1에서는 다섯 번의 miss 중 하나만 그랬습니다. slot 7에서는 스물여섯 번 중 스물한 번이 그랬습니다.

production에서 중요한 것은 이 구분입니다. 찾을 수 없습니다라고 말하는 모델은 알아차릴 수 있는 bug입니다. 이웃 행의 번호를 반환하는 모델은 배포해 버리는 bug입니다. 화면에서는 둘이 똑같아 보이기 때문입니다. 이는 제19장이 검증 가능한 citation으로 막으려 했던 실패가 index가 아니라 prompt 내부에서 도착한 것입니다.

위치만이 아닙니다. 양도 문제입니다.

섹션 링크: 위치만이 아닙니다. 양도 문제입니다.

위치는 한 축입니다. 길이가 다른 축이고, test하기는 더 쉽습니다. 정답을 가운데에 두고 목록을 키우면 됩니다.

recordsprompt tokens적중비율95 % 구간잘못된 줄둘 다 아님
19718/2090 %70–97 %02
315911/2055 %34–74 %90
83153/2015 %5–36 %170
206952/2010 %3–30 %162
401,3243/2015 %5–36 %152
802,5871/205 %1–24 %181
1404,4772/2010 %3–30 %180

record 하나와 97 tokens: 90 %. record 세 개와 159 tokens: 55 %. record 여덟 개와 315 tokens: 15 %. 그리고 거기서부터 140 records와 4,477 tokens까지 계속 낮고 평평합니다. 붕괴 전체가 목록의 첫 번째 줄과 여덟 번째 줄 사이에서 일어납니다.

마지막 열은 정답 내선번호도 아니고 다른 record의 내선번호도 아닌 모든 것입니다. 페이지에 record가 하나뿐일 때 오답이 갈 수 있는 곳은 그곳뿐입니다. 하나의 record에서 나온 두 번의 miss는 반올림해 없애기보다 보고할 가치가 있습니다. 둘 다 거절이 아니었기 때문입니다. 하나는 유일한 줄에 5805라고 적힌 등록부에 5806이라고 답했습니다. 후보가 하나뿐인 97 tokens에서도 이 모델은 스무 번 중 두 번 숫자 하나를 잘못 베낍니다. 그것이 나머지 모든 것을 재는 바닥값입니다.

여기서 두 가지가 따라옵니다. 더 큰 context가 사 주는 것은 더 많이 보낼 권리이지, 읽힐 확실성이 아닙니다. 이 모델에는 32,768-token window가 있지만, 이 task에서 작동 범위는 몇백 tokens입니다. 그리고 threshold도, cliff도, "context full" 상태도 없습니다. degradation은 세 번째 record에서 이미 진행 중이고 여덟 번째에서 완료됩니다. window의 1퍼센트에서입니다. context limit이 무엇이든, 이것을 지배하는 것은 아닙니다.

보통 두 가지 mechanism이 제시됩니다. 첫째는 제9장의 산술입니다. Anthropic도 이 과정과 같은 용어로 말합니다. 모델은 "transformer architecture를 기반으로 하며, 이는 모든 token이 전체 context에 걸쳐 다른 모든 token에 attend할 수 있게 한다. 그 결과 n tokens에 대해 n²개의 쌍별 관계가 생긴다"고 합니다.1 더 긴 sequence에 대한 attention은 같은 operation을 더 많은 재료에 적용하는 것이 아닙니다. 하나의 고정된 probability mass budget이 더 많은 경쟁자 사이에 퍼지는 것입니다. 둘째는 training입니다. 모델은 긴 sequence보다 짧은 sequence를 훨씬 더 많이 보므로, 장거리 positional pattern은 network에서 가장 덜 연습된 부분입니다. 그것은 논거이지 측정이 아니며, 이 장은 그것을 결론낼 수 없습니다.

이미 결론난 것은 shape입니다. 그리고 그것은 2023년부터 그랬습니다. Liu 등은 여러 model family와 size에 걸쳐 multi-document question answering과 key-value retrieval을 test했고, "관련 정보가 input context의 시작 또는 끝에 있을 때 performance가 가장 높은 경우가 많으며, 모델이 긴 context의 가운데에 있는 관련 정보에 접근해야 할 때는 명시적으로 long-context 모델이라도 performance가 크게 저하된다"는 것을 발견했습니다.2 제15장은 그 논문에서 position rule을 가져왔고, 제19장은 retrieved chunks 20개가 4개보다 더 나쁜 점수를 낼 수 있는 이유를 가져왔습니다. 이 사실의 실용적인 형태는 여기서 행동으로 옮겨야 할 유일한 문장입니다. 자신의 모델과 자신의 data로 측정하는 데 5분이면 충분하며, 어떤 published curve도 당신의 curve를 대체하지 못합니다.

자기 window에 무엇이 들어 있는지 아는 사람은 없습니다

섹션 링크: 자기 window에 무엇이 들어 있는지 아는 사람은 없습니다

팀에 agent의 context를 무엇이 채우는지 물어보면 추정치가 돌아옵니다. 어떤 API도 그 답을 반환하지 않기 때문입니다. response는 prompt_tokens, 모든 것을 합친 숫자 하나만 줍니다.

breakdown은 네 번의 count와 세 번의 subtraction으로 복구할 수 있습니다. 렌더링된 전체 prompt, tool definitions를 뺀 같은 prompt, tool definitions가 있는 system message와 없는 system message, 그리고 tool results를 제거한 전체입니다.

buckets.tsTS
async function buckets(messages: Msg[]) {
  const sys = messages.slice(0, 1);
  const withoutResults = messages.filter((m) => m.role !== "tool");
  const [total, sysWithTools, sysNoTools, noResults] = await Promise.all([
    countPrompt(messages, CATALOGUE),        // everything
    countPrompt(sys, CATALOGUE),             // system + scaffolding + schemas
    countPrompt(sys),                        // system + scaffolding
    countPrompt(withoutResults, CATALOGUE),  // everything but tool output
  ]);
  return {
    system: sysNoTools,
    tools: sysWithTools - sysNoTools,                                  
    toolResults: total - noResults,                                    
    conversation: total - sysWithTools - (total - noResults),          
    total,
  };
}

countPrompt는 tokenizing하기 전에 모델 자신의 chat template을 적용합니다. 이는 들리는 것보다 더 중요합니다. 당신의 text가 count되는 것이 아닙니다. role marker, tool-calling preamble, schema rendering은 모두 당신이 입력한 적 없지만 비용을 내는 tokens입니다. 제7장은 tokenizer를 만들었고 제16장은 js-tiktoken로 count했습니다. 여기서는 prompt를 읽을 바로 그 모델에서 count가 나옵니다. 정확히 맞는 유일한 count입니다.

이제 실제 agent를 통과시켜 봅니다. incident investigation 40턴, tool 12개, 현실적인 log dump와 metric series를 반환하는 가짜 operations environment입니다.

turnsystemtool definitionsconversationtool resultstotal prompt이번 turn의 input billed
1851,8171554902,5474,370
2851,8172825292,7135,275
5851,8176471,8704,4198,093
10851,8179462,1414,9894,951
20851,8171,5002,9436,3456,316
30851,8172,1874,0008,0898,059
40851,8173,0535,67710,63221,090

첫 행을 마지막 행과 비교해 읽어 보세요.

turn 1에서 prompt는 2,547 tokens이고 그중 71 %가 tool definitions입니다. system prompt는 3 %입니다. 사용자가 입력한 것은 6 %입니다. agent는 아직 아무것도 하지 않았는데 이미 1,817 tokens의 JSON schema를 들고 있습니다.

turn 40이 되면 prompt는 10,632 tokens이고 비중은 뒤집혀 있습니다. definitions 17 %, conversation 29 %, tool results 53 %입니다. tool output은 turn 5에서 definitions를 넘어섰습니다. conversation은 turn 25가 되어서야 넘어섰습니다. 따라서 session의 처음 60퍼센트 동안 tool catalogue는 지금까지 말해진 모든 것보다 컸습니다.

그다음은 total입니다. 57번의 model call 동안 이 run은 최종 context 10,632에 대해 370,291 input tokens를 billed했습니다. 마지막 prompt를 약 35번 다시 지불한 셈이고, 이는 제16장의 quadratic에 agent multiplier가 올라탄 것입니다. 그 370,291개 중 103,569개, 즉 전체 billed의 28 %는 12개의 tool definitions였고, 매 call마다 byte-identical하게 다시 전송되었습니다.

tool catalogue는 agent에서 가장 큰 fixed cost이며 보이지 않습니다. 당신은 그것을 보지 못하기 때문입니다. object array를 넘기면 provider가 대신 prompt로 렌더링합니다. 같은 12개 tool에서 측정하면 다음과 같습니다.

tooldefs.ts outputTEXT
system prompt + chat scaffolding, no tools:        85 tokens
all twelve definitions:                          1,817 tokens
  of which fixed tool-calling scaffolding:         126 tokens
three tools instead of twelve:                     605 tokens
same twelve, one-sentence descriptions,
  no parameter prose:                            1,291 tokens  (-29 %)

tool당 marginal cost는 문자열 하나를 받는 get_current_time의 80 tokens부터, enum과 각 parameter마다 한 문장의 guidance가 있는 네 parameter를 받는 search_tickets의 263까지 이어집니다. 이것이 제18장의 핵심 조언, description이 API다 뒤에 있는 exchange rate입니다. 좋은 description은 agent의 남은 수명 동안 모든 request에서 약 100 tokens를 씁니다. 여기서 세 가지 결과가 나옵니다.

사용하지 않는 tool도 billed됩니다. agent는 12개 중 7개를 call했습니다. 나머지 5개는 57번의 request마다 697 tokens를 썼습니다. 총 39,729 tokens로, 이 run이 billed된 전체의 10분의 1보다 많았으며, 한 번도 건드리지 않은 capability를 위한 비용이었습니다. 그 다섯 개 중 하나는 trace에서 가장 날카로운 세부사항을 품고 있습니다. 모델은 존재하지 않는 read_log를 세 번 call하려 했습니다. 모델이 원한 tool은 search_logs였고, catalogue에서 두 번째로 비싼 definition으로 237 tokens였습니다. 그 definition 값을 57번 지불했고, 한 번도 쓰지 않았으며, 이름도 끝내 찾지 못했습니다.

prose를 줄이는 것은 가능한 가장 싼 optimisation이며, trade입니다. description을 한 문장으로 자르고 parameter documentation을 제거하자 logic 한 줄 건드리지 않고 call당 526 tokens, 29퍼센트를 절약했습니다. 그리고 모델은 tool을 더 나쁘게 call했습니다. 제18장이 측정한 것이 바로 그것입니다. 요점은 그 trade의 양쪽이 이제 같은 unit 안에 있다는 것입니다.

어느 scale에서는 definitions를 보내는 것 자체가 더 이상 말이 되지 않습니다. Anthropic은 2025년 11월에 수치를 제시했습니다. 연결된 server가 많은 대규모 집합은 request를 읽기 전에 definitions "수십만 tokens"를 처리해야 하며, 이를 code execution — agent가 필요한 definitions만 발견하고 load하는 방식 — 으로 대체하면 "token usage가 150,000 tokens에서 2,000 tokens로 줄어 시간과 비용이 98.7% 절감된다"고 했습니다.3 이 장의 나머지와 같은 생각을 history가 아니라 schemas에 적용한 것입니다. index는 유지하고, entry는 필요할 때 resolve하세요.

그 40-turn transcript에는 두 가지가 심어져 있었습니다. turn 2, 실제 작업이 시작되기 전에 사용자는 상시 rule을 말합니다. 내가 여는 모든 티켓은 내 employee number 4417로 filed되어야 합니다. turn 19, incident 중간에 하나의 사실이 나옵니다. 영향을 받은 shard는 pay-shard-7이며, payments team이 확인했습니다. turn 40에서 사용자는 agent에게 incident ticket을 열라고 요청하고, 이때 둘 다 필요합니다. 각 probe는 서로 다른 여섯 가지 phrasing으로 묻고 6점 만점으로 채점합니다. greedy decoding은 deterministic이므로 한 번의 call은 반복 불가능한 yes/no를 주고, 여섯 번은 rate를 줍니다.

그런 다음 transcript를 일곱 가지 context policy 아래에서 replay합니다. 의도적으로 re-run이 아니라 replay입니다. messages, tool calls, tool results는 일곱 경우 모두 byte-identical하므로 유일한 변수는 각 policy가 무엇을 유지하기로 선택했는지입니다. 제16장은 sliding window가 cacheable prefix를 파괴하기 때문에 나쁜 경제적 선택임을 보였습니다. 이것이 behaviour에 미치는 영향은 다음과 같습니다.

context policy40턴 동안의 input tokensturn-40 promptturn-2 ruleturn-19 fact
full history370,29110,6326/65/6
sliding window, 마지막 12 messages157,5782,9225/60/6
4턴보다 오래된 tool results 생략243,4456,3116/63/6
6턴마다 compaction195,5153,2206/60/6
compaction plus model-written notes200,8493,2866/60/6
사용자 자신의 turns를 앞에 pin168,5503,5596/65/6
사용자 자신의 turns를 뒤에 pin168,8353,5646/66/6
control: 두 turns만 있고 그 밖에는 없음1,9816/66/6

compaction 행에는 compacting 비용도 포함되어 있습니다. 7개 summary에 18,581 input tokens, note-taker에 3,392 tokens가 더 들었습니다. control 행은 0을 0으로 읽을 수 있게 하기 위해 있습니다. 두 messages만 있는 1,981-token prompt에서 이 모델은 두 probe 모두 완벽하게 답합니다. 따라서 어느 행도 task가 너무 어려워서 생긴 결과가 아닙니다.

Full history는 기억하지만, 표에서 가장 비쌉니다. durable content가 두 문장뿐인 session에 370,291 input tokens입니다.

이것은 opening이 남겨 둔 질문에 답합니다. 왜 10,632-token transcript는 사실 하나를 붙잡고 있는데 853-token register는 잃어버릴까요? 길이가 잘못된 변수이기 때문입니다. register는 25개의 동일한 문장 속에 25개의 네 자리 내선번호를 담고 있습니다. 원하는 하나에 대해 거의 완벽한 decoy가 24개 있습니다. transcript에는 employee number 하나와 shard name 하나만 있습니다. Context rot은 volume이기 전에 interference입니다. 그래서 위의 205개 오답 중 136개가 이웃 값이었습니다. window에 대해 유용한 질문은 얼마나 긴지가 아닙니다. 그 안에 답처럼 보이는 것이 얼마나 많은지입니다.

sliding window는 57 % 더 싸고 incident를 잃었습니다. employee number는 agent가 최근 turns에 그것을 반복해 두었기 때문에만 살아남았습니다. turn 19에서 한 번 말한 shard는 마지막 12 messages 안에 없습니다. 그리고 모델은 그렇게 말하지 않습니다. 여섯 번 물었을 때 모델은 *"영향을 받은 payment shard는 shard 4417입니다"*라고 답했습니다. window에 남아 있는 유일한 다른 identifier인 employee number를 붙잡은 것입니다. 그리고 두 번은 log line의 pool_exhausted 문자열에서 끌어온 *"pool"*이라고 답했습니다.

Compaction은 싸고, 같은 사실을 잃었습니다. identifiers, numbers, standing instructions, open questions를 유지하라는 명시적 지시 아래 모델이 작성한 7개의 summary에서, pay-shard-7은 중요한 summary 어디에도 없었습니다. 여섯 guess는 shard 1, pay_shard_1, pool였습니다. Compaction은 시끄럽게 실패하지 않습니다. 유창하고 그럴듯하고 훨씬 짧은 session을 만들지만, 조용히 한 줄을 떨어뜨립니다.

세 행이 turn-19 fact에서 0/6을 기록했습니다. sliding window, compaction, notes가 있는 compaction입니다. 세 행을 합쳐 18개의 오답이 있었고, 그중 "모르겠습니다"는 하나도 없었습니다.

그다음은 민망해야 할 행입니다. 사용자 자신의 40개 messages를 verbatim으로 유지하고, 마지막 4 turns를 full로 더한 뒤 나머지를 모두 버리면 168,550 tokens가 듭니다. full history보다 54 % 적고, 두 probe 모두 full history만큼 또는 그보다 더 잘 맞힙니다. summariser도, note-taker도, second model도 없습니다. role === "user"에 대한 filter 하나뿐입니다. 사용자의 말은 agent window에서 가장 싼 high-value tokens이며, 대부분의 design은 그것을 다른 모든 것과 함께 버립니다.

마지막 두 행은 opening table이 agent 안으로 들어온 것입니다. 같은 pinned block을 system message에서 prompt 끝으로 옮기면 5/6이 6/6이 됩니다. 여섯 trial에서는 significant difference가 아니며 그렇게 제시하지도 않습니다. 이것은 where가 당신이 알고 있든 모르고 있든 설정하고 있는 parameter라는 점을 상기시키기 위한 것입니다.

window를 덜 쓰는 네 가지 방법

섹션 링크: window를 덜 쓰는 네 가지 방법

아래 네 전략은 Anthropic의 것이며 순서도 그렇습니다. 다만 마지막 세 가지만 그들의 long-horizon list에 속합니다.1 네 가지 모두 하나의 instruction을 변주합니다. fetch할 수 있는 것은 carry하지 말고, compressed로 carry할 수 있는 것은 raw로 carry하지 마세요.

content를 미리 load하지 마세요. identifier — file path, query, ticket number, tool name과 arguments — 를 유지하고 필요할 때 resolve하세요. 위 agent에서 가장 큰 bucket은 한 번 읽고, 한 번 사용한 뒤, 30턴 더 들고 다닌 tool output입니다. 4턴보다 오래된 모든 result를 그것이 무엇이었고 어떻게 되가져올 수 있는지 말하는 stub으로 바꾸는 일은 여섯 줄입니다.

policies.tsTS
const elide: Policy = (h) => [SYSTEM, ...h.flatMap((turn, ti) =>
  turn.map((m) => (ti < h.length - 4 && m.role === "tool"
    ? { role: "tool", name: m.name,
        content: `[${m.name} result from turn ${ti + 1}, ${m.content.length} chars, ` +
                 `elided; call ${m.name} again with the same arguments to re-read it]` }
    : m)))];

이것은 corpus를 agent 자신의 과거로 바꾼 제19장입니다. retrieval machinery는 이미 있습니다. 그것은 tool catalogue입니다.

transcript가 threshold를 넘으면 가장 오래된 부분을 model-written summary로 바꾸고 계속합니다. summary를 쓰는 prompt가 전체 design이며, compaction의 승패가 갈리는 곳입니다. identifiers, numbers, standing instructions, open questions는 유지하고, 인사말과 다시 fetch할 수 있는 tool output은 버리세요.

Compaction은 구조적으로 lossy입니다. 무엇을 잃을지는 모델이 당신 대신 고르며, 모델이 잘못 골라도 아무 error도 나지 않습니다. 무료도 아닙니다. compaction마다 compact되는 대상 전체를 input으로 하는 추가 call이 필요합니다.

context 밖에 작은 store를 유지하고 매 turn마다 통째로 다시 주입합니다. summary와 달리 append-only이고 addressable합니다. turn 2에 적힌 rule은 turn 400에도 verbatim으로 남아 있습니다. 여기서 측정한 version은 각 user message 뒤에 모델에게 durable한 것이 들어 있는지 묻습니다.

notes.tsTS
const r = await complete([
  { role: "system", content:
      "You keep a durable note file for a support session. Given one user message, " +
      "output one short note ONLY if it states a standing rule, an identifier or a fact " +
      "that must survive the rest of the session. Otherwise output exactly NONE." },
  { role: "user", content: `Turn ${i + 1}: ${user}` },
], { maxTokens: 40 });
if (!/^none\b/i.test(r.text.trim())) notes.push(`turn ${i + 1}: ${r.text.trim()}`);

이 전략은 여기서 ceiling이 가장 높고, 측정에서는 실패한 전략입니다. 40개의 user messages 동안 note-taker는 3개의 note를 유지했지만, 중요한 두 개는 모두 빠뜨렸습니다. 남은 것은 runbook advice 한 줄, session이 끝난다는 announcement, 그리고 Europe/Madrid is currently 13:45였습니다. 마지막은 invented time입니다. paraphrase하던 tool은 09:52 UTC를 반환했기 때문입니다. note-taker도 모델이며, 이 장의 모든 내용은 그것에도 적용됩니다.

집중된 task에 자기만의 window를 주세요. 자기 system prompt, 작은 catalogue, parent의 history는 없음. 그리고 transcript가 아니라 짧은 답을 반환하게 하세요. 제23장은 하나를 tool schema 뒤에 두고 비용은 여기 남겨 두었습니다. 그 비용이란 child window에서 parent가 결코 비용을 내는 유일한 부분이 child의 답이라는 것입니다.

sub-agent는 위 표에 없습니다. 40턴 동안 실행되지 않기 때문입니다. 한 번 실행되고, 누군가가 scope한 window 안에서 실행됩니다. system prompt와 17~19턴만 받고 다른 것은 없는 상태 — 2,737 tokens — 에서 shard probe에 6/6으로 답했습니다. 표의 모든 policy보다 좋았습니다. employee probe는 0/6이었습니다. 그 숫자가 건네받은 세 turns 안에 없었기 때문입니다.

이것이 두 숫자로 본 sub-agents입니다. 깨끗한 window는 intelligence가 아니라 scope이고, scoping은 어떤 turns가 중요한지 이미 알아야 하는 code가 사전에 수행합니다. 그 답들에서 하나 더 보존할 만한 것이 있습니다. 이것은 무언가를 invent하는 대신 *"None available"*이라고 답한 유일한 policy였습니다. 작고 coherent한 context를 가진 모델은 자신에게 무엇이 없는지 압니다. 크고 noisy한 context를 가진 모델은 모릅니다.

agent memory에 관한 거의 모든 혼란스러운 대화는 하나의 단어를 뒤집어쓴 세 mechanism입니다. lifetime, owner, failure mode가 다르며, 그것들을 같은 곳에 보관하는 system은 아직 알아차리지 못한 문제를 안고 있습니다.

conversation historyretrievalpersistent user memory
담는 것이 session에서 말해진 것당신이 소유한 documents한 사람에 관한 facts
사는 곳하나의 sessionre-index될 때까지모든 sessions에 걸쳐, 영원히
작성자loop, 자동으로ingestion pipeline모델, 의도적으로
prompt에 들어가는 방식매 call마다 full로query가 match될 때 네 passages매 call마다 full로
실패 방식썩을 때까지 커짐잘못된 chunk를 retrieving당신에 대해 잘못 기억함
구축된 장제23장제19장이 장

학술적 framing은 CoALA의 것입니다. CoALA는 language agents를 "modular memory components" 중심으로 구성하고 working memory를 episodic, semantic, procedural store와 분리합니다.4 MemGPT는 같은 생각을 literal하게 받아들여 operating system의 virtual memory를 빌려옵니다. window 안의 빠른 tier, 바깥의 느린 tier, 그리고 모델 자신이 function calls로 그 사이에서 data를 옮깁니다.5 둘 다 product가 어차피 답해야 할 질문을 강제합니다. 얼마나 많이 보관할 수 있는가가 아니라 이것은 어느 store에 속하며, 언제 만료되는가입니다.

실용적 test는 fact마다 하나의 질문입니다. 내일도 여전히 참이어야 하는 것은 무엇인가? turn 12의 tool result는 아무것도 아닙니다. session summary는 session이 끝날 때까지입니다. 사용자의 employee number가 4417이라는 사실은 그들이 직장을 바꿀 때까지입니다. 세 답, 세 store입니다.

이제 window 안에 무엇이 있는지 측정하고, 무엇을 그 안에 남길지 결정하며, agent가 무언가를 잊은 것과 그것을 들고 있었지만 보지 않은 것을 구분할 수 있습니다.

네 전략 중 마지막은 여기에 잘 들어맞지 않습니다. sub-agent는 context policy가 아니라 second agent입니다. 둘이 되는 순간, 그 사이에 무엇이 오가고 어느 쪽이 책임자인지 결정해야 합니다. 제25장이 그것입니다. 다섯 가지 orchestration pattern과 각각의 이름이 실제로 어디서 왔는지, 서로 뒤섞이는 두 topology — sub-agent에게 물어보고 답을 받는 것과, conversation을 넘기고 돌려받지 않는 것 — 그리고 그 장이 가격을 매기는 task에서 더 단순한 arrangement가 이긴다는 측정 결과를 다룹니다. 이어서 그것이 언제 이기지 못하게 되는지 test합니다.

그것은 또한 이 장이 방금 측정한 것을 그대로 물려받습니다. sub-agent는 summary를 반환합니다. summary는 당신이 쓰지 않은 compaction이며, 당신이 볼 수 없는 window를 가진 모델이 만든 것입니다. parent는 좋은 summary와 확신에 찬 잘못된 summary를 구분할 방법이 없습니다. 이 페이지 맨 위에서 84 %와 19 %를 갈랐고, 누락된 18개 fact를 invented answer 18개로 바꾼 것과 같은 구분입니다. 그렇다면 sub-agent가 틀렸을 때, parent는 정확히 무엇을 들여다볼 수 있을까요?


여기의 모든 숫자는 이 machine에서 생성되었고 추정치는 없습니다. 모델은 CPU에서 float32로 실행한 Qwen2.5-0.5B-Instruct이며 greedy decoding을 사용했습니다. chat-completions 형태로 말하고 token-count route를 노출하는 작은 Python endpoint가 loopback으로 serve했습니다. 다시 제14장의 seam입니다. tensor는 Python 쪽에, loop는 TypeScript 쪽에 있습니다. 그래서 모든 count는 해당 모델 자신의 tokenizer가 자신의 chat template에 적용한 결과입니다. position table은 288 calls, 9개 position × 32 trials이며 trial마다 다른 티켓을 썼습니다. length table은 140 calls입니다. agent run은 wall clock 43분 동안 57 model calls입니다. policy table은 같은 transcript 하나를 일곱 policies 아래에서 replay한 것입니다. 구간은 제4장의 Wilson 구간입니다. paid API는 call하지 않았습니다. 그래서 이 장에는 가격이 하나도 없습니다. token counts는 정확하고, 여기에 곱할 rate는 제16장에 있습니다.

  1. Anthropic, Effective context engineering for AI agents, 2025년 9월 29일, anthropic.com/engineering/effective-context-engineering-for-ai-agents, 2026년 9월 7일 열람. 맨 위에서 인용한 두 정의, "attention budget"과 새 token마다 그것을 고갈시킨다는 진술, context rot 설명, n² 쌍별 관계 framing, 그리고 이 장의 뼈대로 사용한 strategies의 출처입니다. 그중 세 가지 — compaction, structured note-taking, multi-agent architectures — 는 그들의 long-horizon list입니다. just-in-time retrieval은 같은 글의 앞부분, context retrieval과 agentic search 아래에 나오며 여기서는 함께 묶었습니다. 2 3 4

  2. Liu, N. F., Lin, K., Hewitt, J., Paranjape, A., Bevilacqua, M., Petroni, F. and Liang, P. Lost in the Middle: How Language Models Use Long Contexts. arXiv:2307.03172 (v1 2023년 7월, v3 2023년 11월). 제15장, 제16장, 제19장에서 인용했고 여기서 측정했습니다. 인용문은 abstract에서 가져왔습니다. 논문의 두 task는 multi-document question answering과 key-value retrieval이며, 효과가 명시적 long-context models에서도 지속된다는 finding이 product decision에 중요한 부분입니다.

  3. Anthropic, Code execution with MCP: building more efficient agents, 2025년 11월 4일, anthropic.com/engineering/code-execution-with-mcp, 2026년 9월 7일 열람. 150,000 tokens에서 2,000 tokens로 줄어든다는 수치와 98.7 % figure, 그리고 upfront로 load된 tool definitions가 request를 읽기 전 context를 차지한다는 observation의 출처입니다.

  4. Sumers, T. R., Yao, S., Narasimhan, K. and Griffiths, T. L. Cognitive Architectures for Language Agents. arXiv:2309.02427 (2023). language agents를 "modular memory components, internal memory 및 external environments와 상호작용하는 structured action space, actions를 선택하는 generalized decision-making process" 중심으로 구성하고, memory를 working, episodic, semantic, procedural로 나눕니다. 제22장은 learning agent에 그 taxonomy를 사용했습니다. 위의 three-store table은 그 실용적 그림자입니다.

  5. Packer, C., Wooders, S., Lin, K., Fang, V., Patil, S. G., Stoica, I. and Gonzalez, J. E. MemGPT: Towards LLMs as Operating Systems. arXiv:2310.08560 (2023년 10월). "전통적 operating systems의 hierarchical memory systems에서 영감을 얻은 technique인 virtual context management"를 제안하며, 모델 자신이 window 안의 fast tier와 그 바깥의 slow tier 사이에서 data를 옮깁니다. window가 memory가 아니라 cache인 이유를 가장 명확히 말한 곳입니다.

이제 모델 선택은 LIA에게 맡기세요

모든 AI 모델을 한곳에서. 오늘 무료로 시작하세요.