3부 11장. Tool Calling의 원리
에이전트를 처음 보면 가장 신기한 장면이 있다. 사용자가 "지난주 매출 알려 줘"라고 말하자, 모델이 갑자기 데이터베이스를 조회하고, 다시 숫자를 정리해 답한다. 처음 보는 사람은 여기서 쉽게 착각한다. 모델이 무슨 초능력이라도 생긴 것처럼 느껴지는 것이다.
하지만 실제로는 훨씬 덜 신비롭고, 그래서 더 중요하다. Tool Calling은 마법이 아니라 인터페이스다. 모델이 스스로 세상에 손을 뻗는 것이 아니라, 시스템이 미리 정해 둔 규칙 안에서 "어떤 도구를 어떤 인자로 호출하면 좋겠다"고 구조화된 형태로 제안하고, 런타임이 그 제안을 검증하고 실행한 뒤, 그 결과를 다시 모델에게 돌려주는 방식이다.
이 장의 목표는 바로 그 장면을 투명하게 만드는 데 있다. 모델이 어떻게 도구를 고르는지, 왜 인자를 구조화해야 하는지, 실행은 누가 맡는지, 그리고 결과가 다시 추론으로 어떻게 들어오는지를 이해하면 Tool Calling은 더 이상 신비한 기능이 아니다. 예측 가능한 설계 요소가 된다.

