Skip to main content
Laravel, building with AI.

Chapter 1

The Boundary

Julian Beaujardin

The most valuable thing in this chapter is how unremarkable it is.

We are going to build an endpoint that sends a prompt to a provider and returns what comes back. There is no cleverness in it. What there is instead is a boundary: one place where the provider is described, one class per thing the application wants from a model, and one set of decisions about credentials, timeouts and retries that every future AI feature inherits for free.

Get this wrong and you will pay for it in every chapter that follows. Get it right and most of the remaining chapters become small.

Start From the Wrong Place, Briefly

Here is what almost everybody writes first, and it is worth looking at honestly, because it is not stupid. It is just unfinished.

public function generate(Request $request): JsonResponse
{
    $response = Http::withToken(
        config('services.openai.token')
    )->post('https://api.provider.example/v1/responses', [
        'model' => 'some-model',
        'input' => $request->input('prompt'),
    ]);

    return response()->json([
        'content' => $response->json(
            'output.0.content.0.text',
        ),
    ]);
}

This works. On a good day it works every time.

What it lacks is every decision you have not made yet. There is no timeout, so a slow provider holds this worker until PHP gives up. There is no check that the credential exists, so an empty one is sent as an empty bearer and comes back as an authentication error that blames you for something you did not do. Nothing limits what the answer may cost. The provider’s URL and payload shape are welded to a controller, so the day you add a second provider, or the day this one renames a field, you will be editing controllers.

And critically, there is nowhere to put the next decision. When you learn something about calling this provider, this shape gives you no place to record it.

Install the SDK, Then Decide Everything It Decided

Laravel now ships a first-party package for exactly this layer.

composer require laravel/ai
php artisan vendor:publish \
    --provider="Laravel\Ai\AiServiceProvider"
php artisan migrate

The AI SDK gives you a provider abstraction across a dozen vendors, agent classes, structured output, tools, streaming, queueing, failover and fakes for your tests. Until recently, a chapter like this one built a manager and a driver by hand to get the first of those. You no longer need to, and you should not. A provider boundary you maintain yourself is a boundary you have to keep current with every vendor’s changes, and the framework team now does that for you.

What the SDK cannot do is make your decisions. It has to ship with defaults, and every default is a decision somebody made without knowing your product. Read them as a list of questions:

The SDK’s default The question it answers for you
A 60-second HTTP timeout How long may one request hold this worker?
No output cap unless you set one, so the provider’s maximum applies What may one answer cost?
Up to 25 tool steps, derived from how many tools you register How long may the model keep going?
One retry on a rate limit whose Retry-After is ten seconds or less Which failures are worth waiting for?
Credentials read from config/ai.php, one key per provider Who pays for this call?

None of those defaults is wrong. Each one is a reasonable answer for nobody in particular. This chapter replaces the ones that matter with answers for you, and the rest of the book keeps doing it.

Checkout

Opening secure checkout

The audio could not be loaded. Try again in a moment.

Members only. Sign in to listen, it is free. Sign in