Skip to main content

Agent Structured Output

PraisonAI supports generating structured JSON output with type safety using AI SDK’s generateObject capability. This ensures agents return data in a predictable format.

Quick Start

import { Agent } from 'praisonai';
import { z } from 'zod';

const agent = new Agent({
  instructions: 'You extract structured data from text',
  llm: 'openai/gpt-4o-mini'
});

// Define output schema
const PersonSchema = z.object({
  name: z.string(),
  age: z.number(),
  email: z.string().email().optional()
});

// Get structured output
const result = await agent.generateObject({
  prompt: 'Extract person info: John Doe is 30 years old, email [email protected]',
  schema: PersonSchema
});

console.log(result.object);
// { name: "John Doe", age: 30, email: "[email protected]" }

Using AI SDK Backend Directly

For more control, use the AI SDK backend directly:
import { resolveBackend } from 'praisonai';
import { z } from 'zod';

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

const WeatherSchema = z.object({
  location: z.string(),
  temperature: z.number(),
  unit: z.enum(['celsius', 'fahrenheit']),
  conditions: z.string()
});

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

console.log(result.object);
// { location: "Paris", temperature: 18, unit: "celsius", conditions: "partly cloudy" }

Schema Types

Using Zod Schemas

Zod is the recommended way to define schemas:
import { z } from 'zod';

// Simple object
const SimpleSchema = z.object({
  title: z.string(),
  count: z.number()
});

// Nested objects
const NestedSchema = z.object({
  user: z.object({
    name: z.string(),
    profile: z.object({
      bio: z.string(),
      links: z.array(z.string())
    })
  })
});

// Arrays
const ListSchema = z.object({
  items: z.array(z.object({
    id: z.number(),
    name: z.string(),
    active: z.boolean()
  }))
});

// Enums
const StatusSchema = z.object({
  status: z.enum(['pending', 'active', 'completed']),
  priority: z.enum(['low', 'medium', 'high'])
});

// Optional fields
const OptionalSchema = z.object({
  required: z.string(),
  optional: z.string().optional(),
  withDefault: z.string().default('default value')
});

Using JSON Schema

You can also use JSON Schema directly:
const jsonSchema = {
  type: 'object',
  properties: {
    name: { type: 'string' },
    age: { type: 'number' },
    tags: { 
      type: 'array',
      items: { type: 'string' }
    }
  },
  required: ['name', 'age']
};

const result = await provider.generateObject({
  messages: [{ role: 'user', content: 'Extract data...' }],
  schema: jsonSchema
});

Common Use Cases

Data Extraction

const ExtractedDataSchema = z.object({
  entities: z.array(z.object({
    name: z.string(),
    type: z.enum(['person', 'organization', 'location']),
    confidence: z.number().min(0).max(1)
  })),
  summary: z.string()
});

const agent = new Agent({
  instructions: 'Extract named entities from text',
  llm: 'openai/gpt-4o-mini'
});

const result = await agent.generateObject({
  prompt: 'Apple Inc. announced that Tim Cook will visit Tokyo next week.',
  schema: ExtractedDataSchema
});

Classification

const ClassificationSchema = z.object({
  category: z.enum(['spam', 'ham', 'uncertain']),
  confidence: z.number(),
  reasoning: z.string()
});

const result = await agent.generateObject({
  prompt: 'Classify this email: "You won $1,000,000! Click here!"',
  schema: ClassificationSchema
});
// { category: "spam", confidence: 0.95, reasoning: "..." }

Sentiment Analysis

const SentimentSchema = z.object({
  sentiment: z.enum(['positive', 'negative', 'neutral']),
  score: z.number().min(-1).max(1),
  aspects: z.array(z.object({
    aspect: z.string(),
    sentiment: z.enum(['positive', 'negative', 'neutral'])
  }))
});

API Response Generation

const APIResponseSchema = z.object({
  success: z.boolean(),
  data: z.object({
    id: z.string(),
    createdAt: z.string(),
    attributes: z.record(z.string())
  }),
  meta: z.object({
    version: z.string(),
    requestId: z.string()
  })
});

Error Handling

try {
  const result = await agent.generateObject({
    prompt: 'Extract data...',
    schema: MySchema
  });
  console.log(result.object);
} catch (error) {
  if (error.code === 'VALIDATION_ERROR') {
    console.error('Schema validation failed:', error.message);
  } else if (error.code === 'RATE_LIMIT') {
    console.error('Rate limited, retry later');
  } else {
    console.error('Generation failed:', error.message);
  }
}

Options

const result = await provider.generateObject({
  messages: [...],
  schema: MySchema,
  
  // Generation options
  maxTokens: 1000,
  temperature: 0.1,  // Lower for more deterministic output
  
  // Retry options
  maxRetries: 3,
  
  // Timeout
  timeout: 30000
});

TypeScript Integration

Full type safety with inferred types:
import { z } from 'zod';

const UserSchema = z.object({
  id: z.number(),
  name: z.string(),
  email: z.string().email()
});

// Type is inferred from schema
type User = z.infer<typeof UserSchema>;

const result = await agent.generateObject({
  prompt: 'Create a user',
  schema: UserSchema
});

// result.object is typed as User
const user: User = result.object;
console.log(user.name); // TypeScript knows this is string

Best Practices

  1. Use specific schemas: More specific schemas produce better results
  2. Add descriptions: Use .describe() to help the model understand fields
  3. Lower temperature: Use temperature: 0.1 for consistent output
  4. Validate output: Always validate the returned object matches expectations
  5. Handle errors: Implement proper error handling for validation failures
const DetailedSchema = z.object({
  title: z.string().describe('A concise title for the item'),
  description: z.string().describe('Detailed description, 2-3 sentences'),
  tags: z.array(z.string()).describe('Relevant tags, max 5'),
  priority: z.number().min(1).max(5).describe('Priority from 1 (low) to 5 (high)')
});

Multi-Agent Structured Output

Use structured output in multi-agent workflows:
import { Agent, Agents } from 'praisonai';

const analyzer = new Agent({
  instructions: 'Analyze text and extract key points',
  llm: 'openai/gpt-4o-mini'
});

const summarizer = new Agent({
  instructions: 'Create structured summaries',
  llm: 'openai/gpt-4o-mini'
});

const SummarySchema = z.object({
  title: z.string(),
  keyPoints: z.array(z.string()),
  sentiment: z.enum(['positive', 'negative', 'neutral']),
  wordCount: z.number()
});

// Chain agents with structured output at the end
const agents = new Agents([analyzer, summarizer]);
const result = await agents.start();

// Get structured output from final agent
const structured = await summarizer.generateObject({
  prompt: result,
  schema: SummarySchema
});