Authenticating...

Function calling

Copy Page as Markdown

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

  1. Make a request to the model with tools it could call
  2. Receive a tool call from the model
  3. Execute code on the application side with input from the tool call
  4. Make a second request to the model with the tool output
  5. 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.

cURLNode.jsTypeScriptPython

Full loop

Accumulate streamed delta.tool_calls into one assistant message, execute each call, append role: "tool" results, then call the model again.

TypeScriptPython

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.

cURLNode.jsTypeScriptPython

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.

TypeScriptPython

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):

FieldDescription
typeMust be "function"
function.nameFunction name, e.g. get_stock_quote
function.descriptionWhen and how to use the function
function.parametersJSON Schema for the function arguments
function.strictWhen 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:

  1. additionalProperties set to false on every object in parameters
  2. Every key in properties listed in required

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.

  1. Append the assistant message (including tool_calls) to messages
  2. For each tool call, parse function.arguments, run your code, and append a role: "tool" message with the same tool_call_id
  3. Call Chat Completions again with the updated messages and the same tools

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:

ValueBehavior
"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_id from session state).
  • Enable strict mode and validate parsed arguments in your application before executing side effects.