툴 콜링은 실행이 아니라 제안이다
에이전트를 붙였는데 모델이 함수를 직접 실행하지 않는다는 오해가 자주 생긴다. 주요 제공사의 공식 문서가 공통으로 명시하는 동작은 하나다. 모델이 반환하는 것은 "어떤 도구를 어떤 인자로 호출하면 되겠다"는 구조화된 제안이고, 실제 실행은 전적으로 애플리케이션 코드의 몫이다. 툴 콜링을 설계한다는 말은 모델에게 실행 권한을 준다는 뜻이 아니라, 모델의 출력 형식을 함수 시그니처로 고정하고 그 결과를 다시 대화에 밀어 넣는 왕복 구조를 만든다는 뜻이다.
한 번의 함수 호출에 필요한 네 단계
- 요청에 도구 목록(이름, 설명, 입력 스키마)을 함께 전달한다.
- 모델이 호출 의사를 담은 블록을 반환한다. 이때 응답에는 호출 식별자가 포함된다.
- 애플리케이션이 실제 함수를 실행한다. 인증, 권한, 타임아웃은 모두 이 구간의 책임이다.
- 실행 결과를 식별자와 짝지어 다시 모델에 보낸다. 모델은 그 결과를 근거로 최종 답을 만들거나 다음 호출을 요청한다.
분기 기준은 텍스트가 아니라 중단 신호다
응답 본문을 정규식으로 파싱해 호출 여부를 판단하는 구현은 깨지기 쉽다. 각 API는 별도의 신호 필드를 제공한다. Anthropic Messages API는 stop_reason이 tool_use인지로, OpenAI Chat Completions는 finish_reason이 tool_calls인지로, Gemini API는 응답 파트에 functionCall이 들어 있는지로 판단하도록 문서화돼 있다. 에이전트 설계에서 루프 제어문은 이 필드 하나만 보고 갈라져야 한다.
스키마가 곧 계약서다
도구의 입력 스키마는 검증 규칙인 동시에 프롬프트다. 모델은 필드 이름과 description을 읽고 인자를 채우기 때문에, 설명이 비어 있는 파라미터는 환각의 입구가 된다. 단위(초인지 밀리초인지), 열거 가능한 값, 필수와 선택의 구분을 스키마 안에서 명시하는 편이 시스템 프롬프트에 장황하게 적는 것보다 안정적이다.
제공사별 사양 — 골격은 같고 이름이 다르다
세 제공사의 함수 호출 규약은 개념적으로 동일한 골격을 공유한다. 도구를 선언하고, 호출 의사를 받고, 결과를 식별자로 되돌린다. 다만 필드 이름과 제어 옵션의 어휘가 달라서, 추상화 계층 없이 코드를 옮기면 이 지점에서 반드시 걸린다.
비교표 (2026년 8월 기준, 각 사 공식 문서 표기)
| 항목 | Anthropic Messages API | OpenAI (Chat Completions 기준) | Google Gemini API |
|---|---|---|---|
| 도구 정의 필드 | name, description, input_schema | type: function 아래 name, description, parameters | functionDeclarations 아래 name, description, parameters |
| 스키마 표기 | JSON Schema | JSON Schema (엄격 모드는 지원 부분집합이 별도 규정됨) | OpenAPI 스키마의 서브셋 |
| 호출 제어 | tool_choice: auto / any / tool / none | tool_choice: auto / none / required / 특정 함수 지정 | functionCallingConfig.mode: AUTO / ANY / NONE |
| 병렬 호출 제어 | disable_parallel_tool_use 옵션 | parallel_tool_calls 옵션 | 병렬 호출 및 연쇄 호출 지원 |
| 중단 신호 | stop_reason: tool_use | finish_reason: tool_calls | 응답 파트의 functionCall |
| 결과 반환 | user 메시지의 tool_result 블록, tool_use_id로 대응 | role: tool 메시지, tool_call_id로 대응 | functionResponse 파트 |
강제 모드는 만능이 아니다
어느 API든 "반드시 도구를 하나 호출하라"에 해당하는 모드를 제공한다. 이 모드는 분류기처럼 쓸 때 유용하지만, 부작용이 있다. 사용자가 도구와 무관한 질문을 해도 모델은 규약상 무언가를 호출해야 하므로 억지 인자를 만들어 낸다. 강제 모드는 입력이 이미 특정 도메인으로 좁혀진 단계에서만 켜고, 대화형 진입점에서는 자동 모드를 두는 편이 안전하다.
엄격 스키마 준수의 대가
스키마를 구조적으로 보장하는 옵션을 켜면 파싱 실패는 사라지지만 표현 가능한 스키마가 제한된다. 예를 들어 OpenAI의 엄격 모드는 additionalProperties를 false로 두고 모든 속성을 required에 넣도록 요구하며, 선택 필드는 널 허용 타입으로 표현하도록 규정한다. 재귀 구조나 일부 키워드처럼 지원 목록에 없는 문법은 그대로 쓸 수 없다. 이 제약을 모르고 기존 JSON Schema를 그대로 올리면 정의 등록 단계에서 거절된다.
요금과 한계 — 툴 콜링 구조가 비용을 만든다
도구 정의는 매 턴 청구되는 입력 토큰이다
도구 목록은 요청마다 함께 전송되고, 시스템 프롬프트와 마찬가지로 입력 토큰으로 계산된다. 도구를 30개 붙여 두면 사용자가 "안녕"이라고만 쳐도 30개 정의가 매번 과금 대상이 된다. 여기서 나오는 실무적 함의는 명확하다. 도구 개수를 늘리는 것은 기능 추가가 아니라 고정비 증가다. 정확한 단가와 토큰 산정 방식은 각 사 요금 페이지와 토큰 카운팅 API로 확인해야 하며, 추정치로 예산을 잡으면 안 된다.
왕복 횟수가 곧 호출 횟수다
함수 호출 한 번은 최소 두 번의 API 요청을 만든다. 호출 의사를 받는 요청과 결과를 넣어 최종 답을 받는 요청이다. 도구를 세 번 연쇄로 쓰는 에이전트는 네 번 청구된다. 게다가 대화 이력은 누적되므로 뒤로 갈수록 입력 토큰이 커진다. 프롬프트 캐싱을 지원하는 API라면 도구 정의와 시스템 프롬프트처럼 변하지 않는 앞부분을 캐시 경계 앞에 배치하는 것이 비용 구조상 유리하다. 캐시는 접두사 일치를 전제로 하므로, 도구 정의 순서를 매 요청 무작위로 바꾸면 캐시가 무효화된다.
서버 실행형 도구는 과금 축이 다르다
웹 검색이나 코드 실행처럼 제공사 서버에서 실행되는 내장 도구는 토큰과 별도로 사용량 단위 요금이 붙는 경우가 있다. 직접 구현한 도구와 같은 비용 모델로 가정하면 예산이 어긋난다. 어떤 도구가 어느 축으로 과금되는지는 공식 요금 문서에서 도구별로 확인해야 한다.
설계 기준과 주의점
기준 하나 — 도구 개수보다 경계
도구가 많아질수록 이름이 비슷해지고, 모델은 유사한 두 도구 사이에서 흔들린다. search_user와 find_customer가 공존하면 선택 오류는 프롬프트로 못 막는다. 기능이 겹치면 합치고, 합칠 수 없으면 description에 "언제 쓰지 않는가"를 명시하는 편이 낫다. 도구 수가 계속 늘어나는 구조라면 단일 에이전트에 전부 붙이는 대신 역할별로 도구 집합을 나누는 쪽을 검토한다.
기준 둘 — 실패를 어떻게 돌려줄 것인가
함수가 예외를 던졌을 때 프로세스를 중단하는 대신, 오류 메시지를 결과 형식에 담아 모델에 되돌려주는 경로가 필요하다. Anthropic API는 tool_result 블록에 오류 표시를 담을 수 있도록 규정하고 있고, 다른 API에서도 결과 문자열에 실패 사유를 넣어 재시도를 유도하는 방식이 일반적이다. 다만 되돌려주는 오류 메시지에 내부 스택 트레이스나 자격 증명이 섞이지 않도록 걸러야 한다. 모델에 전달된 문자열은 그대로 사용자 답변에 인용될 수 있다.
기준 셋 — 루프 상한과 권한 경계
모델이 결과에 만족하지 못해 같은 도구를 반복 호출하는 상황은 정상 동작 범위 안에서 발생한다. 최대 반복 횟수, 누적 토큰 상한, 전체 시간 제한을 코드 쪽에 두지 않으면 비용은 무한대로 열려 있다. 권한도 마찬가지다. 모델이 인자를 만들어 낸다는 사실은 곧 인자를 신뢰할 수 없다는 뜻이므로, 삭제나 결제 같은 비가역 동작은 실행 전 검증 또는 사용자 확인 단계를 코드에서 강제해야 한다. 이것은 프롬프트로 대체할 수 있는 성격의 통제가 아니다.
어떤 경우에 적합한가
툴 콜링을 쓰는 것이 맞는 조건
- 입력이 자연어이고 출력이 정해진 시스템 호출로 귀결되는 경우. 사용자가 표현을 다양하게 바꿔도 도달점이 유한한 함수 집합이라면 적합하다.
- 모델이 판단해야 할 분기가 실제로 존재하는 경우. 호출 순서가 항상 고정이라면 함수 호출을 모델에 맡길 이유가 없다.
- 실행 결과가 답변의 근거가 되어야 하는 경우. 조회 결과를 그대로 근거로 삼아야 하는 업무는 툴 콜링의 왕복 구조와 잘 맞는다.
다른 방식이 나은 조건
- 흐름이 고정된 파이프라인. 이 경우 일반 코드로 순서를 짜고 모델은 단계별 변환에만 쓰는 편이 비용과 지연 모두 유리하다.
- 구조화된 데이터만 필요한 경우. 외부 실행 없이 형식만 맞추면 된다면 구조화 출력 기능으로 충분하고, 왕복이 필요 없다.
- 지연 시간이 엄격한 경우. 도구를 한 번 쓸 때마다 왕복이 늘어나므로, 응답 시간 예산이 빠듯한 화면에는 맞지 않는다.
정리하면 에이전트 설계의 난이도는 모델 성능이 아니라 도구 경계, 실패 경로, 상한선을 어디에 두느냐에서 결정된다. 위에 정리한 필드 이름과 옵션은 2026년 8월 기준 공식 문서 표기이며, API 사양과 요금 정책은 개정이 잦으므로 구현 직전에 해당 제공사 문서에서 다시 확인하는 절차를 습관으로 두는 편이 안전하다.