How to Fix Your Context

TMT

https://www.dbreunig.com/2025/06/26/how-to-fix-your-context.html

컨텍스트 실패 완화 및 회피

이전 게시물 “How Long Contexts Fail”[번역]에 이어, 이번에는 이러한 실패를 완화하거나 완전히 피할 수 있는 방법을 살펴보겠습니다.

하지만 그 전에, 긴 컨텍스트가 실패할 수 있는 몇 가지 방식을 간단히 요약해보겠습니다:

  • 컨텍스트 오염(Context Poisoning): 환각(hallucination)이나 기타 오류가 컨텍스트에 포함되어 반복적으로 참조되는 경우
  • 컨텍스트 산만(Context Distraction): 컨텍스트가 너무 길어져 모델이 훈련 중에 학습한 내용을 무시하고 컨텍스트에만 과도하게 집중하는 경우
  • 컨텍스트 혼란(Context Confusion): 컨텍스트에 불필요한 정보가 포함되어 모델이 저품질의 응답을 생성하는 경우
  • 컨텍스트 충돌(Context Clash): 새로운 정보나 도구가 컨텍스트에 추가되어 프롬프트 내의 다른 정보와 충돌하는 경우

여기서 중요한 것은 정보 관리입니다. 컨텍스트에 포함된 모든 것이 응답에 영향을 미칩니다. “Garbage in, garbage out(쓰레기가 들어가면, 쓰레기가 나온다)”라는 오래된 프로그래밍 격언이 다시 등장합니다. 다행히 위의 문제를 해결할 수 있는 다양한 방법이 있습니다.

컨텍스트 관리 전략

  • RAG: LLM이 더 나은 응답을 생성할 수 있도록 관련 정보를 선별적으로 추가하는 것
  • 도구 로드아웃: 컨텍스트에 추가할 도구 정의 중 관련 있는 것만 선택하는 것
  • 컨텍스트 격리: 각 컨텍스트를 별도의 전용 스레드에 분리하는 것
  • 컨텍스트 가지치기: 컨텍스트에서 불필요하거나 더 이상 필요하지 않은 정보를 제거하는 것
  • 컨텍스트 요약: 축적된 컨텍스트를 간결한 요약으로 압축하는 것
  • 컨텍스트 오프로딩: 정보를 LLM의 컨텍스트 외부에 저장하는 것(보통 데이터를 저장·관리하는 도구를 통해 수행)

RAG

Retrieval-Augmented Generation(RAG)은 LLM이 더 나은 응답을 생성할 수 있도록 관련 정보를 선별적으로 추가하는 행위입니다.

RAG에 대해서는 이미 많은 글이 있으므로, 오늘은 자세히 다루지 않겠습니다. RAG는 여전히 매우 활발하게 사용되고 있습니다.

모델의 컨텍스트 윈도우가 커질 때마다 “RAG는 죽었다”는 논쟁이 새롭게 시작됩니다. 마지막으로 큰 이슈가 되었던 것은 Llama 4 Scout가 _1,000만 토큰 윈도우_를 도입했을 때였습니다. 이 정도 크기에서는 “그냥 다 집어넣자”는 유혹이 정말 큽니다.

하지만 앞서 다뤘듯이, 컨텍스트를 잡동사니 서랍처럼 다루면, 그 잡동사니가 응답에 영향을 미칩니다. 더 알고 싶다면, 여기에 좋은 새 강좌가 있습니다.

도구 로드아웃(Tool Loadout)

Tool Loadout는 컨텍스트에 추가할 도구 정의를 선별하는 행위입니다.

“로드아웃(loadout)”이라는 용어는 게임에서 특정 캐릭터, 레벨, 팀 구성, 자신의 스킬셋에 맞게 능력, 무기, 장비를 조합해 선택하는 것을 의미합니다.

여기서는, 주어진 작업에 가장 적합한 도구를 선별하는 것을 의미합니다.

도구를 선택하는 가장 간단한 방법은 도구 설명에 RAG를 적용하는 것입니다. Tiantian Gan과 Qiyao Sun이 “RAG MCP” 논문에서 바로 이 방법을 사용했습니다. 도구 설명을 벡터 데이터베이스에 저장하고, 입력 프롬프트에 따라 가장 관련성 높은 도구를 선택했습니다.

