Qwen3 함수 호출

Qwen3 함수 호출 (Function Calling)

대규모 언어 모델과 함수 호출은 크고 계속 진화하는 주제예요. AI 애플리케이션, 특히 현재 AI 기술의 한계를 보완하려는 AI 네이티브 애플리케이션이나 성능과 사용자 상호작용, 효율성 향상을 위해 AI 기술 통합을 추구하는 기존 애플리케이션에게 특히 중요해요. 이 가이드에서는 Qwen3로 함수 호출을 사용하는 방법과 그것으로 목표를 달성하는 방법을 소개할게요.

출처: 문서

본문

이 가이드에서는 먼저 Qwen3로 함수 호출을 사용하는 방법을 보여드리고, 그다음 Qwen3 함수 호출의 기술적 세부 사항(주로 템플릿)을 소개할게요.

함수 호출이란?

📝 참고: "도구 사용(tool use)"이라는 다른 용어로 같은 개념을 지칭하기도 해요. 어떤 이들은 도구가 함수의 일반화된 형태라고 주장할 수 있지만, 현재로서는 프로그래밍 인터페이스의 다른 I/O 타입이라는 기술적 차이만 존재해요.

대규모 언어 모델(LLM)은 강력한 존재예요. 하지만 때로 LLM만으로는 충분하지 못해요.

한편으로 LLM은 본질적인 모델링 한계가 있어요. 첫째, 훈련 데이터에 없는 것, 특히 훈련이 끝난 뒤에 일어난 일은 모르죠. 또한 우도(likelihood) 방식으로 배우기 때문에 수학 계산처럼 고정된 규칙 집합이 있는 작업에는 충분히 정확하지 않을 수 있어요.

다른 한편으로, LLM을 프로그램 방식으로 다른 것들과 Plug-and-Play 서비스처럼 사용하기는 쉽지 않아요. LLM은 대부분 해석의 여지가 있는 모호한 단어로 말하는 반면, 다른 소프트웨어나 애플리케이션, 시스템은 미리 정의되고 고정되며 구조화된 코드와 프로그래밍 인터페이스로 소통하거든요.

이를 위해 함수 호출은 LLM이 다른 것들과 어떻게 상호작용해야 하는지 규정하는 공통 프로토콜을 만듭니다. 절차는 주로 다음과 같아요:

  1. 애플리케이션이 함수 집합과 함수 지침을 LLM에 제공해요.
  2. LLM은 사용자 쿼리에 응답해 함수 하나 또는 여러 개를 사용하거나 사용하지 않기로 선택하며, 강제되어 사용할 수도 있어요.
  3. LLM이 함수를 사용하기로 하면 함수 지침에 따라 함수를 어떻게 사용해야 하는지 진술해요.
  4. 애플리케이션이 선택된 함수를 그대로 실행해 결과를 얻고, 추가 상호작용이 필요하면 그 결과를 LLM에 전달해요.

LLM이 이 프로토콜을 이해하고 따르는 방법은 많아요. 언제나 그렇듯 핵심은 프롬프트 엔지니어링이거나 모델이 알고 있는 내재화된 템플릿이에요. Qwen3에는 함수 호출 성능을 극대화하기 위해 Hermes 스타일 도구 사용을 권장해요.

함수 호출 추론

함수 호출은 기본적으로 프롬프트 엔지니어링으로 구현되므로 Qwen3 모델의 입력을 수동으로 구성할 수 있어요. 하지만 함수 호출을 지원하는 프레임워크가 그 수고로운 작업을 도와줘요.

다음에서는 Qwen-Agent와 vLLM으로 (전용 함수 호출 채팅 템플릿을 통한) 사용법을 소개할게요.

예시 케이스

추론 사용법을 보여드리기 위해 예시를 사용할게요. Python 3.11을 사용한다고 가정할게요.

