Agent Mentor Learn
컨텍스트 엔지니어링: 유한한 주의를 값어치 있는 곳에 쓰기 · 3 / 6강

레슨 3: 적시 검색: 에이전트가 스스로 컨텍스트를 가져오게 하기

학습 목표:

  • 주의 예산으로 사전 로드의 숨은 비용을 값 매기고, 어떤 자료가 초기 컨텍스트에 들어갈 자격이 있는지 판단하기
  • 적시 검색이 어떻게 돌아가는지 기술하기: 가벼운 식별자, 신호로서의 메타데이터, 탐색을 통해 점진적으로 발견되는 관련 컨텍스트
  • 구체적인 에이전트 하나를 놓고 하이브리드 전략 그려 보기 — 무엇을 사전 로드하고, 무엇을 식별자로 남겨 실행 시점에 가져오게 할지

전제: 레슨 1과 2를 읽었고, 이 시리즈의 코스 7 '에이전트 하네스 기초: 루프와 통제'의 하네스 루프를 손 닿는 곳에 두고 있어야 합니다 | 이전: 레슨 2 << | 다음: 레슨 4 >>

먼저, 전부 밀어 넣고 싶은 충동을 참으십시오

코드베이스를 위한 질의응답 에이전트를 만든다고 해 봅시다. 저장소에는 소스 파일이 200개 있고, 사용자는 '이 함수는 어디에 정의되어 있나요', '이 설정을 바꾸면 무엇이 깨지나요' 같은 것을 묻습니다. 뻔한 수순은 200개 파일을 전부 읽어 초기 컨텍스트에 붙여 넣는 것입니다. 요즘 컨텍스트 윈도는 크니까 들어갈 테고요.

들어갑니다. 그렇다고 들어갈 자격이 있는 것은 아닙니다. 이유는 레슨 1에서 다뤘습니다. 모델은 대량의 컨텍스트를 '주의 예산'을 끌어다 쓰며 파싱하고, "Every new token introduced depletes this budget by some amount."(새로 들어오는 토큰은 하나하나 이 예산을 얼마간 고갈시킨다)1 셈은 갈수록 나빠지기만 합니다. "as the number of tokens in the context window increases, the model's ability to accurately recall information from that context decreases."(컨텍스트 윈도 안의 토큰 수가 늘어날수록, 그 컨텍스트에서 정보를 정확히 회상하는 모델의 능력은 떨어진다)1 그나마 다행인 것은 이것이 낭떠러지가 아니라 비탈이라는 점입니다. "some models exhibit more gentle degradation than others, this characteristic emerges across all models,"(어떤 모델은 다른 모델보다 완만한 저하를 보이지만, 이 특성은 모든 모델에서 나타난다) 그리고 이 요인들이 함께 "create a performance gradient rather than a hard cliff."(단단한 절벽이 아니라 성능의 경사를 만든다)1 여기서 레슨 1의 결론이 되돌아옵니다. 여기서 한 번 더 반복할 만합니다. "context, therefore, must be treated as a finite resource with diminishing marginal returns."(따라서 컨텍스트는 한계 수익이 체감하는 유한한 자원으로 다뤄져야 한다)1

200개 파일로 돌아가 봅시다. 사용자는 구체적인 질문을 하나 하고, 정말로 관련 있는 파일은 두세 개쯤일 것입니다. 나머지 197개가 싣고 오는 십수만 토큰은 무해한 배경이 아닙니다. 그것들은 같은 예산에서, 정작 중요한 내용과 주의를 놓고 경쟁합니다. 게다가 에이전트는 루프 안에서 돌고, "An agent running in a loop generates more and more data that could be relevant for the next turn of inference."(루프 안에서 도는 에이전트는 다음 추론 턴에 관련이 있을 수 있는 데이터를 점점 더 많이 생성한다)1 초기 컨텍스트가 이미 8분의 7쯤 차 있다면, 루프는 몇 턴 만에 벽에 부딪힙니다.

