Laravel + AI: Slimmere applicaties bouwen

Laatst bijgewerkt:

Leestijd: 8 min

Laravel + AI: Slimmere applicaties bouwen

De meeste gesprekken over het "toevoegen van AI" aan een webapplicatie beginnen met een bedrijfsdoel: supportreacties automatiseren, gebruikers in gewone taal laten zoeken, leads automatisch kwalificeren, een berg ongestructureerde data samenvatten. Ze beginnen zelden met "laten we een AI-leverancier kiezen en zelf een HTTP-client bouwen." Toch was dat tweede deel jarenlang onvermijdelijk als je op Laravel wilde bouwen.
Dat veranderde met de Laravel AI SDK, een eigen package van Laravel die stabiel werd naast Laravel 13. Het biedt Laravel-applicaties één consistente manier om te werken met OpenAI, Anthropic, Google Gemini, Groq, xAI en andere providers, samen met de bouwstenen (agents, tools, gestructureerde output, streaming en vectorzoeken) die nodig zijn om "we zouden AI moeten toevoegen" om te zetten in een uitgeleverde functie.

Deze post laat zien hoe dat er in de praktijk uitziet.

Waarom dit meer is dan hype

Voordat we bij de code komen, is het de moeite waard om concreet te zijn over waar AI daadwerkelijk goed in is binnen een typische bedrijfsapplicatie, want "slimmere applicaties" kan heel verschillende dingen betekenen:

Support en interne tools: Een agent die vragen beantwoordt op basis van je eigen documentatie in plaats van algemene webkennis.

Semantisch zoeken: Gebruikers laten zoeken op betekenis in plaats van exacte trefwoorden, wat nuttig is voor productcatalogi, kennisbanken en CRM-gegevens.

Gestructureerde data-extractie: Rommelige input, zoals contactformulieren, geüploade documenten en supporttickets, omzetten naar schone, getypeerde data waar je applicatie mee kan werken.

Natuurlijke-taalinterfaces: Niet-technische gegevens laten opvragen ("laat me bestellingen boven $500 van vorige maand zien") zonder SQL te schrijven.

Niets hiervan vereist een data science-team. Het vereist een applicatielaag die een model kan aanroepen, de juiste context kan meegeven en iets nuttigs kan doen met een gestructureerde respons. Precies daarvoor is de AI SDK gebouwd.

Eén SDK, elke grote provider

Aan de slag gaan lijkt op het installeren van elk ander Laravel-package:

bash

composer require laravel/ai

env

OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...

Vanaf daar hoef je voor het genereren van tekst niet het aanvraagformaat van elke provider te leren:

php

use Laravel\Ai\Facades\Ai;

$response = Ai::prompt('Summarize this customer feedback in two sentences: ' . $feedback);

Van provider wisselen, of vergelijken hoe twee modellen dezelfde prompt afhandelen, is een parameterwijziging in plaats van een herschrijving:

php

$response = Ai::provider('anthropic')->prompt($feedback);

Die overdraagbaarheid is belangrijker dan het klinkt. Modelprijzen, rate limits en kwaliteit veranderen voortdurend. Een applicatie die direct is verbonden met de SDK van één leverancier, erft diens storingen en prijswijzigingen zonder gemakkelijke uitweg. Een applicatie die op de AI SDK is gebouwd, kan van provider wisselen, of automatisch tussen providers failoveren, zonder de bedrijfslogica aan te raken.

Agents: de bouwsteen voor echte functies

Voor alles wat verder gaat dan één prompt organiseert de SDK AI-logica in agentklassen in plaats van API-aanroepen over controllers te verspreiden.

bash

php artisan make:agent SupportAgent

php

class SupportAgent extends Agent
{
    public function instructions(): string
    {
        return 'You are a support assistant for Brightness Group clients. '
            . 'Answer using the provided documentation. If you are not sure, say so.';
    }

    public function tools(): array
    {
        return [
            new SearchDocumentation(),
        ];
    }
}

$response = SupportAgent::make()->prompt('How do I reset my API token?');

Omdat een agent een gewone PHP-klasse is die wordt opgelost via de servicecontainer van Laravel, gedraagt hij zich als de rest van je applicatie: hij kan via dependency injection worden ingezet, unittesten worden en worden geversioneerd in broncode, in plaats van te bestaan als een promptstring die ergens in een controller begraven ligt.

Agents tools geven

Agents worden pas echt nuttig zodra ze kunnen handelen, niet alleen reageren. Tools zijn de manier waarop je die mogelijkheid toekent, of het nu gaat om het bevragen van je eigen database, het aanroepen van een interne API, of het doorzoeken van het web.

bash

php artisan make:tool CheckOrderStatus

php

class CheckOrderStatus extends Tool
{
    public function schema(): array
    {
        return ['order_id' => 'required|integer'];
    }

    public function handle(array $input): string
    {
        $order = Order::findOrFail($input['order_id']);

        return "Order #{$order->id} is currently: {$order->status}";
    }
}

Zodra een tool is opgenomen in de tools()-methode van een agent, bepaalt het model op basis van het gesprek wanneer die wordt aangeroepen, en handelt de SDK de uitvoering ervan af en voert het resultaat terug in de respons. De door de provider beheerde tools WebSearch, WebFetch en FileSearch breiden dit verder uit, waardoor een agent live dingen kan opzoeken in plaats van alleen te vertrouwen op wat hij al weet.

Gestructureerde output voor automatisering, niet alleen gesprekken

Chatinterfaces zijn de voor de hand liggende AI-functie, maar gestructureerde output is vaak de waardevollere voor interne automatisering. In plaats van vrije tekst kun je een model dwingen om data terug te geven die overeenkomt met een schema dat je applicatie al begrijpt.

