Structured Outputs vs Function Calling: Picking in 2026
Teams reach for either structured outputs or function calling to solve the same visible problem, "I want the model to return JSON I can parse." Under the hood they are different mechanisms, with different failure modes and different ergonomics. Picking the wrong one for your use case leads to brittle code and mysterious production incidents.
What Each Actually Does
Structured outputs
You pass a JSON schema (or equivalent) alongside the prompt. The provider's decoding layer constrains token sampling so the model cannot produce output that violates the schema. The response is guaranteed-parseable JSON matching the shape you described.
Function calling (tool use)
You declare tools. Each with a name, description, and input schema. The model chooses whether and which to call. When it decides to call a tool, the response includes a tool-use block with the chosen tool and its arguments. You execute the tool, return the result, and the model continues.
The Conceptual Split
- Structured output = the model's terminal answer must match a specific shape.
- Function calling = the model is choosing which action to take, and the arguments are shaped by the tool's schema.
If there is no choice to be made. The model should just return data in a fixed shape. Structured output is the right tool. If the model must decide something, including whether to act at all, function calling is the right tool.
Reliability in Practice
Both mechanisms, on modern frontier models, achieve near-perfect schema adherence for reasonable schemas. The observed failure modes differ:
- Structured output failures tend to be schema-edge cases: overly complex nested optionals, long enums, schemas that imply choices the decoder cannot efficiently sample. The shape holds; the content quality can degrade.
- Function calling failures tend to be decision-making: the model calls the wrong tool, calls none when it should, or calls one with plausible-looking but wrong arguments.
Provider Differences
- Anthropic. Strong function-calling support with stop-reason signalling (
tool_use). Structured output is typically achieved via tool use with a single tool whose input schema is your target shape. A clean, uniform API. - OpenAI / Azure OpenAI. First-class
response_format: { type: 'json_schema' }for structured outputs, independent of tool use. Function calling is its own surface.
Structured Output in Anthropic (via a single tool)
const SummarySchema = {
name: 'return_summary',
description: 'Return the final structured summary',
input_schema: {
type: 'object',
properties: {
title: { type: 'string', maxLength: 120 },
tags: { type: 'array', items: { type: 'string' }, maxItems: 5 },
sentiment: { enum: ['positive', 'neutral', 'negative'] },
},
required: ['title', 'tags', 'sentiment'],
},
};
const res = await anthropic.messages.create({
model: 'claude-opus-4-7',
max_tokens: 1024,
tools: [SummarySchema],
tool_choice: { type: 'tool', name: 'return_summary' }, // force the shape
messages: [{ role: 'user', content: 'Summarise this article...' }],
});
// res.content contains a tool_use block with the structured object
const summary = res.content.find((b) => b.type === 'tool_use').input;
Function Calling for Multi-Step Agents
const tools = [
{ name: 'search_crm', description: 'Search CRM by customer name', input_schema: { /* ... */ } },
{ name: 'create_ticket', description: 'Open a support ticket', input_schema: { /* ... */ } },
];
// Loop: model decides which tool (if any) to call; we execute; repeat
let messages = [{ role: 'user', content: userQuery }];
for (let step = 0; step < MAX_STEPS; step++) {
const res = await anthropic.messages.create({ model, tools, messages, max_tokens: 1024 });
if (res.stop_reason === 'end_turn') break;
for (const block of res.content) {
if (block.type === 'tool_use') {
const output = await execute(block.name, block.input);
messages.push({ role: 'assistant', content: res.content });
messages.push({ role: 'user', content: [{ type: 'tool_result', tool_use_id: block.id, content: output }] });
}
}
}
The Decision Rule
- Single shape, no decisions. Structured output (or a single forced tool).
- Pick from a finite set of actions and supply their arguments. Function calling.
- The model may need to call multiple tools in sequence. Function calling, in a loop with
tool_usestop-reason checks. - The model sometimes returns a direct answer and sometimes takes an action. Function calling. The tool is optional.
Anti-Patterns
- Overly deep structured schemas. A schema with deeply nested optionals and long enums degrades quality. Flatten where you can.
- Tool descriptions that lie. The model uses the description to decide when to call the tool. Vague or misleading descriptions produce wrong choices.
- Re-prompting to fix bad JSON. If you are doing this, the mechanism is wrong. Use the native schema-enforcing mode.