LLM(대형 언어 모델) 기반 에이전트 시스템이 고도화됨에 따라, 우리는 **‘도구의 역설(Paradox of Tools)’**에 직면했다. 에이전트가 더 많은 능력을 갖추기 위해 더 많은 도구(Tools)를 연결할수록, 역설적으로 에이전트는 무거워지고 비효율적으로 변한다.

 

최근 Anthropic이 제시한 MCP(Model Context Protocol)와 코드 실행(Code execution) 모델은 이 문제를 해결할 강력한 해법을 제시한다. 본 글에서는 현재 에이전트 시스템이 가진 구조적 비효율성을 진단하고, 이를 타개할 MCP 기반의 새로운 접근법과 아키텍처적 시사점을 논한다.


1. 현재의 병목: 컨텍스트 윈도우의 오염 (Context Pollution)

기존의 Function Calling(도구 호출) 방식은 도구의 수가 늘어날수록 확장성에 치명적인 한계를 드러낸다. 이는 크게 두 가지 측면에서 기인한다.

① 정의(Definition) 자체가 차지하는 공간 비용

전통적인 방식에서는 에이전트가 사용할 수 있는 모든 도구의 이름, 설명, 파라미터 스키마를 JSON 형태로 프롬프트에 미리 로드해야 한다. 수천 개의 API를 연동한다고 가정해보자. 에이전트는 작업을 시작하기도 전에 도구의 명세서(Manual)를 읽는 데만 막대한 양의 토큰을 소모한다. 이는 실제 추론에 사용되어야 할 컨텍스트 공간을 잠식한다.

② 중간 데이터(Intermediate Data)의 중복 적재

"구글 드라이브의 2시간 분량 회의 녹취록을 가져와 세일즈포스에 첨부하라"는 작업을 예로 들어보자.

  • 기존 방식: 에이전트는 녹취록 전체 텍스트를 구글 드라이브에서 읽어와 컨텍스트 윈도우에 적재한다. 그 후, 세일즈포스 도구를 호출할 때 이 텍스트를 다시 파라미터로 전달한다.
  • 문제점: 최종 결과는 단순히 '첨부 완료'라는 상태값이면 충분하다. 그러나 이 과정에서 대용량의 raw data가 컨텍스트 윈도우를 가득 채우며, 정작 중요한 '추론'을 위한 공간은 사라진다.

2. 해결책: 탐색과 코드 실행 (Discovery & Execution)

Anthropic의 MCP 접근법은 에이전트에게 '모든 도구'를 쥐여주는 대신, **'도구를 찾는 방법'과 '코드를 작성하는 능력'**을 부여함으로써 이 문제를 해결한다.

동적 탐색 (Dynamic Discovery)

에이전트는 모든 도구의 JSON을 갖고 있지 않다. 대신 ls, grep과 같은 터미널 명령어처럼, 현재 환경에 존재하는 도구를 탐색할 수 있는 최상위 도구만을 가진다. 예를 들어 github_api.py, jira_api.py 등의 존재를 확인한 뒤, 필요한 경우에만 해당 도구의 내부 명세를 들여다본다. 이는 불필요한 초기 토큰 소모를 획기적으로 줄인다.