php

class LeadExtractorAgent extends Agent implements HasStructuredOutput
{
    public function outputSchema(): array
    {
        return [
            'is_qualified' => 'boolean',
            'company_size' => 'string',
            'stated_need' => 'string',
        ];
    }
}

$result = LeadExtractorAgent::make()->prompt($formSubmission);

if ($result['is_qualified']) {
    Lead::create($result);
}

Dit is het patroon achter veel praktische bedrijfsautomatisering: supporttickets classificeren, gestructureerde data uit contracten halen, of leads uit een contactformulier scoren, allemaal zonder handmatige parseerregels te schrijven die breken zodra iemand iets anders formuleert.

Semantisch zoeken en retrieval-augmented generation

Zoeken op trefwoorden faalt zodra de formulering van een gebruiker niet overeenkomt met de formulering van je data. Semantisch zoeken vergelijkt betekenis in plaats van exacte tekst, en de AI SDK bouwt dit rechtstreeks in de query builder van Laravel via embeddings en de pgvector-extensie van PostgreSQL.

php

$embedding = Str::of($product->description)->toEmbeddings();

Product::where('id', $product->id)->update(['embedding' => $embedding]);

$matches = Product::whereVectorSimilarTo('embedding', 'cozy winter jacket for hiking')
    ->limit(5)
    ->get();

Agents kunnen dit ook als tool gebruiken, via de ingebouwde SimilaritySearch-tool, zodat een support- of salesagent vragen kan beantwoorden op basis van je productcatalogus of documentatie in plaats van algemene modelkennis. Deze combinatie, relevante data ophalen en vervolgens een respons genereren op basis daarvan, is wat de meeste mensen bedoelen met retrieval-augmented generation, en het is een paar regels code in plaats van een aparte vectordatabase en integratielaag.

AI-interacties snel houden

Modelaanroepen zijn traag in vergelijking met een typische databasequery, vaak één tot enkele seconden. Twee functies pakken dit aan zonder de gebruiker naar een leeg scherm te laten staren.

Streaming stuurt tokens naar de browser terwijl het model ze genereert, zodat een respons meteen begint te verschijnen in plaats van in één keer aan te komen:

php

foreach (Ai::prompt($question)->stream() as $chunk) {
    echo $chunk;
}

Voor werk dat helemaal niet binnen de requestcyclus hoeft te gebeuren, zoals achtergrondgeneratie, batchclassificatie of geplande rapporten, zet je het in de wachtrij:

php

GenerateProductDescription::dispatch($product)->onQueue('ai');
Gespreksgeheugen zonder het zelf te bouwen

Gesprekken met meerdere beurten hebben geschiedenis nodig, en die opslaglaag zelf bouwen is omslachtig. De trait RemembersConversations regelt dit met een paar migraties:

php

class SupportAgent extends Agent
{
    use RemembersConversations;
}

$conversation = SupportAgent::make()->startConversation();
$conversation->prompt('What is your return policy?');
$conversation->prompt('And how long does a refund take?');

De tweede prompt heeft automatisch toegang tot de eerste uitwisseling, zonder dat jij berichtarrays of een aangepast databaseschema hoeft te beheren.

Praktische overwegingen voordat je live gaat


Een paar dingen zijn het waard om bewust te beslissen in plaats van pas in productie te ontdekken.

Kosten en caching. Dezelfde tekst herhaaldelijk embedden verspilt geld. De SDK ondersteunt het cachen van embeddings, zodat identieke input niet bij elke aanvraag opnieuw naar een provider wordt gestuurd.

Data die naar derden gaat. Alles wat in een prompt of tool-aanroep wordt meegegeven, verlaat doorgaans je infrastructuur en gaat naar een externe provider. Voor klantgegevens, PII, of alles wat contractueel beperkt is, vereist dit dezelfde zorgvuldigheid als elke andere integratie met derden, en providers zoals Ollama laten je modellen lokaal draaien wanneer dat belangrijk is.

Foutafhandeling. Providers hebben wel degelijk storingen en rate limits. Door een array van providers mee te geven in plaats van één, kan een aanvraag automatisch failoveren in plaats van een fout te tonen aan de gebruiker.

Agents testen. De SDK bevat een testlaag specifiek voor het mocken van modelresponses, zodat het gedrag van agents gedekt kan worden door je normale testsuite in plaats van te vertrouwen op handmatige, ad-hoc verificatie tegen een live API.

Geen van deze punten is een reden om AI-ontwikkeling te vermijden. Het zijn dezelfde soort beslissingen die je maakt bij elke externe afhankelijkheid, en de SDK geeft je de aanknopingspunten om ze goed af te handelen in plaats van ze er achteraf bij te plakken.

Waar te beginnen

Het makkelijkste startpunt is zelden een klantgerichte chatbot. Het is meestal een interne workflow met lagere inzet: inkomende supporttickets classificeren, gestructureerde data uit een formulier halen, of semantisch zoeken toevoegen aan een bestaand zoekvak. Dit soort taken is behapbaar genoeg om snel op te leveren, en ze bouwen de vertrouwdheid van het team met agents, tools en gestructureerde output op, voordat je iets klantgerichts aanpakt.

Als je team een AI-functie voor een bestaande Laravel-applicatie aan het uitwerken is, of aan het beoordelen is of een use case geschikt is voordat er engineeringtijd aan wordt besteed, is dat een gesprek dat de moeite waard is om vroeg te voeren. De architectuurbeslissingen, wat synchroon draait, wat in de wachtrij komt, welke data je infrastructuur mag verlaten, zijn veel goedkoper om goed te doen vóór de eerste regel code dan erna.