AI 에이전트를 위한 효과적인 도구, AI 에이전트로 작성하기
모델 컨텍스트 프로토콜(Model Context Protocol, MCP)을 활용하면 LLM 에이전트에 수백 가지 도구를 연결해 실제 업무를 처리할 수 있습니다. 그렇다면 이 도구들의 효과를 극대화하려면 어떻게 해야 할까요?
이 글에서는 다양한 에이전트 AI 시스템의 성능을 개선하는 데 가장 효과적이었던 기법들을 소개합니다1.
먼저 다음 내용을 다룹니다:
이어서, 이 과정에서 발견한 고품질 도구 작성을 위한 핵심 원칙들을 정리합니다:

컴퓨팅에서 결정적(deterministic) 시스템은 동일한 입력에 항상 동일한 출력을 내놓는 반면, 에이전트와 같은 비결정적(non-deterministic) 시스템은 같은 조건에서도 매번 다른 응답을 생성할 수 있습니다.
기존의 소프트웨어 개발은 결정적 시스템 간의 계약을 정의하는 작업이었습니다. 예를 들어, getWeather(“NYC”) 같은 함수 호출은 실행할 때마다 항상 정확히 같은 방식으로 뉴욕의 날씨를 가져옵니다.
도구는 결정적 시스템과 비결정적 에이전트 사이의 계약을 나타내는 새로운 유형의 소프트웨어입니다. 사용자가 "오늘 우산을 가져가야 할까요?"라고 물으면, 에이전트는 날씨 도구를 호출할 수도 있고, 일반 지식으로 답할 수도 있으며, 먼저 위치를 묻는 확인 질문을 던질 수도 있습니다. 때로는 에이전트가 환각을 일으키거나 도구 사용법 자체를 파악하지 못하는 경우도 있습니다.
따라서 에이전트를 위한 소프트웨어를 작성할 때는 근본적으로 접근 방식을 바꿔야 합니다. 다른 개발자나 시스템을 위해 함수와 API를 작성하듯 도구와 MCP 서버를 만드는 것이 아니라, 에이전트에 맞춰 설계해야 합니다.
우리의 목표는 에이전트가 다양한 전략으로 폭넓은 과제를 효과적으로 해결할 수 있는 영역을 넓히는 것입니다. 다행히 경험상, 에이전트에게 가장 '인체공학적'인 도구는 사람이 보기에도 놀라울 만큼 직관적입니다.
이 섹션에서는 에이전트와 협업해 도구를 작성하고 개선하는 방법을 설명합니다. 먼저 도구의 빠른 프로토타입을 구축하고 로컬에서 테스트하세요. 이후 종합적인 평가를 실행해 변경 사항의 효과를 측정합니다. 에이전트와 함께 평가와 개선 과정을 반복하면, 실제 업무에서 높은 성능을 달성할 수 있습니다.
에이전트가 어떤 도구를 편리하게 사용하고 어떤 도구에 어려움을 겪을지는 직접 해보기 전까지 예측하기 어렵습니다. 우선 도구의 빠른 프로토타입을 만들어 보세요. Claude Code로 도구를 작성한다면(원샷으로도 가능), 도구가 의존하는 소프트웨어 라이브러리, API, SDK(MCP SDK 포함)의 문서를 Claude에 제공하면 도움이 됩니다. LLM 친화적인 문서는 공식 문서 사이트에서 단일 llms.txt 파일로 제공되는 경우가 많습니다(Anthropic API 문서도 마찬가지입니다).
도구를 로컬 MCP 서버나 데스크톱 확장(DXT)으로 래핑하면 Claude Code 또는 Claude 데스크톱 앱에서 바로 연결해 테스트할 수 있습니다.
로컬 MCP 서버를 Claude Code에 연결하려면 claude mcp add <name> <command> [args...]를 실행하세요.
로컬 MCP 서버나 DXT를 Claude 데스크톱 앱에 연결하려면 각각 Settings > Developer 또는 Settings > Extensions로 이동하세요.
프로그래밍 방식의 테스트를 위해 Anthropic API 호출에 도구를 직접 전달할 수도 있습니다.
직접 도구를 사용해 보면서 거친 부분을 찾아내세요. 사용자 피드백을 수집해 도구가 지원해야 할 사용 사례와 프롬프트에 대한 감각을 키워 나가세요.
다음으로, Claude가 도구를 얼마나 잘 활용하는지 평가를 통해 측정해야 합니다. 실제 사용 사례에 기반한 평가 태스크를 다량으로 생성하는 것부터 시작하세요. 결과를 분석하고 도구 개선 방향을 결정하는 과정에서 에이전트와 협업하는 것을 권장합니다. 전 과정을 확인하려면 도구 평가 쿡북을 참고하세요.