체이닝 대신 코드 작성 (Write Code, Don't Chain)

이 접근법의 핵심은 에이전트가 도구를 순차적으로 호출(Chaining)하는 것이 아니라, 도구를 제어하는 코드를 작성한다는 점이다.

  1. 에이전트는 목표 달성을 위해 필요한 도구들을 파악한다.
  2. 해당 도구들을 조합하여 실행할 수 있는 Python 코드를 작성한다.
  3. 이 코드는 MCP Server를 통해 격리된 샌드박스 환경에서 실행된다.
  4. 에이전트는 실행의 **최종 결과(Result)**만을 컨텍스트로 반환받는다.

즉, 에이전트는 단순한 'Operator'에서 로직을 설계하는 'Programmer'로 진화한다.


3. 실전 사례: Repo Detective와 98.7%의 효율 혁명

이 기술의 진가는 Anthropic 엔지니어링 팀이 설계한 'Repo Detective(코드 저장소 탐정)' 벤치마크에서 극명하게 드러납니다. 수천 개의 파일로 이루어진 거대한 레거시 코드 저장소에서 특정 기능의 구현 위치를 찾아내 버그를 수정해야 하는, 개발자들에게는 매우 익숙하면서도 고통스러운 시나리오입니다.

 

이 실험은 **"컨텍스트 오염(Context Pollution)을 어떻게 통제하는가"**가 에이전트 성능의 핵심임을 증명합니다.

[접근법 A: 전통적인 도구 호출 (The Brute-Force Way)]

기존 에이전트는 마치 **'모든 책을 일일이 펴보는 도서관 사서'**와 같습니다.

  1. 무차별적 파일 로딩: 파일명만으로는 내용을 확신할 수 없으므로, 에이전트는 read_file 도구를 반복적으로 호출합니다.
  2. 컨텍스트 오염 발생: 파일을 열어 내용을 확인하는 순간, 해당 파일의 텍스트 데이터가 에이전트의 컨텍스트 윈도우(Context Window)로 쏟아져 들어옵니다.
  3. 치명적 비효율: 열어본 파일이 찾던 파일이 아니더라도, 이미 소모된 토큰과 점유된 컨텍스트 공간은 회복되지 않습니다. 수십 개의 파일을 열어보는 과정에서 이전의 중요한 지시사항이나 추론 맥락이 밀려나(Eviction) 망각되는 현상이 발생합니다.

[접근법 B: MCP 코드 실행 (The Programmatic Way)]

반면, 코드 실행 에이전트는 **'데이터베이스 쿼리를 날리는 엔지니어'**와 같습니다. 탐색과 필터링의 주체가 LLM의 '두뇌(Context)'가 아닌, 격리된 '샌드박스(Compute)'입니다.

  1. 로직을 통한 위임: 에이전트는 파일을 직접 여는 대신, 파이썬 스크립트를 작성합니다.
  2. Python
    # 에이전트가 작성한 코드 예시
    import os
    # 모든 파일을 순회하며 'payment_gateway' 로직이 포함된 파일 경로만 반환
    ...
    
  3. 외부에서의 연산: 이 코드는 MCP 서버의 샌드박스에서 실행됩니다. 수천 개의 파일을 읽고 검사하는 무거운 작업은 샌드박스 내에서 수행되며, 에이전트의 컨텍스트와는 무관합니다.
  4. 정제된 결과 수신: 스크립트는 검색 조건에 완벽히 부합하는 단 하나의 파일 경로만을 에이전트에게 반환합니다. 에이전트는 정확히 타겟팅 된 파일만 컨텍스트에 로드합니다.

[결과: 98.7%의 컨텍스트 오염 감소]

이 구조적 차이는 충격적인 효율성 격차를 만들어냈습니다.

  • 기존 방식은 수많은 파일을 컨텍스트에 올렸다가 버리는 과정을 반복하며 막대한 리소스를 낭비했습니다.
  • MCP 코드 실행 방식은 탐색 과정을 코드로 오프로딩(Offloading)함으로써, 기존 대비 컨텍스트 오염을 98.7% 감소시켰습니다.

결론적으로, MCP를 활용한 코드 실행은 단순한 기능 추가가 아닙니다. 이는 에이전트가 **'정보를 처리하는 방식'**을 인간의 직관적 탐색에서 기계의 논리적 연산으로 전환하여, LLM의 가장 비싼 자원인 컨텍스트 윈도우를 보호하는 핵심 전략입니다.


4. 아키텍처 비교: Single Agent Optimization vs Multi-Agent System

여기서 한 가지 논리적인 의문이 제기될 수 있다. "단일 에이전트의 컨텍스트 오염을 막기 위해, 별도의 작업자(Laborer) 에이전트에게 중간 처리를 위임하면 되지 않는가?"

이는 **Multi-Agent System (Orchestrator-Worker 패턴)**과 MCP Code Execution 간의 트레이드오프(Trade-off) 문제로 귀결된다.

접근법 A: 잡부 에이전트 (Laborer Agent) 활용

  • 개념: Orchestrator가 Worker에게 작업을 위임한다. Worker가 데이터를 처리하고 요약된 결과만 보고한다.
  • 장점: 역할이 명확하게 분리되며, 복잡하고 이질적인 업무 흐름(Workflow) 관리에 적합하다.
  • 단점: 에이전트 간 통신 비용(Latency)과 시스템 복잡도가 증가한다. 각 Worker 역시 내부적으로는 비효율적인 도구 사용 문제를 겪을 수 있다.

접근법 B: MCP 기반 코드 실행

  • 개념: 단일 에이전트 내에서 도구 사용 프로세스를 최적화한다.
  • 장점: 즉각적인 실행 속도, 낮은 토큰 비용, 아키텍처의 단순함.
  • 단점: 단일 컨텍스트 내에서 처리하기 힘든 초거대 작업에는 한계가 있을 수 있다.

결론: 상호보완적 관계

두 방식은 대립적이라기보다 상호보완적이다. Multi-Agent 시스템을 구축하더라도, 각 Worker(Laborer) 에이전트가 내부적으로 MCP 기반의 코드 실행 방식을 채택해야 한다. 즉, MCP Code Execution은 에이전트라는 '단위(Unit)'의 효율성을 극대화하는 기술이며, Multi-Agent 패턴은 이 단위들을 조직하는 구조적 해법이다.


5. 위임의 딜레마와 검증의 필수성 (The Dilemma of Delegation & Verification)

MCP를 통한 코드 실행이든, 멀티 에이전트 시스템이든 본질은 **'작업의 위임(Delegation)'**이다. 하지만 맹목적인 위임은 해결책이 아니라 또 다른 병목을 낳는다. 우리는 '무엇을' 위임할 것인가, 그리고 그 결과를 '어떻게' 믿을 것인가에 대해 냉철하게 따져봐야 한다.

① 코드 실행의 함정: 계산기 놀이 vs 문제 해결 (Granularity & Cohesion)

에이전트가 코드를 작성한다고 해서 모든 문제가 해결되는 것은 아니다. 가장 경계해야 할 것은 **'단위(Granularity)의 오류'**다.

  • 하위-하위 문제(Sub-sub-problem)의 착각: 에이전트가 단순히 계산기 수준의 작은 로직을 처리하기 위해 코드를 작성한다면, 코드를 생성하고 샌드박스를 오가는 오버헤드가 더 클 수 있다. 이는 컨텍스트 최적화에 실패한 것이다.
  • 목표 지향적 응집성(Goal-Oriented Cohesion): 코드 실행은 단순한 연산 도구가 아니라, **독립적인 문제 하나를 완결 짓는 '해결사'**가 되어야 한다. 작성된 코드는 그 자체로 응집성을 가져야 하며, 샌드박스 내부에서 발생하는 사소한 오류는 에이전트의 개입 없이 코드 내부의 예외 처리나 재시도 로직으로 스스로 치유(Self-healing)되어야 한다. 그래야만 비로소 메인 에이전트의 컨텍스트를 보호할 수 있다.

물론 LLM의 추론 및 계획 능력이 향상됨에 따라 이 간극은 줄어들겠지만, "코드를 짤 줄 아는 능력"이 곧 "문제를 해결하는 능력"을 담보하지 않음을 명심해야 한다.

② 멀티 에이전트의 과제: 생성보다 어려운 검증 (Generation vs. Verification)

반면, 다른 에이전트(Worker)에게 작업을 맡기는 방식은 '핵심 하위 문제(Core Sub-problem)' 전체를 떼어낼 수 있어 컨텍스트 확보에 유리하다. 하지만 여기서 문제는 **'신뢰 비용'**으로 전이된다.

LLM의 세계에서는 작업 수행(Generation)보다 **수행 결과의 검증(Verification)**이 몇 배 더 어렵고 중요하다. "작업을 완료했다"는 에이전트의 말을 그대로 믿는 것은 시스템의 붕괴를 의미한다.

  • Critic(비평가)의 도입: 모든 작업 생성 에이전트(Generator) 뒤에는 반드시 그 결과를 뜯어보는 비평가 에이전트(Critic)가 붙어야 한다.
  • 객관적 증명(Objective Proof): 비평가의 기준은 주관적 감상이 아닌 객관적 지표여야 한다. 수학에서 논리적 증명이 필요하듯, 소프트웨어 엔지니어링에서는 **'테스트 코드'**가 그 역할을 한다.

즉, 에이전트는 결과물만 던지는 것이 아니라, 그 결과물이 올바르게 작동함을 증명하는 테스트 모듈을 함께 제출해야 한다.

③ 결론: 검증 가능한 위임만이 유효하다

결국 효율적인 에이전트 시스템을 구축한다는 것은 **'어떻게 위임할 것인가(How to delegate)'**와 **'어떻게 검증할 것인가(How to verify)'**를 설계하는 일이다.

 

객관적인 검증 방법론과 견고한 테스트 작성법, 그리고 이를 자동화하는 TDD(Test Driven Development) for Agents 아키텍처는 그 자체로 방대한 주제이므로, 별도의 지면을 통해 심도 있게 다루도록 하겠다. 하지만 원칙은 분명하다. 검증되지 않은 위임은 도박일 뿐이다.

+ Recent posts