Skip to content

Laravel AI SDK

Official Laravel AI SDK (laravel/ai) থেকে openai-compatible provider দিয়ে Tokens ব্যবহার করুন: config/ai.php, .env, প্রথম call, streaming, tool, timeout আর Laravel 12 ও 13-এর error handling।

যেসব tool-এ কাজ করেLaravel AI SDK
Markdown-এ দেখুন
এই পাতায়

Laravel AI SDK (laravel/ai) হলো agent, text generation আর অন্যান্য AI feature-এর জন্য Laravel-এর official package। এতে একটা openai-compatible driver আছে, যা OpenAI-র মতো /chat/completions endpoint আছে এমন যেকোনো server-এর সাথে কথা বলে, আর Tokens ঠিক তেমনই। config/ai.php-এ Tokens-এর URL আর key দিয়ে একটা provider declare করুন, তারপর agent call করার সময় নাম ধরে সেটা বেছে নিন।

Laravel-এর agent layer ছাড়া শুধু PHP-র সাধারণ OpenAI client চাইলে PHP পেজ দেখুন।

কী কী যাচাই করা হয়েছে

এই পেজ লেখা হয়েছে Laravel 13.x ও 12.x-এর জন্য Laravel AI SDK-র documentation (laravel.com/docs, 2026 সালের অক্টোবরে দেখা) আর laravel/ai 1.2.0-এর source দেখে (release হয়েছে 7 অক্টোবর 2026-এ)। 12.x-এর পেজে openai-compatible driver-এর কথা লেখা নেই, তাই ওই অংশ এসেছে 13.x-এর docs আর package-এর source থেকে। Code-টা documentation আর source দেখে মেলানো হয়েছে, Tokens-এর বিরুদ্ধে শুরু থেকে শেষ পর্যন্ত চালিয়ে দেখা হয়নি।

