Tools (function calling)¶
Give the model a set of callable functions and let it decide when to invoke them. The model returns tool-call requests; your code executes them; you pass the results back for the model's final reply.
The tool-schema shape differs per provider — this page shows the
native flagship for each cloud. The Anthropic through-line's tool
API is documented in Claude tool use
and works identically on Bedrock / Vertex / Foundry with the same
tools=[...] payload.
Official docs verified 2026-08-08
- Azure OpenAI function calling: switching-endpoints
- Vertex Gemini function calling: Gemini API quickstart
- Bedrock Converse toolConfig: Bedrock Converse
Native flagship¶
The example: a get_current_temperature tool. The reader can swap
in any function-schema — the shape is the load-bearing part.
import os, json
from openai import OpenAI
client = OpenAI(
api_key=os.environ["AZURE_OPENAI_API_KEY"],
base_url=os.environ["AZURE_OPENAI_BASE_URL"],
)
tools = [{
"type": "function",
"function": {
"name": "get_current_temperature",
"description": "Get current temperature for a given location.",
"parameters": {
"type": "object",
"properties": {
"location": {"type": "string", "description": "City name"},
},
"required": ["location"],
},
},
}]
resp = client.chat.completions.create(
model=os.environ["AZURE_OPENAI_DEPLOYMENT"],
messages=[{"role": "user", "content": "Temperature in London?"}],
tools=tools,
)
call = resp.choices[0].message.tool_calls[0]
args = json.loads(call.function.arguments)
print(call.function.name, args) # get_current_temperature {'location': 'London'}
import os
from google import genai
from google.genai import types
client = genai.Client(
vertexai=True,
project=os.environ["GOOGLE_CLOUD_PROJECT"],
location=os.environ.get("GOOGLE_CLOUD_LOCATION", "us-central1"),
)
get_temp = types.FunctionDeclaration(
name="get_current_temperature",
description="Get current temperature for a given location.",
parameters=types.Schema(
type=types.Type.OBJECT,
properties={
"location": types.Schema(type=types.Type.STRING),
},
required=["location"],
),
)
resp = client.models.generate_content(
model=os.environ.get("GEMINI_MODEL", "gemini-3.6-flash"),
contents="Temperature in London?",
config=types.GenerateContentConfig(tools=[types.Tool(function_declarations=[get_temp])]),
)
fc = resp.candidates[0].content.parts[0].function_call
print(fc.name, dict(fc.args)) # get_current_temperature {'location': 'London'}
import os, boto3
client = boto3.client(
"bedrock-runtime",
region_name=os.environ.get("AWS_REGION", "us-east-1"),
)
tool_config = {
"tools": [{
"toolSpec": {
"name": "get_current_temperature",
"description": "Get current temperature for a given location.",
"inputSchema": {"json": {
"type": "object",
"properties": {
"location": {"type": "string", "description": "City name"},
},
"required": ["location"],
}},
},
}],
}
resp = client.converse(
modelId=os.environ.get("BEDROCK_MODEL_ID", "amazon.nova-pro-v1:0"),
messages=[{"role": "user", "content": [{"text": "Temperature in London?"}]}],
toolConfig=tool_config,
)
# tool call arrives as a contentBlock of type toolUse
for block in resp["output"]["message"]["content"]:
if "toolUse" in block:
print(block["toolUse"]["name"], block["toolUse"]["input"])
Claude through-line (same shape on all 3 clouds)¶
Claude's tools shape is one dict passed to messages.create(tools=[...])
regardless of which client you use (AnthropicFoundry /
AnthropicVertex / AnthropicBedrock). No per-cloud adaptation.
tools = [{
"name": "get_current_temperature",
"description": "Get current temperature for a given location.",
"input_schema": {
"type": "object",
"properties": {"location": {"type": "string"}},
"required": ["location"],
},
}]
msg = client.messages.create( # client from any of Foundry / Vertex / Bedrock
model=…,
max_tokens=1024,
tools=tools,
messages=[{"role": "user", "content": "Temperature in London?"}],
)
for block in msg.content:
if block.type == "tool_use":
print(block.name, block.input)
The pattern in code¶
tools=[…]on the request.- Model returns a tool-call content block (not final text).
- Your app executes the tool, appends its result as a new turn, and re-calls the model to get the final natural-language reply.
- The reply is normal chat text — the loop is optional; call once, execute, call again.
The full multi-turn tool loop for each provider is in
examples/call-an-llm/service/tools_loop.py.