딥 에이전트와 컨텍스트 엔지니어링: 모든 것을 기억하는 방법
요약
본 글은 에이전트가 장시간 작업 수행 시 발생하는 '컨텍스트 부패(Context rot)' 문제를 다룹니다. Deep Agents는 LangChain의 오픈 소스 하니스로, 오프로딩, 요약본 생성, 스킬, 서브 에이전트, 장기 메모리 등 다섯 가지 기술을 활용하여 컨텍스트를 활성 창 밖으로 관리함으로써 정확도 저하를 방지합니다.
핵심 포인트
- 컨텍스트 부패는 에이전트가 많은 정보를 처리하며 발생하는 정확도 저하 현상입니다.
- Deep Agents는 LangChain 기반의 오픈 소스 하니스로, 컨텍스트 관리를 전문적으로 수행합니다.
- 오프로딩 및 요약본 생성은 대규모 데이터를 활성 창 밖으로 이동시켜 메모리 부하를 줄입니다.
- 장기 메모리는 에이전트가 학습한 내용을 파일에 저장하여 지속적인 지식 유지가 가능하게 합니다.
핵심 요약
- '컨텍스트 부패(Context rot)'는 장시간 실행되는 에이전트가 모델이 담을 수 있는 것보다 더 많은 컨텍스트를 쌓으면서 발생하며, 이는 정확도 저하로 이어집니다.
- LangChain의 오픈 소스 에이전트 하니스인 Deep Agents는 다섯 가지 기술을 사용하여 컨텍스트를 활성 창(active window) 밖으로 이동시켜 (삭제하지 않으면서) 컨텍스트 부패를 방지합니다. - Deep Agents에서 에이전트의 메모리는 사용자가 제어하는 스토리지에 일반 파일로 저장되므로, 학습한 모든 것을 유지하면서 모델이나 제공업체를 전환할 수 있습니다.
시험 전날 밤새워 공부했던 경험을 해본 사람이라면 그 느낌을 알 것입니다. 더 많이 공부할수록 초반 챕터 내용이 희미해지기 시작합니다.
에이전트도 같은 문제를 가지고 있습니다. 시간이 지남에 따라 더 많은 작업(지침, 도구 결과, 파일 등)을 맡게 되면서 점점 더 많은 정보를 수용하게 됩니다. 결국 이는 모델의 *컨텍스트 창(context window)*에 편안하게 담기에는 너무 많은 양이 됩니다. 모델이 더 많은 히스토리, 노이즈, 도구 출력을 가지고 있을수록 정확도와 추론 능력이 떨어지는 경향을 보입니다.
에이전트 엔지니어링 분야에서 우리는 이를 컨텍스트 부패(context rot)라고 부릅니다. 이 블로그에서는 에이전트의 컨텍스트 창을 관리하는 기술과 Deep Agents 하니스가 미들웨어(middleware)라는 개념을 사용하여 이러한 기술들을 에이전트 실행에 주입하는 방법을 다룹니다.
컨텍스트 엔지니어링 기술 이해하기
간단히 말해, 에이전트는 그 주변에 하니스(harness)가 둘러진 모델일 뿐입니다.