평가 태스크 생성
초기 프로토타입이 준비되면, Claude Code를 활용해 도구를 빠르게 탐색하고 수십 개의 프롬프트-응답 쌍을 생성할 수 있습니다. 프롬프트는 실제 사용 사례에서 영감을 얻어야 하며, 현실적인 데이터 소스와 서비스(예: 사내 지식 베이스, 마이크로서비스)를 기반으로 해야 합니다. 도구를 충분히 검증하지 못하는 지나치게 단순하거나 피상적인 "샌드박스" 환경은 피하세요. 좋은 평가 태스크는 여러 번의 도구 호출—수십 건에 달할 수도 있는—을 필요로 합니다.
좋은 태스크의 예시입니다:
반면, 다음은 약한 태스크의 예시입니다:
purchase_complete와 customer_id=9182를 검색해줘.각 평가 프롬프트에는 검증 가능한 응답이나 결과를 함께 지정해야 합니다. 검증기는 정답과 샘플 응답 간의 단순 문자열 비교처럼 간단할 수도 있고, Claude를 판정자로 활용하는 고급 방식일 수도 있습니다. 서식, 구두점, 유효한 대안 표현 등 사소한 차이 때문에 올바른 응답을 거부하는 과도하게 엄격한 검증기는 피하세요.
각 프롬프트-응답 쌍에 대해, 태스크 해결 시 에이전트가 호출해야 할 도구를 선택적으로 지정할 수 있습니다. 이를 통해 평가 중 에이전트가 각 도구의 목적을 제대로 이해하는지 측정할 수 있습니다. 다만 올바른 해결 경로가 여러 개일 수 있으므로, 전략을 지나치게 세부적으로 지정하거나 특정 방식에 과적합하지 않도록 주의하세요.
평가 실행
LLM API를 직접 호출하는 프로그래밍 방식으로 평가를 실행하는 것을 권장합니다. LLM API 호출과 도구 호출을 번갈아 실행하는 간단한 에이전트 루프(while 루프)를 사용하세요. 평가 태스크마다 하나의 루프를 실행합니다. 각 평가 에이전트에게는 단일 태스크 프롬프트와 도구를 제공합니다.
평가 에이전트의 시스템 프롬프트에서는 구조화된 응답 블록(검증용)뿐 아니라, 추론 및 피드백 블록도 출력하도록 지시하는 것이 좋습니다. 이러한 블록을 도구 호출과 응답 블록 이전에 출력하도록 하면, 체인 오브 쏘트(CoT) 동작이 유발되어 LLM의 실질적인 추론 능력이 향상될 수 있습니다.
Claude로 평가를 실행하는 경우, 인터리브드 씽킹(interleaved thinking)을 켜면 별도의 설정 없이 유사한 기능을 활용할 수 있습니다. 이를 통해 에이전트가 특정 도구를 호출하거나 호출하지 않는 이유를 파악하고, 도구 설명과 스펙에서 개선이 필요한 부분을 구체적으로 찾아낼 수 있습니다.
전체 정확도 외에도, 개별 도구 호출 및 태스크의 총 실행 시간, 전체 도구 호출 횟수, 총 토큰 소비량, 도구 오류 등의 지표를 함께 수집하는 것이 좋습니다. 도구 호출을 추적하면 에이전트가 자주 사용하는 워크플로를 파악할 수 있고, 도구를 통합할 수 있는 기회도 발견할 수 있습니다.

