AI APIs

Building Reliable Agents: Structured Outputs and Tool Use with the xAI API

As Large Language Models (LLMs) mature, the focus in production engineering is shifting from simple chat interfaces to complex, autonomous agent workflows. For these agents to be reliable, they must move beyond probabilistic text generation to deterministic data structures and precise external actions. The xAI API offers powerful capabilities for both, but implementing them correctly requires a deep understanding of schema validation and tool registration.

The Challenge of Non-Deterministic Output

In traditional LLM applications, getting the exact JSON structure you need is notoriously difficult. Without strict constraints, models may hallucinate keys, omit required fields, or return text wrapped in markdown blocks. This fragility breaks downstream processing pipelines. The solution lies in enforcing structured outputs at the API level, ensuring the model returns data that strictly adheres to a predefined JSON Schema.

Enforcing Structured Outputs

xAI’s API allows developers to pass a response_format parameter. When configured with a json_schema, the model is constrained to output only valid JSON matching that schema. This is critical for agents that need to parse configuration, extract entities, or generate dynamic code snippets.

Consider a scenario where an agent needs to extract contact information from an email. Instead of relying on regex post-processing, we can define a schema directly in the request.

import xai

client = xai.Client(api_key="your-api-key")

response = client.chat.completions.create(
    model="grok-2",
    messages=[
        {
            "role": "user",
            "content": "Extract details from: 'Hi, I'm John Doe, CEO of TechCorp. Email: john@techcorp.com.'"
        }
    ],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "contact_info",
            "schema": {
                "type": "object",
                "properties": {
                    "name": {"type": "string"},
                    "role": {"type": "string"},
                    "company": {"type": "string"},
                    "email": {"type": "string", "format": "email"}
                },
                "required": ["name", "email"],
                "additionalProperties": False
            }
        }
    }
)

# Accessing the clean, parsed data
print(response.choices[0].message.content)

Notice the use of additionalProperties: False. This ensures the model does not include unexpected fields, maintaining the integrity of your database or internal data structures.

Orchestrating Actions with Tool Use

While structured outputs handle data, tool use (or function calling) handles action. Agents need to interact with the outside world—querying databases, making API calls, or performing calculations. The xAI API allows you to define tools that the model can call dynamically.

When registering tools, precision is key. The tool descriptions must clearly define what the tool does and what arguments it expects. The model will then decide whether to call the tool and which parameters to pass, based on the user's intent.

def get_weather(location: str) -> dict:
    """Get current weather for a location."""
    return {"temperature": 72, "unit": "F", "location": location}

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "Retrieve current weather data",
            "parameters": {
                "type": "object",
                "properties": {
                    "location": {"type": "string", "description": "City name or zip code"}
                },
                "required": ["location"]
            }
        }
    }
]

response = client.chat.completions.create(
    model="grok-2",
    messages=[{"role": "user", "content": "What's the weather in Seattle?"}],
    tools=tools
)

The response will contain a tool_calls object. Your application logic must execute the get_weather function with the provided arguments, then feed the result back into the conversation loop so the model can formulate a natural language response.

Conclusion

Combining structured outputs with robust tool use transforms the xAI API from a text generator into a functional agent engine. By enforcing strict JSON schemas, you eliminate parsing errors and ensure data consistency. By integrating tool definitions, you enable your agents to act upon the world rather than just discuss it. For developers building the next generation of AI-powered applications, mastering these patterns is no longer optional—it is essential.

Share: