Structured Output
Use structuredOutput: true on any Object or Array node to collapse that entire subtree into a single constrained LLM call instead of decomposing it into per-field calls. This is ObjectWeaver's hybrid mode — you choose the strategy per field, not per definition.
When to Use It
The fundamental trade-off is between cost and depth. OW's normal orchestration fires one LLM call per field, repeating the input document each time. Structured output fires one call for the whole subtree, but the model has to produce all the fields in a single pass.
Use structuredOutput: true
- Extraction arrays — lists of entities, dates, citations, transactions. You're finding structured facts, not reasoning about them.
- Simple objects — metadata, classification, tagging where each property is low-complexity.
- Wide objects — 8+ properties that would otherwise each trigger a separate LLM call.
- Cost-sensitive workloads — when running thousands of documents and deep reasoning isn't required.
Leave as normal OW decomposition
- Reasoning fields — risk assessment, strategic analysis, recommendations where each sub-field deserves the model's full output window.
- Fields with
selectFieldschains — when a field's quality depends on specific prior results injected as context. - Fields needing different models — when you want to route sub-fields to different models or temperatures.
If a field is about finding things → use structured output. If a field is about thinking about things → use orchestration.
Basic Usage
Add structuredOutput: true to any object or array node in your definition:
{
"type": "object",
"properties": {
"parties": {
"type": "array",
"structuredOutput": true,
"instruction": "Extract all parties mentioned in the document",
"items": {
"type": "object",
"properties": {
"name": { "type": "string", "instruction": "Full legal name" },
"role": { "type": "string", "instruction": "Role in the matter" },
"represented_by": { "type": "string", "instruction": "Legal counsel if mentioned" }
}
}
},
"risk_assessment": {
"type": "object",
"instruction": "Analyse litigation risk in depth",
"properties": {
"vulnerabilities": {
"type": "string",
"instruction": "Identify specific legal vulnerabilities"
},
"recommendation": {
"type": "string",
"instruction": "Recommend next steps based on identified risks",
"selectFields": ["risk_assessment.vulnerabilities"]
}
}
}
}
}
parties fires one API call and returns a JSON array. risk_assessment uses normal OW decomposition — vulnerabilities gets its own call, then recommendation gets a separate call with vulnerability analysis injected via selectFields.
How It Works
When OW encounters a node with structuredOutput: true, the StructuredOutputProcessor:
- Converts the subtree to JSON Schema — walks all child properties, nested objects, and array item types and builds the
response_formatconstraint. - Sends a single constrained call — builds one prompt from the field's
instructionand submits it with the JSON Schema response format. The LLM returns structured JSON. - Stores the result normally — the parsed value is stored in the execution context exactly like any other field. Downstream fields can reference it via
selectFields. - Falls back automatically — if the structured call fails (context too large, schema too complex), OW silently retries using normal per-field decomposition. No configuration needed.
The Hybrid Pattern
The most powerful use of structured output is mixing it with orchestration in a single definition. This is the hybrid approach:
{
"type": "object",
"properties": {
"metadata": {
"type": "object",
"structuredOutput": true,
"instruction": "Extract document metadata",
"properties": {
"title": { "type": "string" },
"date": { "type": "string" },
"jurisdiction": { "type": "string" }
}
},
"parties": {
"type": "array",
"structuredOutput": true,
"instruction": "Extract all named parties",
"items": { "type": "object", "properties": {
"name": { "type": "string" },
"role": { "type": "string" }
}}
},
"strategic_brief": {
"type": "object",
"instruction": "Produce a strategic brief",
"properties": {
"summary": { "type": "string", "instruction": "Executive summary of key issues" },
"recommendation": {
"type": "string",
"instruction": "Strategic recommendation",
"selectFields": ["parties", "strategic_brief.summary"]
}
}
}
}
}
metadata and parties — extraction — collapse to 2 LLM calls. strategic_brief — reasoning — expands to multiple calls with full context per field.
Cost Impact
Normal OW orchestration repeats the entire input document in every LLM call. For a 4,400-token document with 228 fields, that's ~1M input tokens. Hybrid mode collapses extraction fields to a handful of structured calls:
| Approach | API calls | Est. input tokens | Input cost (Gemini Flash Lite) |
|---|---|---|---|
| Pure orchestration | ~228 | ~1,010,000 | $0.0757 |
| Hybrid | ~25 | ~35,000 | $0.0026 |
| Pure structured | 1 | ~3,755 | $0.0003 |
The hybrid approach used 97% fewer input tokens than pure orchestration in the document analysis benchmark, while maintaining orchestration's depth advantage on reasoning fields (2.1× more content, 7 vs 4 vulnerabilities identified in risk analysis).
At scale across 1,000 documents:
| Approach | Total input cost | Quality on reasoning |
|---|---|---|
| Pure orchestration | $75.70 | Deep |
| Hybrid | $2.60 | Deep |
| Pure structured | $0.28 | Compressed |
Constraints
structuredOutput: trueis valid onobjectandarraynodes only, not on leafstring/number/booleanfields.- The JSON Schema sent to the provider must be within the provider's schema complexity limits. OW falls back to decomposition automatically if this limit is hit.
- Fields inside a
structuredOutputsubtree cannot useselectFieldsto reference fields outside that subtree. Cross-subtree context must be passed at the parent level.
Further Reading
- The Hybrid Approach: Structured Output Inside Orchestration — full benchmark data, cost arithmetic, and caching details
- When Structured Output Beats Orchestration — And When It Doesn't — head-to-head comparison with baselines
- Where Orchestration Wins — the cases where full decomposition is worth the cost
- Select Fields — injecting context from earlier fields into downstream prompts
- Processing Order — controlling the sequence of field generation