Laravel & PHP5 min lezen

Laravel 13 AI-functionaliteit bouwen die ook in productie werkt

Een praktische gids voor Laravel AI met gestructureerde uitvoer, queues, goedkeuring, evaluaties, kosten en observability.

JDoor Jeffrey Klaassen van Oorschot

De AI SDK van Laravel voelt als een echt onderdeel van het framework in plaats van een verzameling losse provider-wrappers. Dat is prettig, maar ook verraderlijk. Een nette API maakt een probabilistische afhankelijkheid niet voorspelbaar. Zo zou ik een AI-functionaliteit bouwen die ik zes maanden na de release nog steeds met vertrouwen wil beheren.

Begin met een productbeslissing, niet met een agent

Voordat ik een provider kies of een agentklasse genereer, beschrijf ik de taak in één zin. ‘Help een supportmedewerker een antwoord op te stellen op basis van een bestaande case’ is een taak. ‘Voeg AI toe aan support’ is dat niet. Die ene zin bepaalt welke context is toegestaan, hoe goede uitvoer eruitziet, wie verantwoordelijk blijft en of de functie veilig mag falen.

Ik bepaal ook of het model adviseert of handelt. Tekst opstellen die een mens controleert is iets anders dan een terugbetaling uitvoeren of rechten wijzigen. Laravel ondersteunt tools en menselijke goedkeuring, maar die goedkeuring moet echt betekenis hebben. Handelingen met financiële, destructieve of externe gevolgen krijgen een expliciete bevestiging of blijven volledig buiten de model-loop.

  • Benoem één gebruiker en één meetbare taak
  • Bepaal vooraf het maximale gevolg van een fout antwoord
  • Ontwerp de niet-AI-terugvaloptie vóór de release

Gebruik gestructureerde uitvoer als grens

Vrije tekst is prima wanneer het resultaat rechtstreeks in een tekstvak terechtkomt. Voor applicatielogica is het een slecht contract. Laravel-agents kunnen HasStructuredOutput implementeren en een JSON-schema definiëren. Ik gebruik dat zodra code een beslissing moet nemen op basis van het antwoord. Het schema bewaakt de vorm; normale domeinvalidatie bepaalt nog steeds of de waarden inhoudelijk kloppen.

Een confidence-waarde is geen waarheid. Ik gebruik die nooit als enige voorwaarde om iets automatisch vrij te geven. Zo’n waarde kan helpen om onzekere voorstellen naar een andere gebruikersflow te sturen, maar betrouwbare tests zijn gebaseerd op bekende voorbeelden en niet op de vraag of het model zichzelf overtuigend vindt.

Een klein contract voor gestructureerde uitvoer
final class SupportDraft implements Agent, HasStructuredOutput
{
    use Promptable;

    public function instructions(): string
    {
        return 'Draft a factual reply using only the supplied case history.';
    }

    public function schema(JsonSchema $schema): array
    {
        return [
            'reply' => $schema->string()->required(),
            'missing_information' => $schema->array()->items(
                $schema->string()
            )->required(),
            'needs_human_review' => $schema->boolean()->required(),
        ];
    }
}

Gebruik queues, maar maak retries veilig

Provider-calls zijn traag en mislukken soms. Een queue houdt de request snel, maar introduceert ook een lastig scenario: de provider kan klaar zijn terwijl onze worker een timeout krijgt. Daarom maak ik vóór dispatch een operation-record met een unieke sleutel, input-hash, promptversie, model, status en uiteindelijk resultaat. Een retry controleert eerst dat record en genereert niet blind opnieuw.

Modelwerk en zakelijke bijwerkingen houd ik gescheiden. De AI-job mag een actie voorstellen; een gewone applicatieservice controleert rechten en actuele toestand voordat die actie wordt uitgevoerd. Dat is nodig omdat queued context veroudert. Een terugbetaling die geldig was bij het maken van de prompt kan dertig seconden later niet meer geldig zijn.

Een evaluatieset is een test-suite voor gedrag

Ik maak een evaluatieset voordat ik prompts ga verfijnen. Twintig tot vijftig zorgvuldig beoordeelde cases zijn genoeg om te starten. Daarin zitten normale vragen, ontbrekende context, dubbelzinnigheid, prompt-injection, gegevens van een andere tenant en voorbeelden waarbij weigeren het juiste antwoord is. Elke case krijgt criteria die een mens consequent kan toepassen.

Die set draait opnieuw wanneer instructies, tools, retrieval, provider of model veranderen. Ik bewaar uitvoer en beoordeling. Een gemiddelde score kan een ernstig veiligheidsprobleem verbergen, dus autorisatie- en safety-cases volg ik afzonderlijk. Agent::fake() en prompt-asserties zijn nuttig voor deterministische applicatietests, maar vervangen geen evaluatie met een echt model.

  • Applicatietest: kreeg de juiste agent alleen toegestane context?
  • Contracttest: voldoet de uitvoer aan het schema?
  • Evaluatie: is het antwoord bruikbaar, onderbouwd en veilig?
  • Productie: hoe vaak wordt het antwoord aangepast, afgewezen of geëscaleerd?

Meet kosten en fouten per gebruikersactie

Een maandelijkse providerfactuur vertelt te weinig. Ik registreer latency, provider, model, tokens, geschatte kosten, retries, tool-calls en uitkomst bij een stabiele productactie. Laravel publiceert events rond prompts, tools, embeddings, bestanden en gegenereerde media. Dat zijn goede meetpunten, zolang logs veilige metadata bevatten en geen ruwe privégegevens.

Een fallback-model moet dezelfde evaluaties doorstaan als het primaire model. Providers interpreteren prompts en schema’s niet identiek. Ik activeer een fallback pas wanneer die dezelfde cases aankan en maak gebruik ervan zichtbaar in telemetry. Soms is ‘probeer het later opnieuw’ betrouwbaarder dan een zelfverzekerd maar aantoonbaar slechter antwoord.

Praktische checklist

  • Beschrijf eerst de taak en het maximale gevolg
  • Gebruik gestructureerde uitvoer voor applicatiebeslissingen
  • Sla een idempotente operatie op vóór queueing
  • Evalueer elke wijziging aan prompt, model, tools en retrieval
  • Meet kosten, aanpassingen, afwijzingen, latency en fallback-gebruik

Verder lezen

Laravel & PHP

Betrouwbare webhookverwerking in Laravel

Een praktische Laravel-webhookarchitectuur voor signatures, duplicaten, snelle acknowledgement, queues, ordering, herstel en observability.

5 min lezenLees artikel