যা যা লাগবে#

  • PHP 8.3 বা নতুন, আর Laravel 12 বা 13। laravel/ai 1.2.0-এর শর্ত php ^8.3 আর illuminate/* ^12.0|^13.0।
  • API keys থেকে নেওয়া একটা Tokens key।
  • /models থেকে একটা model ID। আপনার agent tool ব্যবহার করলে এমন model নিন যা tool calling সাপোর্ট করে (Choosing a model)।

Install করুন#

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

Publish করলে config/ai.php আর একটা migration তৈরি হয়। Migration বানায় agent_conversations আর agent_conversation_messages table, যেখানে SDK conversation জমা রাখে। Conversation memory এখনই ব্যবহার না করলেও এটা চালিয়ে নিন।

আগের কোনো release থেকে আপনার config/ai.php আগে থেকেই থাকলে composer update laravel/ai চালান, তারপর আপনার file-টা এখনকার published file-এর সাথে মিলিয়ে দেখুন। পুরোনো copy-তে openai-compatible entry না-ও থাকতে পারে, সেক্ষেত্রে নিচে দেখানো মতো হাতে যোগ করে নিন।

Tokens provider সাজান#

config/ai.php-এর providers array-তে একটা provider যোগ করুন। নামটা আপনার ইচ্ছা, এই পেজে tokens ব্যবহার করা হয়েছে।

config/ai.php
return [
    'default' => 'tokens',

    // ...

    'providers' => [
        // ... the providers that ship in the file stay as they are

        'tokens' => [
            'driver' => 'openai-compatible',
            'url' => env('TOKENS_BASE_URL', 'https://tokens.bd/v1'),
            'key' => env('TOKENS_API_KEY'),
            'models' => [
                'text' => [
                    'default' => env('TOKENS_MODEL', 'deepseek/deepseek-v4.1-flash'),
                ],
            ],
        ],
    ],
];
.env
TOKENS_API_KEY=tok_live_your_key

প্রতিটা option কীভাবে কাজ করে:

  • url বাধ্যতামূলক। https://tokens.bd/v1 দিন, /v1-সহ। Driver শেষের slash কেটে তার নিচে chat/completions-এ post করে, তাই request যায় https://tokens.bd/v1/chat/completions-এ।
  • key SDK-তে ঐচ্ছিক, থাকলে bearer token হিসেবে যায়। Tokens-এর ক্ষেত্রে এটা অবশ্যই লাগবে।
  • models.text.default হলো সেই model, যা call-এ আলাদা করে কোনোটার নাম না দিলে ব্যবহার হয়। এটা না থাকলে model: না দেওয়া call-এ InvalidArgumentException throw হয়, যেখানে লেখা থাকে provider-এর একটা default text model লাগবে।
  • 'default' => 'tokens' দিলে text-এর জন্য এই provider-ই default হয়ে যায়। Default না ছুঁতে চাইলে এটা বাদ দিন, আর নিচের উদাহরণগুলোর মতো প্রতিটা call-এ provider: 'tokens' দিন।

Key-কে config file থেকে দূরে রাখুন

ওপরের মতো env() দিয়ে key পড়ুন, আর .env version control-এর বাইরে রাখুন। যে server config cache করে রাখে, সেখানে .env বা config/ai.php বদলানোর পর php artisan config:clear চালান (অথবা আবার config:cache)।

Laravel 12 ও 13: variable-এর নাম আলাদা, config একই#

Laravel-এর docs-এ variable-এর নাম version ভেদে আলাদা, আর সেটা শুধু built-in openai provider-এর বেলায় কাজে আসে:

DocsCustom OpenAI URL-এর variableopenai-compatible provider
Laravel 13.xOPENAI_URLDocumented। Shipped config/ai.php-এ env-এর নাম: OPENAI_COMPATIBLE_URL, OPENAI_COMPATIBLE_API_KEY।
Laravel 12.xOPENAI_BASE_URLপেজে বর্ণনা নেই। Driver আছে laravel/ai package-এ, যা Laravel 12 ও 13 দুটোই সাপোর্ট করে।

Variable-এর নাম বলতে বোঝায় আপনার config/ai.php যা env()-কে দেয়, তার বেশি কিছু নয়। ওপরের tokens entry নিজের নাম ব্যবহার করে, তাই দুই version-এই চলে। File-এ আগে থেকে যে entry আছে সেটাই চাইলে .env-এ OPENAI_COMPATIBLE_URL=https://tokens.bd/v1 আর OPENAI_COMPATIBLE_API_KEY দিন, আর ওই entry-তে models.text.default যোগ করুন।

Built-in openai provider কেন নয়#

Built-in openai provider-ও custom url নেয়। Package-এর source অনুযায়ী সেটা request পাঠায় {url}/responses-এ, অর্থাৎ OpenAI Responses API-তে, আর openai-compatible driver পাঠায় {url}/chat/completions-এ। Tokens দুটোই চালায় (Chat Completions, Responses)। এই পেজে openai-compatible নেওয়া হয়েছে কারণ docs তৃতীয় পক্ষের gateway-র জন্য এই driver-টার কথাই বলে, আর এটা Chat Completions format পাঠায়, যা সবচেয়ে বেশি সাপোর্ট পাওয়া format।

প্রথম call করুন#

Anonymous agent-এর জন্য আলাদা class লাগে না। এটা route-এ রাখুন, নয়তো php artisan tinker-এ চালান:

php
use function Laravel\Ai\agent;

$response = agent(
    instructions: 'Answer in one short paragraph.',
)->prompt(
    'When should I use a queue instead of running code in the request?',
    provider: 'tokens',
    model: 'deepseek/deepseek-v4.1-flash',
);

echo $response->text;

$response->text হলো উত্তর। (string) $response একই text দেয়। config/ai.php-এ আপনার দেওয়া নামের provider-এর জন্য provider-এ সাধারণ string দিলেই চলে। models.text.default set থাকলে model: বাদ দিতে পারেন।

ঠিকমতো চলছে কি না দেখুন#

আগে Laravel-এর বাইরে থেকে দেখুন key দিয়ে কোন কোন model চলে:

bash
curl -s https://tokens.bd/v1/models -H "Authorization: Bearer $TOKENS_API_KEY"

তারপর app-এর ভেতরে:

bash
php artisan tinker
php
\Laravel\Ai\agent(instructions: 'Reply with one word.')->prompt('Say ready.', provider: 'tokens')->text

ছোট একটা উত্তর এলে বুঝবেন URL, key আর model ঠিক আছে। 404 model_not_found মানে ID ভুল; 401 মানে key পৌঁছায়নি। নিচের Troubleshooting দেখুন।

Agent class#

যা বারবার কাজে লাগবে তার জন্য একটা agent class বানান, আর attribute দিয়ে তার provider ও model বেঁধে দিন:

bash
php artisan make:agent ReviewCoach
app/Ai/Agents/ReviewCoach.php
namespace App\Ai\Agents;

use Laravel\Ai\Attributes\Model;
use Laravel\Ai\Attributes\Provider;
use Laravel\Ai\Attributes\Timeout;
use Laravel\Ai\Contracts\Agent;
use Laravel\Ai\Promptable;
use Stringable;

#[Provider('tokens')]
#[Model('deepseek/deepseek-v4.1-flash')]
#[Timeout(120)]
class ReviewCoach implements Agent
{
    use Promptable;

    public function instructions(): Stringable|string
    {
        return 'You review pull request descriptions and suggest one improvement.';
    }
}
php
$response = (new \App\Ai\Agents\ReviewCoach)->prompt('Fix login redirect');
echo $response->text;

Provider, Model আর Timeout attribute-গুলো আছে Laravel-এর docs-এর agent configuration section-এ। Provider একটা Lab enum-এর মান, একটা string বা একটা array নেয়।

Response stream করুন#

stream() একটা StreamableAgentResponse ফেরত দেয়। সেটা route থেকে return করলে browser-এ server-sent event হিসেবে চলে যায়:

routes/web.php
use function Laravel\Ai\agent;

Route::get('/ask', function () {
    return agent(instructions: 'Answer briefly.')
        ->stream('Explain job batching in Laravel.', provider: 'tokens');
});

Event নিজে সামলাতে চাইলে, যেমন Artisan command-এ, stream-এর ওপর loop চালান:

php
use Laravel\Ai\Streaming\Events\Error;
use Laravel\Ai\Streaming\Events\TextDelta;

$stream = agent(instructions: 'Answer briefly.')
    ->stream('Explain job batching in Laravel.', provider: 'tokens');

foreach ($stream as $event) {
    if ($event instanceof TextDelta) {
        echo $event->delta;
    } elseif ($event instanceof Error) {
        // $event->type holds the error code, $event->message the text
        fwrite(STDERR, "{$event->type}: {$event->message}\n");
    }
}

Laravel-এর docs-এ একটা then() callback-এর কথাও আছে, যেটা পুরো response stream হয়ে গেলে চলে; তার StreamedAgentResponse-এ থাকে text, events আর usage। Driver Tokens-এর কাছে stream_options.include_usage চায়, তাই token count আসে stream-এর শেষে। Wire format-এর জন্য Streaming দেখুন।

Tool#

Tool হলো এমন class যার একটা description, একটা schema আর একটা handle method আছে। একটা বানিয়ে নিন:

bash
php artisan make:tool GetWeather
app/Ai/Tools/GetWeather.php
namespace App\Ai\Tools;

use Illuminate\Contracts\JsonSchema\JsonSchema;
use Laravel\Ai\Contracts\Tool;
use Laravel\Ai\Tools\Request;
use Stringable;

class GetWeather implements Tool
{
    public function description(): Stringable|string
    {
        return 'Current weather for a city.';
    }

    public function handle(Request $request): Stringable|string
    {
        return $request['city'].': light rain, 29C'; // call your real weather source here
    }

    public function schema(JsonSchema $schema): array
    {
        return [
            'city' => $schema->string()->required(),
        ];
    }
}

এটা anonymous agent-কে দিন, অথবা agent class-এর tools() method থেকে return করুন:

php
use App\Ai\Tools\GetWeather;
use function Laravel\Ai\agent;

$response = agent(
    instructions: 'Use the weather tool when asked about weather.',
    tools: [new GetWeather],
)->prompt('Is it raining in Dhaka?', provider: 'tokens');

echo $response->text;

SDK tool-এর definition পাঠায় Chat Completions format-এ, আর loop-টা আপনার হয়ে নিজেই চালায়। Tool calling শুধু সেই model-এ চলে যা এটা সাপোর্ট করে, তাই /models-এ model-এর পেজ দেখুন আর পড়ুন Tool calling।

Timeout#

Agent-এর timeout-এর default 60 সেকেন্ড। এটা call পিছু, class পিছু, বা দুই জায়গাতেই বাড়াতে পারেন:

php
$response = $agent->prompt('...', provider: 'tokens', timeout: 180);

Class-এর জন্য #[Timeout(180)] দিন। মানটা ওই request-এর HTTP client timeout, সেকেন্ডে। Laravel-এর HTTP client-এ এটা Guzzle-এর timeout option, যাকে Guzzle বলে request-এর মোট সময়। তাই লম্বা stream করা উত্তর ওই সীমায় কেটে যেতে পারে। আপনার সবচেয়ে লম্বা generation-এর চেয়ে বেশি মান দিন।

আরও কয়েকটা সীমা জেনে রাখুন:

  • Upstream থেকে response header আসার জন্য gateway 600 সেকেন্ড পর্যন্ত অপেক্ষা করে, তাই ওর দিক থেকে লম্বা generation-এ সমস্যা নেই।
  • তার আগেই PHP নিজে web request থামিয়ে দিতে পারে। php.ini-তে max_execution_time দেখুন (web request-এর জন্য PHP-র default 30 সেকেন্ড), অথবা লম্বা কাজ queue-তে চালান।

Error সামলান#

SDK কিছু HTTP status নিজের exception-এ রূপান্তর করে। Tokens-এর ক্ষেত্রে:

StatusExceptionTokens-এর code
402Laravel\Ai\Exceptions\InsufficientCreditsExceptioninsufficient_credits, no_funding, outstanding_debt, member_cap_reached
429Laravel\Ai\Exceptions\RateLimitedExceptionrate_limited, concurrency_limit, window_exhausted, model_limit_reached, rate_limit_exceeded
502, 503, 504Laravel\Ai\Exceptions\ProviderOverloadedExceptionupstream_unreachable, no_upstream_available, upstream_timeout
connection ব্যর্থ হলেLaravel\Ai\Exceptions\ProviderConnectionExceptionনেই; request Tokens পর্যন্ত পৌঁছায়ইনি
বাকি সব 4xx ও 5xxIlluminate\Http\Client\RequestExceptioninvalid_api_key, model_not_found, model_not_allowed_on_key আর বাকিগুলো

Tokens-এর code থাকে response body-তে। SDK-র exception আসল error-টাকে previous exception হিসেবে রেখে দেয়:

php
use Illuminate\Http\Client\RequestException;
use Laravel\Ai\Exceptions\AiException;

try {
    $text = agent(instructions: 'Say hi.')->prompt('hi', provider: 'tokens')->text;
} catch (AiException|RequestException $e) {
    $request = $e instanceof RequestException ? $e : $e->getPrevious();
    $response = $request instanceof RequestException ? $request->response : null;

    logger()->warning('Tokens call failed', [
        'status' => $response?->status(),
        'code' => $response?->json('error.code'),
        'request_id' => $response?->header('x-tokens-request-id'),
    ]);

    throw $e;
}

প্রতিটা ব্যর্থতার সাথে x-tokens-request-id log করে রাখুন। ওটা ধরে Support আপনার request খুঁজে বের করতে পারে (Errors)। 429 window_exhausted হলে window reset না হওয়া পর্যন্ত retry করে লাভ নেই; Retry-After বলে দেয় কখন।

openai-compatible driver কী কী করে#

Package-এর source অনুযায়ী এই driver text generation (streaming আর tool-সহ), embeddings আর transcription করে। Image generation আর text-to-speech চলে SDK-র অন্য provider দিয়ে, এটা দিয়ে নয়। Embeddings-এর জন্য provider config-এ models.embeddings.default লাগে; Tokens embeddings চালায় (Embeddings), তবে এই পেজে সেই setup ধাপে ধাপে দেখানো হয়নি।

সমস্যা হলে#

লক্ষণকারণ ও সমাধান
The [tokens] openai-compatible provider requires a 'url' to be configuredurl ফাঁকা। tokens entry দেখুন আর config cache clear করুন।
... requires a default text modelmodels.text.default দিন, নয়তো call-এ model: দিন।
404 model_not_foundModel ID ভুল। /models থেকে copy করুন।
প্রতিটা call-এ 404, error message-এ একটা path-এর উল্লেখURL-এ /v1 নেই। https://tokens.bd/v1 দিন।
401 missing_api_key বা invalid_api_keyচলমান process-এ TOKENS_API_KEY ফাঁকা, প্রায়ই কারণ config cache করা। php artisan config:clear চালান।
RateLimitedExceptionওপরে দেখানো মতো error.code পড়ুন। rate_limited আর concurrency_limit Retry-After-এর পর ঠিক হয়; window_exhausted ঠিক হয় plan reset হলে।
InsufficientCreditsExceptionBilling-এ টাকা যোগ করুন।
cURL error 28: Operation timed outtimeout-এর মান response আসার সময়ের চেয়ে কম। বাড়ান।
Stream করা text মাঝপথে থেমে যায়মোট timeout শেষ হয়ে গেছে, অথবা PHP-র max_execution_time request থামিয়ে দিয়েছে। দুটোই বাড়ান।

Tokens-এর সব error code আছে Errors পেজে, আর সাধারণ সমাধান পাবেন Troubleshooting-এ।

এই পাতাটা কি কাজে লেগেছে?

এখনো আটকে আছেন? Support ticket খুলুন

আপনার agent set up করতে সাহায্য লাগবে?

Connection tester দিয়ে সংযোগ পরীক্ষা করে নিন, অথবা একটা API key তৈরি করুন।