컨텍스트 부패를 해결하기 위해 에이전트가 사용할 수 있는 컨텍스트 엔지니어링 기술은 주로 두 가지 범주로 나뉩니다:
- 컨텍스트 창에 불필요한 정보가 들어오는 것을 방지하는 것 - 이미 컨텍스트 창에 있는 것을 관리하고 필터링하는 것
이 하니스는 주어진 작업에 대해 모델에게 적절한 시점에 적절한 컨텍스트를 제공하기 위해 이러한 방법들을 전략적으로 적용합니다.
하지만 이것을 잘 수행하는 하니스를 구성하는 것은 말처럼 쉽지 않으며, 많은 노력이 필요합니다 (만약 당신이 시험 전날 밤새워 공부하는 타입이라면 너무 많은 노력일 수도 있습니다).
Deep Agents는 LangChain의 오픈 소스 하네스입니다. 이 하네스는 사용자가 선택한 모델을 감싸서 컨텍스트를 활성 창(active window) 밖으로 이동시키는 기술(파일, 요약본 또는 별도의 에이전트 내부)을 적용합니다. 따라서 메인 에이전트는 필요한 정보만 가지고 있게 되며 (필요할 경우 나중에 원시 데이터 복구 가능):
오프로딩(Offloading): 대규모 도구 결과와 사용자 메시지는 파일 시스템에 저장되고, 모델은 미리보기를 보게 됩니다. 요약본 생성(Summarization): 대화가 컨텍스트 한계에 가까워지면, 이전 메시지들이 요약본으로 압축됩니다. 스킬(Skills): 작업 지식(task know-how)은 모델이 관련성이 있다고 판단할 때만 로드됩니다. 서브 에이전트(Subagents): 잡다한 작업은 별도의 컨텍스트 창에서 실행되며, 결과만 반환됩니다. 장기 메모리(Long-term memory): 에이전트가 학습한 내용은 다음 대화로 이어지는 파일에 저장됩니다.
일반적인 사용 사례에 컨텍스트 엔지니어링 적용하기
위의 기술들이 실제 사용 사례, 즉 경쟁 분석 에이전트에 어떻게 적용될 수 있는지 살펴보겠습니다. 이 에이전트는 매주 월요일마다 다섯 개 경쟁사를 조사하고 팀 템플릿으로 보고서를 작성합니다. 단일 실행은 다음과 같습니다:
- 회사 A에 대한 시장 데이터 내보내기 가져오기 (수만 행)
- 뉴스 검색, 기사 몇 개 읽고 메모하기
- 회사 B부터 E까지 반복
- 보고서 초안 작성, 피드백을 기반으로 수정하고 형식 지정하기
4단계에 이르러 에이전트는 다섯 개의 원시 내보내기 데이터, 수십 개의 검색 결과, 그리고 두 개의 오래된 초안들을 모든 모델 호출을 통해 처리했습니다. 이 중 대부분은 최종 보고서 형식을 지정하는 데는 관련성이 없습니다.
검색 증강 생성(Retrieval-Augmented Generation, RAG) 방법 또는 파일 시스템 검색은 에이전트가 필요한 것만 가져오도록 돕지만, 이는 여전히 문제의 절반만을 해결할 뿐입니다. 심지어 정밀한 에이전트라 할지라도 불필요한 메시지, 도구 결과, 중간 작업들을 축적하기 때문에, 이 하네스는 컨텍스트 창 내부와 주변에 이미 있는 것들까지 관리해야 합니다.
이러한 기술 구현 방법: 미들웨어
에이전트는 루프(loop) 형태로 작동합니다. 모델이 무엇을 할지 결정하고, 도구를 호출하며, 결과를 읽고, 작업이 완료될 때까지 이 과정을 반복합니다. 미들웨어(Middleware)는 이러한 루프의 특정 지점에 연결되는 코드입니다. 예를 들어, 에이전트가 시작하기 전, 각 모델 호출 주변, 또는 각 도구 호출 주변에 붙을 수 있습니다.
- 각 지점에서 컨텍스트를 읽고 다음 단계가 실행되기 전에 변경할 수 있습니다.
- 본 게시물에 나오는 모든 컨텍스트 엔지니어링 기법은 이러한 지점 중 하나에 연결된 미들웨어 조각입니다.
- 대부분의 기능은 내장되어 있으므로, 이 기술들을 사용하기 위해 직접 미들웨어를 작성할 필요는 없습니다 (특정 항목을 사용자 정의하고 싶지 않은 경우 제외).
오프로딩(Offloading): 컨텍스트 창 밖으로 빼내기
우리 에이전트가 모든 도구 호출이나 사용자 메시지에서 반환되는 모든 데이터를 항상 볼 필요는 없습니다. 특히 데이터 양이 많을 경우에는 더욱 그렇습니다.
예를 들어, pull_market_report라는 도구를 호출할 때마다 전체 데이터 내보내기(수천 개의 행)가 반환되지만, 에이전트는 그중 몇 가지 숫자만 필요하므로 모델에게 해당 행들만 보도록 제한할 수 있습니다.

FilesystemMiddleware는 도구가 호출될 때마다 실행됩니다:
- 도구 결과가 약 20,000 토큰을 초과하면, 전체 결과는 대화에 들어가기 전에
/large_tool_results/{tool_call_id}에 저장됩니다. - 모델은 짧은 미리보기(첫 몇 줄과 마지막 몇 줄)와 파일 경로만 보게 됩니다.
- 에이전트가 나중에 Company B의 분기별 매출을 필요로 할 때,
read_file을 사용하여 해당 파일을 페이지 단위로 읽어옵니다.
사용자/인간 메시지 중 크기가 큰 것(예: 붙여넣은 통화 녹취록)도 더 높은 임계값(50,000 토큰)에서 동일한 처리를 받으며 /conversation_history/에 저장됩니다.
요약(Summarization): 이미 존재하는 것을 압축하기
장황한 도구 호출을 오프로딩하려고 노력하더라도, 컨텍스트는 장기간 실행됨에 따라 점진적으로 쌓이기 시작합니다 (예: 다섯 개 회사에 대한 검색, 메모 및 초안 작성분). 요약 기능을 사용하여 에이전트의 전체 컨텍스트 창을 지금까지 발생한 내용을 요약하는 것으로 압축할 수 있으며, 이를 통해 연구 작업을 계속 진행할 수 있도록 합니다.