결과 분석
에이전트는 모순되는 도구 설명, 비효율적인 도구 구현, 혼란스러운 도구 스키마 등 다양한 문제를 발견하고 피드백을 제공하는 훌륭한 협력자입니다. 다만 에이전트의 피드백과 응답에서 빠져 있는 내용이 포함된 내용보다 더 중요할 수 있다는 점을 기억하세요. LLM이 항상 자신의 의도를 정확히 표현하지는 않습니다.
에이전트가 막히거나 혼란스러워하는 지점을 관찰하세요. 평가 에이전트의 추론 및 피드백(또는 CoT)을 읽으며 거친 부분을 찾아내세요. 원본 트랜스크립트(도구 호출과 도구 응답 포함)를 검토해 에이전트의 CoT에 명시적으로 드러나지 않는 행동도 포착하세요. 행간을 읽으세요. 평가 에이전트가 정답과 올바른 전략을 반드시 알고 있는 것은 아닙니다.
도구 호출 지표를 분석하세요. 중복 호출이 많다면 페이지네이션이나 토큰 제한 파라미터의 적정 수준을 조정할 필요가 있을 수 있고, 잘못된 파라미터로 인한 도구 오류가 많다면 설명을 명확히 하거나 더 나은 예시를 추가해야 할 수 있습니다. Claude의 웹 검색 도구를 출시할 때, Claude가 도구의 query 파라미터에 불필요하게 2025를 추가해 검색 결과에 편향을 일으키고 성능을 저하시키는 문제를 발견했습니다(도구 설명을 개선해 올바른 방향으로 유도했습니다).
에이전트에게 결과 분석과 도구 개선을 맡길 수도 있습니다. 평가 에이전트의 트랜스크립트를 모아서 Claude Code에 붙여넣기만 하면 됩니다. Claude는 트랜스크립트 분석과 다수의 도구를 한꺼번에 리팩터링하는 데 뛰어납니다. 예를 들어, 변경 사항이 생겼을 때 도구 구현과 설명이 서로 일관성을 유지하도록 정리할 수 있습니다.
실제로, 이 글에 담긴 대부분의 조언은 Claude Code로 내부 도구 구현을 반복 최적화하는 과정에서 얻은 것입니다. 평가는 실제 프로젝트, 문서, 메시지를 포함한 내부 워크스페이스 위에서 만들어졌으며, 내부 워크플로의 복잡성을 그대로 반영합니다.
홀드아웃 테스트 세트를 활용해 "학습용" 평가에 과적합되지 않도록 했습니다. 이 테스트 세트를 통해, 연구원이 직접 작성하거나 Claude가 생성한 "전문가 수준" 도구 구현에서도 추가적인 성능 개선을 이끌어낼 수 있음을 확인했습니다.
다음 섹션에서는 이 과정에서 배운 내용을 공유합니다.
이 섹션에서는 그간의 경험을 효과적인 도구 작성을 위한 몇 가지 핵심 원칙으로 정리합니다.
도구가 많다고 반드시 좋은 결과로 이어지는 것은 아닙니다. 흔히 관찰되는 실수는, 에이전트에 적합한지 여부와 관계없이 기존 소프트웨어 기능이나 API 엔드포인트를 단순히 감싸기만 한 도구를 만드는 것입니다. 에이전트는 기존 소프트웨어와 근본적으로 다른 "어포던스(affordance)"를 갖기 때문입니다. 즉, 도구를 활용해 수행할 수 있는 행동을 인식하는 방식 자체가 다릅니다.
LLM 에이전트는 한 번에 처리할 수 있는 정보량에 한계가 있어 "컨텍스트"가 제한적인 반면, 컴퓨터 메모리는 저렴하고 풍부합니다. 주소록에서 연락처를 검색하는 작업을 예로 들어보겠습니다. 기존 소프트웨어는 연락처 목록을 하나씩 순차적으로 확인하면서 효율적으로 처리할 수 있습니다.
하지만 LLM 에이전트가 모든 연락처를 반환하는 도구를 사용한 뒤 토큰 단위로 하나씩 읽어야 한다면, 제한된 컨텍스트 공간을 무관한 정보로 낭비하게 됩니다. 주소록에서 연락처를 찾기 위해 첫 페이지부터 끝까지 한 줄씩 읽는 것, 즉 무차별 탐색(brute-force search)과 같습니다. 에이전트든 사람이든, 더 자연스럽고 효율적인 방법은 알파벳순으로 해당 페이지를 바로 펼치는 것입니다.
평가 작업에 부합하는 핵심 워크플로우를 겨냥해 소수의 잘 설계된 도구부터 만들고, 거기서부터 확장해 나가는 것을 권장합니다. 주소록 사례에서는 list_contacts 도구 대신 search_contacts이나 message_contact 도구를 구현하는 편이 낫습니다.
도구는 여러 기능을 통합하여, 내부적으로 여러 개의 개별 작업(또는 API 호출)을 한꺼번에 처리할 수 있습니다. 예를 들어, 도구 응답에 관련 메타데이터를 함께 포함하거나, 자주 연속으로 수행되는 다단계 작업을 단일 도구 호출로 처리할 수 있습니다.
몇 가지 예시를 살펴보겠습니다:
list_users, list_events, create_event 도구를 각각 구현하는 대신, 일정 가능 여부를 확인하고 바로 이벤트를 생성하는 schedule_event 도구를 구현하는 것이 좋습니다.read_logs 도구를 구현하는 대신, 관련 로그 라인과 주변 컨텍스트만 반환하는 search_logs 도구를 구현하는 것이 좋습니다.get_customer_by_id, list_transactions, list_notes 도구를 각각 구현하는 대신, 고객의 최근 관련 정보를 한 번에 모아서 반환하는 get_customer_context 도구를 구현하세요.구현하는 각 도구는 명확하고 고유한 목적을 가져야 합니다. 도구는 사람이 동일한 기본 리소스에 접근했을 때 작업을 분할하고 해결하는 방식과 유사하게 에이전트가 작업을 수행할 수 있도록 지원하면서, 동시에 중간 출력으로 소모될 컨텍스트를 줄여야 합니다.
도구가 지나치게 많거나 기능이 겹치면 에이전트가 효율적인 전략을 선택하는 데 방해가 됩니다. 어떤 도구를 만들고, 어떤 도구를 만들지 않을지 신중하게 계획하면 큰 효과를 볼 수 있습니다.
AI 에이전트는 수십 개의 MCP 서버와 수백 개의 도구에 접근할 수 있으며, 그중에는 다른 개발자가 만든 도구도 포함됩니다. 기능이 겹치거나 목적이 모호한 도구가 있으면 에이전트가 어떤 도구를 사용해야 할지 혼란을 겪을 수 있습니다.
네임스페이싱(관련 도구를 공통 접두사로 묶는 방식)은 다수의 도구 간 경계를 명확히 하는 데 도움이 되며, MCP 클라이언트에서 기본적으로 이를 적용하는 경우도 있습니다. 예를 들어 서비스별(asana_search, jira_search)이나 리소스별(asana_projects_search, asana_users_search)로 네임스페이싱을 적용하면, 에이전트가 적시에 적절한 도구를 선택하는 데 도움이 됩니다.
접두사 기반과 접미사 기반 네임스페이싱 중 어떤 방식을 선택하느냐에 따라 도구 사용 평가 결과에 무시할 수 없는 차이가 발생한다는 점을 확인했습니다. 그 영향은 LLM마다 다르므로, 자체 평가를 통해 적합한 네이밍 방식을 선택하시기 바랍니다.
에이전트는 잘못된 도구를 호출하거나, 올바른 도구에 잘못된 파라미터를 전달하거나, 도구를 너무 적게 호출하거나, 도구 응답을 잘못 처리할 수 있습니다. 작업의 자연스러운 분할 단위를 이름에 반영한 도구를 선별적으로 구현하면, 에이전트 컨텍스트에 로드되는 도구 수와 설명을 줄이는 동시에 에이전트가 컨텍스트 내에서 수행해야 할 연산을 도구 호출 자체로 이전할 수 있습니다. 이를 통해 에이전트의 전반적인 실수 가능성을 낮출 수 있습니다.
같은 맥락에서, 도구 구현 시 에이전트에게 신호 대비 잡음이 높은 정보만 반환하도록 주의해야 합니다. 유연성보다 문맥적 관련성을 우선시하고, 저수준 기술 식별자(예: uuid, 256px_image_url, mime_type)는 되도록 배제하세요. name, image_url, file_type 같은 필드가 에이전트의 후속 판단과 응답에 훨씬 직접적으로 기여합니다.
에이전트는 암호 같은 식별자보다 자연어 이름이나 용어, 식별자를 다룰 때 훨씬 높은 성능을 보입니다. 임의의 영숫자 UUID를 의미적으로 해석 가능한 자연어(또는 0부터 시작하는 인덱스 체계)로 변환하는 것만으로도 Claude의 검색 작업에서 할루시네이션이 줄어들고 정확도가 크게 향상되는 것을 확인했습니다.
경우에 따라, 후속 도구 호출을 트리거하기 위해(예: search_user(name=’jane’) → send_message(id=12345)) 에이전트가 자연어 출력과 기술 식별자 출력 모두를 유연하게 사용해야 할 수 있습니다. 도구에 간단한 response_format enum 파라미터를 노출하면, 에이전트가 “concise” 또는 “detailed” 응답 중 어떤 형식으로 반환받을지 직접 제어할 수 있습니다(아래 이미지 참고).
GraphQL에서 원하는 정보만 골라 받을 수 있는 것처럼, 더 많은 형식을 추가해 유연성을 높일 수도 있습니다. 다음은 도구 응답의 상세 수준을 제어하는 ResponseFormat enum 예시입니다:
enum ResponseFormat {
DETAILED = "detailed",
CONCISE = "concise"
}상세 도구 응답 예시 (206 토큰):

