or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

advanced

error-handling.mdtype-inference.md
glossary.mdindex.mdquick-reference.mdtask-index.md
tile.json

structured-outputs.mddocs/guides/

Structured Outputs Guide

This guide covers generating type-safe, validated responses using Zod schemas or JSON schemas.

Basic Structured Output

Simple Schema

import { createAgent } from "langchain";
import { z } from "zod";

const ContactSchema = z.object({
  name: z.string(),
  email: z.string().email(),
  phone: z.string(),
});

const agent = createAgent({
  model: "openai:gpt-4o",
  tools: [],
  responseFormat: ContactSchema,
});

const result = await agent.invoke({
  messages: [
    {
      role: "user",
      content: "Extract: John Doe, john@example.com, (555) 123-4567",
    },
  ],
});

console.log(result.structuredResponse);
// { name: "John Doe", email: "john@example.com", phone: "(555) 123-4567" }

Complex Schema

import { createAgent } from "langchain";
import { z } from "zod";

const OrderSchema = z.object({
  orderId: z.string(),
  customer: z.object({
    name: z.string(),
    email: z.string().email(),
    address: z.object({
      street: z.string(),
      city: z.string(),
      state: z.string(),
      zip: z.string(),
    }),
  }),
  items: z.array(
    z.object({
      productId: z.string(),
      name: z.string(),
      quantity: z.number(),
      price: z.number(),
    })
  ),
  total: z.number(),
  status: z.enum(["pending", "confirmed", "shipped", "delivered"]),
});

const agent = createAgent({
  model: "openai:gpt-4o",
  tools: [],
  responseFormat: OrderSchema,
});

Union Types

Multiple Possible Schemas

import { createAgent } from "langchain";
import { z } from "zod";

const EmailSchema = z.object({
  type: z.literal("email"),
  to: z.string().email(),
  subject: z.string(),
  body: z.string(),
});

const TaskSchema = z.object({
  type: z.literal("task"),
  title: z.string(),
  description: z.string(),
  dueDate: z.string().optional(),
});

const ReminderSchema = z.object({
  type: z.literal("reminder"),
  text: z.string(),
  time: z.string(),
});

// Agent can return any of these schemas
const agent = createAgent({
  model: "openai:gpt-4o",
  tools: [],
  responseFormat: [EmailSchema, TaskSchema, ReminderSchema],
});

const result = await agent.invoke({
  messages: [{ role: "user", content: "Remind me to call John at 3pm" }],
});

// Response matches one of the schemas
if (result.structuredResponse.type === "reminder") {
  console.log(result.structuredResponse.text);
  console.log(result.structuredResponse.time);
}

Discriminated Union

const ResponseSchema = z.discriminatedUnion("action", [
  z.object({
    action: z.literal("respond"),
    message: z.string(),
  }),
  z.object({
    action: z.literal("transfer"),
    department: z.string(),
    reason: z.string(),
  }),
  z.object({
    action: z.literal("escalate"),
    priority: z.enum(["low", "medium", "high"]),
    issue: z.string(),
  }),
]);

const agent = createAgent({
  model: "openai:gpt-4o",
  tools: [],
  responseFormat: ResponseSchema,
});

Response Format Strategies

Tool Strategy

import { createAgent, toolStrategy } from "langchain";
import { z } from "zod";

const SummarySchema = z.object({
  mainPoints: z.array(z.string()),
  sentiment: z.enum(["positive", "neutral", "negative"]),
});

const agent = createAgent({
  model: "openai:gpt-4o",
  tools: [],
  responseFormat: toolStrategy(SummarySchema, {
    name: "generate_summary",
    strict: true,
  }),
});

Provider Strategy

import { createAgent, providerStrategy } from "langchain";
import { z } from "zod";

const AnalysisSchema = z.object({
  topic: z.string(),
  keyFindings: z.array(z.string()),
  recommendations: z.array(z.string()),
  confidence: z.number().min(0).max(1),
});

// Use provider-native JSON schema support (when available)
const agent = createAgent({
  model: "openai:gpt-4o",
  tools: [],
  responseFormat: providerStrategy(AnalysisSchema),
});

JSON Schema Format

Direct JSON Schema

import { createAgent } from "langchain";

const jsonSchema = {
  name: "weather_info",
  strict: true,
  schema: {
    type: "object",
    properties: {
      location: {
        type: "string",
        description: "City name",
      },
      temperature: {
        type: "number",
        description: "Temperature in Celsius",
      },
      conditions: {
        type: "string",
        enum: ["sunny", "cloudy", "rainy", "snowy"],
      },
    },
    required: ["location", "temperature", "conditions"],
    additionalProperties: false,
  },
};

const agent = createAgent({
  model: "openai:gpt-4o",
  tools: [],
  responseFormat: jsonSchema,
});

Common Use Cases

Data Extraction

const ExtractionSchema = z.object({
  entities: z.array(
    z.object({
      name: z.string(),
      type: z.enum(["person", "organization", "location"]),
      relevance: z.number().min(0).max(1),
    })
  ),
  relationships: z.array(
    z.object({
      from: z.string(),
      to: z.string(),
      type: z.string(),
    })
  ),
});

