Function calling
Function calling (also known as tool calling) lets SubQ models interface with
external systems and data outside their training data. Pass function tools
defined by a JSON schema in the tools parameter of a
Chat Completions request. The model may
return a tool call; your application executes the function and sends the
tool call output back so the model can finish the reply.
How it works
Tools — functionality you give the model. A function tool is a JSON Schema
definition the model can choose to call, for example get_stock_quote, account
lookup, or issuing a refund.
Tool calls — requests from the model to use a tool. If the prompt needs
live data, the assistant message includes a tool_calls array with a function
name and JSON-encoded arguments.
Tool call outputs — results your application returns. Send a message with
role: "tool", the matching tool_call_id, and a string content (often JSON).
The tool calling flow
- Make a request to the model with tools it could call
- Receive a tool call from the model
- Execute code on the application side with input from the tool call
- Make a second request to the model with the tool output
- Receive a final response from the model (or more tool calls)
Example
End-to-end flow for a get_stock_quote function. The first request declares the
tool; the model returns a tool call; your code runs the function and sends the
result back for a final answer.
Request with tools
Set stream to true and include your function definitions in tools.
Full loop
Accumulate streamed delta.tool_calls into one assistant message, execute each
call, append role: "tool" results, then call the model again.
Example assistant tool call (after accumulating the stream):
{
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_abc123",
"type": "function",
"function": {
"name": "get_stock_quote",
"arguments": "{\"symbol\":\"NVDA\",\"currency\":\"USD\",\"include_extended_hours\":false}"
}
}
]
}Example tool message you send back:
{
"role": "tool",
"tool_call_id": "call_abc123",
"content": "{\"symbol\":\"NVDA\",\"price\":210.96,\"currency\":\"USD\",\"change\":8.18,\"change_percent\":4.03,\"open\":202.0,\"high\":211.0,\"low\":201.92,\"previous_close\":202.78,\"market_cap\":5110000000000,\"pe_ratio\":32.31,\"market_open\":false,\"extended_hours\":null,\"as_of\":\"2026-07-10T21:22:00Z\"}"
}Multiple tools
Pass several function tools in the same tools array. The model may return
zero, one, or many tool_calls in a single turn — execute each one and append a
role: "tool" message for every tool_call_id before calling the model again.
This example combines get_stock_quote with get_account_positions so the model
can answer a prompt that needs both market data and account holdings.
Example assistant message with two tool calls:
{
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_quote1",
"type": "function",
"function": {
"name": "get_stock_quote",
"arguments": "{\"symbol\":\"NVDA\",\"currency\":\"USD\",\"include_extended_hours\":false}"
}
},
{
"id": "call_pos1",
"type": "function",
"function": {
"name": "get_account_positions",
"arguments": "{\"account_id\":\"acct_42\",\"symbol\":\"NVDA\"}"
}
}
]
}Dispatch by function.name. Reuse the same streaming accumulator from the
single-tool example for each model turn.
Defining functions
Declare functions in the tools array of each Chat Completions request. Each
entry uses the Chat Completions shape (type plus a nested function object):
| Field | Description |
|---|---|
type | Must be "function" |
function.name | Function name, e.g. get_stock_quote |
function.description | When and how to use the function |
function.parameters | JSON Schema for the function arguments |
function.strict | When true, enforce schema adherence for arguments |
{
"type": "function",
"function": {
"name": "get_stock_quote",
"description": "Retrieves the latest quote for a stock ticker.",
"parameters": {
"type": "object",
"properties": {
"symbol": {
"type": "string",
"description": "Ticker symbol, e.g. NVDA or MSFT"
},
"currency": {
"type": ["string", "null"],
"enum": ["USD", "EUR"],
"description": "Quote currency. Defaults to USD when null."
},
"include_extended_hours": {
"type": "boolean",
"description": "When true, include pre-market and after-hours price if available."
}
},
"required": ["symbol", "currency", "include_extended_hours"],
"additionalProperties": false
},
"strict": true
}
}Because parameters is JSON Schema, you can use property types, enums,
descriptions, and nested objects. The example above mixes string, nullable
enum, and boolean arguments; the tool output can return numbers, integers,
booleans, and nested objects as needed.
Strict mode
Set strict to true so function arguments adhere to the schema. Recommended
for production. Strict schemas require:
additionalPropertiesset tofalseon every object inparameters- Every key in
propertieslisted inrequired
Mark a field optional by allowing null in its type (for example
"type": ["string", "null"]) while still listing it in required.
Handling function calls
Assume zero, one, or many tool calls in a turn. See Multiple tools for a two-function example.
- Append the assistant message (including
tool_calls) tomessages - For each tool call, parse
function.arguments, run your code, and append arole: "tool"message with the sametool_call_id - Call Chat Completions again with the updated
messagesand the sametools
The result in content is typically a string — JSON, plain text, or a short
success/failure token for side-effect-only functions (for example "success").
Tool choice
By default the model decides when to call tools. Control that with
tool_choice:
| Value | Behavior |
|---|---|
"auto" | Default. Call zero, one, or multiple functions |
"required" | Call one or more functions |
"none" | Do not call tools (same as omitting tools) |
{"type":"function","function":{"name":"get_stock_quote"}} | Force that specific function |
{
"tool_choice": {
"type": "function",
"function": { "name": "get_stock_quote" }
}
}Streaming tool calls
With stream: true, tool calls arrive as deltas on
choices[0].delta.tool_calls. Each delta may include an index, partial id,
function.name, and function.arguments. Concatenate by index until the
stream ends, then parse arguments as JSON.
Text content (if any) still arrives on delta.content in the same stream.
Best practices
- Write clear names and descriptions. Say when to use the function, what each parameter means, and what the output represents. Use the system message for when not to call a tool.
- Keep the tool list small. Fewer tools usually improve accuracy; prefer a focused set over a large catalog in one turn.
- Offload known values in code. Do not ask the model to fill arguments you
already know (for example an
order_idfrom session state). - Enable strict mode and validate parsed arguments in your application before executing side effects.
Related
- Chat Completions API — request fields and response shape
- Structured outputs — schema-constrained JSON replies
- Models — which models support tool calls
- OpenAI Function calling — full OpenAI reference