추론 + 툴 콜

추론 + 툴 콜 (Tool Calls with Reasoning)

추론(reasoning) 모델이 툴 콜(tool call)을 하도록 OpenAI 호환 API로 구성하는 예제입니다. 모델이 생각을 한 뒤 함수를 호출하고, 그 결과를 다시 넣어 최종 답을 얻는 멀티턴 흐름을 보여줍니다.

출처: 문서

본문

/v1/chat/completionstools를 넘기고 모델이 tool_calls를 내보내면, 그 호출 결과를 대화에 이어붙여 최종 응답을 받습니다. 추론 모델에는 --reasoning-parser를 지정합니다.

openai_chat_completion_tool_calls_with_reasoning.py

# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
"""An example demonstrates how to use tool calling with reasoning models
like QwQ-32B. The reasoning will not be parsed by the tool 
calling process; only the final output will be parsed.

To run this example, you need to start the vLLM server with both 
the reasoning parser and tool calling enabled.

```bash
vllm serve Qwen/QwQ-32B \
     --reasoning-parser deepseek_r1 \
     --enable-auto-tool-choice --tool-call-parser hermes
     

"""

from openai import OpenAI

Now, simulate a tool call

def get_current_weather(city: str, state: str, unit: "str"): return ( "The weather in Dallas, Texas is 85 degrees fahrenheit. It is " "partly cloudly, with highs in the 90's." )

available_tools = {"get_current_weather": get_current_weather}

Modify OpenAI's API key and API base to use vLLM's API server.

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

properties = { "city": { "type": "string", "description": "The city to find the weather for, e.g. 'San Francisco'", }, "state": { "type": "string", "description": "the two-letter abbreviation for the state that the city is" " in, e.g. 'CA' which would mean 'California'", }, "unit": { "type": "string", "description": "The unit to fetch the temperature in", "enum": ["celsius", "fahrenheit"], }, }

tools = [ { "type": "function", "function": { "name": "get_current_weather", "description": "Get the current weather in a given location", "parameters": { "type": "object", "properties": properties, "required": ["city", "state", "unit"], }, }, } ] messages = [ {"role": "user", "content": "Hi! How are you doing today?"}, {"role": "assistant", "content": "I'm doing well! How can I help you?"}, { "role": "user", "content": ( "Can you tell me what the temperate will be in Dallas, in fahrenheit?" ), }, ]

def extract_reasoning_and_calls(chunks: list): reasoning = "" tool_call_idx = -1 arguments = [] function_names = [] for chunk in chunks: if chunk.choices[0].delta.tool_calls: tool_call = chunk.choices[0].delta.tool_calls[0] if tool_call.index != tool_call_idx: tool_call_idx = chunk.choices[0].delta.tool_calls[0].index arguments.append("") function_names.append("")

        if tool_call.function:
            if tool_call.function.name:
                function_names[tool_call_idx] = tool_call.function.name

            if tool_call.function.arguments:
                arguments[tool_call_idx] += tool_call.function.arguments
    else:
        if hasattr(chunk.choices[0].delta, "reasoning"):
            reasoning += chunk.choices[0].delta.reasoning
return reasoning, arguments, function_names

def main(): client = OpenAI( api_key=openai_api_key, base_url=openai_api_base, )

models = client.models.list()
model = models.data[0].id

print("---------Full Generate With Automatic Function Calling-------------")
tool_calls = client.chat.completions.create(
    messages=messages, model=model, tools=tools
)
print(f"reasoning: {tool_calls.choices[0].message.reasoning}")
print(f"function name: {tool_calls.choices[0].message.tool_calls[0].function.name}")
print(
    f"function arguments: "
    f"{tool_calls.choices[0].message.tool_calls[0].function.arguments}"
)

print("----------Stream Generate With Automatic Function Calling-----------")
tool_calls_stream = client.chat.completions.create(
    messages=messages, model=model, tools=tools, stream=True
)

chunks = list(tool_calls_stream)

reasoning, arguments, function_names = extract_reasoning_and_calls(chunks)

print(f"reasoning: {reasoning}")
print(f"function name: {function_names[0]}")
print(f"function arguments: {arguments[0]}")

print("----------Full Generate With Named Function Calling-----------------")
tool_calls = client.chat.completions.create(
    messages=messages,
    model=model,
    tools=tools,
    tool_choice={"type": "function", "function": {"name": "get_current_weather"}},
)

tool_call = tool_calls.choices[0].message.tool_calls[0].function
print(f"reasoning: {tool_calls.choices[0].message.reasoning}")
print(f"function name: {tool_call.name}")
print(f"function arguments: {tool_call.arguments}")
print("----------Stream Generate With Named Function Calling--------------")

tool_calls_stream = client.chat.completions.create(
    messages=messages,
    model=model,
    tools=tools,
    tool_choice={"type": "function", "function": {"name": "get_current_weather"}},
    stream=True,
)

chunks = list(tool_calls_stream)

reasoning, arguments, function_names = extract_reasoning_and_calls(chunks)
print(f"reasoning: {reasoning}")
print(f"function name: {function_names[0]}")
print(f"function arguments: {arguments[0]}")
print("\n\n")

if name == "main": main()


## 더 알아보기 (Learn more)

- [Reasoning Outputs](https://docs.vllm.ai/en/latest/features/reasoning_outputs/) — 추론 출력 기능
- [Tool Calling](https://docs.vllm.ai/en/latest/features/tool_calling/) — 툴 콜링
- [OpenAI-Compatible Server](https://docs.vllm.ai/en/latest/serving/online_serving/openai_compatible_server/) — OpenAI 호환 서버