> ## Documentation Index
> Fetch the complete documentation index at: https://praison.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Structured Output

> Return schema-constrained JSON from an Agent with outputSchema

Set `outputSchema` on an `Agent` to make it return JSON that matches your schema.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph LR
    Agent[🤖 Agent] --> Schema[📋 JSON Schema]
    Schema --> JSON[✅ JSON Output]

    classDef agent fill:#8B0000,stroke:#7C90A0,color:#fff
    classDef schema fill:#189AB4,stroke:#7C90A0,color:#fff
    classDef output fill:#10B981,stroke:#7C90A0,color:#fff

    class Agent agent
    class Schema schema
    class JSON output
```

> [!NOTE]
>
> `outputSchema` works on **every provider** (OpenAI, Anthropic, Google, Groq, Mistral, Ollama, and more). On OpenAI it uses `response_format: json_schema` natively; on other providers it routes through the AI SDK backend's `generateObject({ schema })`. Cross-provider support landed in [PraisonAI PR #4412](https://github.com/MervinPraison/PraisonAI/pull/4412) — earlier releases dropped the schema on non-OpenAI providers.

## Quick Start

**1. Simplest — one outputSchema**

```typescript theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
import { Agent } from 'praisonai';

const agent = new Agent({
  instructions: 'Extract person info as JSON.',
  llm: 'gpt-4o-mini',
  outputSchema: {
    type: 'object',
    properties: {
      name: { type: 'string' },
      age: { type: 'number' },
      email: { type: 'string' }
    },
    required: ['name', 'age']
  }
  // outputSchemaName defaults to 'response'
});

const result = await agent.start(
  'John Doe is 30 years old, email john@example.com'
);
console.log(result);
// result is a JSON string matching the schema:
// {"name":"John Doe","age":30,"email":"john@example.com"}
```

**2. With outputSchemaName and a nested schema**

```typescript theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
import { Agent } from 'praisonai';

const agent = new Agent({
  instructions: 'Extract an order as JSON.',
  llm: 'gpt-4o-mini',
  outputSchemaName: 'order',
  outputSchema: {
    type: 'object',
    properties: {
      id: { type: 'string' },
      customer: {
        type: 'object',
        properties: {
          name: { type: 'string' },
          email: { type: 'string' }
        },
        required: ['name']
      },
      items: {
        type: 'array',
        items: {
          type: 'object',
          properties: {
            sku: { type: 'string' },
            qty: { type: 'number' }
          },
          required: ['sku', 'qty']
        }
      }
    },
    required: ['id', 'customer', 'items']
  }
});

const json = await agent.start('Order 42 for Ada (ada@example.com): 2x SKU-1, 1x SKU-9');
console.log(JSON.parse(json));
```

***

## How It Works

On OpenAI, the agent forwards `outputSchema` as `response_format: { type: 'json_schema', json_schema: { name, schema } }`. On other providers it routes the schema through the AI SDK backend's `generateObject({ schema })`. Both paths return the raw JSON string.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
sequenceDiagram
    participant User
    participant Agent
    participant LLM as LLM Provider

    User->>Agent: start("Extract person info...")
    Agent->>LLM: request + schema (json_schema or generateObject)
    LLM-->>Agent: JSON string
    Agent-->>User: JSON string (matches schema)
```

| Field | Type | Default | Description |
| - | - | - | - |
| `outputSchema` | `Record<string, any>` | `undefined` | JSON Schema for the response. |
| `outputSchemaName` | `string` | `'response'` | Name used in `response_format.json_schema.name`. |

> [!NOTE]
>
> `outputSchema` is a **JSON Schema object** (`Record<string, any>`), not a Zod schema. If you keep schemas in Zod, convert first with `zodToJsonSchema(MySchema)`.

***

## Provider support

`outputSchema` works on every provider PraisonAI TS supports today.

| Provider prefix | How the schema is enforced |
| - | - |
| `openai/...` | Native `response_format: { type: 'json_schema', json_schema: { ... } }` |
| `anthropic/...`, `google/...`, `groq/...`, `mistral/...`, `ollama/...`, and other AI SDK providers | AI SDK `backend.generateObject({ schema })` |