간결한 도구 응답 예시 (72 토큰):

thread_ts로 식별되며, 스레드 답글을 가져오려면 이 값이 필요합니다. thread_ts 및 기타 ID(channel_id, user_id)는 “detailed” 도구 응답에서 가져올 수 있어, 이 값이 필요한 후속 도구 호출에 활용할 수 있습니다. “concise” 도구 응답은 스레드 내용만 반환하고 ID는 포함하지 않습니다. 이 예시에서 “concise” 도구 응답은 약 1/3 수준의 토큰만 사용합니다.도구 응답의 구조—XML, JSON, Markdown 등—역시 평가 성능에 영향을 미칠 수 있으며, 모든 상황에 맞는 단일 정답은 없습니다. LLM은 다음 토큰 예측으로 학습되기 때문에 학습 데이터에서 자주 접한 형식에서 더 좋은 성능을 보이는 경향이 있습니다. 최적의 응답 구조는 작업과 에이전트에 따라 크게 달라지므로, 자체 평가를 통해 가장 적합한 응답 구조를 선택하시기 바랍니다.
컨텍스트의 질을 최적화하는 것도 중요하지만, 도구 응답으로 에이전트에게 반환되는 컨텍스트의 양을 최적화하는 것도 그에 못지않게 중요합니다.
컨텍스트를 많이 소모할 수 있는 도구 응답에는 페이지네이션, 범위 선택, 필터링, 잘라내기(truncation) 등을 적절히 조합하고, 합리적인 기본 파라미터 값을 설정하는 것을 권장합니다. Claude Code에서는 도구 응답을 기본적으로 25,000 토큰으로 제한하고 있습니다. 에이전트의 유효 컨텍스트 길이는 시간이 지남에 따라 늘어나겠지만, 컨텍스트 효율적인 도구의 필요성은 계속될 것입니다.
응답을 잘라내는 경우, 에이전트에게 유용한 안내를 함께 제공해야 합니다. 지식 검색 작업에서 광범위한 검색 한 번 대신 작고 정밀한 검색을 여러 번 수행하는 등 토큰 효율적인 전략을 에이전트에게 직접 권장할 수 있습니다. 마찬가지로, 도구 호출 중 오류가 발생하면(예: 입력 유효성 검사 실패 시) 불투명한 오류 코드나 트레이스백 대신, 구체적이고 실행 가능한 개선 방법을 명확히 전달하도록 오류 응답을 설계하세요.
잘라낸 도구 응답 예시:

