도구 호출 (Tool Calling)

도구 호출 (Tool Calling)

모델이 스스로 계산기를 쓰거나 날씨를 조회하도록 만들고 싶다면 도구 호출(tool calling)을 써요. 모델은 애플리케이션이 정의한 함수를 요청하고, 애플리케이션이 그 함수를 실행한 결과를 다시 모델에 돌려주는 구조예요.

출처: Cerebras Inference - Tool Calling

지원 모델

모델 tool_choice 스트릭트 모드 병렬 호출 멀티턴 호출 가용성
qwen-3.8-27b none, auto, required, 이름 지정 함수 공개 공유 티어
kimi-k2.7-code none, auto, required, 이름 지정 함수 고객 트라이얼 전용
gpt-oss-120b none, auto, required, 이름 지정 함수 공개 공유 티어
gemma-4-31b none, auto, required, 이름 지정 함수 전용 엔드포인트

어떻게 동작하나요

도구 호출은 크게 다섯 단계로 진행돼요.

  1. 도구 정의 — 모델이 접근할 각 도구의 이름, 설명, 입력 파라미터를 제공해요.
  2. 요청 전송 — API 호출에 사용 가능한 도구 정의와 함께 프롬프트를 보내요.
  3. 도구 선택 — 모델이 해당 요청에 도구가 도움이 될지 판단하고, 필요하다면 도구 이름과 인자를 반환해요.
  4. 도구 실행 — 클라이언트 애플리케이션이 모델의 도구 호출 요청을 받아 지정된 도구(예: 외부 API 호출)를 실행하고 결과를 가져와요.
  5. 최종 응답 생성 — 도구 결과를 모델에 보내 대화를 이어가요.

기본 도구 호출

먼저 Cerebras 클라이언트를 초기화해요. API 키가 아직 없다면 Quickstart를 먼저 완료해 주세요.

import os
import json
import re
from cerebras.cloud.sdk import Cerebras

# Initialize Cerebras client
client = Cerebras(
    api_key=os.environ.get("CEREBRAS_API_KEY"),
)

다음으로 애플리케이션이 실행할 함수를 정의해요. 아래는 기본 사칙연산을 수행하는 계산기 예시예요.

def calculate(expression):
    expression = re.sub(r'[^0-9+\-*/().]', '', expression)

    try:
        result = eval(expression)
        return str(result)
    except (SyntaxError, ZeroDivisionError, NameError, TypeError, OverflowError):
        return "Error: Invalid expression"

도구 이름·설명·파라미터를 담은 스키마를 정의해요. 지원되는 JSON Schema 부분집합에서는 strict: true가 제한 디코딩(constrained decoding)을 써서 도구 호출 인자가 스키마를 따르는 것을 보장해요.

tools = [
    {
        "type": "function",
        "function": {
            "name": "calculate",
            "strict": True,
            "description": "A calculator tool that can perform basic arithmetic operations. Use this when you need to compute mathematical expressions or solve numerical problems.",
            "parameters": {
                "type": "object",
                "properties": {
                    "expression": {
                        "type": "string",
                        "description": "The mathematical expression to evaluate"
                    }
                },
                "required": ["expression"],
                "additionalProperties": False
            }
        }
    }
]

메시지와 도구 스키마를 함께 보내요. 응답에 도구 호출이 포함될 수 있어요.

messages = [
    {"role": "system", "content": "You are a helpful assistant with access to a calculator. Use the calculator tool to compute mathematical expressions when needed."},
    {"role": "user", "content": "What's the result of 15 multiplied by 7?"},
]

response = client.chat.completions.create(
    model="qwen-3.8-27b",
    messages=messages,
    tools=tools,
    parallel_tool_calls=False,
)

응답에서 도구 호출이 있는지 확인하고, 있으면 요청한 함수를 실행한 뒤 결과를 모델에 돌려줘요.

choice = response.choices[0].message

if choice.tool_calls:
    function_call = choice.tool_calls[0].function
    if function_call.name == "calculate":
        # Logging that the model is executing a function named "calculate".
        print(f"Model executing function '{function_call.name}' with arguments {function_call.arguments}")

        # Parse the arguments from JSON format and perform the requested calculation.
        arguments = json.loads(function_call.arguments)
        result = calculate(arguments["expression"])

        # Note: This is the result of executing the model's request (the tool call), not the model's own output.
        print(f"Calculation result sent to model: {result}")

        # Send the result back to the model to fulfill the request.
        messages.append({
            "role": "tool",
            "content": json.dumps(result),
            "tool_call_id": choice.tool_calls[0].id
        })

        # Request the final response from the model, now that it has the calculation result.
        final_response = client.chat.completions.create(
            model="qwen-3.8-27b",
            messages=messages,
        )

        # Handle and display the model's final response.
        if final_response:
            print("Final model output:", final_response.choices[0].message.content)
        else:
            print("No final response received")
