API 그대로 노출했을 때 발생하는 '팽창'과 '혼선'

ChatGPT나 Claude 같은 LLM에 사내 API를 연결해 자동화 도구를 만들 때 실무자가 가장 먼저 시도하는 방법은 단순하다. 기존 API 엔드포인트를 그대로 노출하고, 에이전트가 API 명세서를 읽어 파라미터를 채워 호출하기를 기대하는 방식이다. 이는 단순한 유스케이스에서는 작동하지만, MCP(Model Context Protocol) 툴의 성능이 기대에 못 미치는 주원인이 된다. 단순한 API 패스스루(Passthrough) 방식은 모델의 추론 능력을 저하시키는 두 가지 문제를 야기한다.

첫 번째는 팽창(Bloat)이다. MCP 툴 정의는 호출 여부와 상관없이 매번 LLM의 컨텍스트에 로드된다. 여러 MCP 서버를 동시에 연결하면 질문을 던지기 전부터 상당한 양의 컨텍스트가 소모된다. 컨텍스트 창이 불필요한 도구 정의로 가득 차면 모델이 복잡한 지시사항을 누락하거나 엉뚱한 답변을 내놓는 등 추론 능력이 저하된다.

두 번째는 혼선(Confusion)이다. 추론 능력이 저하된 모델은 도구 선택 단계에서 잘못된 판단을 내려 엉뚱한 도구를 호출하거나 부적절한 파라미터를 입력한다. 특히 도구 간 의미적 유사성이 높거나 옵션이 너무 많을 때 심해진다. 이를 해결하기 위해 툴 설명에 구체적인 예시를 추가하면, 로드되는 토큰 양이 늘어나 다시 팽창 문제를 악화시키는 모순이 발생한다.

잘못된 호출 이후의 재시도(Retry) 과정은 이 악순환을 가속화한다. 실패 기록과 수정 시도가 컨텍스트에 누적되면서 팽창 속도가 빨라지고, 한 세션이 빠르게 무용지물이 된다. 결국 MCP 툴 설계의 핵심은 LLM이 무엇을 언제 보게 할 것인가를 결정하는 컨텍스트 엔지니어링에 있다. 팽창과 혼선 사이의 균형을 잡아야 도구 호출 정확도를 높이고 토큰 낭비를 막을 수 있다.

응답 토큰 2/3를 줄이는 온디맨드 출력과 에러 설계

일반적인 API는 요청한 데이터의 모든 필드를 한 번에 반환하지만, LLM 툴 설계는 정반대로 접근해야 한다. 50개의 필드를 한꺼번에 반환하는 툴은 컨텍스트를 빠르게 채워 모델의 추론 효율을 떨어뜨린다. 의사결정에 필요한 5개의 핵심 필드만 기본 응답으로 설정하고, 상세 정보가 필요할 때만 호출하는 온디맨드(On-demand) 방식을 적용한다. Anthropic의 연구에 따르면 이 방식을 통해 응답 토큰을 약 2/3가량 절감할 수 있으며, 불필요한 텍스트를 제거해 모델이 핵심 정보에 더 집중하게 만든다.

툴 호출 실패 시 반환하는 에러 메시지의 구체성 또한 중요하다. 단순히 `no results`라고 보내면 LLM은 쿼리 문법 오류인지 데이터 부재인지 판단하지 못해 잘못된 추측을 반복한다. 대신 `search requires 2 or more terms in query`와 같이 구체적인 수정 방향을 제시해야 한다. LLM은 이 메시지를 통해 파라미터 수정 방향을 정확히 인지하며, 이는 불필요한 재시도 횟수를 줄여 컨텍스트 팽창을 막는 실질적인 장치가 된다.

자연어 설명을 넘어 스키마 제약으로 모델의 추측 가능성을 제거하는 방법도 있다. Enum(열거형)을 설정하고 기본값을 지정하면 LLM이 파라미터 값을 결정하기 위해 수행하는 내부 추론 과정을 생략할 수 있다. 텍스트 기반 설명은 모델 버전마다 해석이 달라질 수 있지만, 엄격한 스키마 제약은 어떤 LLM에서도 동일한 입력값을 보장한다. 입력값과 출력 형식을 강제해 오류 가능성을 차단하는 것이 호출 정확도를 높이는 가장 확실한 방법이다.

