Developers / Docs / Tool calling

Tool calling

Describe your functions with JSON Schema and the model decides when to call them and with which arguments. Your code runs the function and sends the result back.

Models

The Qwen models on ARK Cloud (Qwen3.6-35B-A3B, Qwen3.5-122B-A10B, Qwen3.8-Flash-Next, Qwen3.8-27B, Qwen3.5-4B) call tools. Bielik-11B-v3.0-Instruct does not.

1. Offer the tools

import json

tools = [{
    "type": "function",
    "function": {
        "name": "get_exchange_rate",
        "description": "Current exchange rate between two currencies.",
        "parameters": {
            "type": "object",
            "properties": {
                "base": {"type": "string", "description": "ISO 4217 code, e.g. EUR"},
                "quote": {"type": "string", "description": "ISO 4217 code, e.g. PLN"},
            },
            "required": ["base", "quote"],
        },
    },
}]

messages = [{"role": "user", "content": "How many zloty is 250 euro today?"}]
response = client.chat.completions.create(
    model="arklabsai/Qwen3.6-35B-A3B",
    messages=messages,
    tools=tools,
)
call = response.choices[0].message.tool_calls[0]
print(call.function.name, json.loads(call.function.arguments))
# get_exchange_rate {'base': 'EUR', 'quote': 'PLN'}

When the model wants a tool, finish_reason is tool_calls and the message carries the calls instead of text:

choices[0]
{
  "index": 0,
  "message": {
    "role": "assistant",
    "tool_calls": [
      {
        "id": "call_6f0f2c8d0b3c4f6a9d1e2b7c5a8e4f10",
        "index": 0,
        "type": "function",
        "function": { "name": "get_exchange_rate", "arguments": "{\"base\": \"EUR\", \"quote\": \"PLN\"}" }
      }
    ],
    "refusal": null,
    "annotations": []
  },
  "finish_reason": "tool_calls"
}

2. Run the tool and return the result

Append the assistant message with its tool_calls, then one tool message per call with the result, and ask again. ARK hands results to the model in conversation order, so keep each tool message right after the call it answers.

Python
messages.append(response.choices[0].message)             # the assistant turn with tool_calls
rate = 4.27                                               # your code calls the real service here
messages.append({"role": "tool", "tool_call_id": call.id, "content": json.dumps({"rate": rate})})

final = client.chat.completions.create(
    model="arklabsai/Qwen3.6-35B-A3B",
    messages=messages,
    tools=tools,
)
print(final.choices[0].message.content)

Control when tools are used

tool_choiceBehaviour
"auto" (default)The model decides whether to call a tool.
"none"No tool calls; the tools are left out of the prompt.
"required"The model must call at least one tool.
{"type": "function", "function": {"name": "…"}}The model must call that tool.
{"type": "allowed_tools", "allowed_tools": {"mode": "auto", "tools": […]}}Restrict the call to a subset of the offered tools.

Set parallel_tool_calls: false to receive at most one call per turn. On the Qwen models a forced choice is enforced, not just requested: the reply is a call to the tool.

Tool calls in a stream

When streaming, each tool call arrives in a single chunk with its complete arguments string, rather than in fragments, so you can parse it as soon as it arrives. The final content chunk carries finish_reason: "tool_calls".

Good to know

  • strict: true in a function definition is accepted, but arguments are not validated against the schema: validate them in your code.
  • Tools and thinking work together: with reasoning_effort medium or high, the Qwen models think before they call a tool (see Reasoning).
  • Custom tools ({"type": "custom", "custom": {…}}) and the legacy functions / function_call fields are supported for older clients.
  • The Anthropic API supports tools too, with tool_use and tool_result blocks. See Messages API.