도움이 되지 않는 오류 응답 예시:

도움이 되는 오류 응답 예시:

이제 도구 개선에 가장 효과적인 방법 중 하나를 살펴보겠습니다. 바로 도구 설명(description)과 명세(spec)에 프롬프트 엔지니어링을 적용하는 것입니다. 이 정보는 에이전트의 컨텍스트에 로드되므로, 전체적으로 에이전트의 도구 호출 행동을 효과적으로 유도하는 역할을 합니다.
도구 설명과 명세를 작성할 때는, 팀에 새로 합류한 동료에게 이 도구를 어떻게 설명할지 떠올려 보세요. 특수한 쿼리 형식, 전문 용어의 정의, 기저 리소스 간의 관계처럼 여러분이 암묵적으로 알고 있는 맥락을 명시적으로 풀어 써야 합니다. 엄격한 데이터 모델을 적용해 예상 입출력을 명확히 기술하여 모호함을 제거하세요. 특히 입력 파라미터의 이름은 의미가 분명해야 합니다. 예를 들어 user 대신 user_id처럼 직관적인 이름을 사용하세요.
평가 체계가 갖춰져 있으면 프롬프트 엔지니어링의 효과를 더 높은 신뢰도로 측정할 수 있습니다. 도구 설명을 조금만 다듬어도 극적인 개선이 일어나기도 합니다. 실제로 Claude Sonnet 3.5는 SWE-bench Verified 평가에서 도구 설명을 정밀하게 다듬은 뒤 오류율이 크게 줄고 작업 완료율이 높아지며 최고 수준의 성능을 달성했습니다.
도구 정의에 관한 추가 모범 사례는 개발자 가이드에서 확인할 수 있습니다. Claude용 도구를 개발 중이라면, 도구가 Claude의 시스템 프롬프트에 동적으로 로드되는 방식도 함께 읽어 보시길 권합니다. 또한 MCP 서버용 도구를 작성하는 경우, tool annotations를 활용하면 어떤 도구가 외부 접근을 필요로 하는지, 또는 파괴적 변경을 수행하는지 명시할 수 있습니다.
에이전트를 위한 효과적인 도구를 만들려면, 기존의 예측 가능하고 결정론적인 소프트웨어 개발 방식에서 벗어나 비결정론적 패턴으로 사고를 전환해야 합니다.
이 글에서 설명한 반복적이고 평가 중심적인 프로세스를 통해, 우리는 성공적인 도구가 갖는 일관된 패턴을 발견했습니다. 효과적인 도구는 의도적이고 명확하게 정의되어 있고, 에이전트 컨텍스트를 신중하게 활용하며, 다양한 워크플로에서 유연하게 조합할 수 있고, 에이전트가 실제 작업을 직관적으로 해결할 수 있게 해줍니다.
앞으로 에이전트가 세상과 상호작용하는 구체적인 메커니즘은 계속 진화할 것입니다. MCP 프로토콜의 업데이트부터 기반 LLM 자체의 업그레이드까지 다양한 변화가 예상됩니다. 체계적이고 평가 중심적인 접근 방식으로 도구를 개선해 나간다면, 에이전트의 역량이 향상될 때 도구 역시 함께 발전할 수 있을 것입니다.
이 글은 Ken Aizawa가 작성했으며, Research(Barry Zhang, Zachary Witten, Daniel Jiang, Sami Al-Sheikh, Matt Bell, Maggie Vo), MCP(Theodora Chu, John Welsh, David Soria Parra, Adam Jones), Product Engineering(Santiago Seira), Marketing(Molly Vorwerck), Design(Drew Roper), Applied AI(Alexander Bricken, Christian Ryan) 등 여러 팀 동료들의 소중한 기여가 있었습니다.
1기반 LLM 자체의 학습은 별도입니다.