시나리오: 어느 위치의 온도를 모델에게 물어본다고 가정해 봐요. 보통 모델은 실시간 정보를 제공할 수 없다고 답할 거예요. 하지만 특정 도시의 현재 온도와 주어진 날짜의 온도를 각각 얻는 두 도구가 있고, 모델이 이 도구들을 활용하도록 하려고 해요.

예시 케이스를 설정하려면 다음 코드를 사용할 수 있어요:

준비 코드:

import json

def get_current_temperature(location: str, unit: str = "celsius"):
    """Get current temperature at a location.

    Args:
        location: The location to get the temperature for, in the format "City, State, Country".
        unit: The unit to return the temperature in. Defaults to "celsius". (choices: ["celsius", "fahrenheit"])

    Returns:
        the temperature, the location, and the unit in a dict
    """
    return {
        "temperature": 26.1,
        "location": location,
        "unit": unit,
    }

def get_temperature_date(location: str, date: str, unit: str = "celsius"):
    """Get temperature at a location and date.

    Args:
        location: The location to get the temperature for, in the format "City, State, Country".
        date: The date to get the temperature for, in the format "Year-Month-Day".
        unit: The unit to return the temperature in. Defaults to "celsius". (choices: ["celsius", "fahrenheit"])

    Returns:
        the temperature, the location, the date and the unit in a dict
    """
    return {
        "temperature": 25.9,
        "location": location,
        "date": date,
        "unit": unit,
    }

def get_function_by_name(name):
    if name == "get_current_temperature":
        return get_current_temperature
    if name == "get_temperature_date":
        return get_temperature_date