지연 로딩(Lazy Loading)을 통한 토큰 85% 절감 전략

모든 도구 정의를 한꺼번에 로드하는 대신 필요한 순간에만 꺼내 쓰는 방식이 있다. 우선 다목적 도구 하나에 여러 기능을 몰아넣는 설계에서 벗어나, 이를 여러 개의 구체적인 도구로 분리한다. 작업 범위가 좁고 명확해질수록 엉뚱한 파라미터를 선택하는 빈도가 줄어든다. 여기서 더 나아가 지연 로딩(Lazy Loading) 발견 도구를 도입한다. 수십 개의 도구 설명을 상시 유지하는 대신, 별도의 검색 도구를 통해 현재 작업에 필요한 정의만 선택적으로 불러오게 설계하는 것이다.

이러한 접근은 Anthropic의 Tool Search Tool과 Amazon Bedrock AgentCore Gateway(에이전트의 도구 연결과 호출 과정을 최적화하는 게이트웨이)에서 증명되었다. Anthropic은 관련 있는 정의만 선별적으로 불러왔을 때 토큰 사용량이 최대 85%까지 감소했다고 보고했다. 이는 비용 절감을 넘어 모델이 읽어야 할 불필요한 텍스트를 제거함으로써 추론의 정밀도를 높이는 효과를 가져온다.

지연 로딩을 클라이언트 측에서 구현한 방식이 스킬(Skills)이다. 도구 사용에 필요한 세부 컨텍스트나 가이드를 로컬 파일에 저장하고, 관련 작업이 시작되는 시점에만 해당 파일을 읽어 컨텍스트에 추가한다. 서버 코드를 수정하거나 배포할 필요 없이 로컬 설정만으로 동작을 최적화할 수 있어 배포 속도가 빠르다. 다만 로컬 파일 기반이므로 스킬의 로드 시점을 정밀하게 제어하기 어렵고, 파일 버전이 최신 상태로 유지되지 않으면 동작의 일관성이 깨질 수 있다.

모델 독립성을 확보하는 인트로스펙션과 에이전트 백엔드

개별 툴의 최적화를 넘어 시스템 전체의 제어권을 확보하려면 인트로스펙션(Introspection)과 에이전트 백엔드 구조를 검토해야 한다. 인트로스펙션 도구는 외부 LLM을 호출하여 현재 상황에서 다른 도구들을 어떻게 사용해야 하는지 최적화된 지침을 생성해 제공한다. 서버 운영자가 직접 모델을 선택하고 골든 쿼리(Golden Query, 정답이 검증된 표준 질의문)를 통해 프롬프트 엔지니어링을 수행할 수 있어 실무적 이점이 크다. 클라이언트 LLM은 최종 호출 버튼만 누르고, 실제 파라미터 값은 서버 측 LLM이 가이드라인을 주는 방식이다.

더 높은 제어권이 필요하다면 에이전트 기반 MCP 서버를 구축해야 한다. 이 구조에서 개별 도구는 기술적 API 엔드포인트가 아닌 자연어 엔드포인트로 작동한다. 클라이언트가 자연어로 요청하면, 서버 측 에이전트가 내부적으로 어떤 도구를 어떤 순서로 호출하고 데이터를 가공할지 결정하여 최종 결과만 반환한다. 이 과정에서 지연 로딩이나 스키마 제약 같은 최적화 기법을 서버 내부에 내재화할 수 있다. 클라이언트는 복잡한 도구 정의를 읽을 필요가 없어 컨텍스트 팽창 문제를 원천적으로 차단하며, 서버 운영자는 클라이언트 LLM의 종류나 버전 업데이트와 무관하게 일관된 품질을 유지할 수 있다.

