Define response schemas to receive type-safe, predictable data from your AI agents using DataModels or array schemas.
Structured output constrains the LLM to return JSON matching your defined schema. Instead of parsing free-form text, you get predictable data structures that integrate seamlessly with your application.
Define a DataModel and use it as your response schema:
Copy
use LarAgent\Core\Abstractions\DataModel;use LarAgent\Attributes\Desc;class WeatherInfo extends DataModel{ #[Desc('The city name')] public string $city; #[Desc('Temperature in Celsius')] public float $temperature; #[Desc('Weather condition')] public string $condition;}
Copy
class WeatherAgent extends Agent{ protected $responseSchema = WeatherInfo::class; public function instructions() { return 'Provide weather information for the requested location.'; }}
Copy
$weather = WeatherAgent::ask('What is the weather in Paris?');echo $weather->city; // 'Paris'echo $weather->temperature; // 18.5echo $weather->condition; // 'Partly cloudy'
For dynamic schemas or complex logic, override the structuredOutput() method:
Copy
class DynamicAgent extends Agent{ public function structuredOutput() { // Dynamically choose schema based on context if ($this->requiresDetailedResponse()) { return DetailedReport::generateSchema(); } return SummaryReport::generateSchema(); } // Enable automatic DataModel reconstruction public function getResponseSchemaClass(): ?string { return $this->requiresDetailedResponse() ? DetailedReport::class : SummaryReport::class; }}
When you override structuredOutput(), also override getResponseSchemaClass() to enable automatic DataModel reconstruction. Or skip if you want response returned as array.
class UserProfile extends DataModel{ public string $name; // Text public int $age; // Integer public float $score; // Decimal public bool $isActive; // Boolean public array $tags; // Generic array public ?string $nickname; // Nullable (optional) public UserStatus $status; // Enum (string-backed or int-backed) public Address $address; // Nested DataModel public SkillArray $skills; // DataModelArray: collection of DataModels}
Add descriptions to guide the LLM on what each field should contain:
Copy
use LarAgent\Attributes\Desc;class ContactInfo extends DataModel{ #[Desc('Full legal name of the person')] public string $name; #[Desc('Valid email address format')] public string $email; #[Desc('Phone number with country code')] public ?string $phone = null;}
Descriptive #[Desc] attributes significantly improve the quality and accuracy of extracted data.
class Article extends DataModel{ #[Desc('Article title')] public string $title; #[Desc('Article subtitle (optional)')] public ?string $subtitle = null; #[ExcludeFromSchema] public string $status = 'draft';}
Use #[ExcludeFromSchema] to exclude properties from the schema passed to the LLM.
These properties wonβt be affected by the AI response β they remain
completely controlled by you with their default values and defined methods.
// Represents sentiment analysis for a single reviewclass ReviewSentiment extends DataModel{ #[Desc('Overall sentiment: positive, negative, or neutral')] public string $sentiment; #[Desc('Confidence score from 0.0 to 1.0')] public float $confidence; #[Desc('Key points from the review')] public array $keyPoints;}
App/DataModels/ReviewSentimentArray.php
Copy
// Typed collection of ReviewSentiment instancesclass ReviewSentimentArray extends DataModelArray{ public static function allowedModels(): array { return [ReviewSentiment::class]; }}
App/DataModels/ReviewAnalysis.php
Copy
// Complete analysis result containing all reviews and summaryclass ReviewAnalysis extends DataModel{ #[Desc('Product being reviewed')] public string $productName; #[Desc('Average sentiment score')] public float $averageScore; #[Desc('Individual review analyses')] public ReviewSentimentArray $reviews; #[Desc('Summary recommendation')] public string $recommendation;}
App/AiAgents/ReviewAnalyzerAgent.php
Copy
// Agent that analyzes product reviews using the ReviewAnalysis schemaclass ReviewAnalyzerAgent extends Agent{ protected $model = 'gpt-4o'; protected $responseSchema = ReviewAnalysis::class; public function instructions() { return 'Analyze product reviews and provide sentiment analysis.'; }}
Copy
$reviews = <<<REVIEWS1. "Great product! Fast shipping, excellent quality."2. "Decent but overpriced. Works as expected."3. "Disappointed. Broke after a week."REVIEWS;// Analyze reviews and get structured response$analysis = ReviewAnalyzerAgent::ask("Analyze these reviews:\n{$reviews}");echo "Product: {$analysis->productName}\n";echo "Average Score: {$analysis->averageScore}\n";echo "Recommendation: {$analysis->recommendation}\n";foreach ($analysis->reviews as $review) { echo "- {$review->sentiment} ({$review->confidence})\n";}