CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-langchain

TypeScript framework for building LLM-powered applications with agents, tools, middleware, and model interoperability

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

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.

docs

glossary.md

index.md

quick-reference.md

task-index.md

tile.json