그래서 질문은 이렇게 바뀝니다. 언제 자료를 모델 앞에 곧바로 놓고, 언제는 자료가 어디에 있는지만 알려 주고 직접 가져오게 할 것인가? 이 레슨 전체가 그 이야기입니다.

두 전략을 나란히 놓고 보기

각각을 평이하게 진술하는 것부터 시작하겠습니다.

사전 로드: 추론이 시작되기 전에 필요할 수 있는 모든 것을 초기 컨텍스트에 넣습니다. 모델은 첫 턴에 그 전부를 보며, 무엇도 검색할 필요가 없습니다.

적시 검색: 초기 컨텍스트에는 원자료가 하나도 없고 가벼운 식별자만 들어 있습니다. "maintain lightweight identifiers (file paths, stored queries, web links, etc.)"(가벼운 식별자(파일 경로, 저장된 쿼리, 웹 링크 등)를 유지)1하는 방식이며, 에이전트가 실행 시점에 필요한 만큼 도구를 통해 내용을 로드하게 합니다.

사전 로드적시 검색
초기 컨텍스트크다작다
자료가 도착하는 시점첫 턴부터 모델 앞에도구 호출이 한 턴에서 여러 턴 먼저 든다
토큰이 쓰이는 곳대부분 '쓸모가 있을지도 모르는 것'에'지금 확실히 필요한 것'에
전형적인 실패 양상주의가 묽어지고 핵심 내용이 파묻힌다검색이 헤매며 공회전해 턴과 예산을 태운다

여러분이 실제로 일하는 방식을 떠올려 보십시오. 코드베이스를 통째로 외우고 있지는 않습니다. 들고 다니는 것은 '인증 로직은 auth 디렉터리에 있다', '설정 파싱은 아마 config.js에 있을 것이다' 같은, 내용을 가리키는 색인이고, 세부가 필요할 때 파일을 엽니다. 적시 검색은 그 일하는 방식을 에이전트에게 건네주는 것입니다.

다만 표의 마지막 칸을 다시 보십시오. 검색은 공짜가 아닙니다. 적시에 한 번 가져올 때마다 완전한 도구 호출 왕복이 일어납니다. 모델이 호출을 발행하고, 하네스가 실행하고, 결과가 돌아오고, 모델이 다시 추론합니다. 이 시리즈의 코스 7 '에이전트 하네스 기초: 루프와 통제'에서 여러분은 하네스에 턴 상한과 예산 상한이라는 두 개의 밸브를 달았습니다. 검색이 쓰는 것이 바로 그 두 밸브가 다스리는 것입니다. 그러니 '언제나 적시에'도 답이 아닙니다. 이것은 계산해야 할 청구서이고, 이 레슨 뒤쪽의 절충 프레임이 그 셈을 합니다.

적시 검색은 실제로 어떻게 돌아가는가

세 가지가 이것을 굴러가게 합니다. 식별자의 집합(무엇이 있고 대략 어디에 있는지 모델이 알도록), 몇 개의 검색 도구, 그리고 여러 턴의 탐색을 허용하는 루프입니다. 이것이 합쳐지면 "allows agents to incrementally discover relevant context through exploration."(에이전트가 탐색을 통해 관련 컨텍스트를 점진적으로 발견하도록 해 준다)1

여기서 저평가되는 부분이 있습니다. 식별자의 메타데이터 자체가 신호입니다. 파일 이름과 디렉터리 구조는 그 내용이 무엇을 위한 것이고 관련성이 얼마나 될지를 둘 다 광고합니다1. tests/refund.test.js 를 열어 보지 않아도 안에 무엇이 있을지 알 수 있고, 2년 동안 손대지 않은 legacy/ 디렉터리는 출발점으로 삼을 곳이 아닐 공산이 큽니다. Anthropic이 자사 멀티 에이전트 리서치 시스템을 정리한 글은 그 밑에 깔린 동작을 날카롭게 짚습니다. "The essence of search is compression: distilling insights from a vast corpus."(검색의 본질은 압축이다. 방대한 말뭉치에서 통찰을 증류해 내는 것)2 적시 검색의 모든 단계 — 디렉터리를 나열하고, 키워드를 검색하고, 파일을 고르는 것 — 가 그 압축을 수행하며, '관련이 있을지도 모르는 넓은 띠'를 '내가 실제로 읽어야 하는 작은 조각'으로 좁힙니다.

