Vikhrmodels/Qwen2.5-7B-Instruct-Tool-Planning-v0.1
This model is a experimental supervised fine-tuned version of Qwen/Qwen2.5-7B-Instruct for the Tool Planning task on synthetic data of the English Vikhrmodels/tool-plannings-v0.1 dataset.
Tool Planning means modified version of Function Calling task with additional model's capabilities of reasoning about calls.
In this model, the features include:
- Simple Function — the model has one function in its arsenal, and it is able to call it if necessary at the user's common request.
- Multiple Function — the model has several functions in its arsenal, and it is able to call one of them if necessary at the user's request.
- Parallel Multiple Function — the model has several functions in its arsenal, and it is able to call some of them if necessary at the user's request.
- Tool Planning — firstly the model is thinking about user's intent of function calling and secondly does calling.
- Tool Relevance Detection — the model is able to determine the relevance of a function calling.
- Tool Error Handling — the model is able to react non-hallucinative to broken/erroneous tool executions.
All examples of these features are described below.
Model card tree
Usage (HuggingFace Transformers)
Below we share some code snippets on how to get quickly started with running the model. First, install the Transformers library with:
pip install transformers==4.48.3
Prepare your functions
You should write the functions (tools) used by the model in Python code and make sure to add Python docstrings as in the example below:
def get_weather(city: str):
"""
A function that returns the weather in a given city.
Args:
city: The city to get the weather for.
"""
import random
return "sunny" if random.random() > 0.5 else "rainy"
# Either immediately in JSON format:
get_sunrise_sunset_times = {
"type": "function",
"function": {
"name": "get_sunrise_sunset_times",
"description": "A function that returns the time of sunrise and sunset at the present moment, for a given city, in the form of a list: [sunrise_time, sunset_time].",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "The city to get the sunrise and sunset times for."
}
},
"required": ["city"]
}
}
}
tools = [get_weather, get_sunrise_sunset_times]
Just use chat template
Next, you need to download the model and tokenizer:
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained(
"Vikhrmodels/Qwen2.5-7B-Instruct-Tool-Planning-v0.1",
device_map="auto",
torch_dtype=torch.bfloat16, # recommended dtype
)
tokenizer = AutoTokenizer.from_pretrained(
"Vikhrmodels/Qwen2.5-7B-Instruct-Tool-Planning-v0.1",
)
To get the result of generation, just use apply_chat_template
. In order to take into account our written functions (tools),
we need to pass them as a list through the tools
attribute and also use add_prompt_generation=True
.
history_messages = [
{"role": "user", "content": "Hi, can you tell me the time of sunrise in Los Angeles?"},
]
inputs = tokenizer.apply_chat_template(
history_messages,
tokenize=False,
add_generation_prompt=True, # adding prompt for generation
tools=tools, # our functions (tools)
)
input_tokens = tokenizer(
inputs,
add_special_tokens=False,
return_tensors='pt'
).to(model.device)
generated_ids = model.generate(
**input_tokens,
max_new_tokens=256,
do_sample=False,
)[0]
generated_response = tokenizer.decode(
generated_ids[input_tokens.input_ids.shape[-1]:],
skip_special_tokens=False, # `skip_special_tokens=False` for debug
)
print(generated_response)
Then our generated_response
will look like this:
<|start_thinking|>The user wants to know the time of sunrise in Los Angeles. I will use the get_sunrise_sunset_times API to retrieve this information.<|end_thinking|><tool_call>[
{"tool_call_id": "0", "tool_name": "get_sunrise_sunset_times", "parameters": {"city": "Los Angeles"}}
]</tool_call><|im_end|>
Usage (VLLM)
For corrected work online serving in VLLM you need additionally load qwen2_tool_parser.py and chat_template.jinja from this repository.
vllm serve Vikhrmodels/Qwen2.5-7B-Instruct-Tool-Planning-v0.1 \
--download-dir "/path/to/cache" \
--chat-template "/path/to/chat_template.jinja" \
--tool-parser-plugin "/path/to/qwen2_tool_parser.py" \
--tool-call-parser "qwen2" \
--enable-auto-tool-choice
After that you can start doing requests:
from openai import OpenAI
import json
client = OpenAI(base_url="http://localhost:8000/v1", api_key="dummy")
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather in a given location",
"parameters": {
"type": "object",
"properties": {
"location": {"type": "string", "description": "City and state."},
},
"required": ["location"]
}
}
}
]
response = client.chat.completions.create(
model=client.models.list().data[0].id,
messages=[
{"role": "user", "content": "What's the weather in Krasnodar and Moscow?"}
],
tools=tools,
)
print(response.choices[0].message)
ChatCompletionMessage(
content='<|start_thinking|>I need to get the weather for Krasnodar and Moscow.<|end_thinking|>',
refusal=None,
role='assistant',
audio=None,
function_call=None,
tool_calls=[
ChatCompletionMessageToolCall(
id='chatcmpl-tool-73646c73148e4af9ac53656d6aa3e3c6',
function=Function(arguments='{"location": "Krasnodar"}', name='get_weather'),
type='function'),
ChatCompletionMessageToolCall(
id='chatcmpl-tool-95d93590d1a24df6a4f44a87a83f7761',
function=Function(arguments='{"location": "Moscow"}', name='get_weather'),
type='function')
],
reasoning_content=None)
Tool Planning Examples
The model is using grounded system prompt for tool planning. We do not recommend changing it too much, as this may cause hallucinations!
But you can try to add first message as system
role with additional system rules in your chat history and it adds at the end of this grounded system prompt.
<|im_start|>system
You have been trained to have advanced reasoning and tool-use capabilities and you should make best use of these skills to serve user's requests.
# Tool Use
Think about how you can make best use of the provided tools to help with the task and come up with a high level plan that you will execute first.
0. Start by writing <|start_thinking|> followed by a detailed step by step plan of how you will solve the problem. For each step explain your thinking fully and give details of required tool calls (if needed). Unless specified otherwise, you write your plan in natural language. When you finish, close it out with <|end_thinking|>.
You can optionally choose to skip this step when the user request is so straightforward to address that only a trivial plan would be needed.
NOTE: You MUST skip this step when you are directly responding to the user's request without using any tools.
Then carry out your plan by repeatedly executing the following steps.
1. Action: write <tool_call> followed by a list of JSON-formatted tool calls, with each one containing "tool_name" and "parameters" fields.
When there are multiple tool calls which are completely independent of each other (i.e. they can be executed in parallel), you should list them out all together in one step. When you finish, close it out with </tool_call>.
2. Observation: you will then receive results of those tool calls in JSON format in the very next turn, wrapped around by <tool_response> and </tool_response>. Carefully observe those results and think about what to do next. Note that these results will be provided to you in a separate turn. NEVER hallucinate results.
Every tool call produces a list of results (when a tool call produces no result or a single result, it'll still get wrapped inside a list). Each result is clearly linked to its originating tool call via its "tool_call_id".
3. Reflection: start the next turn by writing <|start_thinking|> followed by what you've figured out so far, any changes you need to make to your plan, and what you will do next. When you finish, close it out with <|end_thinking|>.
You can optionally choose to skip this step when everything is going according to plan and no special pieces of information or reasoning chains need to be recorded.
NOTE: You MUST skip this step when you are done with tool-use actions and are ready to respond to the user.
You can repeat the above 3 steps multiple times (could be 0 times too if no suitable tool calls are available or needed), until you decide it's time to finally respond to the user.
4. Response: then break out of the loop and write <|start_response|> followed by a piece of text which serves as a response to the user's last request. Use all previous tool calls and results to help you when formulating your response. When you finish, close it out with <|end_response|>.
# Available Tools
Here is the list of tools that you have available to you.
You can ONLY use the tools listed here. When a tool is not listed below, it is NOT available and you should NEVER attempt to use it.
Each tool is represented as a JSON object with fields like "name", "description", "parameters" (per JSON Schema), and optionally, "responses" (per JSON Schema).
\`\`\`json
[
{"name": "get_weather", "description": "A function that returns the weather in a given city.", "parameters": {"type": "object", "properties": {"city": {"type": "string", "description": "The city to get the weather for."}}, "required": ["city"]}, "responses": null},
{"name": "get_sunrise_sunset_times", "description": "A function that returns the time of sunrise and sunset at the present moment, for a given city, in the form of a list: [sunrise_time, sunset_time].", "parameters": {"type": "object", "properties": {"city": {"type": "string", "description": "The city to get the sunrise and sunset times for."}}, "required": ["city"]}, "responses": null}
]
\`\`\`
<|im_end|>
For corrected display used [\ `] instead of [`]
About the structure of prompt:
- This model always will answer with new tokens:
<|start_response|>
...text from model...<|end_response|>
. This content is the main one for user and it contains inassistant
incontent
field. - This model always starts thinking before tool calls with new tokens:
<|start_thinking|>
...thinking...<|end_thinking|>
. It contains inassistant
intool_plan
field. - After thinking model starts generate tool calls (function calling) with Qwen2.5 tokens (it can be a multiple/parallel calling too):
<tool_call>[
{"tool_call_id": "...", "tool_name": "...", "parameters": {...}},
{"tool_call_id": "...", "tool_name": "...", "parameters": {...}},
...
]</tool_call><|im_end|>
tool_call_id
is local tool id.
tool_name
is name of tool(function) calling.
It contains in assistant
in tool_calls
field.
- Responses from tools are located between
<tool_response>
...all last locals tools...</tool_response>
. Every local tool contains separately in specific roletool
:
{
"role": "tool",
"tool_call_id": "0", # MUST BE matches with the corresponding call above.
"content": { "tool_name_1_returns": ... } # MUST BE dict with key "tool_name" + "_returns"
},
{
"role": "tool",
"tool_call_id": "1", # MUST BE matches with the corresponding call above.
"content": { "tool_name_1_returns": ... }
},
{
"role": "tool",
"tool_call_id": "2", # MUST BE matches with the corresponding call above.
"content": { "tool_name_2_returns": ... },
"is_error_tool": True # You can add it if your tool is corrupted. But then you must provide error description in content.
}
Local tool ids mean that ids must match only in one pair tool call and tool response, next tool call must reset the counter and start from 0 again.
Simple Function
history
messages = [
{"role": "user", "content": "Hey dude, what can you do?"},
{"role": "assistant", "content": "I can retrieve a list of unpaid invoices and process payments for specific invoices."},
{"role": "user", "content": "Okey, then retrieve a list for me"},
{
"role": "assistant",
"tool_plan": "I will retrieve a list of unpaid invoices.",
"tool_calls": [
{
"id": "0",
"type": "function",
"function": {
"name": "find_unpaid_invoices",
"arguments": {}
}
}
]
},
{
"role": "tool",
"tool_call_id": "0",
"content": { "find_unpaid_invoices_returns": ["Utility Debts", "Housing and Utilities Arrears"]}
},
{"role": "assistant", "content": "Here is the list of unpaid invoices: Utility Debts and Housing and Utilities Arrears."},
{"role": "user", "content": "Ooh, I forget about this! Lets pay Utility Debts in the amount of $100 please"},
{
"role": "assistant",
"tool_plan": "I will process the payment for the Utility Debts invoice.",
"tool_calls": [
{
"id": "0",
"type": "function",
"function": {
"name": "pay_invoice",
"arguments": {"invoice_id": "Utility Debts", "amount": 100}
}
}
]
},
{
"role": "tool",
"tool_call_id": "0",
"content": { "pay_invoice_returns": "Success"}
},
]
prompt with generation
<|im_start|>system
...grounded_system_prompt...
<|im_end|>
<|im_start|>user
Hey dude, what can you do?<|im_end|>
<|im_start|>assistant
<|start_response|>I can retrieve a list of unpaid invoices and process payments for specific invoices.<|end_response|><|im_end|>
<|im_start|>user
Okey, then retrieve a list for me<|im_end|>
<|im_start|>assistant
<|start_thinking|>I will retrieve a list of unpaid invoices.<|end_thinking|><tool_call>[
{"tool_call_id": "0", "tool_name": "find_unpaid_invoices", "parameters": {}}
]</tool_call><|im_end|>
<|im_start|>system
<tool_response>[
{
"tool_call_id": "0",
"results": {
"0": {"find_unpaid_invoices_returns": ["Utility Debts", "Housing and Utilities Arrears"]}
},
"is_error_tool": False
}
]</tool_response><|im_end|>
<|im_start|>assistant
<|start_response|>Here is the list of unpaid invoices: Utility Debts and Housing and Utilities Arrears.<|end_response|><|im_end|>
<|im_start|>user
Ooh, I forget about this! Lets pay Utility Debts in the amount of $100 please<|im_end|>
<|im_start|>assistant
<|start_thinking|>I will process the payment for the Utility Debts invoice.<|end_thinking|><tool_call>[
{"tool_call_id": "0", "tool_name": "pay_invoice", "parameters": {"invoice_id": "Utility Debts", "amount": 100}}
]</tool_call><|im_end|>
<|im_start|>system
<tool_response>[
{
"tool_call_id": "0",
"results": {
"0": {"pay_invoice_returns": "Success"}
},
"is_error_tool": False
}
]</tool_response><|im_end|>
<|im_start|>assistant
<|start_response|>The payment for the Utility Debts invoice has been processed successfully.<|end_response|><|im_end|>
Multiple Function
history
messages = [
{"role": "user", "content": "Hey dude, what can you do?"},
{"role": "assistant", "content": "I can provide weather information for a given city and also provide the sunrise and sunset times for a given city."},
{"role": "user", "content": "Thats great! Okey, can you provide weather in Krasnodar, Moscow and Krasnoyarsk for me please."},
{
"role": "assistant",
"tool_plan": "The user wants weather information for three cities: Krasnodar, Moscow, and Krasnoyarsk.",
"tool_calls": [
{
"id": "0",
"type": "function",
"function": {
"name": "get_weather",
"arguments": {
"city": "Krasnodar"
}
}
},
{
"id": "1",
"type": "function",
"function": {
"name": "get_weather",
"arguments": {
"city": "Moscow"
}
}
},
{
"id": "2",
"type": "function",
"function": {
"name": "get_weather",
"arguments": {
"city": "Krasnoyarsk"
}
}
},
]
},
{
"role": "tool",
"tool_call_id": "0",
"content": { "get_weather_returns": "sunny" }
},
{
"role": "tool",
"tool_call_id": "1",
"content": { "get_weather_returns": "sunny" }
},
{
"role": "tool",
"tool_call_id": "2",
"content": { "get_weather_returns": "rainy" }
},
]
prompt with generation
<|im_start|>system
...grounded_system_prompt...
<|im_end|>
<|im_start|>user
Hey dude, what can you do?<|im_end|>
<|im_start|>assistant
<|start_response|>I can provide weather information for a given city and also provide the sunrise and sunset times for a given city.<|end_response|><|im_end|>
<|im_start|>user
Thats great! Okey, can you provide weather in Krasnodar, Moscow and Krasnoyarsk for me please.<|im_end|>
<|im_start|>assistant
<|start_thinking|>The user wants weather information for three cities: Krasnodar, Moscow, and Krasnoyarsk.<|end_thinking|><tool_call>[
{"tool_call_id": "0", "tool_name": "get_weather", "parameters": {"city": "Krasnodar"}},
{"tool_call_id": "1", "tool_name": "get_weather", "parameters": {"city": "Moscow"}},
{"tool_call_id": "2", "tool_name": "get_weather", "parameters": {"city": "Krasnoyarsk"}}
]</tool_call><|im_end|>
<|im_start|>system
<tool_response>[
{
"tool_call_id": "0",
"results": {
"0": {"get_weather_returns": "sunny"}
},
"is_error_tool": False
},
{
"tool_call_id": "1",
"results": {
"0": {"get_weather_returns": "sunny"}
},
"is_error_tool": False
},
{
"tool_call_id": "2",
"results": {
"0": {"get_weather_returns": "rainy"}
},
"is_error_tool": False
}
]</tool_response><|im_end|>
<|im_start|>assistant
<|start_response|>The weather in Krasnodar is sunny, the weather in Moscow is sunny, and the weather in Krasnoyarsk is rainy.<|end_response|><|im_end|>
Parallel Multiple Function
history
messages = [
{"role": "user", "content": "Hey dude, what can you do?"},
{"role": "assistant", "content": "I can provide weather information for a given city and also provide the sunrise and sunset times for a given city."},
{"role": "user", "content": "Thats great! Okey, can you provide weather in Krasnodar, Moscow and only the sunrise time in Krasnoyarsk for me please."},
{
"role": "assistant",
"tool_plan": "The user has requested weather information for three cities and only the sunrise time for one city. I will first retrieve the weather information for Krasnodar and Moscow, and then retrieve the sunrise time for Krasnoyarsk.",
"tool_calls": [
{
"id": "0",
"type": "function",
"function": {
"name": "get_weather",
"arguments": {
"city": "Krasnodar"
}
}
},
{
"id": "1",
"type": "function",
"function": {
"name": "get_weather",
"arguments": {
"city": "Moscow"
}
}
},
{
"id": "2",
"type": "function",
"function": {
"name": "get_sunrise_sunset_times",
"arguments": {
"city": "Krasnoyarsk"
}
}
},
]
},
{
"role": "tool",
"tool_call_id": "0",
"content": { "get_weather_returns": "sunny" }
},
{
"role": "tool",
"tool_call_id": "1",
"content": { "get_weather_returns": "sunny" }
},
{
"role": "tool",
"tool_call_id": "2",
"content": { "get_sunrise_sunset_times_returns": ["6:00 AM", "6:00 PM"] }
},
]
prompt with generation
<|im_start|>system
...grounded_system_prompt...
<|im_end|>
<|im_start|>user
Hey dude, what can you do?<|im_end|>
<|im_start|>assistant
<|start_response|>I can provide weather information for a given city and also provide the sunrise and sunset times for a given city.<|end_response|><|im_end|>
<|im_start|>user
Thats great! Okey, can you provide weather in Krasnodar, Moscow and only the sunrise time in Krasnoyarsk for me please.<|im_end|>
<|im_start|>assistant
<|start_thinking|>The user has requested weather information for three cities and only the sunrise time for one city. I will first retrieve the weather information for Krasnodar and Moscow, and then retrieve the sunrise time for Krasnoyarsk.<|end_thinking|><tool_call>[
{"tool_call_id": "0", "tool_name": "get_weather", "parameters": {"city": "Krasnodar"}},
{"tool_call_id": "1", "tool_name": "get_weather", "parameters": {"city": "Moscow"}},
{"tool_call_id": "2", "tool_name": "get_sunrise_sunset_times", "parameters": {"city": "Krasnoyarsk"}}
]</tool_call><|im_end|>
<|im_start|>system
<tool_response>[
{
"tool_call_id": "0",
"results": {
"0": {"get_weather_returns": "sunny"}
},
"is_error_tool": False
},
{
"tool_call_id": "1",
"results": {
"0": {"get_weather_returns": "sunny"}
},
"is_error_tool": False
},
{
"tool_call_id": "2",
"results": {
"0": {"get_sunrise_sunset_times_returns": ["6:00 AM", "6:00 PM"]}
},
"is_error_tool": False
}
]</tool_response><|im_end|>
<|im_start|>assistant
<|start_response|>The weather in Krasnodar is sunny, the weather in Moscow is sunny, and the sunrise time in Krasnoyarsk is 6:00 AM.<|end_response|><|im_end|>
Tool Error Handling
history
messages = [
{"role": "user", "content": "Hey dude, what can you do?"},
{"role": "assistant", "content": "I can provide weather information for a given city and also provide the sunrise and sunset times for a given city."},
{"role": "user", "content": "Thats great! Okey, can you provide weather in Krasnodar, Moscow and only the sunrise time in Krasnoyarsk for me please."},
{
"role": "assistant",
"tool_plan": "The user has requested weather information for three cities and only the sunrise time for one city. I will first retrieve the weather information for Krasnodar and Moscow, and then retrieve the sunrise time for Krasnoyarsk.",
"tool_calls": [
{
"id": "0",
"type": "function",
"function": {
"name": "get_weather",
"arguments": {
"city": "Krasnodar"
}
}
},
{
"id": "1",
"type": "function",
"function": {
"name": "get_weather",
"arguments": {
"city": "Moscow"
}
}
},
{
"id": "2",
"type": "function",
"function": {
"name": "get_sunrise_sunset_times",
"arguments": {
"city": "Krasnoyarsk"
}
}
},
]
},
{
"role": "tool",
"tool_call_id": "0",
"content": { "get_weather_returns": "sunny" }
},
{
"role": "tool",
"tool_call_id": "1",
"content": { "get_weather_returns": "sunny" }
},
{
"role": "tool",
"tool_call_id": "2",
"content": { "get_sunrise_sunset_times_returns": {"error": True, "message": "Server is unavailable now"} },
"is_error_tool": True
},
]
prompt with generation
<|im_start|>system
...grounded_system_prompt...
<|im_end|>
<|im_start|>user
Hey dude, what can you do?<|im_end|>
<|im_start|>assistant
<|start_response|>I can provide weather information for a given city and also provide the sunrise and sunset times for a given city.<|end_response|><|im_end|>
<|im_start|>user
Thats great! Okey, can you provide weather in Krasnodar, Moscow and only the sunrise time in Krasnoyarsk for me please.<|im_end|>
<|im_start|>assistant
<|start_thinking|>The user has requested weather information for three cities and only the sunrise time for one city. I will first retrieve the weather information for Krasnodar and Moscow, and then retrieve the sunrise time for Krasnoyarsk.<|end_thinking|><tool_call>[
{"tool_call_id": "0", "tool_name": "get_weather", "parameters": {"city": "Krasnodar"}},
{"tool_call_id": "1", "tool_name": "get_weather", "parameters": {"city": "Moscow"}},
{"tool_call_id": "2", "tool_name": "get_sunrise_sunset_times", "parameters": {"city": "Krasnoyarsk"}}
]</tool_call><|im_end|>
<|im_start|>system
<tool_response>[
{
"tool_call_id": "0",
"results": {
"0": {"get_weather_returns": "sunny"}
},
"is_error_tool": False
},
{
"tool_call_id": "1",
"results": {
"0": {"get_weather_returns": "sunny"}
},
"is_error_tool": False
},
{
"tool_call_id": "2",
"results": {
"0": {"get_sunrise_sunset_times_returns": {"error": true, "message": "Server is unavailable now"}}
},
"is_error_tool": True
}
]</tool_response><|im_end|>
<|im_start|>assistant
<|start_response|>The weather in Krasnodar and Moscow is sunny. Unfortunately, the server is currently unavailable, so I cannot provide the sunrise time for Krasnoyarsk.<|end_response|><|im_end|>
Limitations
This is the experimental checkpoint and some hallucinations are possible. If you find something interesting in model behavior, please create issue and lets discuss it!
- The model the most stability works in
greedy search
or lowtemperature(about < 0.5)
- The model can feel some problems with long user plan. It confuses the trajectory of calls and changes the order in which related tasks are performed. In fact, this is not a mistake, but a violation of the user's requirement.
- The model can solve very easy tasks on the fly, right in the process of calls (for example, basic arithmetic).
Evaluation
Task | Acc(%) |
---|---|
Simple | 73.25 |
Multiple | 93.00 |
Parallel | 90.00 |
Parallel Multiple | 81.00 |
Relevance Detection | 64.71 |
Irrelevance Detection | 85.72 |
Authors
- Downloads last month
- 101