DeepSeek-v3를 프롬프트할 때, 도구가 30개를 넘으면 올바른 도구 선택이 매우 중요해집니다. 30개를 넘으면 도구 설명이 겹치기 시작해 혼란이 생깁니다. _100개_가 넘으면 모델이 테스트에서 거의 반드시 실패했습니다. RAG 기법으로 30개 미만의 도구만 선택하면 프롬프트가 훨씬 짧아지고 도구 선택 정확도가 최대 3배까지 향상되었습니다.

더 작은 모델에서는 30개에 훨씬 못 미치는 시점부터 문제가 시작됩니다. 지난번에 언급한 “Less is More” 논문에서는 Llama 3.1 8b가 46개의 도구를 주면 벤치마크에서 실패하지만, 19개만 주면 성공한다고 밝혔습니다. 이 문제는 컨텍스트 윈도우 한계가 아니라, 컨텍스트 혼란 때문입니다.

이 문제를 해결하기 위해 “Less is More” 팀은 LLM 기반 도구 추천기를 사용해 도구를 동적으로 선택하는 방법을 개발했습니다. LLM에 “사용자 쿼리에 답하기 위해 필요하다고 ‘생각’하는 도구의 수와 종류”에 대해 추론하도록 프롬프트를 주었습니다. 이 결과를 의미론적으로 검색(다시 도구 RAG)해 최종 로드아웃을 결정했습니다. 이 방법을 Berkeley Function Calling Leaderboard에서 테스트한 결과, Llama 3.1 8b의 성능이 44% 향상되었습니다.

“Less is More” 논문은 더 작은 컨텍스트의 두 가지 추가 이점을 언급합니다: 전력 소비 감소와 속도 향상입니다. 이는 엣지(휴대폰이나 PC 등 특수 서버가 아닌 환경)에서 LLM을 운영할 때 매우 중요한 지표입니다. 동적 도구 선택 방법이 모델의 결과를 개선하지 못한 경우에도, 전력과 속도 면에서 각각 18%, 77%의 절감 효과가 있었습니다.

다행히 대부분의 에이전트는 소수의, 직접 선별한 도구만 필요합니다. 하지만 기능의 폭이나 통합 수가 늘어나야 한다면, 항상 로드아웃을 고려해야 합니다.

컨텍스트 격리(Context Quarantine)

Context Quarantine은 각 컨텍스트를 별도의 스레드에 격리해, 각각을 하나 이상의 LLM이 독립적으로 사용하는 행위입니다.

컨텍스트가 너무 길거나 관련 없는 내용이 포함되지 않도록 하려면, 작업을 더 작고 독립적인 작업으로 나누고 각 작업에 별도의 컨텍스트를 부여하는 것이 좋습니다.

이 전략의 예시는 많지만(1, 2), 접근하기 쉬운 사례로 Anthropic의 멀티 에이전트 연구 시스템에 대한 블로그 글이 있습니다. 그들은 다음과 같이 씁니다:

검색의 본질은 압축이다: 방대한 코퍼스에서 인사이트를 추출하는 것. 서브에이전트는 각자 고유한 컨텍스트 윈도우로 병렬로 동작하며, 질문의 다양한 측면을 동시에 탐색한 뒤, 리드 연구 에이전트에게 가장 중요한 토큰을 압축해 전달한다. 각 서브에이전트는 관심사의 분리를 제공하며—각기 다른 도구, 프롬프트, 탐색 경로를 사용—경로 의존성을 줄이고 철저하고 독립적인 탐구를 가능하게 한다.

연구 작업은 이 설계 패턴에 잘 맞습니다. 질문을 받으면 여러 하위 질문이나 탐색 영역을 식별해, 각각을 여러 에이전트로 독립적으로 프롬프트할 수 있습니다. 이는 정보 수집과 요약을 더 빠르게 할 수 있을 뿐 아니라(컴퓨트가 충분하다면), 각 컨텍스트가 너무 많은 정보나 관련 없는 정보를 쌓지 않게 해 더 높은 품질의 결과를 제공합니다:

내부 평가에 따르면, 멀티 에이전트 연구 시스템은 여러 독립적인 방향을 동시에 추구하는 폭넓은 쿼리에서 특히 뛰어났습니다. Claude Opus 4를 리드 에이전트로, Claude Sonnet 4를 서브에이전트로 둔 멀티 에이전트 시스템은 단일 에이전트 Claude Opus 4보다 내부 연구 평가에서 90.2% 더 나은 성과를 보였습니다. 예를 들어, Information Technology S&P 500 기업의 모든 이사회 구성원을 식별하라는 질문에서, 멀티 에이전트 시스템은 이를 하위 작업으로 분해해 서브에이전트가 각각 처리함으로써 정답을 찾았지만, 단일 에이전트 시스템은 느린 순차적 검색으로 실패했습니다.