코드로 내려가 봅시다. 그 코드베이스 질의응답 에이전트에게 도구 세 개를 주겠습니다. 구현은 셋 다 짧습니다.

그다음 도구 정의를 레슨 2의 기준 — "self-contained,"(자족적), "extremely clear with respect to their intended use,"(의도된 용도에 대해 극도로 명확), 그리고 "minimal overlap in functionality"(기능의 겹침이 최소) — 으로 씁니다.1

시스템 프롬프트에는 안정적인 부분만 담습니다. 맡은 일, 인용 요구사항, 검색에 관한 거동 관례입니다. 파일 내용은 한 줄도 등장하지 않는다는 점에 주목하십시오.

이것을 작은 이커머스 저장소에 연결하고 '주문 환불 금액은 어디에서 계산되나요?'라고 물으면 전형적인 실행은 이런 모습입니다. (저장소 내용은 예시입니다. 각 호출의 모양과 각 반환의 형식은 위 구현이 정해 놓은 것입니다. 3번 턴의 파일 본문은 너무 길어 싣지 못하므로 한 줄짜리 괄호 설명이 대신합니다.)

턴 1  list_files({ path: "." })   →  README.md      src/      tests/턴 2  grep({ pattern: "Refund", path: "src" })   →  src/payments/refund.js:12:export function calculateRefundAmount(order, policy) {      src/orders/service.js:6:import { calculateRefundAmount } from "../payments/refund.js";      src/orders/service.js:88:  const amount = calculateRefundAmount(order, policy);턴 3  read_file({ path: "src/payments/refund.js" })   →  (이 파일은 60줄, 전문 반환)턴 4  모델이 도구 호출을 멈추고 곧바로 답한다.      "환불 금액은 src/payments/refund.js:12 의 calculateRefundAmount 에서      계산됩니다. orders 모듈이 src/orders/service.js:88 에서 그것을      호출합니다."

2번 턴과 3번 턴 사이에 무슨 일이 일어났는지 보십시오. grep은 일치한 줄 세 개를 돌려주었고, 모델은 두 파일을 다 읽지 않았습니다. 줄 내용만으로 정의가 refund.js 에 있고 service.js 는 단지 import 하고 호출하는 쪽임을 알아내, 정확히 파일 하나만 열었습니다. 메타데이터가 모델을 대신해 1차 걸러내기를 해 준 것입니다. "the metadata of these references provides a mechanism to efficiently refine behavior."(이 참조들의 메타데이터는 거동을 효율적으로 정련하는 장치를 제공한다)1 궤적 전체에서 컨텍스트에 들어온 것은 디렉터리 목록 하나, grep 출력 세 줄, 그리고 60줄짜리 파일 하나입니다. 200개 파일이 아니라 말이지요.

두 번 볼 만한 세부가 둘 더 있습니다. 첫째는 두 구현에 박아 넣은 잘라내기입니다. grep은 최대 50줄, read_file은 최대 400줄을 반환합니다. 레슨 2는 도구가 "returning information that is token efficient"(토큰 효율적인 정보를 반환)1해야 한다고 짚었습니다. 검색 도구는 컨텍스트의 공급자이고, 공급자가 출하량을 스스로 제한할 때에만 루프가 살아남습니다. 둘째는 실패 사례입니다. grep이 계속 빈손으로 돌아오면 모델은 키워드를 바꿔 가며 몇 번이고 검색할 수 있습니다. 그것이 바로 하네스 과정의 공회전 감지와 예산 밸브가 잡아내라고 있는 상황입니다. 탐색은 좋지만, 경계 없는 탐색은 그렇지 않습니다.

하이브리드가 보통의 경우입니다

결론이 '적시 검색의 승리'일 것이라 예상했을지도 모르겠습니다. 아닙니다. 실제 시스템이 양 극단 중 한쪽에 앉는 일은 드물고, 흔한 모양은 하이브리드입니다. "retrieving some data up front for speed, and pursuing further autonomous exploration at its discretion."(속도를 위해 일부 데이터는 미리 가져오고, 그 이상의 자율적 탐색은 재량에 맡겨 이어 간다)1

매일 쓰는 Claude Code가 살아 있는 사례입니다. "CLAUDE.md files are naively dropped into context up front, while primitives like glob and grep"(CLAUDE.md 파일은 앞쪽에서 컨텍스트에 그대로 투입되는 한편, glob과 grep 같은 원시 도구는)1 실행 시점의 적시 탐색을 뒷받침합니다. 공식 문서는 이를 평이하게 기술합니다. "CLAUDE.md is a special file that Claude reads at the start of every conversation."(CLAUDE.md는 Claude가 모든 대화의 시작에 읽는 특별한 파일이다)3 매번 빠짐없이 로드되기 때문에, 문서는 넓게 적용되는 자료만 담고 모든 줄마다 이렇게 물으라고 권합니다. "Would removing this cause Claude to make mistakes?"(이것을 지우면 Claude가 실수를 하게 되는가?)3 답이 아니라면 그 줄은 나가야 합니다. 문서는 그 결과를 단도직입적으로 적습니다. "Bloated CLAUDE.md files cause Claude to ignore your actual instructions!"(비대해진 CLAUDE.md 파일은 Claude가 여러분의 실제 지시를 무시하게 만든다)3

스킬은 세 번째 길을 갑니다. "Claude loads them on demand without bloating every conversation."(Claude는 모든 대화를 비대하게 만들지 않으면서 필요할 때 그것들을 로드한다)3 이 셋을 나란히 세우면 하이브리드 전략의 계층 그림이 나옵니다.

  • CLAUDE.md: 안정적이고 매 턴 구속력이 있다 → 처음에 사전 로드;
  • 스킬: 포장된 전문 역량이며 특정 작업에만 쓰인다 → 필요할 때 로드;
  • 코드베이스 자체: 방대하고 매번 아주 일부만 필요하다 → glob과 grep으로 적시에 탐색.

자기 에이전트를 설계할 때 여러분이 그리는 것은 바로 그 그림의 한 판본입니다. 어떤 자료가 'CLAUDE.md 자리'에 앉고, 어떤 자료가 '코드베이스 자리'에 앉는가 하는 그림입니다.

바로 적용할 수 있는 절충 프레임

후보 자료 하나하나에 두 가지를 물으십시오.

  1. 안정적인가? 특정 질문과 무관하게, 시간이 지나도 내용이 제자리에 있는가?
  2. 매 턴 — 또는 거의 매 턴 — 쓰이는가?

둘 다 예 → 사전 로드. 전형적인 경우는 코딩 표준, 핵심 비즈니스 제약, 에이전트의 행동 규범, 최상위 디렉터리 구조입니다. 이런 자료는 대개 크기도 작습니다. '매 턴 필요하다'고 내세운 것이 알고 보니 거대하다면, 정말로 매 턴 필요한지부터 의심하십시오.

하나라도 아니오 → 식별자를 남기고 적시에 검색. 전형적인 경우는 어느 모듈의 전체 소스(그 모듈에 대한 질문에만 필요), 과거 티켓(특정 장애를 쫓을 때에만 참조), 긴 설계 문서(방향을 맞출 때에만 열림)입니다.

그다음 검색 비용을 저울에 올리고 결과를 한 번 더 확인하십시오. 한 번 가져올 때마다 왕복이 하나 늘고, 지연이 늘고, 예산이 나갑니다. 그러니 작고 자주 쓰이는 자료를 고집스럽게 검색 쪽으로 밀어 넣지 마십시오. 사전 로드 자리 600단어를 아끼자고 세션마다 list_files 턴을 하나 더 치르는 것은 손해 보는 거래입니다. 반대 방향으로, 나올 일이 거의 없을 2,000줄짜리 스크립트를 사전 로드하는 것은 순수한 주의 예산 소각입니다1.

Claude Code 문서는 걸린 것을 한 줄로 정리합니다. "The context window is the most important resource to manage."(컨텍스트 윈도는 관리해야 할 가장 중요한 자원이다)3 사전 로드와 적시 검색은 대립하는 교리가 아닙니다. 그 자원을 관리하는 데 쓰는 두 손입니다.

이 레슨이 RAG를 건너뛰는 것은 의도적입니다

'검색'이라고 하면 많은 사람이 곧장 벡터 스토어, 임베딩, RAG 파이프라인을 떠올립니다. 이 레슨은 그중 어느 것도 의도적으로 건드리지 않습니다. 과정 README가 그 경계를 긋고 있고, 여기서 '적시 검색'이 뜻하는 것은 더 소박합니다. 파일 시스템과 검색 도구를 쥔 에이전트가 필요할 때 내용을 끌어오는 것입니다.

이것은 교육적 태만이 아닙니다. 파일 경로에는 계층과 이름의 의미가 공짜로 딸려 오고, grep 결과는 정확하며 설명 가능합니다. 이 한 쌍만으로도 탐색을 통해 관련 컨텍스트를 점진적으로 발견하는 루프 하나를 온전히 지탱하기에 이미 충분합니다1. 에이전트 구축에 대한 Anthropic의 지침도 이에 걸맞은 분수 감각을 제시합니다. "you should consider adding complexity only when it demonstrably improves outcomes."(복잡성은 그것이 결과를 입증 가능하게 개선할 때에만 더하는 것을 고려해야 한다)4 동사에 주목하십시오. 고려한다입니다. 금지가 아니라 저울질하는 자세입니다. 코드베이스 질의응답 에이전트라면, 가장 단순한 길(파일 시스템 더하기 grep)을 걸으며 어디서 부족한지 측정할 수 있을 때까지 가 보는 편이 첫날부터 벡터 검색을 세우는 것보다 그 자세에 더 어울립니다.

풀어 놓은 채로 남겨 둘 실 하나. 적시 검색을 아무리 규율 있게 해도, 긴 작업을 갈아 나가는 에이전트는 턴이 지날수록 도구 결과를 계속 쌓아 가고1 컨텍스트 윈도는 어쨌든 천장을 향해 기어오릅니다. 그 시점이 되면 '적게 가져오기'를 잘하는 것만으로는 충분하지 않습니다. 버리는 것과 적어 두는 것도 잘해야 합니다. 그것이 레슨 4입니다.

정리

  • '들어간다'는 사전 로드의 근거가 아니다. 새로 들어오는 토큰은 하나하나 주의 예산을 고갈시키고, 토큰 수가 늘수록 컨텍스트에서의 정확한 회상은 떨어진다 — 단단한 절벽이 아니라 성능의 경사다. 컨텍스트는 한계 수익이 체감하는 유한한 자원으로 관리해야 한다1
  • 적시 검색이 돌아가는 방식: 컨텍스트에는 가벼운 식별자(파일 경로, 저장된 쿼리, 웹 링크)만 두고, 도구가 실행 시점에 필요할 때 내용을 로드한다. 식별자의 메타데이터 — 파일 이름, 디렉터리 구조 — 는 그 자체로 관련성을 알리는 신호이고, 그것이 에이전트가 탐색을 통해 관련 컨텍스트를 점진적으로 발견하게 해 준다1
  • 검색은 공짜가 아니다. 한 번 가져올 때마다 도구 호출 왕복이 일어나며, 지연과 함께 하네스 과정의 제어 밸브가 다스리는 턴과 예산을 쓴다
  • 하이브리드가 보통의 경우다. 속도를 위해 일부 데이터는 미리 가져오고, 그 이상의 자율적 탐색은 모델의 재량에 맡긴다1. Claude Code가 이미 만들어진 참조다 — CLAUDE.md는 처음에 통째로 투입되고, 스킬은 필요할 때 로드되며, 코드베이스는 glob과 grep으로 그 자리에서 탐색된다1 3
  • 프레임은 두 질문이다. 안정적인가? 매 턴 필요한가? 둘 다 예면 사전 로드하고, 아니면 식별자를 남긴다. 작고 자주 쓰이는 자료를 검색으로 밀어 넣지 말고, 크고 드문 자료를 사전 로드로 밀어 넣지 않는다
  • 이 레슨에서 '적시 검색'은 파일 시스템과 검색 도구를 통해 필요할 때 끌어오는 것을 뜻하며, 벡터 스토어는 관여하지 않는다. 더 무거운 검색 장치를 들이기 전에 그 분수 감각을 기억한다 — 복잡성은 그것이 결과를 입증 가능하게 개선할 때에만 더하는 것을 고려한다4

>> 레슨 4: 컴팩션과 노트: 긴 작업을 위한 컨텍스트 관리

Footnotes

  1. Effective context engineering for AI agents — Anthropic Engineering — https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

  2. How we built our multi-agent research system — Anthropic Engineering — https://www.anthropic.com/engineering/multi-agent-research-system

  3. Best practices for Claude Code — Claude Code Docs — https://code.claude.com/docs/en/best-practices 2 3 4 5 6

  4. Building Effective AI Agents — Anthropic Engineering — https://www.anthropic.com/engineering/building-effective-agents 2

연습

01

사내 온콜 운영 질의응답 에이전트의 컨텍스트를 설계하고 있고, 후보 자료 다섯 가지가 탁자 위에 있습니다.

레벨 1: 컨텍스트 목록 분류하기
  1. 온콜 핸드북(약 500단어 — 프로덕션 데이터베이스 비밀번호를 절대 알려 주지 않는 것 같은, 모든 답변이 지켜야 하는 절대선);
  2. 과거 장애 티켓 800건 전부(건마다 수백에서 수천 단어);
  3. 서비스 카탈로그의 최상위 구조(서비스 이름 40개와 각각 한 줄짜리 담당 범위, 약 600단어);
  4. 어느 서비스의 전체 배포 스크립트(약 2,000줄, 배포 질문에만 관련);
  5. 흔한 알림 키워드를 티켓 검색 쿼리로 잇는 매핑 표(약 30줄).

이 레슨의 프레임을 써서 각 항목을 '사전 로드'와 '식별자를 남기고 적시에 검색' 중 하나로 분류하고, 각각에 한 줄짜리 근거를 다십시오.

완료 기준 · 로컬에서 확인
02

이 시리즈의 코스 7 '에이전트 하네스 기초: 루프와 통제'에서 쓴 하네스 루프를 꺼내, 이 레슨의 세 도구(list_files, grep, read_file)를 등록하고, 여러분 소유의 실제 저장소를 가리키게 해서 질의응답 에이전트로 만드십시오. 요구사항입니다.

레벨 2: 하네스에 검색 도구 달기
  • 시스템 프롬프트에는 안정적인 정보만 사전 로드한다 — 맡은 일, 인용 요구사항, 검색 관례 — 파일 내용은 넣지 않는다;
  • 세 도구 설명이 모두 자족적이고 서로 겹치지 않으며, 반환값이 잘려 있다;
  • 실제 질문을 하나 돌려 도구 호출 궤적을 기록하고, 굵은 데서 가는 데로 가는 점진적 발견이 나타나는지 확인한다.
완료 기준 · 로컬에서 확인