TOOLS = [
    {
        "type": "function",
        "function": {
            "name": "get_current_temperature",
            "description": "Get current temperature at a location.",
            "parameters": {
                "type": "object",
                "properties": {
                    "location": {
                        "type": "string",
                        "description": 'The location to get the temperature for, in the format "City, State, Country".',
                    },
                    "unit": {
                        "type": "string",
                        "enum": ["celsius", "fahrenheit"],
                        "description": 'The unit to return the temperature in. Defaults to "celsius".',
                    },
                },
                "required": ["location"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "get_temperature_date",
            "description": "Get temperature at a location and date.",
            "parameters": {
                "type": "object",
                "properties": {
                    "location": {
                        "type": "string",
                        "description": 'The location to get the temperature for, in the format "City, State, Country".',
                    },
                    "date": {
                        "type": "string",
                        "description": 'The date to get the temperature for, in the format "Year-Month-Day".',
                    },
                    "unit": {
                        "type": "string",
                        "enum": ["celsius", "fahrenheit"],
                        "description": 'The unit to return the temperature in. Defaults to "celsius".',
                    },
                },
                "required": ["location", "date"],
            },
        },
    },
]
MESSAGES = [
    {"role": "user",  "content": "What's the temperature in San Francisco now? How about tomorrow? Current Date: 2024-09-30."},
]

특히 도구는 JSON Schema를 사용해 설명해야 하고, 메시지에는 가능한 한 많은 가용 정보를 담아야 해요. 도구와 메시지의 설명은 아래에서 확인할 수 있어요.

예시 도구 — 도구는 다음 JSON으로 설명해야 해요:

[
  {
    "type": "function",
    "function": {
      "name": "get_current_temperature",
      "description": "Get current temperature at a location.",
      "parameters": {
        "type": "object",
        "properties": {
          "location": {
            "type": "string",
            "description": "The location to get the temperature for, in the format \"City, State, Country\"."
          },
          "unit": {
            "type": "string",
            "enum": [
              "celsius",
              "fahrenheit"
            ],
            "description": "The unit to return the temperature in. Defaults to \"celsius\"."
          }
        },
        "required": [
          "location"
        ]
      }
    }
  },
  {
    "type": "function",
    "function": {
      "name": "get_temperature_date",
      "description": "Get temperature at a location and date.",
      "parameters": {
        "type": "object",
        "properties": {
          "location": {
            "type": "string",
            "description": "The location to get the temperature for, in the format \"City, State, Country\"."
          },
          "date": {
            "type": "string",
            "description": "The date to get the temperature for, in the format \"Year-Month-Day\"."
          },
          "unit": {
            "type": "string",
            "enum": [
              "celsius",
              "fahrenheit"
            ],
            "description": "The unit to return the temperature in. Defaults to \"celsius\"."
          }
        },
        "required": [
          "location",
          "date"
        ]
      }
    }
  }
]

각 도구는 두 필드를 가진 JSON 객체예요:

  • type: 도구의 타입을 지정하는 문자열로, 현재는 "function"만 유효해요.
  • function: 함수 사용 지침을 상세히 담은 객체.

각 함수는 세 필드를 가진 JSON 객체예요:

  • name: 함수의 이름을 나타내는 문자열.
  • description: 함수가 무엇에 쓰이는지 설명하는 문자열.
  • parameters: 함수가 받는 파라미터를 지정하는 JSON Schema. JSON Schema 구성 방법은 링크된 문서를 참고하세요. 주목할 필드로는 type, required, enum이 있어요.

대부분의 프레임워크는 tool 형식을 사용하고 일부는 function 형식을 사용해요. 어느 것을 사용할지는 이름을 보면 명확해요.

예시 메시지 — 우리 쿼리는 What's the temperature in San Francisco now? How about tomorrow? Current Date: 2024-09-30.예요.

[
    {"role": "user",  "content": "What's the temperature in San Francisco now? How about tomorrow? Current Date: 2024-09-30."}
]

Qwen-Agent

Qwen-Agent는 사실 AI 애플리케이션 개발을 위한 Python 에이전트 프레임워크예요. 의도된 사용 사례는 효율적인 추론보다 더 상위 수준이지만, Qwen3의 함수 호출에 대한 표준 구현을 포함하고 있어요. 사용자에게 투명한 템플릿을 통해 Qwen3의 함수 호출 능력을 OpenAI 호환 API에 제공해요.

Qwen3 같은 추론 모델의 경우 ReAct처럼 stopword 기반의 도구 호출 템플릿은 권장하지 않아요. 모델이 thought 섹션에서 stopword를 출력해 예상치 못한 도구 호출 동작이 발생할 수 있기 때문이에요.

시작 전에 최신 라이브러리가 설치되어 있는지 확인해요:

pip install -U qwen-agent

준비

Qwen-Agent는 함수 호출을 지원하지 않는 OpenAI 호환 API를 감쌀 수 있어요. 이렇게 만든 API는 대부분의 추론 프레임워크로 서빙하거나 DashScope, Together 같은 클라우드 제공자에서 얻을 수 있어요.

http://localhost:8000/v1에 OpenAI 호환 API가 있다고 가정하면, Qwen-Agent는 함수 호출을 지원하는 모델 추론 클래스를 얻기 위한 단축 함수 get_chat_model을 제공해요:

from qwen_agent.llm import get_chat_model

llm = get_chat_model({
    "model": "Qwen/Qwen3-8B",
    "model_server": "http://localhost:8000/v1",
    "api_key": "EMPTY",
    "generate_cfg": {
      "extra_body": {
        "chat_template_kwargs": {"enable_thinking": False}  # default to True
      }
    }
})

위에서 model_server는 다른 OpenAI 호환 API 클라이언트에서 흔히 쓰는 api_base예요. API 서버가 확인하지 않더라도 api_key를 제공하는 것이 좋아요 (코드에 평문으로 넣지 말고). 그 경우 아무 값이나 설정하면 돼요. generate_cfg로 모델 파라미터를 전달할 수 있어요. 여기서는 Qwen3의 think와 no_think 모드를 제어하는 방법을 보여드렸어요. API마다 제어 방법이 다를 수 있어요.

모델 입력에는 system, user, assistant 히스토리의 공통 메시지 구조를 사용해야 해요:

messages = MESSAGES[:]

현재 Qwen-Agent는 tools가 아닌 functions와 함께 동작해요. 이는 도구 설명을 약간 바꿔야 한다는 뜻이에요. 즉 function 필드를 추출하면 돼요:

functions = [tool["function"] for tool in TOOLS]

도구 호출과 도구 결과

모델과 상호작용하려면 chat 메서드를 사용해야 해요:

for responses in llm.chat(
    messages=messages,
    functions=functions,
):
    pass
messages.extend(responses)

chat 메서드는 list의 generator를 반환하며, 각각은 여러 메시지를 담을 수 있어요.

no_think 모드의 결과:

[
    {"role": "assistant", "content": "", "function_call": {"name": "get_current_temperature", "arguments": "{\"location\": \"San Francisco, California, United States\", \"unit\": \"celsius\"}"}},
    {"role": "assistant", "content": "", "function_call": {"name": "get_temperature_date", "arguments": "{\"location\": \"San Francisco, California, United States\", \"date\": \"2024-10-01\", \"unit\": \"celsius\"}"}},
]

think 모드의 결과:

[
    {"role": "assistant", "content": "", "reasoning_content": "Okay, the user is asking for the current temperature in San Francisco and the temperature for tomorrow. Let me check the available tools.\n\nFirst, there's the get_current_temperature function. It requires the location and optionally the unit. Since the user didn't specify the unit, I'll default to celsius. The location should be \"San Francisco, State, Country\". Wait, the example format is \"City, State, Country\", but San Francisco is a city in California, USA. So the location parameter would be \"San Francisco, California, United States\".\n\nThen, for tomorrow's temperature, the user mentioned the current date is 2024-09-30, so tomorrow would be 2024-10-01. The get_temperature_date function requires location, date, and unit. Again, using the same location and default unit. I need to format the date as \"Year-Month-Day\", which is 2024-10-01.\n\nWait, the current date given is 2024-09-30. If today is September 30, then tomorrow is October 1st. So the date parameter for the second function call should be \"2024-10-01\".\n\nI should make two separate function calls: one for the current temperature and another for tomorrow's date. Let me structure the JSON for both tool calls accordingly."},
    {"role": "assistant", "content": "", "function_call": {"name": "get_current_temperature", "arguments": "{\"location\": \"San Francisco, California, United States\", \"unit\": \"celsius\"}"}},
    {"role": "assistant", "content": "", "function_call": {"name": "get_temperature_date", "arguments": "{\"location\": \"San Francisco, California, United States\", \"date\": \"2024-10-01\", \"unit\": \"celsius\"}"}},
]

보시다시피 Qwen-Agent는 모델 생성을 사용하기 쉬운 구조적 형식으로 파싱하려 해요. 함수 호출 관련 세부 정보는 메시지의 function_call 필드에 담겨요:

  • name: 호출할 함수를 나타내는 문자열.
  • arguments: 함수를 호출할 인자의 JSON 형식 문자열.

thinking 모드에서는 먼저 thought를 생성한 다음 도구 호출을 생성해요.

그다음 중요한 부분 — 함수 호출을 확인하고 적용하는 단계예요:

 1for message in responses:
 2    if fn_call := message.get("function_call", None):
 3        fn_name: str = fn_call['name']
 4        fn_args: dict = json.loads(fn_call["arguments"])
 5
 6        fn_res: str = json.dumps(get_function_by_name(fn_name)(**fn_args))
 7
 8        messages.append({
 9            "role": "function",
10            "name": fn_name,
11            "content": fn_res,
12        })

도구 결과를 얻으려면:

  • 1행: 모델이 생성한 순서대로 함수 호출을 순회해야 해요.
  • 2행: 생성된 메시지의 function_call 필드를 확인해 모델이 판단한 함수 호출이 필요한지 확인할 수 있어요.
  • 3-4행: 함수의 이름과 인자를 뜻하는 name, arguments 등 관련 세부 정보도 그곳에서 찾을 수 있어요.
  • 6행: 세부 정보로 함수를 호출하고 결과를 얻어야 해요. 여기서는 get_function_by_name이라는 함수가 이름으로 관련 함수를 얻는 데 도움을 준다고 가정해요.
  • 8-12행: 결과를 얻은 뒤 함수 결과를 content로, role을 "function"으로 하여 메시지에 추가해요.

이제 메시지는 다음과 같아요:

no_think 모드:

[
    {"role": "user", "content": "What's the temperature in San Francisco now? How about tomorrow? Current Date: 2024-09-30."},
    {"role": "assistant", "content": "", "function_call": {"name": "get_current_temperature", "arguments": "{\"location\": \"San Francisco, California, United States\", \"unit\": \"celsius\"}"}},
    {"role": "assistant", "content": "", "function_call": {"name": "get_temperature_date", "arguments": "{\"location\": \"San Francisco, California, United States\", \"date\": \"2024-10-01\", \"unit\": \"celsius\"}"}},
    {"role": "function", "name": "get_current_temperature", "content": '{"temperature": 26.1, "location": "San Francisco, California, United States", "unit": "celsius"}'},
    {"role": "function", "name": "get_temperature_date", "content": '{"temperature": 25.9, "location": "San Francisco, California, United States", "date": "2024-10-01", "unit": "celsius"}'},
]

think 모드:

[
    {"role": "user", "content": "What's the temperature in San Francisco now? How about tomorrow? Current Date: 2024-09-30."},
    {"role": "assistant", "content": "", "reasoning_content": "Okay, the user is asking for the current temperature in San Francisco and the temperature for tomorrow. Let me check the available tools.\n\nFirst, there's the get_current_temperature function. It requires the location and optionally the unit. Since the user didn't specify the unit, I'll default to celsius. The location should be \"San Francisco, State, Country\". Wait, the example format is \"City, State, Country\", but San Francisco is a city in California, USA. So the location parameter would be \"San Francisco, California, United States\".\n\nThen, for tomorrow's temperature, the user mentioned the current date is 2024-09-30, so tomorrow would be 2024-10-01. The get_temperature_date function requires location, date, and unit. Again, using the same location and default unit. I need to format the date as \"Year-Month-Day\", which is 2024-10-01.\n\nWait, the current date given is 2024-09-30. If today is September 30, then tomorrow is October 1st. So the date parameter for the second function call should be \"2024-10-01\".\n\nI should make two separate function calls: one for the current temperature and another for tomorrow's date. Let me structure the JSON for both tool calls accordingly."},
    {"role": "assistant", "content": "", "function_call": {"name": "get_current_temperature", "arguments": "{\"location\": \"San Francisco, California, United States\", \"unit\": \"celsius\"}"}},
    {"role": "assistant", "content": "", "function_call": {"name": "get_temperature_date", "arguments": "{\"location\": \"San Francisco, California, United States\", \"date\": \"2024-10-01\", \"unit\": \"celsius\"}"}},
    {"role": "function", "name": "get_current_temperature", "content": '{"temperature": 26.1, "location": "San Francisco, California, United States", "unit": "celsius"}'},
    {"role": "function", "name": "get_temperature_date", "content": '{"temperature": 25.9, "location": "San Francisco, California, United States", "date": "2024-10-01", "unit": "celsius"}'},
]

최종 응답

마지막으로 모델을 다시 실행해 최종 모델 결과를 얻어요:

for responses in llm.chat(messages=messages, functions=functions):
    pass
messages.extend(responses)

최종 응답은 다음과 같을 거예요.

no_think 모드:

[
    {"role": "assistant", "content": "The current temperature in San Francisco, CA, USA is **26.1°C**.  \n\nFor tomorrow (2024-10-01), the temperature is projected to be **25.9°C**.  \n\nThere is a slight decrease in temperature expected from today to tomorrow."}
]

think 모드:

[
    {"role": "assistant", "content": "", "reasoning_content": "Okay, the user asked for the current temperature in San Francisco and tomorrow's temperature. I called the get_current_temperature function for now and get_temperature_date for tomorrow. The responses came back with 26.1°C today and 25.9°C tomorrow. Let me present this info clearly.\n\nFirst, confirm the location to make sure there's no confusion. The current temp is 26.1°C, so I'll state that. Then, tomorrow's date is 2024-10-01, which is October 1st, so I'll mention the date in a user-friendly way. The temp drops slightly to 25.9°C. I should note the unit is Celsius as per the default. Keep the answer concise but informative. Maybe add a brief note about the slight decrease. Make sure the dates are correctly formatted and the temperatures are accurate based on the data provided."},
    {"role": "assistant", "content": "The current temperature in San Francisco, CA, USA is **26.1°C**.  \n\nFor tomorrow (2024-10-01), the temperature is projected to be **25.9°C**.  \n\nThere is a slight decrease in temperature expected from today to tomorrow."}
]

vLLM

vLLM은 LLM 추론과 서빙을 위한 빠르고 사용하기 쉬운 라이브러리예요. transformers의 토크나이저를 사용해 입력을 포맷하므로 입력 준비에 어려움이 없어요. 또한 vLLM은 지원되는 형식이면 생성된 도구 호출을 자동으로 파싱하는 헬퍼 함수도 구현해요.

  • vllm >= v0.8.5 필요.
  • 자세한 내용은 vLLM 문서를 참고하세요.

vllm의 OpenAI 호환 API와 openai Python 라이브러리의 API 클라이언트를 사용할게요.

준비

Qwen3의 경우 tokenizer_config.json의 채팅 템플릿이 이미 Hermes 스타일 도구 사용을 지원해요. vLLM으로 OpenAI 호환 API를 시작하기만 하면 돼요:

vllm serve Qwen/Qwen3-8B --enable-auto-tool-choice --tool-call-parser hermes --reasoning-parser deepseek_r1

입력은 준비 코드와 동일해요:

tools = TOOLS
messages = MESSAGES

클라이언트도 초기화해요:

from openai import OpenAI

openai_api_key = "EMPTY"
openai_api_base = "http://localhost:8000/v1"

client = OpenAI(
    api_key=openai_api_key,
    base_url=openai_api_base,
)

model_name = "Qwen/Qwen3-8B"

도구 호출과 도구 결과

create chat completions 엔드포인트로 모델을 쿼리할 수 있어요. no_think 모드의 예시예요:

response = client.chat.completions.create(
    model=model_name,
    messages=messages,
    tools=tools,
    temperature=0.7,
    top_p=0.8,
    max_tokens=512,
    extra_body={
        "repetition_penalty": 1.05,
        "chat_template_kwargs": {"enable_thinking": False}  # default to True
    },
)

vLLM이 도구 호출을 대신 파싱해야 하며, 응답(response.choices[0])의 주요 필드는 다음과 같아야 해요.

Choice(
    finish_reason='tool_calls',
    index=0,
    logprobs=None,
    message=ChatCompletionMessage(
        content=None,
        role='assistant',
        function_call=None,
        tool_calls=[
            ChatCompletionMessageToolCall(
                id='chatcmpl-tool-924d705adb044ff88e0ef3afdd155f15',
                function=Function(arguments='{"location": "San Francisco, CA, USA"}', name='get_current_temperature'),
                type='function',
            ),
            ChatCompletionMessageToolCall(
                id='chatcmpl-tool-7e30313081944b11b6e5ebfd02e8e501',
                function=Function(arguments='{"location": "San Francisco, CA, USA", "date": "2024-10-01"}', name='get_temperature_date'),
                type='function',
            ),
        ],
    ),
    stop_reason=None,
)

함수 인자는 Qwen-Agent가 따르는 JSON 형식 문자열이라는 점을 참고하세요. 이전과 마찬가지로 도구 호출이 생성됐지만 형식이 잘못되어 파싱할 수 없는 가장자리(코너 케이스)가 있을 수 있어요. 프로덕션 코드에서는 직접 파싱을 시도해야 해요.

그다음 아래처럼 도구 결과를 얻고 메시지에 추가할 수 있어요:

messages.append(response.choices[0].message.model_dump())

if tool_calls := messages[-1].get("tool_calls", None):
    for tool_call in tool_calls:
        call_id: str = tool_call["id"]
        if fn_call := tool_call.get("function"):
            fn_name: str = fn_call["name"]
            fn_args: dict = json.loads(fn_call["arguments"])

            fn_res: str = json.dumps(get_function_by_name(fn_name)(**fn_args))

            messages.append({
                "role": "tool",
                "content": fn_res,
                "tool_call_id": call_id,
            })

OpenAI API는 tool_call_id로 도구 결과와 도구 호출 사이의 관계를 식별한다는 점을 유의하세요.

메시지는 이제 다음과 같아요:

[
    {'role': 'user', 'content': "What's the temperature in San Francisco now? How about tomorrow? Current Date: 2024-09-30."},
    {'content': None, 'role': 'assistant', 'function_call': None, 'tool_calls': [
        {'id': 'chatcmpl-tool-924d705adb044ff88e0ef3afdd155f15', 'function': {'arguments': '{"location": "San Francisco, CA, USA"}', 'name': 'get_current_temperature'}, 'type': 'function'},
        {'id': 'chatcmpl-tool-7e30313081944b11b6e5ebfd02e8e501', 'function': {'arguments': '{"location": "San Francisco, CA, USA", "date": "2024-10-01"}', 'name': 'get_temperature_date'}, 'type': 'function'},
    ]},
    {'role': 'tool', 'content': '{"temperature": 26.1, "location": "San Francisco, CA, USA", "unit": "celsius"}', 'tool_call_id': 'chatcmpl-tool-924d705adb044ff88e0ef3afdd155f15'},
    {'role': 'tool', 'content': '{"temperature": 25.9, "location": "San Francisco, CA, USA", "date": "2024-10-01", "unit": "celsius"}', 'tool_call_id': 'chatcmpl-tool-7e30313081944b11b6e5ebfd02e8e501'},
]

최종 응답

도구 결과를 시드(seed)하고 응답을 얻기 위해 엔드포인트를 다시 호출해요:

response = client.chat.completions.create(
    model=model_name,
    messages=messages,
    tools=tools,
    temperature=0.7,
    top_p=0.8,
    max_tokens=512,
    extra_body={
        "repetition_penalty": 1.05,
    },
)

messages.append(response.choices[0].message.model_dump())

최종 응답(response.choices[0].message.content)은 다음과 같아야 해요.

The current temperature in San Francisco is approximately 26.1°C. For tomorrow, the forecasted temperature is around 25.9°C.

마지막으로

Qwen3에 함수 호출을 사용하는 어떤 방식을 선택하든, 프롬프트 엔지니어링의 제한과 이점이 적용된다는 점을 명심하세요:

  • 적절한 프롬프트나 템플릿을 써도 모델 생성이 항상 프로토콜을 따르리라는 보장은 없어요. 특히 모델이 스스로 생각하고 궤도를 유지하는 데 더 의존하는 복잡한 템플릿은, 템플릿과 제어/특수 토큰 사용에 더 의존하는 간단한 템플릿보다 확실하지 않아요. 후자는 물론 어떤 훈련을 요구해요.
  • 프로덕션 코드에서는 실패할 경우에 대비해 대책이나 보정이 마련되어 있는지 준비하세요.
  • 특정 시나리오에서 생성이 기대에 못 미치면 템플릿을 다듬어 지침이나 제약을 더 추가할 수 있어요. 여기 언급된 템플릿은 충분히 일반적이지만, 여러분의 사용 사례에 가장 좋거나 가장 구체적이거나 가장 간결하지 않을 수 있어요.
  • 궁극적인 해결책은 여러분만의 데이터로 파인튜닝하는 거예요.

즐겁게 프롬프팅하세요!

더 알아보기 (Learn more)