AI는 실제로 API를 어떻게 호출하는가? — 처음부터 이해하는 Tool Calling
Foundation model은 스스로 코드를 실행하지 않고, 호출할 도구와 입력을 구조화된 요청으로 출력합니다. 애플리케이션이 실제 함수를 실행해 결과를 돌려주면 모델이 답변을 완성하며, 글에서는 Amazon Bedrock의 Converse API로 날씨·날짜 도구, 프롬프트 주입, MCP까지 단계적으로 설명합니다.

본문
Foundation model은 학습이 끝난 뒤의 실시간 정보에 접근할 수 없으므로 날씨, 현재 가격, 오늘 날짜처럼 계속 바뀌는 질문에 직접 답할 수 없습니다. 이 글은 이 닫힌 상자에 외부 세계로 향하는 창을 추가하는 방법으로 Tool Calling을 설명합니다. 핵심은 모델이 코드를 직접 실행하는 것이 아니라는 점입니다. 모델은 “이 도구를 이 입력으로 호출하고 싶다”는 구조화된 요청을 출력하고, 실제 실행은 애플리케이션 코드가 담당합니다. 글에서는 이를 “모델은 brain이고, 코드는 hands”라고 표현합니다.
Tool Calling의 실제 흐름
Tool Calling은 매번 일정한 흐름으로 진행됩니다. 먼저 애플리케이션이 사용자의 질문과 함께 모델이 사용할 수 있는 도구 목록을 보냅니다. 모델은 자신이 알고 있는 내용만으로 답할 수 있는지 판단하고, 외부 정보가 필요하면 도구 이름과 입력값을 담은 구조화된 요청을 반환합니다. 애플리케이션은 이 요청을 읽고 실제 함수를 실행한 뒤, 결과를 toolResult 형태로 다시 모델에 전달합니다. 모델은 그 결과를 바탕으로 최종 답변을 작성하거나, 추가 도구 호출을 요청합니다.
예제는 Amazon Bedrock의 Converse API와 Claude Model을 사용합니다. Bedrock에서는 toolConfig에 모델이 사용할 도구를 등록합니다. 각 도구의 정의는 이름, 자연어 설명, 입력 인자를 표현하는 input schema로 구성됩니다. 예를 들어 날씨 도구는 get_weather라는 이름을 사용하고, “한 도시의 현재 날씨를 가져온다”고 설명하며, city라는 문자열 인자를 필수로 받습니다. 글은 도구 설명과 schema가 모델이 해당 도구를 언제 어떻게 사용할지 판단하는 유일한 정보이므로, 이를 하나의 prompt처럼 다뤄야 한다고 강조합니다.
하나의 도구: 날씨 API 호출
첫 번째 예제의 도구는 get_weather입니다. 실제 함수에는 AI 코드가 들어 있지 않고, 일반적인 Python 코드로 작성되어 있습니다. 함수는 먼저 Open-Meteo의 지오코딩 API에 도시 이름을 보내 위도와 경도를 얻습니다. 이어서 Open-Meteo forecast API에 좌표와 current 항목을 전달해 temperature_2m, weather_code, wind_speed_10m을 조회합니다. 숫자로 반환된 weather_code는 clear sky, partly cloudy, overcast, light rain, moderate rain 같은 사람이 읽을 수 있는 문자열로 매핑합니다. Open-Meteo는 API 키 없이 사용할 수 있는 무료 날씨 API로 소개됩니다.
사용자가 “Do I need an umbrella in Toronto today?”라고 질문하면 모델은 애플리케이션에 stopReason이 tool_use인 응답을 보냅니다. 응답에는 toolUseId, name이 get_weather인 도구 이름, 그리고 city가 Toronto인 input이 포함됩니다. 모델에게 특정 도구나 인자를 직접 지정하지 않았지만, 질문의 의도를 읽고 get_weather와 Toronto를 선택한 것입니다. 다만 이 시점에도 날씨 API는 아직 실행되지 않았습니다.
애플리케이션은 요청을 읽어 get_weather("Toronto")를 실행하고, 실제 API에서 가져온 결과를 모델에 돌려줍니다. 예시 결과에는 Toronto, Canada, 기온 23.8도, overcast, 풍속 3.9kph가 포함됩니다. 모델은 이 실시간 결과를 바탕으로 “현재 Toronto 날씨를 보면 지금은 우산이 필요하지 않을 가능성이 높다”고 답합니다. 이 답변은 모델 내부에 미리 저장되어 있던 문장이 아니라, 도구 호출을 통해 얻은 현재 데이터에서 만들어진 결과입니다.
도구가 하나뿐이면 흐름은 직선형입니다. 질문과 도구 정의를 전송하고, 도구 요청을 받고, 함수를 실행하고, 결과를 다시 전송한 뒤, 최종 답변을 받습니다. 글의 코드에서는 첫 번째 Converse 호출 뒤 assistant 메시지를 messages에 추가하고, 응답의 content에서 toolUse 블록을 찾은 다음, 해당 입력으로 실제 함수를 호출합니다. 마지막으로 toolResult를 messages에 추가해 두 번째 Converse 호출을 수행합니다.
도구가 없으면 모델은 모른다고 답합니다
같은 상태에서 “What’s today’s date?”라고 물으면 모델은 날짜 도구가 없기 때문에 도구를 호출하지 않습니다. 현재 날짜에 접근할 수 없다고 답합니다. 글은 이 동작을 환각과 대비해 설명합니다. 모델이 알 수 없는 정보를 억지로 만들어내는 대신, 자신에게 해당 정보가 없다는 사실을 밝힐 수 있다는 점이 중요한 차이입니다.
날짜를 알려주려면 get_current_datetime이라는 두 번째 도구를 추가할 수 있습니다. 이 도구는 별도 인자를 받지 않으며, Python의 datetime을 사용해 date, day_of_week, time을 반환합니다. 이제 모델이 날씨와 날짜를 모두 사용할 수 있는 상태에서 “Toronto에 우산이 필요한가? 그리고 오늘 날짜는 무엇인가?”라고 질문하면, get_weather에는 city가 Toronto로 전달되고 get_current_datetime에는 빈 객체가 전달됩니다. 애플리케이션은 두 함수를 실행해 두 결과를 모두 모델에 전달하고, 모델은 하나의 답변 안에서 두 정보를 결합합니다.
여러 도구에서는 반복 루프가 필요합니다
도구가 두 개가 되면 애플리케이션은 모델이 어떤 도구를 선택할지, 몇 번 호출할지, 첫 번째 결과를 본 뒤 추가 호출을 요청할지 미리 알 수 없습니다. 따라서 하나의 도구에서 사용한 직선형 코드를 while True 루프로 바꿉니다. 모델 응답을 messages에 추가한 뒤 stopReason이 tool_use가 아니면 텍스트 블록을 모아 최종 답변으로 사용하고 루프를 종료합니다.
반대로 stopReason이 tool_use이면 assistant 메시지의 각 content 블록을 순회하며 toolUse를 찾습니다. 요청된 name을 실제 Python 함수에 매핑한 TOOLS 딕셔너리에서 함수를 꺼내고, input을 인자로 전달해 실행합니다. 각 실행 결과는 toolUseId와 함께 toolResult로 묶어 다시 messages에 추가합니다. 모델이 더 이상 도구를 요청하지 않고 답변을 작성할 때까지 이 과정을 반복합니다. 글은 이 반복 구조가 여러 도구를 조합하고 다음 행동을 결정하는 Agent의 씨앗이라고 설명합니다.
Tool Calling과 프롬프트 주입의 차이
글은 현재 날짜를 AI assistant가 알려주는 방식에 대해서도 두 가지 접근을 구분합니다. 첫 번째는 방금 설명한 도구 호출입니다. 모델이 도구를 요청하고, 애플리케이션이 함수를 실행해 결과를 돌려줍니다. 두 번째는 사실을 system prompt에 직접 삽입하는 방식입니다.
Anthropic이 공개한 Claude 관련 설명에 따르면 Claude의 웹 인터페이스와 모바일 앱은 대화 시작 시 system prompt에 현재 날짜 같은 최신 정보를 넣을 수 있습니다. 이 경우 날짜를 얻기 위해 별도 도구를 실행하지 않습니다. 애플리케이션이 datetime.now()로 날짜를 구한 뒤 “Today’s date is …”라는 텍스트를 system prompt에 넣으면, 모델은 이를 대화 컨텍스트로 읽고 도구 호출 없이 답할 수 있습니다.
따라서 저렴하고 정적인 정보는 prompt에 주입하고, 날씨처럼 실시간으로 계속 변하는 정보는 도구를 사용하는 방식으로 구분할 수 있습니다. 날짜를 미리 애플리케이션이 알고 있으므로 주입은 한 줄로 처리할 수 있지만, 현재 날씨를 미리 넣어두면 더 이상 실시간 조회가 아니므로 도구 호출이 필요합니다. 또한 날씨 도구 schema에 city만 있고 날짜 인자가 없다면 다음 주 예보를 요청할 수 없습니다. 예보를 지원하려면 날짜나 기간을 받는 별도의 도구 정의가 필요합니다.
많은 도구를 연결하는 MCP
실제 시스템에서는 날씨와 날짜 두 개가 아니라 캘린더 조회, CRM 검색, 데이터베이스 질의, 이메일 전송, 파일 읽기 등 수십 개의 도구를 연결할 수 있습니다. 각 도구마다 schema를 작성하고, 실제 함수를 구현하고, 등록하고, 도구 설명과 구현이 바뀔 때마다 동기화해야 합니다. 글은 여러 애플리케이션과 수십 개의 도구를 직접 연결하는 방식이 유지보수 문제를 만들 수 있다고 설명합니다.
이 문제를 해결하기 위한 개념으로 Model Context Protocol, 즉 MCP를 소개합니다. MCP는 Anthropic이 시작했고 업계 여러 곳에서 사용되는 도구·데이터 연결을 위한 open standard입니다. 글에서는 MCP를 AI 도구를 위한 USB-C에 비유합니다. USB-C가 기기마다 다른 케이블과 커넥터를 하나의 표준으로 통합하듯이, MCP는 모델과 도구가 통신하는 공통 방식을 제공합니다.
MCP 환경에서는 도구가 MCP server 뒤에 있고, 서버가 자신이 제공하는 도구와 각 도구의 기능, 필요한 입력값을 설명합니다. 애플리케이션은 MCP client로서 서버에 “무엇을 제공하나요?”라고 질의하고, 실행 시점에 도구를 발견합니다. GitHub, 데이터베이스, Slack 등을 위한 MCP server가 있다면 애플리케이션이 모든 통합 코드를 직접 작성하지 않고 서버에 연결해 도구를 사용할 수 있다는 구조입니다. 글은 MCP 자체를 구현하지는 않고, Tool Calling이 하나의 모델이 도구를 사용하는 방식이라면 MCP는 모델이 도구를 발견하고 연결하는 방식이라고 정리합니다.
이 글의 최종 구분은 명확합니다. 모델은 도구를 선택하고 인자를 채우지만 실제 실행은 애플리케이션 코드가 담당합니다. 도구가 무엇을 하고 무엇을 하지 않는지는 이름, 설명, schema로 전달되므로 이를 정확하게 작성해야 합니다. 정적인 사실은 컨텍스트에 주입하고, 실시간 사실은 도구로 가져오며, 도구가 몇 개를 넘어 복잡해지면 MCP 같은 표준을 검토합니다. 여러 도구를 정해진 순서로 호출하고 결과를 확인한 뒤 다음 행동을 선택하는 반복 과정은 다음 단계인 Agent 구조로 이어집니다.
원문: dev.to / 번역·요약: Trawling