AI

How to Use an AI SDK in Laravel

Learn how to connect an AI SDK to Laravel for chat, content generation, and internal automation—with safe key handling, timeouts, queues, and output validation.

Editorial featured image for: How to Use an AI SDK in Laravel

Introduction

Laravel is a natural place to run AI features: generate drafts, summarize tickets, classify support messages, or power an internal assistant. The hard part is not calling a model once—it is wiring the SDK so keys stay safe, requests do not block users, and model output is validated before you trust it.

This tutorial walks through a practical pattern for using an AI SDK inside a Laravel app.

What you will build

  • An AI client bound in the service container
  • A thin service for chat / text generation
  • A queued Job for slow requests
  • Basic validation and logging around model output

Prerequisites

  • Laravel 10 or 11
  • PHP 8.1+
  • An API key from your AI provider
  • Queue driver configured for production (database or redis)

Step 1: Store secrets correctly

Never hardcode API keys. Put them in .env and map them through config/:

AI_API_KEY=
AI_BASE_URL=https://api.openai.com/v1
AI_MODEL=gpt-4.1-mini
AI_TIMEOUT=30
// config/services.php
'ai' => [
    'key' => env('AI_API_KEY'),
    'base_url' => env('AI_BASE_URL'),
    'model' => env('AI_MODEL', 'gpt-4.1-mini'),
    'timeout' => (int) env('AI_TIMEOUT', 30),
],

Step 2: Install and bind the SDK

Exact package names differ by provider. The important part is a single application service that wraps the vendor client:

composer require openai-php/laravel
php artisan vendor:publish --provider="OpenAI\Laravel\ServiceProvider"
namespace App\Services\AI;

use OpenAI\Client;

class TextGenerator
{
    public function __construct(
        private Client $client,
        private string $model
    ) {}

    public function complete(string $system, string $user): string
    {
        $response = $this->client->chat()->create([
            'model' => $this->model,
            'messages' => [
                ['role' => 'system', 'content' => $system],
                ['role' => 'user', 'content' => $user],
            ],
            'temperature' => 0.3,
        ]);

        return trim((string) ($response->choices[0]->message->content ?? ''));
    }
}
// AppServiceProvider
$this->app->singleton(TextGenerator::class, function () {
    return new TextGenerator(
        client: \OpenAI::client(config('services.ai.key')),
        model: config('services.ai.model'),
    );
});

Adjust the client construction to match the SDK you chose. Keep one binding so Controllers never build clients ad hoc.

Step 3: Call it from a Controller (short requests only)

use App\Services\AI\TextGenerator;
use Illuminate\Http\Request;

public function summarize(Request $request, TextGenerator $ai)
{
    $data = $request->validate([
        'text' => ['required', 'string', 'max:8000'],
    ]);

    $summary = $ai->complete(
        'Summarize the text in 3 bullet points. No fluff.',
        $data['text']
    );

    abort_if($summary === '', 502, 'Empty model response');

    return response()->json(['summary' => $summary]);
}

Use synchronous calls only when latency is acceptable. Anything that may take several seconds should go to a Queue.

Step 4: Move slow work to a Job

php artisan make:job GenerateArticleDraft
namespace App\Jobs;

use App\Models\Post;
use App\Services\AI\TextGenerator;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;

class GenerateArticleDraft implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public int $tries = 3;
    public int $timeout = 90;

    public function __construct(public Post $post) {}

    public function handle(TextGenerator $ai): void
    {
        $draft = $ai->complete(
            'Write a clear technical article draft in Markdown.',
            'Topic: ' . $this->post->title
        );

        $this->post->update([
            'content' => $draft,
            'status' => 'draft',
        ]);
    }
}
GenerateArticleDraft::dispatch($post);

Step 5: Validate model output

Treat LLM text as untrusted input:

  • Reject empty responses
  • Enforce max length before saving
  • Strip or escape HTML if the output will be rendered
  • For structured tasks, ask for JSON and decode with validation rules
$json = $ai->complete(
    'Return JSON only with keys title and outline (array of strings).',
    $topic
);

$data = json_decode($json, true);
abort_if(! is_array($data), 422, 'Invalid AI JSON');

$validated = validator($data, [
    'title' => ['required', 'string', 'max:160'],
    'outline' => ['required', 'array', 'min:3'],
    'outline.*' => ['string', 'max:200'],
])->validate();

Best practices

  • Keep prompts in classes or config—not scattered across Controllers
  • Log model, latency, and failure reasons (never log full secrets)
  • Add rate limiting on public AI endpoints
  • Prefer draft-first flows for generated content
  • Write feature tests with a fake client so CI does not call the live API

Common mistakes

  • Putting AI_API_KEY in the repository
  • Calling the model inside a web request that users must wait on
  • Saving raw HTML from the model without sanitizing
  • No timeout / retry strategy
  • One giant “do everything” prompt instead of narrow tasks

Conclusion

Using an AI SDK in Laravel is mostly good engineering: config for secrets, a service boundary for the vendor client, queues for slow work, and validation before persistence. Once that skeleton exists, swapping models or providers becomes a small change instead of a rewrite.

FAQ

Which AI SDK should I pick?

Pick the official or well-maintained client for your provider, then wrap it. Your app should depend on TextGenerator, not on vendor classes everywhere.

Can I stream responses in Laravel?

Yes, many SDKs support streaming. Use it for chat UIs; keep queued Jobs for batch generation.

Do I need Redis?

Not to start. database queues work. Redis helps when AI traffic and retries grow.

Leave a Reply

Your email address will not be published. Required fields are marked *