inspector-apm/inspector-laravel
Inspector is a real-time APM tool for Laravel. This package integrates your app to monitor errors, slow requests, SQL queries, background jobs, and performance bottlenecks with minimal setup, helping you diagnose issues and improve production performance.
Version 5.0.0 adds Laravel AI SDK support, so the first thing to confirm is that your laravel/framework and laravel/ai constraints actually resolve together:
composer require <vendor>/<package>:^5.0 laravel/ai
php artisan vendor:publish --tag=<package>-config
Look first at:
config/ai.php (or the SDK's equivalent) — credentials and default provider live there, not in the package config.Minimum .env for a first run:
AI_PROVIDER=openai
OPENAI_API_KEY=sk-...
First use case — a single non-streaming call to prove the wiring end to end:
use Laravel\Ai\Facades\Ai;
$response = Ai::text()
->model(config('ai.default'))
->prompt('Summarise this support ticket in one sentence: ...');
return $response->text;
If that returns without a BindingResolutionException or a 401, the integration is sound and you can move on to the patterns below. If you are upgrading from 4.x, run your existing test suite before touching application code — the facade/contract surface is where breakage will surface first.
Wrap the SDK, don't sprinkle it. Keep AI calls behind a small application-level service or action class so provider swaps and model changes stay in one place. The package binding is an implementation detail; your controllers and jobs should depend on your own interface.
final class TicketSummariser
{
public function __construct(private readonly AiClient $ai) {}
public function __invoke(Ticket $ticket): string
{
return $this->ai->complete(
prompt: view('prompts.summarise', ['ticket' => $ticket])->render(),
maxTokens: 200,
);
}
}
Prefer queued jobs for anything user-facing that takes more than ~2 seconds. Chat UIs are the obvious exception, but even there, dispatch the persistence and post-processing (title generation, tagging, embedding) to a queue rather than blocking the request:
ProcessTicket::dispatch($ticket)->afterResponse();
Stream when the UX demands it. With the AI SDK, streaming typically means returning a StreamedResponse and consuming it in the browser. In Blade/Livewire, disable output buffering and any middleware that buffers responses (compression, Debugbar in some configs) or the stream will appear to hang and then dump all at once.
Use tool/function calling for anything that touches your database. Let the model request data through declared tools rather than pasting rows into the prompt. This keeps prompts small, makes access control enforceable in PHP, and gives you an audit trail of what the model actually asked for.
Multi-provider as a config concern, not a code concern. Route by task, not by hardcoded class:
// config/ai.php
'tasks' => [
'summarise' => ['provider' => 'openai', 'model' => 'gpt-4o-mini'],
'reasoning' => ['provider' => 'anthropic', 'model' => 'claude-sonnet-4'],
'embed' => ['provider' => 'openai', 'model' => 'text-embedding-3-small'],
],
Cheap models for classification and extraction, expensive ones only for reasoning. This is the single highest-leverage cost control in a Laravel app.
Fake it in tests. The AI SDK ships testing helpers — use them in feature tests so CI never hits a live endpoint, and reserve real calls for a small, tagged, manually-run integration suite:
Ai::fake(['The ticket concerns a refund.']);
$this->post('/tickets/1/summarise')->assertSee('refund');
Embeddings + whereVectorSimilarTo (or the query-builder equivalent your driver offers) is the natural pairing with Eloquent. Store embeddings in a vector/json column, chunk long documents before embedding, and always store the model name alongside the vector so you can re-embed selectively when you change models.
php artisan config:cache freezes values; if you read API keys from a runtime source (Vault, per-tenant settings), bypass config() for that value or you'll ship stale credentials. Related: php artisan config:clear locally after editing .env.^5.0 and read the upgrade guide for removed/renamed methods before bumping; treat 5.0.x patch releases as the stabilisation window.Debugbar, laravel-responsecache, and gzip middleware all break or distort streams. Exclude streaming routes from them.AppServiceProvider.local and .env.testing so accidental loops during development don't generate real spend.How can I help you explore Laravel packages today?