else:
    # Handle cases where the model's response does not include expected tool calls.
    print("Unexpected response from the model")

이 예시는 대략 아래와 같은 출력을 만들어요.

Model executing function 'calculate' with arguments {"expression": "15 * 7"}
Calculation result sent to model: 105
Final model output: 15 * 7 = 105

스트릭트 모드

지원되는 JSON Schema 부분집합을 쓰는 스키마에서, 스트릭트 모드는 도구 호출 인자가 스키마를 따르는 것을 보장해요.

스트릭트 모드가 없으면 도구 호출에 이런 문제가 생길 수 있어요.

  • 2 대신 "2" 같은 잘못된 파라미터 타입
  • 누락된 필수 파라미터
  • 예상치 못한 파라미터
  • 잘못된 형태의 인자 JSON

스트릭트 모드는 이런 스키마 위반을 막아줘요. 활성화는 도구 정의의 function 객체 안에서 stricttrue로 설정하면 돼요.

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "strict": True,  # Enable constrained decoding
            "description": "Get the current weather for a location",
            "parameters": {
                "type": "object",
                "properties": {
                    "location": {
                        "type": "string",
                        "description": "City and country, such as San Francisco, USA"
                    },
                    "unit": {
                        "type": "string",
                        "enum": ["celsius", "fahrenheit"]
                    }
                },
                "required": ["location", "unit"],
                "additionalProperties": False
            }
        }
    }
]

스키마 요구사항

스트릭트 모드를 쓸 때는 스키마의 모든 객체에 additionalProperties: false를 설정해야 해요. 스키마 제한에 대한 자세한 내용은 Structured Outputs의 Strict Mode 제한을 참고하세요.

모델별로 주의할 점이 있어요. kimi-k2.7-code는 요청의 모든 함수에 같은 strict 값을 주거나, 모든 함수에 생략해야 해요. qwen-3.8-27b의 스트릭트 도구 스키마에서는 pattern, minLength, maxLength를 쓰지 말아야 해요.

멀티턴 도구 호출

실제 워크플로는 대부분 도구를 한 번만 부르지 않아요. 멀티턴 도구 호출은 모델이 도구를 호출하고, 그 출력을 반영한 뒤, 같은 대화 안에서 또 다른 도구를 호출할지 스스로 결정하게 해요. messages에 각 도구 결과를 추가하고 모델에게 계속 진행하라고 요청하는 방식으로, client.chat.completions.create()를 도구 호출이 사라질 때까지 반복 호출하면 돼요. 도구 결과는 {"role": "tool", "tool_call_id": ..., "content": ...} 형태로 돌려주고, 응답의 tool_calls가 없어지면 대화를 끝내면 돼요.

병렬 도구 호출

병렬 도구 호출은 모델이 하나의 응답에서 여러 개의 독립적인 도구 호출을 요청하게 해서 지연을 줄여줘요. 예를 들어 "토론토가 몬트리올보다 따뜻한가요?"라는 질문에 두 도시의 날씨를 각각 확인해야 한다면, 두 요청을 한 번에 처리할 수 있어요. 이런 병렬 호출은 다음 경우에 유용해요.

  • 하나의 요청이 서로 다른 도시의 날씨처럼 여러 독립적인 데이터 포인트를 필요로 할 때
  • 도구 호출이 다른 도구 호출의 결과에 의존하지 않을 때

parallel_tool_calls 파라미터로 이 동작을 명시적으로 제어할 수 있어요. True로 설정하면 병렬 실행(기본값), False로 설정하면 순차 실행을 강제해요.

response = client.chat.completions.create(
    model="qwen-3.8-27b",
    messages=messages,
    tools=tools,
    parallel_tool_calls=True,  # Enable parallel calling (default)
)

병렬 호출에서는 응답의 tool_calls 배열의 모든 항목을 순회하고, 각 도구 결과를 messagestool_call_id와 함께 추가한 뒤, 모든 도구를 처리하고 나서 최종 응답을 다시 요청하면 돼요.

더 알아보기