이 접근법은 도구 로드아웃에도 도움이 됩니다. 에이전트 설계자는 각기 다른 로드아웃과 도구 사용 지침을 가진 여러 에이전트 아키타입을 만들 수 있습니다.

따라서 에이전트 빌더의 과제는, 별도의 스레드로 분리할 수 있는 작업 기회를 찾는 것입니다. 여러 에이전트가 컨텍스트를 공유해야 하는 문제에는 이 전략이 적합하지 않습니다.

에이전트의 도메인이 병렬화에 적합하다면, Anthropic의 전체 글을 꼭 읽어보세요. 정말 훌륭합니다.

컨텍스트 가지치기(Context Pruning)

Context Pruning은 컨텍스트에서 불필요하거나 더 이상 필요하지 않은 정보를 제거하는 행위입니다.

에이전트는 도구를 실행하고 문서를 조립하면서 컨텍스트를 축적합니다. 때로는 지금까지 모은 내용을 점검하고 불필요한 부분을 제거하는 것이 필요합니다. 이 작업은 메인 LLM에 맡길 수도 있고, 별도의 LLM 기반 도구를 설계해 컨텍스트를 검토·편집하게 할 수도 있습니다. 또는 가지치기 작업에 더 특화된 방법을 선택할 수도 있습니다.

컨텍스트 가지치기는 비교적 오랜 역사를 가지고 있습니다. 컨텍스트 길이가 자연어처리(NLP) 분야에서 더 큰 병목이었던 ChatGPT 이전 시절부터 사용되었습니다. 최근의 가지치기 방법으로는 Provence가 있습니다. “질문 응답을 위한 효율적이고 강인한 컨텍스트 프루너”입니다.

Provence는 빠르고, 정확하며, 사용이 간단하고, 비교적 작습니다(1.75GB). 몇 줄만으로 호출할 수 있습니다:

from transformers import AutoModel

provence = AutoModel.from_pretrained("naver/provence-reranker-debertav3-v1", trust_remote_code=True)

# Alameda, CA의 위키피디아 마크다운 버전 읽기
with open('alameda_wiki.md', 'r', encoding='utf-8') as f:
    alameda_wiki = f.read()

# 질문에 따라 기사 가지치기
question = 'What are my options for leaving Alameda?'
provence_output = provence.process(question, alameda_wiki)

Provence는 기사의 95%를 잘라내고, 관련 있는 부분만 남겼습니다. 완벽했습니다.

Provence나 유사한 기능을 사용해 문서나 전체 컨텍스트를 정리할 수 있습니다. 또한, 컨텍스트를 딕셔너리 등 구조화된 형태로 유지하다가, LLM 호출 직전에 문자열로 조립하는 패턴은 가지치기 작업에 매우 유리합니다. 이렇게 하면 주요 지침과 목표는 보존하면서, 문서나 히스토리 섹션만 가지치기하거나 요약할 수 있습니다.

컨텍스트 요약(Context Summarization)

Context Summarization은 축적된 컨텍스트를 간결한 요약으로 압축하는 행위입니다.

컨텍스트 요약은 작은 컨텍스트 윈도우를 다루기 위한 도구로 처음 등장했습니다. 채팅 세션이 최대 컨텍스트 길이에 가까워지면, 요약을 생성해 새 스레드를 시작했습니다. ChatGPT나 Claude에서 사용자가 직접 요약을 요청해, 그 결과를 새 세션에 붙여넣는 식이었습니다.

하지만 컨텍스트 윈도우가 커지면서, 에이전트 빌더들은 단순히 한도를 넘지 않기 위한 것 이상의 요약의 이점을 발견했습니다. 컨텍스트가 커질수록 산만해지고, 모델이 훈련 중에 학습한 내용을 덜 활용하게 됩니다. 이를 컨텍스트 산만(Context Distraction)이라 불렀습니다. 포켓몬 플레이 Gemini 에이전트 팀은 100,000 토큰을 넘어서면 이런 현상이 나타난다고 밝혔습니다:

Gemini 2.5 Pro는 1M+ 토큰 컨텍스트를 지원하지만, 에이전트에 효과적으로 활용하는 것은 새로운 연구 과제입니다. 이 에이전트 환경에서, 컨텍스트가 100k 토큰을 크게 넘어서면, 에이전트가 방대한 히스토리에서 반복 행동을 선호하고, 새로운 계획을 합성하는 경향이 나타났습니다. 이 현상은 일화적이지만, 검색을 위한 장기 컨텍스트와 다단계 생성적 추론을 위한 장기 컨텍스트의 중요한 차이를 보여줍니다.

컨텍스트 요약은 쉽게 할 수 있지만, 특정 에이전트에 최적화하는 것은 어렵습니다. 어떤 정보를 반드시 보존해야 하는지, LLM 기반 압축 단계에 어떻게 명확히 지시할지 아는 것이 중요합니다. 이 기능을 별도의 LLM 기반 단계나 앱으로 분리해, 평가 데이터를 수집하고 직접 최적화하는 것이 좋습니다.

컨텍스트 오프로딩(Context Offloading)

Context Offloading은 정보를 LLM의 컨텍스트 외부에 저장하는 행위로, 보통 데이터를 저장·관리하는 도구를 통해 이루어집니다.

이 방법은 너무 간단해서 효과가 없을 것 같지만, 실제로는 매우 잘 작동합니다.

Anthropic의 이 기법에 대한 좋은 글이 있습니다. 그들은 “think” 도구를 소개하는데, 사실상 스크래치패드(scratchpad)입니다:

“think” 도구를 통해 Claude에게 최종 답변을 도출하는 과정에서 별도의 공간을 할당해 추가적인 사고 단계를 포함할 수 있게 했습니다… 이는 도구 호출이 여러 번 이어지거나, 사용자와의 다단계 대화에서 특히 유용합니다.

Anthropic의 연구와 글을 높이 평가하지만, 이 도구의 이름은 마음에 들지 않습니다. 만약 이 도구의 이름이 ‎⁠scratchpad⁠였다면, 기능이 즉시 이해됐을 것입니다. 모델이 컨텍스트를 어지럽히지 않고, 나중에 참고할 수 있도록 메모를 남기는 공간입니다. “think”라는 이름은 “extended thinking”과 혼동되고, 불필요하게 모델을 의인화합니다… 하지만 이만 하겠습니다.

메모와 진행 상황을 기록할 공간을 두는 것은 효과가 있습니다. Anthropic은 “think” 도구와 도메인 특화 프롬프트를 결합하면(에이전트라면 당연히 하겠지만), 특수화된 에이전트 벤치마크에서 최대 54%의 성능 향상을 보인다고 밝혔습니다.

Anthropic은 컨텍스트 오프로딩 패턴이 유용한 세 가지 시나리오를 제시합니다:

  1. 도구 출력 분석. Claude가 이전 도구 호출의 출력을 신중히 처리해야 하며, 접근 방식을 되돌릴 필요가 있을 때;
  2. 정책 중심 환경. Claude가 상세한 지침을 따라야 하고, 준수 여부를 검증해야 할 때;
  3. 순차적 의사결정. 각 행동이 이전 행동에 기반하고, 실수가 치명적인(다단계 도메인에서 흔히 발생) 경우.

컨텍스트 관리는 에이전트 구축에서 가장 어려운 부분입니다. Karpathy가 말했듯이, “컨텍스트 윈도우를 딱 맞게 채우는 것”과 도구, 정보, 정기적인 컨텍스트 유지보수를 현명하게 배치하는 것이 에이전트 설계자의 핵심 임무입니다.

위의 모든 전략에서 얻을 수 있는 핵심 통찰은 컨텍스트는 공짜가 아니다 라는 점입니다. 컨텍스트의 모든 토큰이 모델의 행동에 긍정적이든 부정적이든 영향을 미칩니다. 현대 LLM의 거대한 컨텍스트 윈도우는 강력한 기능이지만, 정보 관리를 소홀히 해도 된다는 뜻은 아닙니다.

다음 에이전트를 만들거나 기존 에이전트를 최적화할 때, “이 컨텍스트의 모든 요소가 제 역할을 하고 있는가?”를 자문해보세요. 그렇지 않다면, 이제 여섯 가지 해결책이 있습니다.

Edit this page

On this Page