Back to blog

Product · Jul 1, 2026

Facio's Structured Output Discipline: How AI Agents Produce Outputs Other Systems Can Actually Trust

An AI agent's free-text response is unusable by other systems. Downstream pipelines can't parse it reliably; databases can't store it; APIs can't consume it. Production agents produce structured outputs — JSON, Markdown, schema-validated payloads — that other systems can ingest, validate, and trust. Facio's structured output discipline gives agents the patterns for reliable, machine-readable outputs: explicit schemas, validation before return, type safety, and clear error contracts. Here's how the discipline works.

Structured OutputSchema ValidationInteroperabilityType SafetyOutput Contracts

Facio's Structured Output Discipline: How AI Agents Produce Outputs Other Systems Can Actually Trust

An AI agent's free-text response is unusable by other systems. "I found three issues with your deployment: the image is wrong, the env var is missing, and there's a typo in the manifest." A human can read this and act on it. A deployment pipeline cannot. The pipeline needs structured data: which issues, where in the configuration, what severity, what fix.

Production AI agents produce structured outputs — JSON, Markdown with defined sections, schema-validated payloads — that downstream systems can ingest, validate, and trust. The structured output is the interface between the agent's reasoning and the rest of the world's automation.

Facio's structured output discipline gives agents the patterns for reliable, machine-readable outputs: explicit schemas, validation before return, type safety, error contracts, and consistent field naming. The discipline turns an agent from "writes paragraphs" into "produces data."

Here's how the discipline works, what the patterns look like, and why structured output is what makes AI agents composable with the rest of the enterprise stack.

The Free-Text Output Problem

Most LLM-based agents default to free-text output. The model produces a paragraph or a list of bullet points, and the user reads it. This is fine for human consumption but breaks down for system integration:

Downstream pipelines can't parse free text reliably. "The customer is happy" is easy for a human; for a system, it's ambiguous. Happy with what? What metric indicates happiness? What action should the system take?

APIs can't consume free text. An API expects JSON, form-encoded data, or another defined format. Free text isn't valid input.

Databases can't store free text meaningfully. A column of free-text responses is searchable but not queryable. "Find all responses where the customer was unhappy" requires regex parsing of natural language, which is brittle.

Tests can't verify free text. "Verify the agent says 'all tests passed'" is not a meaningful test — the agent could say "all tests were successful" and fail the test despite being correct.

HITL reviewers can't process free text efficiently. A reviewer reading through 50 agent responses has to scan each one. A reviewer reading 50 structured payloads can scan the structured fields and focus on what's relevant.

The free-text default works for prototypes. It breaks down the moment the agent's output becomes input to another system.

The Structured Output Spectrum

Structured outputs come in a spectrum from "barely structured" to "strictly typed":

Level 1: Markdown with Sections

The agent produces Markdown with consistent section headers:

## Summary
The deployment failed due to missing environment variables.

## Issues Found
- Missing DATABASE_URL
- Missing REDIS_HOST

## Severity
Critical — service cannot start

## Recommended Action
Add the missing env vars and redeploy.

This is lightly structured. A human can scan it; a system can extract sections with simple parsing. The structure is implied by convention, not enforced by tooling.

Level 2: JSON with Schema Hint

The agent produces JSON, with field names that imply a schema:

{
  "summary": "Deployment failed due to missing environment variables.",
  "issues": [
    {"name": "DATABASE_URL", "type": "missing"},
    {"name": "REDIS_HOST", "type": "missing"}
  ],
  "severity": "critical",
  "recommended_action": "Add missing env vars and redeploy."
}

This is moderately structured. The fields have names; the types are inferable. A system can parse it; a database can store it; an API can consume it.

Level 3: JSON with Validated Schema

The agent produces JSON, and the runtime validates the JSON against a defined schema before returning:

{
  "summary": "Deployment failed due to missing environment variables.",
  "issues": [
    {"name": "DATABASE_URL", "type": "missing"},
    {"name": "REDIS_HOST", "type": "missing"}
  ],
  "severity": "critical",
  "recommended_action": "Add missing env vars and redeploy."
}

