🧠 Laravel AI SDK : construire des applications intelligentes avec Laravel
📚 Introduction
Jusqu’ici, intégrer une fonctionnalité IA dans une application Laravel passait par un patchwork de SDK officiels (OpenAI, Anthropic, Google), de wrappers communautaires plus ou moins maintenus, et beaucoup de glue code pour gérer le retry, le streaming, les tool calls et les structured outputs.
Avec la sortie du Laravel AI SDK officiel (en même temps que Laravel 13), tout cela rentre dans le rang. C’est un package maintenu par Laravel, installable via Composer, qui offre une API unifiée pour les providers majeurs : OpenAI, Anthropic, Gemini, Groq, xAI, DeepSeek, Mistral, Cohere, Azure, Bedrock, Ollama, OpenRouter, ElevenLabs… Texte, images, audio, transcription, embeddings, reranking, vector stores : tout y passe, avec des helpers de test natifs.
🚀 Installation
composer require laravel/ai
php artisan vendor:publish --provider="Laravel\Ai\AiServiceProvider"
php artisan migrateOn déclare ensuite les clés API dans le .env :
ANTHROPIC_API_KEY=...
OPENAI_API_KEY=...
GEMINI_API_KEY=...🤖 Premier agent
Le SDK est résolument orienté objet : un agent = une classe. La commande Artisan make:agent scaffolde le squelette :
php artisan make:agent SalesCoachnamespace App\Ai\Agents;
use Laravel\Ai\Contracts\Agent;
use Laravel\Ai\Promptable;
use Stringable;
class SalesCoach implements Agent
{
use Promptable;
public function instructions(): Stringable|string
{
return 'You are a sales coach, analyzing transcripts and providing feedback.';
}
}Côté contrôleur, on l’invoque comme n’importe quel service :
use App\Ai\Agents\SalesCoach;
$response = (new SalesCoach)
->prompt('Analyze this sales transcript...');
return (string) $response;On peut surcharger le provider et le modèle pour un prompt précis :
use Laravel\Ai\Enums\Lab;
$response = (new SalesCoach)->prompt(
'Analyze this sales transcript...',
provider: Lab::Anthropic,
model: 'claude-haiku-4-5-20251001',
timeout: 120,
);🧱 Structured Output
C’est probablement la fonctionnalité qui transforme le plus la façon de construire des features IA. Au lieu de parser du texte ou du JSON à la main, on déclare un schéma typé et on récupère un tableau validé :
use Illuminate\Contracts\JsonSchema\JsonSchema;
use Laravel\Ai\Contracts\Agent;
use Laravel\Ai\Contracts\HasStructuredOutput;
use Laravel\Ai\Promptable;
class SalesCoach implements Agent, HasStructuredOutput
{
use Promptable;
public function instructions(): string
{
return 'You are a sales coach...';
}
public function schema(JsonSchema $schema): array
{
return [
'feedback' => $schema->string()->required(),
'score' => $schema->integer()->min(1)->max(10)->required(),
];
}
}$response = (new SalesCoach)->prompt('Analyze this...');
return $response['score']; // accès direct au champ typéLes schémas supportent les objets imbriqués, les tableaux d’objets, les enums, les contraintes (min/max/required), ce qui couvre la grande majorité des besoins métier.
🛠️ Tools : laisser l’agent appeler du code Laravel
Un tool est une classe Laravel\Ai\Contracts\Tool avec une description, un schéma de paramètres et une méthode handle() :
php artisan make:tool RandomNumberGeneratornamespace App\Ai\Tools;
use Illuminate\Contracts\JsonSchema\JsonSchema;
use Laravel\Ai\Contracts\Tool;
use Laravel\Ai\Tools\Request;
class RandomNumberGenerator implements Tool
{
public function description(): string
{
return 'Generate cryptographically secure random numbers.';
}
public function handle(Request $request): string
{
return (string) random_int($request['min'], $request['max']);
}
public function schema(JsonSchema $schema): array
{
return [
'min' => $schema->integer()->min(0)->required(),
'max' => $schema->integer()->required(),
];
}
}Côté agent, on déclare les tools via HasTools :
use Laravel\Ai\Contracts\HasTools;
class SalesCoach implements Agent, HasTools
{
use Promptable;
public function tools(): iterable
{
return [
new RandomNumberGenerator,
];
}
}Le SDK orchestre automatiquement la boucle prompt → tool call → résultat → relance. Pas de parsing manuel, pas de gestion des tool_calls à la main.
🌐 Provider Tools : WebSearch, WebFetch, FileSearch
Trois tools fournis nativement et exécutés côté provider :
use Laravel\Ai\Providers\Tools\FileSearch;
use Laravel\Ai\Providers\Tools\WebFetch;
use Laravel\Ai\Providers\Tools\WebSearch;
public function tools(): iterable
{
return [
(new WebSearch)->max(5)->allow(['laravel.com', 'php.net']),
(new WebFetch)->max(3)->allow(['docs.laravel.com']),
new FileSearch(stores: ['store_id'], where: [
'author' => 'Taylor Otwell',
'year' => 2026,
]),
];
}L’agent peut chercher sur le web, fetcher une page précise, ou interroger un vector store géré par le provider. Filtrage par métadonnée inclus.
🔁 Streaming et broadcasting
Le streaming est intégré au framework :
Route::get('/coach', function () {
return (new SalesCoach)->stream('Analyze this sales transcript...');
});On peut chainer un callback après la fin du stream, itérer manuellement, ou même streamer au format Vercel AI SDK Protocol pour brancher un front Next.js / React :
return (new SalesCoach)
->stream('Analyze this...')
->usingVercelDataProtocol();Le SDK supporte aussi le broadcast direct sur un canal :
use Illuminate\Broadcasting\Channel;
(new SalesCoach)->broadcastOnQueue(
'Analyze this sales transcript...',
new Channel('coach.{user-id}'),
);Idéal pour un dashboard temps réel sans monter d’infrastructure additionnelle.
🧠 Conversations persistantes
Les agents peuvent gérer leur historique de conversation automatiquement via les traits Conversational et RemembersConversations :
use Laravel\Ai\Concerns\RemembersConversations;
use Laravel\Ai\Contracts\Conversational;
class SalesCoach implements Agent, Conversational
{
use Promptable, RemembersConversations;
}$response = (new SalesCoach)->forUser($user)->prompt('Hello!');
$conversationId = $response->conversationId;
// Plus tard…
$response = (new SalesCoach)
->continue($conversationId, as: $user)
->prompt('Tell me more about that.');On ajoute aussi HasConversations sur le modèle User pour exposer $user->conversations(). Plus besoin de gérer le stockage et la reprise de contexte à la main.
📎 Attachments : PDF, images, fichiers uploadés
Tous les agents acceptent des attachments :
use Laravel\Ai\Files;
$response = (new SalesCoach)->prompt(
'Analyze the attached sales transcript.',
attachments: [
Files\Document::fromStorage('transcript.pdf'),
Files\Image::fromUrl('https://example.com/photo.jpg'),
$request->file('transcript'),
],
);Compatible avec Storage (disques Laravel), URLs distantes, paths locaux et UploadedFile Symfony.
🖼️ Image, Audio, Transcription
Trois modalités complémentaires utilisent une API fluide cohérente :
use Laravel\Ai\Audio;
use Laravel\Ai\Image;
use Laravel\Ai\Transcription;
$image = Image::of('A donut sitting on the kitchen counter')
->quality('high')
->landscape()
->generate();
$path = $image->store(); // Storage::disk('local')
$audio = Audio::of('I love coding with Laravel.')
->female()
->instructions('Said like a pirate')
->generate();
$transcript = Transcription::fromStorage('audio.mp3')
->diarize()
->generate();Et toutes ces opérations sont queueable :
Image::of('A donut...')
->portrait()
->queue()
->then(fn ($image) => $image->store());🔍 Embeddings et RAG
Pour la recherche sémantique, le SDK couvre l’ensemble du pipeline :
use Illuminate\Support\Str;
use Laravel\Ai\Embeddings;
// Un seul texte
$embeddings = Str::of('Napa Valley has great wine.')->toEmbeddings();
// Plusieurs textes
$response = Embeddings::for([
'Napa Valley has great wine.',
'Laravel is a PHP framework.',
])->generate();Côté base de données, des helpers Schema et des macros Eloquent gèrent les colonnes vectorielles (PostgreSQL pgvector ou équivalent) :
Schema::ensureVectorExtensionExists();
Schema::create('documents', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('content');
$table->vector('embedding', dimensions: 1536)->index();
$table->timestamps();
});Et la recherche par similarité devient triviale :
$documents = Document::query()
->whereVectorSimilarTo('embedding', 'best wineries in Napa Valley')
->limit(10)
->get();Le SDK gère automatiquement la génération de l’embedding à partir de la chaîne de recherche. Pour les cas avancés : selectVectorDistance, whereVectorDistanceLessThan, orderByVectorDistance, et caching natif des embeddings.
🏷️ Reranking
Pour affiner un classement de résultats par pertinence (Cohere, Jina, VoyageAI) :
use Laravel\Ai\Reranking;
$response = Reranking::of([
'Django is a Python web framework.',
'Laravel is a PHP web application framework.',
'React is a JavaScript library.',
])->rerank('PHP frameworks');
$response->first()->document; // 'Laravel is a PHP web application framework.'
$response->first()->score; // 0.95Le reranking s’applique aussi directement sur une Collection Eloquent :
$posts = Post::all()->rerank(['title', 'body'], 'Laravel tutorials');C’est la deuxième brique d’une stack RAG sérieuse : embeddings pour le rappel, reranking pour la précision.
📚 Vector Stores
Pour les usages où l’on souhaite déléguer le stockage et l’indexation au provider (OpenAI, Anthropic, Gemini) :
use Laravel\Ai\Files\Document;
use Laravel\Ai\Stores;
$store = Stores::create(
name: 'Knowledge Base',
description: 'Documentation and reference materials.',
expiresWhenIdleFor: days(30),
);
$store->add(Document::fromPath('/path/to/document.pdf'), metadata: [
'author' => 'Taylor Otwell',
'department' => 'Engineering',
]);Le tool FileSearch peut ensuite cibler ce store depuis n’importe quel agent.
⚙️ Configuration via attributs PHP
Comme le reste de Laravel 13, le SDK profite des attributs PHP pour la configuration par défaut d’un agent :
use Laravel\Ai\Attributes\{MaxSteps, MaxTokens, Model, Provider, Temperature, Timeout};
use Laravel\Ai\Enums\Lab;
#[Provider(Lab::Anthropic)]
#[Model('claude-haiku-4-5-20251001')]
#[MaxSteps(10)]
#[MaxTokens(4096)]
#[Temperature(0.7)]
#[Timeout(120)]
class SalesCoach implements Agent
{
use Promptable;
}Deux raccourcis particulièrement utiles : #[UseCheapestModel] et #[UseSmartestModel], qui basculent automatiquement vers le bon modèle selon l’usage. Voir aussi mon post sur les attributs Laravel 13.
🔁 Failover automatique entre providers
Une des fonctionnalités les plus pragmatiques du SDK :
$response = (new SalesCoach)->prompt(
'Analyze this sales transcript...',
provider: [Lab::OpenAI, Lab::Anthropic],
);Si OpenAI est down ou que la quota est dépassée, le SDK retombe automatiquement sur Anthropic. Idem côté image et audio.
🧪 Testing intégré
Le SDK livre des helpers fake() pour chaque capacité : agents, images, audio, transcriptions, embeddings, reranking, files, stores.
use App\Ai\Agents\SalesCoach;
use Laravel\Ai\Prompts\AgentPrompt;
SalesCoach::fake([
'First response',
'Second response',
]);
// ou dynamique
SalesCoach::fake(function (AgentPrompt $prompt) {
return 'Response for: '.$prompt->prompt;
});Et les assertions habituelles :
SalesCoach::assertPrompted('Analyze this...');
SalesCoach::assertNeverPrompted();
SalesCoach::fake()->preventStrayPrompts();Le même pattern existe pour Image::fake(), Audio::fake(), Embeddings::fake(), Reranking::fake(), Files::fake(), Stores::fake(). Pour la première fois côté PHP, on peut tester des features IA sans hacker autour d’un mock HTTP.
🧩 Cohérence avec l’écosystème Laravel 13
Le SDK s’intègre naturellement avec les autres briques modernes de Laravel :
- les attributs PHP de Laravel 13 pour annoter agents et tools,
- Laravel Boost pour exposer l’application à un agent externe via MCP,
- Laravel PAO pour que cet agent comprenne aussi la sortie des outils PHP,
- Laravel Pail pour suivre en temps réel les appels d’agents pendant le développement.
L’ensemble forme une stack cohérente : votre application Laravel devient à la fois un consommateur d’IA (via le SDK) et un environnement exploitable par des agents externes (via Boost et PAO).
⚠️ Quelques précautions
- Coûts et quotas : chaque appel a un coût. Logger les usages et fixer des budgets par provider est indispensable dès le premier déploiement.
- PII et RGPD : ne jamais envoyer de données personnelles non anonymisées à un provider distant sans validation juridique. Pour les sujets sensibles, basculer sur un provider local (Ollama via base URL custom).
- Versionner les prompts et les schémas : ils sont du code applicatif. Mettez-les dans des classes dédiées, testez avec
fake(). - Évaluer la qualité : profitez du structured output pour bâtir un harness d’évaluation simple avec des fixtures.
🎉 Conclusion
Le Laravel AI SDK officiel transforme l’expérience de construction d’applications IA côté PHP. Avec une API unifiée orientée objet, des structured outputs natifs, un système d’agents + tools convaincant, le support du RAG (embeddings + reranking + vector stores) et un toolkit de tests complet, c’est exactement ce qui manquait pour que Laravel soit un choix sérieux dans la nouvelle génération d’applications.
Si vous avez un cas d’usage IA dans le pipeline (extraction documentaire, classification, agent métier, recherche sémantique, génération assistée), c’est le package à installer cette semaine.