- 스파이크는 대규모 도구 결과/사용자 메시지가 도착할 때 발생합니다. 오프로딩(offloading)은 이들 각각을 짧은 미리보기로 교체하여 모델이 보는 컨텍스트가 조금만 증가하도록 합니다.
- 요약(Summarization)은 느린 상승세를 처리합니다: 사용량이 85%에 도달하면 이전 메시지들이 하나의 요약으로 압축되고 컨텍스트는 다시 낮아집니다.
SummarizationMiddleware는 각 모델 호출 직전에 토큰 사용량을 확인합니다:
- 사용량이 임계값(기본적으로 모델의 컨텍스트 창 85%)을 초과하면, 별도의 LLM 호출이 이전 메시지들을 하나의 요약으로 압축합니다.
- 이전 메시지들은 컨텍스트 창에서 제거되고 가장 최근 메시지들은 원문 그대로 유지됩니다.
- 이제 모델은 먼저 요약을 보고, 그 다음 최근 메시지들(따라서 최근 내용이 의역되지 않습니다).
두 가지 중요한 세부 사항:
복구 가능합니다. 요약된 메시지들은 /conversation_history/{session_id}.md에 작성됩니다. 만약 에이전트가 초안을 작성하는 동안 Company A의 연구 자료에서 특정 세부 정보를 필요로 한다면, 이를 다시 읽어올 수 있습니다.순환합니다. 실행이 계속됨에 따라 사용량이 다시 증가하고, 다음 요약에는 이전 요약이 포함됩니다.
특정 토큰 임계값뿐만 아니라 주제가 변경될 때도 요약할 수 있습니다. 요약 프롬프트를 사용자 정의하는 것이 도움이 될 수 있습니다.

Deep Agent의 컨텍스트 관리에 대한 저희 게시물에서 이 두 가지를 더 자세히 다룹니다.
스킬(Skills): 필요한 경우에만 정보 로드하기
귀하의 영업팀이 분기별 비즈니스 검토(QBR)를 위한 특정 형식을 가지고 있다고 가정해 봅시다. 에이전트는 이 지침을 분기에 한 번만 필요로 하므로, 이를 시스템 프롬프트에 유지하는 것은 모든 호출마다 (토큰과 응답 시간 측면에서) 비용을 지불한다는 의미입니다. 대신, 이 정보를 스킬(skill)로 패키징할 수 있습니다.
스킬은 에이전트에게 전문적인 작업을 수행하는 데 필요한 것들을 제공하는 일련의 지침 폴더(선택적 스크립트 및 참고 문서 포함)입니다.

에이전트는 처음에 짧은 설명을 보고, QBR이 발생할 때만 qbr-report에 대한 전체 지침을 로드합니다 (다른 작업에서는 절대 이를 가져오지 않습니다).
Skills는 컨텍스트를 레이어별로 로드하기 때문에, 실제로 관련 있는 내용이 나타날 때까지 윈도우가 작게 유지됩니다. 이를 점진적 공개(progressive disclosure)라고 합니다. 모델은 처음에 '메뉴'를 보고 있다가 필요할 때 전체 레시피를 가져오므로, 열 개의 스킬을 사용하는 비용은 열 개의 한 줄짜리 설명과 비슷한 컨텍스트 비용이 듭니다.

에이전트에게 스킬들을 지정해주면, SkillsMiddleware는 두 가지 후크(hook)를 사용합니다:
- 에이전트가 시작하기 전에, 스킬 폴더를 스캔하여 각 SKILL.md의 헤더만 읽습니다.
- 모델 호출마다 해당 이름과 설명을 시스템 프롬프트에 추가합니다.
전체 지침은 모델이 특정 스킬이 관련 있다고 판단했을 때(그리고 read_file 도구를 사용해 읽을 때) 컨텍스트로 들어오기 때문에, 우리의 에이전트는 템플릿 없이 리서치하고 QBR(Quarterly Business Review) 형식으로 만들 시간이 될 때만 로드합니다.
서브에이전트: 잡음이 많은 작업을 분리하기
작업을 오프로딩하는 것은 결과가 너무 커지는 것을 효과적으로 방지하지만, 서브에이전트는 이미 잡음(noisy)이 많을 것이라고 알고 있는 작업(예: 수십 개의 검색과 페이지를 거쳐 회사 리서치)에 대한 좋은 설계 선택입니다. 서브에이전트가 자체 컨텍스트 윈도우에서 작업을 수행하고 최종 결과만 반환하므로, 메인 에이전트는 '잡음'을 전혀 보지 못합니다.

