Laravel uygulamanıza Claude veya GPT-4o entegre etmek oldukça kolay bir iş gibi gözükebilir. Bir Http::post() çağrısı ile kendinizi deha gibi hissedersiniz. Ancak tek bir kullanıcı endpoint’inizi tekrar tekrar kullanmaya başladığında veya bir bot bunu scriptlediğinde, OpenAI faturanız 300 dolara ulaşır. Çözüm, özel bir Laravel AI middleware katmanı oluşturmaktır ve çoğu eğitim materyali bunu tamamiyle atlamaktadır.
Bu, hayali bir durum değil. Gerçekten yaşanıyor.
Daha akıllı prompts oluşturmak yerine, yapısal bir çözüm gereklidir. Bu kılavuzda, düzgün bir AI yönetim katmanı inşa ediyoruz: katmanlı oran sınırlama, kullanıcı başına token izleme ile birlikte asenkron logging ve korumaların çalıştığını doğrulayan bir Pest test paketi oluşturacağız. Amacımız bir demo yapmak değil; gönderebileceğiz bir uygulama inşa etmek. Prompt versioning ve o yapının prompt tarafında deploy disiplini için prompt migrations rehberine göz atabilirsiniz.
1. Strateji: Neden Laravel AI Middleware Katmanı?
1. Strateji: Neden Laravel AI Middleware Katmanı?
Middleware, Laravel yaşam döngüsünde bu amaç için doğru yerdir çünkü altyapı endişelerini (maliyet, oran limitleri) iş mantığından (prompt’un kendisi) ayırır. Bu decoupling, gpt-4o‘yu, kontrolcülerden birini bile dokunmadan, kendi barındırdığınız bir Llama örneği ile değiştirmeyi mümkün kılar.
O ayrımın çıkış tarafında, modelin geri döndüğünü uygulamanız hareket etmeden önce doğrulamak için schema validation kılavuzuna bakabilirsiniz.
Maliyet izlemek için standart token fiyat formülünü kullanıyoruz:
$$Total Cost = \sum_{i=1}^{n} (Tokens_{in} \cdot Price_{in} + Tokens_{out} \cdot Price_{out})$$
Bu hesaplamayı merkezi bir yere koyun. Kontrolcülerde asla dağınık tutmayın.
2. Veritabanı Şeması: Bir Denetim İzlemek, Sadece Bir Sayıcı Değil
2. Veritabanı Şeması: Bir Denetim İzlemek, Sadece Bir Sayıcı Değil
Sadece kullanıcı total_tokens tam sayısını arttırma tuzağına düşmeyin. Her istek için bir satır oluşturmalısınız, böylece denetim, geri ödeme ve hata ayıklama yapabilirsiniz.
// database/migrations/xxxx_xx_xx_create_ai_usage_logs_table.php
public function up(): void
{
Schema::create('ai_usage_logs', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->string('model_used'); // e.g., 'gpt-4o', 'claude-sonnet-4-6'
$table->string(); // e.g., 'blog_generator', 'chat'
$table->integer()->default();
$table->integer()->default();
$table->decimal(, , )->default();
$table->timestamps();
});
}
3. Katmanlı Oran Sınırlama
3. Katmanlı Oran Sınırlama
Katmanlarınızı AppServiceProvider içinde tanımlayın. Ücretsiz kullanıcılar dakikada 5 istek alır. Premium kullanıcılar ise 100. Birim ekonominizin gerektirdiği şekilde ayarlayın.
// app/Providers/AppServiceProvider.php
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Http\Request;
public function boot(): void
{
RateLimiter::for(, function (Request $request) {
$user = $request->user();
return $user?->is_premium
? Limit::perMinute()->by($user->id)
: Limit::perMinute()->by(->id);
});
}
Kıdemli Geliştirici İpucu: Bunu Redis ile destekleyin, veritabanınızla değil.
CACHE_DRIVER=redisayarını.envdosyanıza ekleyin. Varsayılanfileveyadatabasesürücüsünü kullanıyorsanız, her AI isteği oran sınırlayıcı altında bir veritabanı okuma-yazma döngüsü tetikler — bu, yük altındayken ortaya çıkmayacak gizli bir darboğazdır. Laravel Cache dökümantasyonu için sürücü yapılandırmasına bakın.
4. Middleware Oluşturma
4. Middleware Oluşturma
Sınıfı oluşturun:
php artisan make:middleware EnsureUserHasAiCredits
Bu middleware, istek Controller’a ulaşmadan önce kimlik doğrulama ve kullanıcı başına harcama limitinizi uygular:
// app/Http/Middleware/EnsureUserHasAiCredits.php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class EnsureUserHasAiCredits
{
public function handle(Request $request, Closure $next): Response
{
$user = $request->user();
if (! $user) {
return response()->json([=> );
}
if ($user->monthly_spend >= $user->spending_limit) {
return response()->json([
=> ,
=> route(),
], );
}
return $next($request);
}
}
Middleware’ı Kayıt Etme (Laravel 11+)
Middleware’ı Kayıt Etme (Laravel 11+)
Laravel 11, app/Http/Kernel.php dosyasını kaldırdı. Middleware’inizi bootstrap/app.php dosyasına kaydedin:
// bootstrap/app.php
->withMiddleware(function (Middleware $middleware) {
$middleware->appendToGroup(, [
\App\Http\Middleware\EnsureUserHasAiCredits::class,
]);
})
Daha sonra, oran sınırlayıcıyı rotanıza uygulayın:
// routes/api.php
Route::post(, [AiController::class, ])
->middleware();
5. Model Fiyatlandırmasını Harici Yapma
5. Model Fiyatlandırmasını Harici Yapma
Model fiyatını 0.000005 gibi bir değeri Job’unuz içerisine sabit şekilde yazmak bakım tuzağıdır. OpenAI’den bir fiyat değişikliği geldiğinde, maliyet hesaplamanız sessizce bozulur. Fiyatları config/ai.php dosyasına yerleştirin:
// config/ai.php
return [
=> [
=> [
=> ,
=> ,
],
=> [
=> ,
=> ,
],
],
];
6. Asenkron Kullanım Günlüğü ile Kuyruk Job’u
6. Asenkron Kullanım Günlüğü ile Kuyruk Job’u
API yanıt verdikten sonra asenkron olarak günlüğe kaydedin. Kullanıcıyı bir veritabanı yazımı için bekletmeyin.
// app/Jobs/LogAiUsage.php
namespace App\Jobs;
use App\Models\AiUsageLog;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class LogAiUsage implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public function __construct(
public readonly int $userId,
public readonly array $usageData,
) {}
public function handle(): void
{
= ->usageData[];
= config({}, [
=> ,
=> ,
]);
= (->usageData[] * [])
+ (->usageData[] * []);
AiUsageLog::create([
=> ->userId,
=> ,
=> ->usageData[],
=> ->usageData[],
=> ->usageData[],
=> ,
]);
}
}
Dikkat edin ki
feature_namehem Job yüklemesinde hem decreate()çağrısında yer alır. Orijinal migration bu sütunu tanımlar; eğer insert’tan çıkarırsanız, Laravel yaNOT NULLkısıtlaması hatası verir ya da boş bırakılması durumunda sessizce göz ardı eder. Her iki durumda da, atfedilen verinizi kaybetmiş olursunuz. Yüklemenizi her zaman şemanızla eşleştirin.
7. Kontrolcü: Birleştirmek
7. Kontrolcü: Birleştirmek
// app/Http/Controllers/AiController.php
namespace App\Http\Controllers;
use App\Jobs\LogAiUsage;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use OpenAI\Laravel\Facades\OpenAI;
use Illuminate\Validation\ValidationException;
class AiController extends Controller
{
public function generate(Request $request): JsonResponse
{
= ->validate([
=> [, , ],
=> [, , ],
]);
try {
= OpenAI::chat()->create([
=> ,
[[=> ,=> []]],
]);
} catch ($e) {
report();
return response()->json([=> ], );
} catch ($e) {
// 429, kota aşımı, geçersiz talepleri yakalar
report();
return response()->json([=> ->getMessage()],->getCode() ?: );
}
LogAiUsage::dispatch(auth()->id(),[
=> ,
=> [],
=> ->usage->promptTokens,
=> ->usage->completionTokens,
]);
return response()->json([
=> ->choices[]->message->content,
]);
}
}
Anthropic’in SDK’sını entegre ediyorsanız, desen aynıdır — istemci çağrısını değiştirin ve model dizisini claude-sonnet-4-5 olarak güncelleyin. En son SDK referansı için Anthropic API belgelerine göz atabilirsiniz.
8. Mimariyi Pest ile Test Etme
8. Mimariyi Pest ile Test Etme
Bir üretim sistemi, arkasındaki test paketinin sağlamlığı kadar güvenilirdir. Üç şeyi bağımsız olarak doğrulamamız gerekiyor:
- Oran sınırlayıcı, kotası tükenmiş kullanıcılara engel oluyor.
- Middleware, harcama tavanına ulaşmış kullanıcıları durduruyor.
-
LogAiUsageJob’u doğru yüklemesiyle çalıştırılıyor — gerçek API’yi vurmadan.
Bu son nokta, çoğu AI test eğitimlerinin başarısız olduğu yerdir. Bus::fake() Job’u kuyruklar ama OpenAI facadına hiçbir şey yapmaz. Onu mock etmezseniz, test paketin gerçek API kredilerini yakar.
// tests/Feature/AiGenerationTest.php
use App\Jobs\LogAiUsage;
use App\Models\User;
use Illuminate\Support\Facades\Bus;
use Illuminate\Support\Facades\RateLimiter;
use OpenAI\Laravel\Facades\OpenAI;
use OpenAI\Responses\Chat\CreateResponse;
beforeEach(function () {
Bus::fake();
});
it(, function () {
= User::factory()->create([=> false]);
// Önceki 5 isteği simüle edin — ücretsiz katmanın tavanı
foreach (range(,) as ) {
RateLimiter::hit(. ->id);
}
->actingAs()
->postJson(,[
=> ,
=> ,
])
->assertStatus();
});
it(, function () {
= User::factory()->create([
=> ,
=> ,
]);
->actingAs()
->postJson(,[
=> ,
=> ,
])
->assertStatus()
->assertJsonPath(, );
});
it(, function () {
= User::factory()->create([=> ]);
// OpenAI facadını mock'layın — testler sırasında gerçek API'yi kullanmayın
OpenAI::fake([
CreateResponse::fake([
=> [
[ [=> , => ]],
],
=> [
=> ,
=> ,
=> ,
],
]),
]);
->actingAs()
->postJson(,[
=> ,
=> ,
])
->assertOk()
->assertJsonPath(, );
Bus::assertDispatched(LogAiUsage::, function (LogAiUsage ) use () {
return ->userId === ->id
&& ->usageData[] === && ->usageData[] === && ->usageData[] === ;
});
});
Eğer bu yapının Eloquent tarafını inşa ediyorsanız ve model ilişkilerini ve fabrika durumlarını büyük çapta test etmek istiyorsanız, güçlü Laravel test fabrikaları oluşturma konusundaki desenler, burada User ve AiUsageLog modelleri için doğrudan aktarılabilir.
9. Artık Sahip Olduklarınız
9. Artık Sahip Olduklarınız
Bu mimariyle gönderim yaptığınızda, elde ettiğiniz sonuçlar:
- Maliyet koruması — Laravel
RateLimiterfacadını Redis ile destekleyerek katmanlı oran sınırlama, ayrıca middleware’da zorunlu bir aylık tavan. - Tam denetim izi — her bir token, kullanıcı başına, özellik başına, model başına Eloquent modeli aracılığıyla kaydedilir.
- Taşıma gecikmesinde sıfır etki — asenkron logging, kullanıcıların veritabanı yazımı için beklemesini sağlar.
- Kandırmayan bir test paketi — OpenAI facadı mock’lanmış durumda, böylece CI pipeline’ınız ücretsiz kalır ve iddialarınız güvenilir olur.
Bir hafta sonu projesi ile bir üretim sistemi arasındaki fark, AI entegrasyonu değildir. Bu etrafındaki her şeydir. İşte bu katman.
Kaynaklar:
Kaynak: Orijinal Makale
- 1. Strateji: Neden Laravel AI Middleware Katmanı?
- 2. Veritabanı Şeması: Bir Denetim İzlemek, Sadece Bir Sayıcı Değil
- 3. Katmanlı Oran Sınırlama
- 4. Middleware Oluşturma
- 5. Model Fiyatlandırmasını Harici Yapma
- 6. Asenkron Kullanım Günlüğü ile Kuyruk Job’u
- 7. Kontrolcü: Birleştirmek
- 8. Mimariyi Pest ile Test Etme
- 9. Artık Sahip Olduklarınız


