> ## Documentation Index
> Fetch the complete documentation index at: https://apione.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Structured output and tool calls

> Use model-supported JSON and tools, then validate results in your application.

Chat exposes `response_format`, `tools`, and `tool_choice`. Check model support first, then parse and validate results in your application.

## JSON output

This example requires a model supporting JSON mode. Install dependencies using the [SDK guide](https://apione.ai/docs/en/guides/sdks.md), set `APIONE_API_KEY` and `APIONE_MODEL`, save as `json_output.py`, and run `python json_output.py`.

```python theme={null}
import json
import os
from openai import OpenAI

with OpenAI(
    base_url="https://api.apione.ai/v1",
    api_key=os.environ["APIONE_API_KEY"],
) as client:
    response = client.chat.completions.create(
        model=os.environ["APIONE_MODEL"],
        messages=[
            {"role": "system", "content": 'Return only JSON with a category string: feature, bug, or other.'},
            {"role": "user", "content": "Add search to the help center."},
        ],
        response_format={"type": "json_object"},
    )

choice = response.choices[0]
if choice.finish_reason != "stop" or not choice.message.content:
    raise ValueError("Incomplete output or missing JSON content")
data = json.loads(choice.message.content)
if (
    not isinstance(data, dict)
    or not isinstance(data.get("category"), str)
    or data["category"] not in {"feature", "bug", "other"}
):
    raise ValueError("category does not meet the application's requirements")
print(data)
```

`json_object` requests JSON output. Your application still checks the finish reason, parses the result, and validates fields and allowed values. Asking for JSON in a prompt does not replace a schema constraint.

## JSON Schema

`response_format` can also carry `json_schema`. Supported schema subsets and strict-mode behavior depend on the model. Check model parameters before choosing constraints, and recheck the schema when switching models.

## Tool call flow

1. Declare permitted functions and parameters in `tools`. Use `tool_choice` if needed, after confirming model support.
2. Read `choices[].message.tool_calls`. There may be multiple calls, and ordinary text may be empty.
3. Keep the assistant message. Validate tool names, parse arguments, and check user permissions. Confirm external writes as required by your application before execution.
4. Send each result as a `role: "tool"` message, with `tool_call_id` matching the original call's `id`.
5. Request the model again with the updated history and read the final answer. Limit the number of tool-call rounds in the application.

APIONE returns tool requests; your application executes functions. Do not pass unvalidated model-generated URLs, SQL, or commands directly to an executor.

## Compatibility

For `unsupported_parameter`, remove optional fields and verify a [minimal chat request](https://apione.ai/docs/en/models/chat.md) before restoring them individually. Recheck JSON, tools, and [streaming](https://apione.ai/docs/en/models/streaming.md) when changing models. See the [APIONE Chat reference](https://apione.ai/en/api-docs/reference/ref-chat) for complete fields.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.