Function Calling
Let models call your functions and tools using the OpenAI or Anthropic formats.
Overview
Function calling (tool use) lets a model emit a structured request to call one of your functions. Your application runs the function and returns the result, and the model continues. This powers agents, data retrieval, and interactive workflows.
Yunxin supports both tool-calling surfaces natively:
- OpenAI format (Chat Completions) —
tools/tool_choicewith{"type": "function", ...}definitions and assistanttool_calls. - Anthropic format (Messages) —
toolswithinput_schema, andtool_use/tool_resultcontent blocks.
Tool support is model-dependent. Query GET /v1/models and check for the
function_calling capability before relying on tools.
OpenAI format
Defining tools
Pass tool definitions in the tools array. Each function uses JSON Schema for its parameters:
{
"model": "model-id",
"messages": [{"role": "user", "content": "What's the weather in Tokyo?"}],
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather for a location",
"parameters": {
"type": "object",
"properties": {
"location": {"type": "string", "description": "City name, e.g., Tokyo"},
"unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
},
"required": ["location"]
}
}
}
]
}Tool call flow
tools defined.tool_calls array instead of (or alongside) content.role: "tool" message per result, then call again.import os, json
from openai import OpenAI
client = OpenAI(
api_key=os.environ["YUNXIN_API_KEY"],
base_url="https://api.yuhuanstudio.com/v1",
)
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get weather for a city",
"parameters": {
"type": "object",
"properties": {
"location": {"type": "string"},
"unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
},
"required": ["location"],
},
},
}]
messages = [{"role": "user", "content": "What's the weather in Tokyo and London?"}]
response = client.chat.completions.create(model="model-id", messages=messages, tools=tools)
assistant_message = response.choices[0].message
messages.append(assistant_message)
for tool_call in assistant_message.tool_calls:
args = json.loads(tool_call.function.arguments)
# Execute your function here:
result = {"temperature": 22, "unit": "celsius", "condition": "sunny"}
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": json.dumps(result),
})
final_response = client.chat.completions.create(model="model-id", messages=messages, tools=tools)
print(final_response.choices[0].message.content)Tool choice
| Value | Behavior |
|---|---|
"auto" | Model decides whether to call tools (default). |
"none" | Model will not call any tools. |
"required" | Model must call at least one tool. |
{"type": "function", "function": {"name": "..."}} | Force a specific tool. |
response = client.chat.completions.create(
model="model-id",
messages=messages,
tools=tools,
tool_choice="required",
)Parallel tool calls
Models may request several calls at once:
{
"choices": [{
"message": {
"tool_calls": [
{"id": "call_1", "function": {"name": "get_weather", "arguments": "{\"location\":\"Tokyo\"}"}},
{"id": "call_2", "function": {"name": "get_weather", "arguments": "{\"location\":\"London\"}"}}
]
}
}]
}Disable this with parallel_tool_calls=False (where the model supports the option).
Streaming tool calls
With streaming, tool calls arrive as partial deltas you accumulate by index:
stream = client.chat.completions.create(
model="model-id",
messages=[{"role": "user", "content": "What's the weather in Tokyo and London?"}],
tools=tools,
stream=True,
)
tool_calls = {}
for chunk in stream:
for tc in (chunk.choices[0].delta.tool_calls or []):
idx = tc.index
if idx not in tool_calls:
tool_calls[idx] = {"id": tc.id, "name": tc.function.name, "arguments": ""}
if tc.function and tc.function.arguments:
tool_calls[idx]["arguments"] += tc.function.arguments
for idx, tc in tool_calls.items():
print(f"Tool: {tc['name']}, Args: {tc['arguments']}")Anthropic format
The Messages API uses a different shape for the same concept. Tools declare an
input_schema (JSON Schema), the model returns tool_use content blocks, and you reply with a
tool_result block referencing the tool_use_id:
import os
from anthropic import Anthropic
client = Anthropic(
api_key=os.environ["YUNXIN_API_KEY"],
# The Anthropic SDK appends /v1/messages itself — host only, no /v1.
base_url="https://api.yuhuanstudio.com",
)
tools = [{
"name": "get_weather",
"description": "Get weather for a city",
"input_schema": {
"type": "object",
"properties": {"location": {"type": "string"}},
"required": ["location"],
},
}]
messages = [{"role": "user", "content": "What's the weather in Tokyo?"}]
response = client.messages.create(
model="model-id", max_tokens=1024, tools=tools, messages=messages,
)
# Find the tool_use block and reply with a tool_result
tool_use = next(b for b in response.content if b.type == "tool_use")
result = {"temperature": 22, "unit": "celsius", "condition": "sunny"}
messages.append({"role": "assistant", "content": response.content})
messages.append({
"role": "user",
"content": [{
"type": "tool_result",
"tool_use_id": tool_use.id,
"content": str(result),
}],
})
final = client.messages.create(
model="model-id", max_tokens=1024, tools=tools, messages=messages,
)
print(final.content[0].text)You don't need to mix formats: pick whichever SDK matches your stack. Yunxin handles tool definitions and results natively on both surfaces.
How is this guide?