Laravel Typesafe AI responses with Prism and DTOs

March 10, 2025 · 4 min read

When working with AI models like OpenAI, handling responses in a type-safe and predictable way can be challenging. In this tutorial, we’ll explore how to create type-safe AI responses using Laravel, Prism, and Data Transfer Objects (DTOs). By the end of this guide, you’ll be able to build reliable AI-powered applications with structured and consistent data.
In an app we are building for a client using FilamentPHP for our admin panel, we’re handling a huge dataset of user comments. We analyze these comments with OpenAI to pull out useful insights for our client. While doing this, we realized how valuable it is to use type-safe results. We thought we’d share this method with you so you can try it in your projects and see the benefits for yourself.
Prerequisites
Before we dive in, make sure you have the following setup:
A Laravel project
Prismpackage installed:composer require echolabsdev/prismLaravel Promptspackage installed:composer require laravel/prompts( optional: this is used only for this blog post )An OpenAI API key added to your
.envfile asOPENAI_API_KEY
These tools will help us create a structured and type-safe AI response system.
Laravel AI project example
We’ll create a console command that analyzes the sentiment of a given review. Here’s what the command will do:
Accept user input through a terminal prompt
Use Prism to make a structured request to OpenAI
Return a type-safe response using a DTO
By the end of this tutorial, you’ll have a working example of handling AI responses in a type-safe manner. This is just a simpler example to explain the benefits of using this combination.
Using Prism and DTOs for Laravel Typesafe AI responses
Let’s break down the implementation into three main parts: the console command, the prompt view, and the DTO.
Step 1: Building the Console Command
Here’s the implementation of the SentimentAnalysis console command:
namespace App\Console\Commands;
use App\Data\SentimentData;
use Prism\Prism\Enums\Provider;
use Prism\Prism\Prism;
use Prism\Prism\Schema\EnumSchema;
use Prism\Prism\Schema\NumberSchema;
use Prism\Prism\Schema\ObjectSchema;
use Illuminate\Console\Command;
use function Laravel\Prompts\textarea;
class SentimentAnalysis extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'sentiment';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Analyze the sentiment of a review';
/**
* Execute the console command.
*/
public function handle()
{
$text = textarea('Enter the review:');
$response = Prism::structured()
->using(Provider::OpenAI, 'gpt-4o')
->withProviderMeta(Provider::OpenAI, [
'schema' => [
'strict' => true,
],
])
->withSchema($this->schema())
->withPrompt(view('prompts.sentiment', ['text' => $text])->render())
->generate();
$sentimentData = SentimentData::fromResponse($response->structured);
$this->info(print_r($sentimentData, true));
}
protected function schema(): ObjectSchema
{
return new ObjectSchema(
name: 'sentiment',
description: 'A sentiment analysis of a review',
properties: [
new EnumSchema('sentiment', 'The sentiment of the review', ['positive', 'negative']),
new NumberSchema('score', 'The score of the sentiment, between 0 and 100'),
],
requiredFields: ['sentiment', 'score']
);
}
}Explaining the Sentiment Analysis
The
SentimentAnalysisclass is a Laravel console command that prompts the user for input and processes the response.We’re using Prism to make a structured request to OpenAI. This ensures that the response matches our expected schema.
The
schema()method defines the expected structure of the response, ensuring type safety.The response is mapped to a DTO (
SentimentData) for easy consumption in the application.
Integrating LLM into Laravel using Prism
Prism is a great Laravel package that simplifies the integration of Large Language Models (LLMs), allowing developers to easily switch between AI providers and generate text. With features like Structured Output Handling and Multi-modal Capabilities, Prism improves your application’s functionality while maintaining reliable performance.
Step 2: Creating the Prompt View
Here’s the prompt view that defines how we want the AI to format its response. We like to store these prompts in resources/views/prompts
You are given the text of reviews and your task is to determine the sentiment of the review in the following steps:
1. Identify a list of emotions that the writer expresses, not just positive nor negative.
2. Quote the phrases that are related to the identified emotions.
3. Give the sentiment of the review in a single word either "positive" or "negative" and verify that the sentiment is correct.
4. Give a score between 0 and 100 for the sentiment of the review.
Sentiment:
{{ $text }}Why this matters?
Clear instructions: The prompt view provides clear instructions to the AI, ensuring consistent responses.
Structured output: By structuring the prompt, we can better parse the response and map it to our DTO.
Step 3: Using Laravel DTO
Here’s the DTO that maps the response to type-safe properties:
namespace App\Data;
// PHP8.2+
final readonly class SentimentData
{
public function __construct(
public string $sentiment,
public int $score,
) {}
public static function fromResponse(array $response): self
{
return new self(
sentiment: $response['sentiment'],
score: $response['score'],
);
}
}Why use Laravel DTOs?
Type Safety: The DTO ensures that the response data is type-safe and predictable.
Encapsulation: The DTO encapsulates the response data, making it easier to work within your application.
Immutability: The
readonlyclass ensures that the data cannot be modified after creation.
Internaly, we prefer to use Laravel Data, as its packed with good features such as Typescript transformation, Validation, etc.
Running our Sentiment command
To test the command, run:
php artisan sentimentFollow the prompt to enter your review text, and you’ll receive a type-safe response with the sentiment analysis.
The Laravel command is used only as an example, in a real-world application you would handle the DTO in a Model or something similar.
Conclusion
This approach can be extended to any kind of AI response, making it a powerful pattern for building reliable AI-powered applications with Laravel. With type-safe responses, you can write more maintainable and predictable code, ensuring your application works as expected, no surprises.
Bring Your Ideas to Life 🚀
If you need help with a Laravel project let’s get in touch.
Lucky Media is proud to be recognized as a leading Laravel Development Agency
Technologies

Stay up-to-date
Be updated with all news, products and tips we share!