const agent = createAgent({
  model: "openai:gpt-4o",
  tools: [],
  responseFormat: ExtractionSchema,
});

Classification

const ClassificationSchema = z.object({
  category: z.enum(["technical", "billing", "general", "complaint"]),
  subcategory: z.string(),
  priority: z.enum(["low", "medium", "high", "urgent"]),
  sentiment: z.enum(["positive", "neutral", "negative"]),
  confidence: z.number().min(0).max(1),
});

const agent = createAgent({
  model: "openai:gpt-4o",
  tools: [],
  responseFormat: ClassificationSchema,
});

Content Generation

const ArticleSchema = z.object({
  title: z.string(),
  summary: z.string(),
  sections: z.array(
    z.object({
      heading: z.string(),
      content: z.string(),
      keyPoints: z.array(z.string()),
    })
  ),
  tags: z.array(z.string()),
  readingTimeMinutes: z.number(),
});

const agent = createAgent({
  model: "openai:gpt-4o",
  tools: [],
  responseFormat: ArticleSchema,
});

Analysis and Insights

const AnalysisSchema = z.object({
  overview: z.string(),
  strengths: z.array(z.string()),
  weaknesses: z.array(z.string()),
  opportunities: z.array(z.string()),
  threats: z.array(z.string()),
  recommendations: z.array(
    z.object({
      action: z.string(),
      priority: z.enum(["low", "medium", "high"]),
      impact: z.string(),
    })
  ),
});

const agent = createAgent({
  model: "openai:gpt-4o",
  tools: [],
  responseFormat: AnalysisSchema,
});

With Tools

Combining Tools and Structured Output

import { createAgent, tool } from "langchain";
import { z } from "zod";

const searchTool = tool(
  async ({ query }) => `Results for: ${query}`,
  {
    name: "search",
    description: "Search for information",
    schema: z.object({
      query: z.string(),
    }),
  }
);

const ResearchSchema = z.object({
  topic: z.string(),
  sources: z.array(z.string()),
  summary: z.string(),
  citations: z.array(
    z.object({
      text: z.string(),
      source: z.string(),
    })
  ),
});

// Agent uses tools AND returns structured output
const agent = createAgent({
  model: "openai:gpt-4o",
  tools: [searchTool],
  responseFormat: ResearchSchema,
});

const result = await agent.invoke({
  messages: [{ role: "user", content: "Research AI history" }],
});

console.log(result.structuredResponse);

Error Handling

Parsing Errors

import { createAgent, StructuredOutputParsingError } from "langchain";
import { z } from "zod";

const Schema = z.object({
  value: z.number(),
});

const agent = createAgent({
  model: "openai:gpt-4o",
  tools: [],
  responseFormat: Schema,
});

try {
  const result = await agent.invoke({
    messages: [{ role: "user", content: "Extract the number" }],
  });
  console.log(result.structuredResponse);
} catch (error) {
  if (error instanceof StructuredOutputParsingError) {
    console.error("Parsing failed:", error.message);
    console.error("Raw output:", error.rawOutput);
    console.error("Cause:", error.cause);
  }
}

Multiple Outputs Error

import { MultipleStructuredOutputsError } from "langchain";

try {
  const result = await agent.invoke({ messages: [...] });
} catch (error) {
  if (error instanceof MultipleStructuredOutputsError) {
    console.error("Multiple outputs returned:", error.outputs);
  }
}

Validation and Refinements

Custom Validation

const UserSchema = z.object({
  username: z.string()
    .min(3, "Username must be at least 3 characters")
    .max(20, "Username must be at most 20 characters")
    .regex(/^[a-zA-Z0-9_]+$/, "Username can only contain letters, numbers, and underscores"),
  email: z.string().email("Invalid email format"),
  age: z.number()
    .min(13, "Must be at least 13 years old")
    .max(120, "Invalid age"),
});

Schema Refinements

const PasswordResetSchema = z.object({
  password: z.string().min(8),
  confirmPassword: z.string(),
}).refine(
  data => data.password === data.confirmPassword,
  {
    message: "Passwords must match",
    path: ["confirmPassword"],
  }
);

Optional and Default Values

const ConfigSchema = z.object({
  theme: z.enum(["light", "dark"]).default("light"),
  language: z.string().default("en"),
  notifications: z.boolean().default(true),
  customSettings: z.record(z.any()).optional(),
});

Best Practices

Schema Design

  • Keep schemas focused and specific
  • Use descriptive property names
  • Add .describe() to help the LLM understand fields
  • Use enums for constrained values
  • Make optional properties truly optional

Validation

  • Use Zod's built-in validators (.email(), .url(), .min(), .max())
  • Add custom refinements for complex validation
  • Provide clear error messages
  • Validate critical fields

Performance

  • Simpler schemas generally work better
  • Avoid deeply nested structures when possible
  • Consider using union types for different response types
  • Use providerStrategy when model supports native JSON schema

Error Handling

  • Always handle StructuredOutputParsingError
  • Log raw output for debugging
  • Consider fallback strategies
  • Validate critical fields after parsing

Model Compatibility

  • OpenAI GPT-4/GPT-4o have best support
  • Test with your specific model
  • Consider using toolStrategy for wider compatibility
  • Some models may not support all features

See Structured Output API Reference for complete API documentation.