The agent returns a JSON string that matches your schema in both paths — `JSON.parse(result)` for the object.

Cross-provider structured output landed in [PraisonAI PR #4412](https://github.com/MervinPraison/PraisonAI/pull/4412). If you are on an earlier release, the agent logs `outputSchema is not yet supported with non-OpenAI providers ... — proceeding without structured output` and returns unstructured text.

***

## Multi-turn behaviour

Structured output goes through the agent's full message history, so follow-up prompts see prior turns and stay consistent.

```typescript theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
const agent = new Agent({
  instructions: 'Return the running total as JSON.',
  llm: 'gpt-4o-mini',
  outputSchema: {
    type: 'object',
    properties: { total: { type: 'number' } },
    required: ['total']
  }
});

await agent.chat('Add 5');   // {"total":5}
await agent.chat('Add 3');   // {"total":8} — remembers the previous turn
```

***

## How this differs from `generateObject`

> [!NOTE]
>
> The low-level `provider.generateObject({ schema })` from `resolveBackend` is still available for direct AI SDK use. The recommended, agent-centric path is `outputSchema` on the `Agent`.

```typescript theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
import { resolveBackend } from 'praisonai';
import { z } from 'zod';

const { provider } = await resolveBackend('openai/gpt-4o-mini');

const result = await provider.generateObject({
  messages: [{ role: 'user', content: 'What is the weather in Paris?' }],
  schema: z.object({ location: z.string(), temperature: z.number() })
});

console.log(result.object); // { location: "Paris", temperature: 18 }
```

See the [Zod docs](https://zod.dev) for schema construction.

***

## Common Patterns

### Extraction

```typescript theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
const agent = new Agent({
  instructions: 'Extract the invoice fields as JSON.',
  llm: 'gpt-4o-mini',
  outputSchema: {
    type: 'object',
    properties: {
      invoiceNumber: { type: 'string' },
      total: { type: 'number' },
      dueDate: { type: 'string' }
    },
    required: ['invoiceNumber', 'total']
  }
});

const json = await agent.start('Invoice INV-7 for $240, due 2026-01-15');
```

### Classification

```typescript theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
const agent = new Agent({
  instructions: 'Classify the email as JSON.',
  llm: 'gpt-4o-mini',
  outputSchema: {
    type: 'object',
    properties: {
      category: { type: 'string', enum: ['spam', 'ham'] },
      confidence: { type: 'number' }
    },
    required: ['category', 'confidence']
  }
});

const json = await agent.start('You won $1,000,000! Click here!');
// {"category":"spam","confidence":0.96}
```

### Sentiment

```typescript theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
const agent = new Agent({
  instructions: 'Return sentiment as JSON.',
  llm: 'gpt-4o-mini',
  outputSchema: {
    type: 'object',
    properties: {
      sentiment: { type: 'string', enum: ['positive', 'negative', 'neutral'] },
      score: { type: 'number' }
    },
    required: ['sentiment']
  }
});

const json = await agent.start('The service was fast and friendly.');
```

***

## Best Practices

> [accordion] Mark required fields
>
> List every field you always expect in `required`. It nudges the model to include them and keeps the JSON predictable.

> [accordion] Use enums for fixed choices
>
> Add `enum` on classification fields so the model can only pick valid values.

> [accordion] Parse the result
>
> The agent returns a JSON string. Call `JSON.parse(result)` to get an object.

> [accordion] Works on every provider
>
> Switching the `llm` string from `openai/...` to `anthropic/...`, `google/...`, or any other supported provider does not change your `outputSchema` code. Structured output is guaranteed on every provider from PraisonAI PR #4412 onward.

***

## Related

> [card] [Agent](https://praison.ai/docs/js/agent.md)
>
> Agent configuration

> [card] [Multi-Provider (AI SDK)](https://praison.ai/docs/js/ai-sdk.md)
>
> Switch LLM providers


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.