SubAgentMiddleware를 사용하면 서브에이전트에 제공되는 시스템 프롬프트와 도구를 사용자 정의할 수 있습니다.
market_researcher = {
"name": "market-researcher",
"description": "회사를 리서치하고 가장 주목할 만한 3가지 발전을 반환합니다.",
...
이 경우, 메인 에이전트가 각 회사를 market-researcher 서브에이전트에 전달합니다.
리서처 서브에이전트는 자체 컨텍스트에서 전체 보고서를 읽고 세 가지 글머리 기호만 반환하므로, 메인 에이전트는 이 세 가지 글머리 기호만 보게 됩니다(원문 보고서의 미리보기조차 아닙니다). 게다가, 서브에이전트 작업은 작고 범위가 명확한 경향이 있어 종종 더 저렴한 모델에서 병렬로 실행될 수 있습니다.
장기 메모리: 대화 간 지속성 유지하기
마지막에는 에이전트가 많은 것을 학습했을 것입니다. 그중 일부는 유용하고, 일부는 그렇지 않을 수도 있습니다.
에이전트에게 '요약할 때 문단 대신 글머리 기호를 사용해'라고 지시했다고 가정해 봅시다. 메모리가 없다면, 매주 이 말을 반복해야 할 것입니다. Deep Agents에서는 장기 기억(long-term memory)을 마크다운 파일로 처리합니다. 에이전트를 그 파일에 하나의 인자만으로 지정해주면, MemoryMiddleware가 나머지를 처리합니다:
로드(Load): 실행 시작 시 파일이 읽힙니다.
주입(Inject): 내용이 모델 호출마다 시스템 프롬프트에 추가됩니다.
업데이트(Update): 에이전트가 포맷팅 선호도와 같이 보존할 가치가 있는 것을 학습하면, 파일을 업데이트합니다.
모델을 바꿔도 기억은 유지하기
Deep Agents는 제공자 독립적(provider agnostic)이며, 이는 메모리에도 적용됩니다. 메모리가 사용자가 소유한 저장소의 일반 파일(제공자가 보유하는 것이 아님)이기 때문에, 동일한 백엔드를 다른 모델에 지정할 수 있습니다:
agent = create_deep_agent(
model="openai:gpt-6", # 제공자는 다르지만, 메모리는 같음
memory=["/memories/AGENTS.md"],
...
다음 주에는 다른 모델이 같은 파일을 읽고 여전히 글머리 기호로 요약할 수 있습니다.
염두에 둘 컨텍스트 엔지니어링 전략들
Deep Agents를 기반으로 구축하든, 다른 하네스(harness)를 사용하든, 직접 구축하든 관계없이, 다음 사항들을 확인해 보세요:
대용량 입력은 잘라내기(truncated)가 아니라 오프로드(offloaded)해야 합니다. 자르기는 손실적(lossy)입니다. 오프로딩은 검색 가능하게 유지합니다.
압축(Compaction)은 복구 가능해야 합니다. 요약 후에도 에이전트는 필요한 세부 정보를 다시 얻을 수 있어야 합니다.
노하우는 온디맨드(on demand)로 로드되어야 합니다. 모든 작업에 대한 지침을 시스템 프롬프트에 넣으면 호출마다 컨텍스트 비용이 발생합니다.
잡음이 많은 작업은 격리되어야 합니다. 자체 컨텍스트를 가진 서브 에이전트(Subagents)는 메인 에이전트를 집중하게 유지합니다.
메모리는 사용자가 소유해야 합니다. 사용자가 제어하는 저장소의 메모리는 모델이나 제공자 전환에도 살아남습니다.
기본값은 사용자 정의 가능해야 합니다. 한 작업에 적합한 임계값(Thresholds)이 모든 작업에 적합한 경우는 드뭅니다.
직접 시도해보기
uv add deepagents
실시간 강사에게 더 배우고 싶으신가요? 11월 3일에 다룰 예정이니, 여기서 등록하세요!
컨텍스트 엔지니어링에 대해 더 깊이 알고 싶다면, LangChain Academy의 무료 자율 학습 Deep Agents 코스를 확인해 보세요.
AI 자동 생성 콘텐츠
본 콘텐츠는 LangChain Blog의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기