Validated against schema:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "required": ["summary", "issues", "severity", "recommended_action"],
  "properties": {
    "summary": {"type": "string"},
    "issues": {
      "type": "array",
      "items": {
        "type": "object",
        "required": ["name", "type"],
        "properties": {
          "name": {"type": "string"},
          "type": {"enum": ["missing", "invalid", "warning"]}
        }
      }
    },
    "severity": {"enum": ["info", "warning", "error", "critical"]},
    "recommended_action": {"type": "string"}
  }
}

The validation catches errors before the output reaches the consumer. The schema is the contract.

Level 4: Type-Safe Code Generation

The agent produces output that compiles as code in a typed language:

interface DeploymentCheckResult {
  summary: string;
  issues: Array<{
    name: string;
    type: "missing" | "invalid" | "warning";
  }>;
  severity: "info" | "warning" | "error" | "critical";
  recommended_action: string;
}

const result: DeploymentCheckResult = {
  summary: "Deployment failed due to missing environment variables.",
  issues: [
    { name: "DATABASE_URL", type: "missing" },
    { name: "REDIS_HOST", type: "missing" },
  ],
  severity: "critical",
  recommended_action: "Add missing env vars and redeploy.",
};

The TypeScript compiler validates the structure. If the agent's output doesn't match the type, it doesn't compile. The contract is enforced by the language itself.

Level 5: JSON-LD with Semantic Web Vocabulary

The agent produces structured data with linked semantic meaning:

{
  "@context": "https://schema.org/",
  "@type": "DiagnosticReport",
  "description": "Deployment failed due to missing environment variables.",
  "issue": [
    {
      "@type": "PropertyValue",
      "name": "DATABASE_URL",
      "value": "missing"
    }
  ],
  "severity": "critical",
  "action": "Add missing env vars and redeploy."
}

The semantic vocabulary makes the output interoperable with other systems using the same vocabulary. The contract is universal.

Facio's discipline supports levels 1-4 natively and provides tooling for level 5 when semantic interop is required.

The Schema Definition Discipline

The structured output discipline starts with schemas. The agent (and the team) defines the expected output schema before the agent starts producing it:

# Output Schema: Deployment Check Result

## Fields
- summary (string, required): One-sentence description of the result.
- issues (array, required): List of issues found.
  - Each issue has:
    - name (string, required): The name of the resource/config affected.
    - type (enum, required): One of "missing", "invalid", "warning".
    - location (string, optional): Where in the config the issue is.
    - suggested_fix (string, optional): How to fix the issue.
- severity (enum, required): One of "info", "warning", "error", "critical".
- recommended_action (string, required): What the user should do next.

## Validation Rules
- summary must be ≤200 characters
- issues must contain at least one item if severity is "error" or "critical"
- recommended_action must be actionable (contain a verb)

The schema is documentation. The schema is the contract. The agent references the schema when generating output; the runtime validates against the schema when the agent returns output.

The Output Generation Patterns

The agent's output generation follows patterns that align with the schema:

Pattern 1: Field-by-Field Construction

The agent thinks through each field, populating it from the reasoning:

# Constructing the output
summary = "Deployment failed due to missing environment variables."
# Reasoning: The check found two env vars missing; the service can't start.

issues = [
    {"name": "DATABASE_URL", "type": "missing", "location": "spec.template.spec.containers[0].env"},
    {"name": "REDIS_HOST", "type": "missing", "location": "spec.template.spec.containers[0].env"}
]
# Reasoning: The check looked at the deployment spec and found these env vars referenced but not defined.

severity = "critical"
# Reasoning: The service cannot start without these env vars.

recommended_action = "Add DATABASE_URL and REDIS_HOST to the deployment spec's env section, then redeploy."
# Reasoning: The user can fix this by adding the env vars to their config.

The agent then assembles these into a structured payload:

{
  "summary": "Deployment failed due to missing environment variables.",
  "issues": [
    {"name": "DATABASE_URL", "type": "missing", "location": "spec.template.spec.containers[0].env"},
    {"name": "REDIS_HOST", "type": "missing", "location": "spec.template.spec.containers[0].env"}
  ],
  "severity": "critical",
  "recommended_action": "Add DATABASE_URL and REDIS_HOST to the deployment spec's env section, then redeploy."
}

The field-by-field construction produces structured output consistently because each field has a defined purpose and a defined source.

Pattern 2: Schema-Guided Generation

For agents with native structured output support, the agent is given the schema and generates directly into the structure:

# Schema provided to the model
{
  "type": "object",
  "properties": {
    "summary": {"type": "string"},
    "issues": {"type": "array", ...},
    ...
  }
}

# Agent generates directly into the schema
# Result: JSON that conforms to the schema by construction

The schema-guided generation is more efficient (no post-hoc validation failures) but requires models with structured output support.

Pattern 3: Output Verification

For agents producing critical outputs, the runtime verifies the output against the schema before returning:

# Agent produces output
agent_output = "The deployment failed because..."

# Runtime parses and validates
parsed = json.loads(agent_output)
validate(parsed, schema=deployment_check_schema)

# If valid: return parsed
# If invalid: retry generation with explicit feedback

The verification loop catches malformed outputs and gives the agent a chance to fix them. The output that reaches the consumer is always schema-conformant.

The Error Output Contract

Not all outputs are successful results. The agent may need to return an error. The structured output discipline includes a defined error contract:

{
  "status": "error",
  "error_code": "DEPLOYMENT_CHECK_FAILED",
  "error_message": "Unable to check deployment — the cluster is unreachable.",
  "error_details": {
    "cluster": "production-eu",
    "attempted_at": "2026-07-01T09:45:23Z",
    "retry_count": 3,
    "last_error": "kubectl: Failed to connect to https://k8s.example.com:6443"
  },
  "user_action_required": "Verify network connectivity to the production cluster, then retry.",
  "fallback_options": [
    "Run check against staging cluster",
    "Defer deployment until cluster is reachable",
    "Contact platform team via ask_approval"
  ]
}

The error contract tells the consumer:

  • What went wrong. The status and error code.
  • Why it went wrong. The error details.
  • What to do about it. The user action required.
  • What alternatives exist. The fallback options.

The structured error is actionable. The consumer doesn't have to parse a free-text error message and guess what to do.

The Output Naming Discipline

Structured outputs use consistent naming across the agent's outputs:

  • snake_case for fields. "customer_id", not "customerId" or "CustomerID".
  • Lowercase for enum values. "missing", not "Missing" or "MISSING".
  • Timestamps in ISO 8601. "2026-07-01T09:45:23Z", not "July 1, 2026".
  • Boolean fields named with predicates. "is_valid", not "validity".
  • Arrays named with plurals. "issues", not "issue_list".

The naming discipline makes outputs predictable. A consumer that knows the convention can write code against outputs without reading the schema for every field.

The Output Versioning

Schemas evolve. New fields are added. Old fields are deprecated. The structured output discipline includes versioning:

{
  "schema_version": "1.2",
  "summary": "...",
  "issues": [...],
  ...
}

The schema version is part of the output. Consumers can detect the version and handle accordingly:

# Consumer code
if output["schema_version"] == "1.2":
    # Process new fields
elif output["schema_version"] == "1.1":
    # Process old fields
else:
    # Handle unknown version

Versioning makes schema evolution safe. Old consumers continue working with old schemas; new consumers can use new fields. The agent can be updated without breaking existing integrations.

The Schema Documentation

Schemas need documentation. Facio's discipline requires that every schema has:

  • Field descriptions. What each field means.
  • Examples. What a valid value looks like.
  • Constraints. What values are valid (enums, ranges, patterns).
  • Relationships. What this output relates to in other outputs.
  • Version history. What changed between versions.

The documentation lives alongside the schema. The agent references the docs when generating; the team references them when integrating.

The Output Testing

Structured outputs are testable. The discipline includes:

# Test cases
def test_deployment_check_success():
    result = agent.run("Check deployment")
    assert result.schema_version == "1.2"
    assert result.severity in ["info", "warning", "error", "critical"]
    assert isinstance(result.issues, list)
    if result.severity in ["error", "critical"]:
        assert len(result.issues) > 0
    assert len(result.summary) <= 200

The tests verify the output structure, not the output content. The tests run automatically; the agent's compliance with the schema is measurable.

What Structured Output Doesn't Do

Honest limitations:

  • It doesn't guarantee semantic correctness. The output can be schema-valid and wrong. The structure says "this is the field"; the content says "this is the value" — but the value may be incorrect. Semantic validation is a separate discipline.
  • It doesn't eliminate the need for human review. Even structured outputs need human approval for high-stakes decisions. The structure makes review easier, not unnecessary.
  • It adds upfront cost. Defining schemas, validating outputs, testing — these all take time. The cost is worth it for production workflows but may be excessive for one-off tasks.
  • It constrains the agent's flexibility. The agent can't include information that doesn't fit the schema. For exploratory work where the output is unknown, free text may be more appropriate.
  • It requires schema evolution discipline. As the agent's capabilities grow, the schemas need to evolve. Without discipline, the schemas become legacy, then obsolete, then broken.

The Compound Effect

Structured output compounds. The agent that produces structured outputs:

  • Integrates with everything. Other systems can consume the agent's outputs without parsing free text.
  • Is testable. The agent's behavior is verifiable through output structure, not just content.
  • Scales to fleets. Multiple agents producing the same structured output can be aggregated, compared, monitored centrally.
  • Improves over time. Schema versioning tracks evolution; output testing catches regressions; documentation supports growth.

The agent that produces free text has the opposite trajectory. Hard to integrate. Hard to test. Hard to scale. Hard to improve.

Bottom Line

Free-text agent outputs work for humans. They don't work for systems. Production agents produce structured outputs that other systems can ingest, validate, and trust.

Facio's structured output discipline gives agents the patterns: schema definition before generation, field-by-field or schema-guided construction, output verification, error contracts, naming conventions, versioning, documentation, and testing. The combination makes the agent composable with the rest of the enterprise.

The agent without the discipline is a chat partner. The agent with the discipline is a data producer. The enterprise can build on the data producer. The chat partner is read but not acted on.

Because agents that produce data are agents that can be orchestrated. Agents that produce prose are agents that can be conversed with. The enterprise wants the first.


See the structured output documentation for schema definition patterns, validation tooling, and versioning conventions.

Keep reading

More on Product

View category
Jun 30, 2026Product

Facio's Quota and Rate Limit Awareness: How AI Agents Stay Under the Caps Without Throttling the Workflow

Every external system an AI agent touches has limits. APIs have rate limits per second. Models have token quotas per minute. Storage services have request budgets per hour. Email services have daily send caps. The naive agent hits these limits and fails. The disciplined agent tracks consumption in real time, paces its requests to stay under the caps, batches where possible, and shifts work to alternative windows when quotas are tight. Facio's quota awareness turns a brittle integration into a predictable operation. Here's how the discipline works.

Jun 29, 2026Product

Facio's Graceful Degradation: How AI Agents Keep Working When the Stack Around Them Breaks

Production AI agents operate in hostile environments. MCP servers go offline, APIs return 500s, databases time out, networks drop mid-call. The agent that fails on the first hiccup is a prototype. The agent that degrades gracefully — falling back to alternatives, retrying intelligently, escalating when needed, and continuing with what it has — is a production system. Facio's graceful degradation patterns are the structural discipline that keeps agents working when the world around them isn't. Here's how the patterns work.

Jun 28, 2026Product

Facio's Context Window Discipline: How AI Agents Stay Sharp When Conversations Run for Hours

An AI agent's context window is its working memory — and it's finite. Long sessions accumulate context: every tool call result, every message, every retrieved fact stays in the window until the session ends. The agent gets slower, more expensive, and eventually confused as the context fills. Facio's context window discipline gives agents the structural patterns to stay sharp across hours of work: selective loading, aggressive summarization, strategic forgetting, and checkpoint-driven compaction. Here's how the discipline works.