도구 호출은 "능력"이 아니라 "계약"이다
사람들은 종종 이렇게 말한다. "이 모델은 검색도 하고 파일도 읽고 API도 호출해요." 엄밀히 말하면 반은 맞고 반은 틀리다. 모델이 직접 검색 서버에 접속하거나 파일 시스템을 만지는 것은 아니다. 모델은 그럴 권한도 없고, 보통은 그럴 실행 환경도 없다.
모델이 실제로 하는 일은 더 소박하다. 현재 대화와 상태를 보고, 지금 필요한 행동이 무엇인지 판단한 뒤, 시스템이 제공한 도구 목록 중 하나를 골라 "이 도구를 이런 인자로 호출해 달라"고 형식에 맞춰 출력하는 것이다. 그다음 행동은 런타임이 맡는다.
이 구조를 이해하는 순간 Tool Calling은 훨씬 선명해진다. 핵심은 모델의 지능이 아니라 모델과 시스템 사이의 계약이다. 시스템은 미리 이렇게 말해 둔다.
사용할 수 있는 도구는 무엇인가
각 도구는 어떤 목적을 가지는가
어떤 인자를 받아야 하는가
인자의 형식은 무엇인가
어떤 경우에 호출하면 안 되는가
모델은 이 계약을 바탕으로 선택한다. 좋은 Tool Calling이란 결국 모델이 똑똑해서 생기는 현상이 아니라, 계약이 잘 설계되어 있어서 생기는 현상이다.
실제로는 어떤 순서로 일어나는가
도구 호출의 흐름은 생각보다 단순하다. 다만 이 단순한 흐름 안에서 역할이 정확히 나뉘어 있어야 한다.
사용자의 요청이 들어온다.
시스템은 모델에게 현재 대화와 상태, 그리고 사용 가능한 도구 목록을 함께 준다.
모델은 바로 답할지, 특정 도구를 호출할지 결정한다.
도구 호출이 필요하다고 판단하면, 도구 이름과 구조화된 인자를 출력한다.
런타임은 이 출력을 받아 형식과 권한을 검증한 뒤 실제 도구를 실행한다.
도구 실행 결과를 다시 모델에게 넣는다.
모델은 그 결과를 바탕으로 다음 행동을 고르거나 최종 응답을 만든다.
여기서 중요한 장면은 다섯 번째와 여섯 번째다. 많은 초보자가 이 부분을 흐리게 이해한다. 모델이 도구를 호출한다고 말하지만, 실제 실행은 모델 바깥에서 일어난다. 그리고 도구 결과는 그냥 사라지는 것이 아니라 다시 컨텍스트로 들어와 다음 판단의 재료가 된다.
즉, Tool Calling은 한 번의 동작이 아니다. 선택, 실행, 관찰, 재추론으로 이어지는 짧은 루프다.
모델은 어떻게 도구를 고르는가
모델이 도구를 고르는 방식은 본질적으로 다음 토큰 예측이다. 다만 이 말만 들으면 너무 차갑게 느껴질 수 있다. 좀 더 실감 나게 말하면, 모델은 현재 입력 안에서 "지금 가장 그럴듯한 다음 행동"을 언어적으로 만들어 내는 것이다.
예를 들어 사용자가 "이번 달 서울 지점 매출을 보여 줘"라고 묻는다면, 모델은 자기 내부 지식만으로는 최신 매출을 알 수 없다는 점을 패턴 수준에서 배운 상태다. 그리고 도구 목록 안에 get_sales_report 같은 함수가 있다면, 최종 답변을 바로 쓰기보다 그 도구를 부르는 쪽이 더 그럴듯하다고 판단한다.
반대로 사용자가 "매출총이익이 뭐야?"라고 묻는다면 굳이 데이터 조회 도구가 필요하지 않다. 이 경우에는 도구를 부르지 않고 바로 설명하는 쪽이 낫다.
이 차이는 대단한 철학적 판단이라기보다, 입력에 담긴 단서와 도구 설명의 품질에 크게 좌우된다. 결국 모델은 다음과 같은 신호를 보고 움직인다.
사용자의 요청이 최신 정보나 외부 시스템 접근을 필요로 하는가
계산, 검색, 조회, 실행 같은 행동이 필요한가
제공된 도구 설명이 요청과 자연스럽게 연결되는가
도구를 쓰지 않고 답하면 틀릴 가능성이 큰가
따라서 모델의 선택을 좋게 만들고 싶다면 "더 똑똑한 모델"만 찾을 것이 아니라, 도구 설명과 호출 조건을 더 분명하게 써야 한다.
구조화된 인자가 왜 중요한가
Tool Calling의 진짜 핵심은 도구 이름보다 인자다. 도구를 잘 골라도, 인자를 엉뚱하게 만들면 실행은 실패하거나 잘못된 결과를 낸다.
여기서 구조화가 필요해진다. 자유로운 문장으로 "서울 지점 매출 좀 찾아봐"라고 보내는 대신, 시스템은 보통 branch="seoul", period="2026-04" 같은 형태의 필드를 기대한다. 이런 구조가 있어야 런타임이 안정적으로 값을 읽고, 검증하고, 실제 API나 함수에 전달할 수 있다.
이것은 사람끼리 일할 때도 마찬가지다. 누군가에게 "적당히 처리해 줘"라고 말하면 오해가 생긴다. 하지만 "지점은 서울, 기간은 4월, 통화는 원화로"라고 정리해 주면 실수가 줄어든다. Tool Calling은 모델에게 이런 정리된 양식을 강제하는 장치라고 보면 된다.
구조화된 인자가 주는 이점은 분명하다.
런타임이 자동 검증하기 쉽다.
잘못된 타입이나 누락된 필드를 잡아낼 수 있다.
로그와 추적이 쉬워진다.
같은 도구를 여러 환경에서 재사용하기 좋다.
모델의 자유도를 줄여 예측 가능성을 높인다.
결국 구조화는 모델을 답답하게 만드는 족쇄가 아니라, 시스템을 안전하게 만드는 난간이다.
스키마는 모델에게 주는 문제집이다
도구를 연결할 때 흔히 스키마라는 말을 쓴다. 어렵게 들리지만, 여기서는 아주 단순하게 이해하면 된다. 스키마는 "이 도구를 부르려면 어떤 칸을 어떤 형식으로 채워야 하는가"를 적어 둔 양식이다.
예를 들어 일정 등록 도구가 있다고 해 보자. 이 도구는 제목, 날짜, 시간, 참석자 목록이 필요할 수 있다. 그렇다면 스키마는 단지 입력 칸의 목록이 아니다. 모델이 무엇을 뽑아내야 하는지를 알려 주는 가이드이기도 하다.
좋은 스키마는 모델을 도와준다. 나쁜 스키마는 모델을 헷갈리게 한다.
좋은 스키마는 필드 이름이 분명하다. date와 timezone이 따로 있으면 해석이 쉬워진다. 반면 schedule_info처럼 모든 것을 한 덩어리 문자열에 담게 하면, 결국 다시 문자열 파싱과 추측이 시작된다. 그러면 Tool Calling을 쓰는 이유가 줄어든다.
또 좋은 스키마는 제약을 숨기지 않는다. 필수 입력인지, 허용 가능한 값이 무엇인지, 읽기 전용인지 쓰기 가능한지, 승인 전에는 실행하면 안 되는지 같은 정보가 드러나야 한다. 모델은 규칙이 있을수록 더 안정적으로 행동한다.
한마디로 스키마는 모델에게 주는 시험문제다. 문제를 모호하게 내면 오답이 많아지고, 문제를 분명하게 내면 정답률이 올라간다.
실행은 누가 맡는가
여기서 아주 중요한 선을 하나 그어야 한다. 모델은 호출 요청을 만든다. 하지만 실행은 런타임이 한다.
이 차이를 흐리게 이해하면 설계가 금세 위험해진다. 예를 들어 모델이 send_money라는 도구를 선택했다고 해서, 그 출력만 믿고 곧바로 송금해 버리면 안 된다. 런타임은 최소한 다음을 확인해야 한다.
호출한 도구가 실제로 허용된 도구인가
인자의 형식이 맞는가
필요한 값이 빠지지 않았는가
현재 사용자와 세션이 그 도구를 실행할 권한이 있는가
사람 승인이 필요한 작업은 아닌가
같은 요청이 중복 실행되는 상황은 아닌가
즉, Tool Calling에서 모델은 계획자에 가깝고, 런타임은 집행자이자 문지기다. 이 문지기 역할이 약하면 에이전트는 똑똑해 보이기 전에 먼저 위험해진다.
특히 쓰기 작업에서는 더 조심해야 한다. 조회 도구는 잘못 호출해도 주로 엉뚱한 정보가 나오는 수준에서 끝나지만, 결제, 발송, 삭제, 권한 변경 같은 도구는 한 번의 잘못된 실행이 실제 피해로 이어질 수 있다. 그래서 좋은 시스템은 보통 읽기와 쓰기를 구분하고, 쓰기에는 더 강한 검증과 승인을 둔다.
도구 결과는 왜 다시 모델에게 돌아와야 하는가
Tool Calling은 도구를 부르는 데서 끝나지 않는다. 오히려 진짜 중요한 장면은 결과가 돌아온 뒤에 시작된다.
예를 들어 모델이 고객 주문 조회 도구를 불렀다고 하자. 결과로 주문 상태가 배송 중, 예상 도착일이 내일, 최근 문의 이력이 주소 변경 요청으로 돌아왔다고 해 보자. 이 정보만 보고 시스템이 바로 사용자에게 기계적으로 전달할 수도 있다. 하지만 에이전트는 한 걸음 더 간다. 모델이 이 결과를 해석하고, 현재 대화 맥락과 연결해, 어떤 설명이 가장 적절한지 다시 판단할 수 있기 때문이다.
즉, 도구 결과는 원재료다. 최종 응답은 그 원재료를 바탕으로 만든 문장이다.
이 구조가 중요한 이유는 두 가지다. 첫째, 도구는 대개 구조화된 데이터를 돌려주고, 사용자는 구조화된 JSON이 아니라 이해 가능한 설명을 원한다. 둘째, 한 번의 도구 결과만으로 일이 끝나지 않을 수 있다. 주문 상태를 본 뒤 주소 변경 가능 여부를 다시 확인해야 할 수도 있고, 정책 문서를 조회해야 할 수도 있다.
그래서 Tool Calling은 "호출"보다 "반영"이 더 중요하다고 말할 수 있다. 도구 결과가 다음 추론의 연료가 되지 않으면, 에이전트는 그저 API 래퍼에 머문다.
도구를 부를 때와 말아야 할 때
초보 설계에서 자주 생기는 문제는 두 가지다. 하나는 에이전트가 너무 자주 도구를 부르는 것이고, 다른 하나는 꼭 불러야 할 때도 머뭇거리는 것이다.
이 균형은 생각보다 중요하다. 도구를 너무 아끼면 환각이 늘어난다. 최신 정보가 필요한데도 모델이 아는 척 답해 버릴 수 있기 때문이다. 반대로 도구를 너무 남용하면 비용과 지연이 커지고, 단순한 질문에도 쓸데없는 호출이 이어진다.
좋은 기준은 이렇다. 모델의 내부 지식으로 충분히 안전하게 답할 수 있는가, 아니면 외부 사실 확인이 필요한가. 이 질문을 중심에 두면 된다.
예를 들어 개념 설명, 글쓰기 조언, 일반적인 아이디어 제안은 도구 없이도 가능한 경우가 많다. 반면 오늘 환율, 특정 고객의 주문 상태, 사내 문서의 최신 버전, 실제 파일 내용, 현재 서버 상태는 도구 없이는 답하면 안 되는 경우가 많다.
결국 Tool Calling의 성숙도는 "무조건 많이 호출한다"가 아니라 "필요한 순간에만 정확히 호출한다"는 감각에서 나온다.
예시로 보는 한 번의 도구 호출
상황을 하나 그려 보자. 사용자가 이렇게 말한다.
"김민수 고객의 최근 주문 상태를 확인하고, 아직 발송 전이면 배송지 변경 가능 여부도 알려 줘."
이 요청을 처리하는 에이전트가 있다고 해 보자. 이 에이전트는 find_customer_orders, check_shipping_policy라는 두 도구를 가지고 있다.
먼저 모델은 사용자 요청을 읽고 바로 답할 수 없다고 판단한다. 실제 주문 정보가 필요하기 때문이다. 그래서 find_customer_orders를 고른다. 여기서 중요한 것은 도구 이름만 고르는 것이 아니라, customer_name="김민수", sort="latest", limit=1처럼 구조화된 인자를 만든다는 점이다.
런타임은 이 호출을 검증하고 실제 시스템에 질의한다. 결과로 최근 주문이 주문 확인, 배송 상태가 발송 전이라는 데이터가 돌아온다.
그러면 모델은 이 결과를 읽고 한 번 더 생각한다. 사용자는 단순히 주문 상태만 묻지 않았다. 발송 전이면 배송지 변경 가능 여부도 알고 싶다고 했다. 그래서 두 번째 도구인 check_shipping_policy를 호출한다. 이번에는 order_status="pre_shipment", requested_action="address_change" 같은 인자를 넣을 수 있다.
정책 조회 결과가 "발송 전에는 변경 가능하지만, 결제 완료 후 2시간이 지나면 고객센터 승인 필요"라고 돌아왔다고 해 보자. 이제 모델은 이 두 결과를 합쳐 최종 응답을 만든다.
이 짧은 예시 안에 Tool Calling의 핵심이 다 들어 있다. 모델은 필요한 도구를 순서대로 고르고, 각 단계마다 구조화된 인자를 만들고, 결과를 단순 복사하지 않고 다음 판단에 반영한다. 이 흐름이 바로 에이전트다운 움직임이다.
잘 되는 도구 설명은 무엇이 다른가
같은 모델을 써도 어떤 시스템은 도구 선택이 안정적이고, 어떤 시스템은 자꾸 엉뚱한 함수를 부른다. 그 차이 중 큰 부분은 도구 설명에 있다.
도구 설명은 길다고 좋은 것이 아니다. 핵심은 경계를 분명히 해 주는 것이다. 이 도구가 무엇을 할 수 있는지뿐 아니라, 무엇을 하면 안 되는지도 적어 주는 편이 좋다.
예를 들어 search_documents라는 도구가 있다고 하자. 설명이 "문서를 검색합니다" 정도면 너무 넓다. 반면 "사내 문서 저장소에서 제목과 본문을 검색합니다. 최신 사내 정책이나 내부 문서를 찾을 때 사용합니다. 웹 검색에는 사용하지 않습니다"라고 써 두면 모델은 훨씬 덜 헤맨다.
도구 이름도 의외로 중요하다. 이름이 기능을 분명하게 드러내면 모델의 선택이 쉬워진다. do_task_v2보다 create_calendar_event가 낫고, fetch_info보다 get_invoice_status가 낫다. 사람도 공구함에서 라벨이 붙은 드라이버를 더 빨리 찾듯, 모델도 이름과 설명이 선명할수록 잘 고른다.
Tool Calling이 실패하는 흔한 이유
실무에서 Tool Calling이 흔들리는 이유는 대개 모델 자체보다 인터페이스 설계에 있다. 특히 아래 문제들이 자주 보인다.
도구가 너무 많고 서로 경계가 겹친다.
설명이 모호해서 어떤 상황에 어떤 도구를 써야 하는지 알기 어렵다.
인자 스키마가 느슨해서 문자열 한 칸에 모든 정보를 몰아넣는다.
런타임 검증이 약해 잘못된 인자가 그대로 실행된다.
도구 결과가 너무 길거나 지저분해서 모델이 핵심을 못 잡는다.
실패 시 재질문, 재시도, 사람 승인 같은 다음 행동 규칙이 없다.
이 문제들은 겉으로는 모두 "모델이 이상하게 행동한다"로 보일 수 있다. 하지만 실제로는 시스템이 모델에게 나쁜 작업 환경을 제공한 경우가 많다.
예를 들어 도구 결과를 통째로 길게 밀어 넣으면 모델은 중요하지 않은 필드까지 함께 읽느라 판단력이 떨어질 수 있다. 반대로 필요한 필드가 빠져 있으면 다시 호출하거나 추측하게 된다. 따라서 좋은 Tool Calling은 도구를 연결하는 것에서 끝나지 않고, 결과를 어떤 형식으로 돌려줄지도 함께 설계해야 한다.
Tool Calling은 함수 호출이면서도, 그 이상이다
겉만 보면 Tool Calling은 함수 호출처럼 보인다. 이름이 있고, 인자가 있고, 반환값이 있다. 맞는 말이다. 하지만 에이전트 문맥에서는 한 가지가 더 붙는다. 호출 전후에 추론이 있다는 점이다.
전통적인 프로그램은 개발자가 미리 분기 조건을 짜 둔다. 어떤 값이 오면 어떤 함수를 부를지 코드가 결정한다. 반면 Tool Calling은 그 선택의 일부를 모델에게 맡긴다. 모델은 자연어 요청을 보고 현재 상황에 가장 맞는 함수를 고른다.
그래서 Tool Calling은 함수 호출과 자연어 추론 사이의 다리라고 볼 수 있다. 함수 호출의 단단함과, 자연어 이해의 유연함이 만나는 지점이다.
하지만 바로 그 이유 때문에 더 엄격한 설계가 필요하다. 선택은 유연하게 맡기되, 실행은 엄격하게 통제해야 한다. 이 균형이 무너지면 에이전트는 자유롭지만 불안정한 시스템이 된다.
설계할 때 꼭 기억해야 할 원칙
Tool Calling을 안정적으로 만들고 싶다면 복잡한 비법보다 몇 가지 원칙을 붙잡는 편이 낫다.
첫째, 도구는 적게 시작하라. 비슷한 일을 하는 도구가 여러 개 있으면 모델은 쉽게 헷갈린다. 처음에는 가장 자주 쓰는 몇 개만 두고, 정말 필요한 경우에만 늘리는 편이 좋다.
둘째, 인자는 쪼개서 구조화하라. 문자열 한 칸에 모든 것을 넣지 말고, 날짜, 대상, 범위, 옵션을 나눠 주는 편이 검증과 재사용에 유리하다.
셋째, 읽기와 쓰기를 구분하라. 조회 도구와 실제 변경 도구는 위험도가 다르다. 같은 수준의 자율성을 주면 안 된다.
넷째, 결과도 설계하라. 도구가 무엇을 반환할지, 어떤 필드가 핵심인지, 실패 시 어떤 오류 코드를 줄지 정해 두어야 다음 추론이 안정된다.
다섯째, 실패 경로를 미리 정하라. 인자가 부족하면 무엇을 물을지, 호출이 실패하면 몇 번 재시도할지, 언제 사람에게 넘길지 정해 두지 않으면 루프가 금세 흐트러진다.
이 다섯 가지를 지키면 Tool Calling은 화려하지 않아도 단단해진다. 그리고 실무에서는 대개 화려한 것보다 단단한 것이 오래 간다.
결국 핵심은 예측 가능성이다
Tool Calling을 이해할 때 가장 중요한 관점은 이것이다. 우리는 모델에게 초능력을 주는 것이 아니라, 예측 가능한 방식으로 외부 세계와 연결하고 있는 것이다.
모델은 도구를 선택한다. 그러나 선택은 계약 안에서만 이뤄진다. 모델은 인자를 만든다. 그러나 인자는 스키마에 맞아야 한다. 모델은 결과를 해석한다. 그러나 결과는 런타임이 검증된 실행을 거쳐 가져온 것이다.
이렇게 보면 Tool Calling은 신비로운 기능이 아니다. 오히려 에이전트 시스템에서 가장 공학적인 부분 중 하나다. 인터페이스가 있고, 입력 형식이 있고, 검증이 있고, 반환값이 있고, 다시 추론으로 이어지는 흐름이 있다.
에이전트를 제대로 설계하려면 바로 이 감각이 필요하다. "모델이 알아서 잘 하겠지"가 아니라, "모델이 잘 선택할 수 있도록 인터페이스를 어떻게 설계할까"를 먼저 묻는 태도 말이다.
이제 도구를 실제로 연결할 차례다
이번 장에서 우리는 Tool Calling을 하나의 원리로 보았다. 모델은 도구를 직접 실행하는 존재가 아니라, 도구 사용을 제안하는 판단자다. 구조화된 인자는 실행 가능성을 만든다. 런타임은 검증과 집행을 맡는다. 도구 결과는 다시 추론으로 돌아와 다음 행동과 최종 응답을 바꾼다.
이 흐름을 이해하면, 도구 호출은 더 이상 블랙박스가 아니다. 어떤 순간에 왜 잘 작동하는지, 왜 엉뚱한 호출이 나오는지, 어디를 고쳐야 안정되는지를 읽을 수 있게 된다.
다음 장에서는 이 원리를 바탕으로 실제 도구들을 연결하는 문제로 들어간다. 검색, 파일, 브라우저, 코드 실행 같은 도구는 각각 어떤 성격을 가지며, 어떤 차이점을 이해하고 붙여야 하는가. 이제 인터페이스의 원리를 알았으니, 공구함을 하나씩 열어 볼 차례다.
이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.