Tool calling (function calling)
Let GLM, Kimi, DeepSeek and other models call your functions through BigModel.io with OpenAI tools or Anthropic tool use, including the full request loop.
On this page
Tool calling lets the model ask your code to run a function and then use the result. BigModel.io forwards the standard OpenAI tools format on Chat Completions and Anthropic tools on Messages. Whether a model calls tools well depends on the model itself.
| What you send | Where it works |
|---|---|
tools, tool_choice (and legacy functions, function_call) |
/v1/chat/completions on every group |
Anthropic tools with tool_use / tool_result blocks |
/v1/messages on groups that serve Messages |
On GLM and DeepSeek groups the request body is passed to the model provider unchanged, so every tool option the model supports works. On groups where Chat Completions is converted to another protocol, tools, tool_choice, functions and function_call are kept, but other fields such as parallel_tool_calls are dropped.
Check the model's page in the catalog for a Tool use tag before you build on it.
#Make a tool call
The loop has three steps: send the tools, run the function the model asks for, then send the result back.
import json, os
from openai import OpenAI
client = OpenAI(base_url="https://bigmodel.io/v1", api_key=os.environ["BIGMODEL_API_KEY"])
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather for a city",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"],
},
},
}]
def get_weather(city):
return {"city": city, "temp_c": 21, "sky": "clear"} # your real lookup here
messages = [{"role": "user", "content": "What's the weather in Hangzhou?"}]
first = client.chat.completions.create(model="glm-5.3", messages=messages, tools=tools)
msg = first.choices[0].message
if msg.tool_calls:
messages.append(msg) # keep the assistant turn with its tool_calls
for call in msg.tool_calls:
args = json.loads(call.function.arguments)
messages.append({
"role": "tool",
"tool_call_id": call.id,
"content": json.dumps(get_weather(**args)),
})
final = client.chat.completions.create(model="glm-5.3", messages=messages, tools=tools)
print(final.choices[0].message.content)
else:
print(msg.content)import OpenAI from "openai";
const client = new OpenAI({ baseURL: "https://bigmodel.io/v1", apiKey: process.env.BIGMODEL_API_KEY });
const tools = [{
type: "function",
function: {
name: "get_weather",
description: "Get the current weather for a city",
parameters: { type: "object", properties: { city: { type: "string" } }, required: ["city"] },
},
}];
const getWeather = ({ city }) => ({ city, temp_c: 21, sky: "clear" });
const messages = [{ role: "user", content: "What's the weather in Hangzhou?" }];
const first = await client.chat.completions.create({ model: "glm-5.3", messages, tools });
const msg = first.choices[0].message;
if (msg.tool_calls?.length) {
messages.push(msg);
for (const call of msg.tool_calls) {
const result = getWeather(JSON.parse(call.function.arguments));
messages.push({ role: "tool", tool_call_id: call.id, content: JSON.stringify(result) });
}
const final = await client.chat.completions.create({ model: "glm-5.3", messages, tools });
console.log(final.choices[0].message.content);
} else {
console.log(msg.content);
}curl https://bigmodel.io/v1/chat/completions \
-H "Authorization: Bearer $BIGMODEL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "glm-5.3",
"messages": [{"role": "user", "content": "What is the weather in Hangzhou?"}],
"tools": [{"type":"function","function":{"name":"get_weather","description":"Get the current weather for a city","parameters":{"type":"object","properties":{"city":{"type":"string"}},"required":["city"]}}}]
}'tool_choice controls the call: "auto" (default), "none", "required", or {"type":"function","function":{"name":"get_weather"}} to force one function. Support for "required" and forced functions varies by model.
#Tool use with the Messages API
On groups that serve /v1/messages, use Anthropic's format. The model replies with a tool_use block; you answer with a tool_result block that carries the same id.
import os
from anthropic import Anthropic
client = Anthropic(base_url="https://bigmodel.io", api_key=os.environ["BIGMODEL_API_KEY"])
tools = [{
"name": "get_weather",
"description": "Get the current weather for a city",
"input_schema": {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]},
}]
messages = [{"role": "user", "content": "What's the weather in Hangzhou?"}]
first = client.messages.create(model="glm-5.3", max_tokens=512, tools=tools, messages=messages)
if first.stop_reason == "tool_use":
call = next(b for b in first.content if b.type == "tool_use")
messages += [
{"role": "assistant", "content": first.content},
{"role": "user", "content": [{"type": "tool_result", "tool_use_id": call.id, "content": '{"temp_c": 21}'}]},
]
final = client.messages.create(model="glm-5.3", max_tokens=512, tools=tools, messages=messages)
print(final.content[0].text)#Streaming tool calls
When you stream, tool call arguments arrive in pieces in choices[0].delta.tool_calls[i].function.arguments. Concatenate the pieces per index and parse the JSON only after finish_reason is tool_calls. See Streaming.
#Verify the setup
Run the cURL example. The response should have "finish_reason": "tool_calls" and a tool_calls array with get_weather and {"city":"Hangzhou"} as arguments. If you get plain text instead, the model chose not to call the tool; try "tool_choice": "required" or another model.
#Troubleshooting
The model answers in text and never calls the tool. The model may not support tools, or the description is too vague. Check the model page for a Tool use tag, describe when to use the tool, and try tool_choice.
json.loads fails on the arguments. Models sometimes return invalid JSON in arguments. Catch the error and send it back as the tool result so the model can retry, or validate with a schema library.
400 from the provider about the tool result. Every tool message needs the tool_call_id of a call in the previous assistant turn, and that assistant turn must be included in messages.
409 malformed_session_state on /v1/messages. The history has a tool_result whose id does not match a tool_use, or edited thinking blocks. Send the assistant content back unchanged.
Only one tool is called when you expected several. Parallel calls depend on the model. On converted groups parallel_tool_calls is dropped, so you cannot switch it.
503 api_error "No available accounts". The model is not served to your key's group. See Model IDs.
#Related
- Structured output: use a tool schema to get JSON on any group.
- Streaming and Reasoning & thinking.
- Chat Completions API reference.
Updated · View as Markdown