Laravel AI SDK supports the major AI services out of the box — OpenAI, Anthropic, Gemini, and Mistral. However, the standard providers cannot handle cases like:
An on-premises inference server you built internally (including those with an OpenAI-compatible API)
An emerging AI service that is not yet officially supported
An internal model gateway or billing management layer you want to route requests through
In these cases, implement a custom provider and register it with the SDK’s AiManager to use it through the same API as the standard providers.
The interface that text generation providers implement (src/Contracts/Providers/TextProvider.php).
interface TextProvider{ public function prompt(AgentPrompt $prompt): AgentResponse; public function stream(AgentPrompt $prompt): StreamableAgentResponse; public function textGateway(): TextGateway; public function useTextGateway(TextGateway $gateway): self; public function defaultTextModel(): string; public function cheapestTextModel(): string; public function smartestTextModel(): string;}
The prompt() and stream() implementations can be delegated to existing traits (GeneratesText, StreamsText), so the only methods you actually need to implement are the three model name methods.
Implementation example: custom provider for an OpenAI-compatible API
This example registers an internally built OpenAI-compatible inference server as a provider named my-inference.
1
Create the provider class
Create app/Ai/Providers/MyInferenceProvider.php.
<?phpdeclare(strict_types=1);namespace App\Ai\Providers;use Illuminate\Contracts\Events\Dispatcher;use Laravel\Ai\Contracts\Providers\EmbeddingProvider;use Laravel\Ai\Contracts\Providers\TextProvider;use Laravel\Ai\Gateway\Prism\PrismGateway;use Laravel\Ai\Providers\Concerns\GeneratesEmbeddings;use Laravel\Ai\Providers\Concerns\GeneratesText;use Laravel\Ai\Providers\Concerns\HasEmbeddingGateway;use Laravel\Ai\Providers\Concerns\HasTextGateway;use Laravel\Ai\Providers\Concerns\StreamsText;use Laravel\Ai\Providers\Provider;class MyInferenceProvider extends Provider implements EmbeddingProvider, TextProvider{ use GeneratesEmbeddings; use GeneratesText; use HasEmbeddingGateway; use HasTextGateway; use StreamsText; public function __construct(array $config, Dispatcher $events) { parent::__construct(new PrismGateway($events), $config, $events); } public function defaultTextModel(): string { return $this->config['models']['text']['default'] ?? 'llama3.3-70b'; } public function cheapestTextModel(): string { return $this->config['models']['text']['cheapest'] ?? 'llama3.2-3b'; } public function smartestTextModel(): string { return $this->config['models']['text']['smartest'] ?? 'llama3.3-70b'; } public function defaultEmbeddingsModel(): string { return $this->config['models']['embeddings']['default'] ?? 'nomic-embed-text'; } public function defaultEmbeddingsDimensions(): int { return $this->config['models']['embeddings']['dimensions'] ?? 768; }}
PrismGateway uses Prism and supports OpenAI-compatible APIs. For services with a proprietary non-compatible API, use a custom gateway as described below.
2
Register in AppServiceProvider
Register the provider in the boot method of App\Providers\AppServiceProvider using extend().
<?phpnamespace App\Providers;use App\Ai\Providers\MyInferenceProvider;use Illuminate\Contracts\Events\Dispatcher;use Illuminate\Support\ServiceProvider;use Laravel\Ai\AiManager;class AppServiceProvider extends ServiceProvider{ public function boot(): void { $this->app->make(AiManager::class)->extend( 'my-inference', fn (array $config) => new MyInferenceProvider( $config, $this->app->make(Dispatcher::class) ) ); }}
public function __construct( protected array $config, protected Dispatcher $events,) {}/** * Get the provider's text gateway. */public function textGateway(): TextGateway{ return $this->textGateway ??= new MyInferenceGateway;}
If you need to support tool calls (function calling), you must also implement tool execution and recursive message sending inside generateText(). Refer to the PrismGateway implementation at src/Gateway/Prism/PrismGateway.php.
To test agents that use your custom provider, call the fake method on the agent class. Regardless of whether a custom provider is in use, the fake gateway is set on the provider.
<?phpnamespace Tests\Feature;use App\Ai\Agents\SummaryAgent;use Illuminate\Foundation\Testing\RefreshDatabase;use Tests\TestCase;class SummaryAgentTest extends TestCase{ use RefreshDatabase; public function test_summary_agent_returns_text(): void { SummaryAgent::fake(['This is a summary.']); $response = SummaryAgent::make()->prompt('Long article text...', provider: 'my-inference'); $this->assertEquals('This is a summary.', $response->text); SummaryAgent::assertPrompted('Long article text...'); }}
You can also use extend() to register a test provider from the container.
public function test_with_mock_provider(): void{ $this->app->make(AiManager::class)->extend( 'my-inference', function (array $config) { $gateway = $this->app->make(\Laravel\Ai\Gateway\Prism\PrismGateway::class); $events = $this->app->make(\Illuminate\Contracts\Events\Dispatcher::class); return new MyInferenceProvider($config, $events); } ); // Test code}