인트로스펙션과 에이전트 백엔드 중 선택은 필요한 제어 수준과 운영 비용에 따라 결정한다. 인트로스펙션은 기존 구조를 유지하며 파라미터 선택 오류만 잡고 싶을 때 적합하다. 반면 에이전트 백엔드는 호출 순서가 복잡하거나 클라이언트 LLM의 추론 능력을 신뢰할 수 없는 환경에서 필수적이다. 서버 측에서 모델을 직접 제어하면 특정 쿼리에 대해 항상 동일한 도구를 호출하도록 강제하는 결정론적 동작을 구현할 수 있어 엔터프라이즈 수준의 안정성을 확보할 수 있다.

Kiro CLI와 Amazon Bedrock을 활용한 실무 검증

14개의 필터 가능 필드를 가진 K-12 교육 콘텐츠 검색 백엔드가 이번 실무 검증의 기준점이다. 과목, 학년, 형식, 표준 정렬 등 제어된 어휘를 사용하는 복잡한 조건들이 얽혀 있어, LLM이 교사의 일상 언어를 정확한 API 파라미터로 변환해야 하는 까다로운 환경이다. 실습을 위해서는 Kiro CLI(MCP 서버 상호작용 인터페이스)를 설치하고 `python scripts/setup_agents.py`를 실행해 에이전트 환경을 구성한다. 모든 코드를 로컬에서 실행하며 Amazon Bedrock의 추론 비용만 발생하므로 부담 없이 테스트할 수 있다.

검증은 API를 그대로 노출한 V1 Raw Passthrough 버전부터 설계를 단계적으로 개선한 V6까지 총 6개 버전을 비교한다. V1은 내부 파라미터 이름인 `discipline`, `media_type`, `content_bucket` 등을 그대로 노출하고 짧은 문서 문자열만 제공하는 안티 패턴을 보여준다. 사용자의 자연어와 백엔드가 요구하는 엄격한 값 사이의 간극에서 발생하는 실패 지점을 로컬 환경에서 직접 확인할 수 있으며, 버전이 올라갈수록 도구 정의가 정교해지며 호출 정확도가 상승하는 과정을 관찰하는 것이 핵심이다.

샘플 코드는 GitHub 저장소에서 클론하여 사용할 수 있다. 각 버전의 성능을 객관적으로 비교하려면 `/clear` 명령어로 이전 대화의 컨텍스트를 완전히 초기화해야 한다. 이전 버전의 호출 결과가 남아 있으면 다음 버전의 순수 성능 측정에 간섭을 일으키기 때문이다. 버전 전환은 `/agent swap v1-passthrough`와 같이 명령어를 입력해 수행하며, 동일한 테스트 쿼리를 각 버전에 입력해 응답 정확도와 토큰 소모량을 비교한다.

실무자가 주목해야 할 지점은 모델이 정답에 도달하기 위해 얼마나 많은 불필요한 추론 과정을 거치는가이다. 최적화된 버전은 LLM이 고민할 여지를 줄여 도구 호출의 정확도를 높이고 전체적인 응답 속도를 개선한다. 결국 MCP 툴 설계의 성패는 모델의 추론 능력을 맹신하는 것이 아니라, 모델이 실수할 수 없는 구조를 만드는 구체적인 설계 기준을 확보하는 데 있다.

단순히 API를 연결하는 것과 LLM이 효율적으로 사용할 수 있는 도구를 설계하는 것은 별개의 설계 영역이다. 컨텍스트 팽창을 막고 도구 호출의 정확도를 높이는 힘은 모델의 추론 능력이 아니라 설계자가 쥐고 있는 제어권에서 나온다. 지연 로딩과 온디맨드 출력이라는 구체적인 제약이 없다면 LLM은 언제든 불필요한 토큰을 낭비하며 경로를 이탈한다.

본문에서 제시한 설계 기준을 현재 운영 중인 API 인터페이스에 즉시 대입해 보라. LLM의 무작위성을 제거하고 엔터프라이즈 수준의 안정성을 확보하는 유일한 방법은 모델의 지능을 맹신하는 것이 아니라 모델이 실수할 수 없는 구조를 만드는 것이다.