symfony/ai-bedrock-platform
AWS Bedrock bridge for Symfony AI. Invoke Bedrock foundation models (Claude, Llama, Nova, and more) via the Bedrock Runtime API, with helpers aligned to Bedrock request/response schemas for easy integration into Symfony apps.
composer require symfony/ai-bedrock-platform aws/aws-sdk-php
php artisan vendor:publish --provider="Symfony\AiBedrock\BedrockServiceProvider"
This generates config/bedrock.php. Configure AWS credentials and default region:
return [
'aws' => [
'region' => env('AWS_REGION', 'us-east-1'),
'credentials' => [
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
],
],
'models' => [
'default' => 'anthropic.claude-v2',
],
];
config/app.php):
'providers' => [
// ...
Symfony\AiBedrock\BedrockServiceProvider::class,
],
BedrockClient facade or service container binding:
use Symfony\AiBedrock\Client\BedrockClientInterface;
// In a controller or service:
$client = app(BedrockClientInterface::class);
$response = $client->invokeModel('anthropic.claude-v2', [
'prompt' => 'Explain Laravel dependency injection.',
'max_tokens_to_sample' => 100,
]);
$response = $client->invokeModel('anthropic.claude-v2', [
'prompt' => 'Generate a blog post about Laravel AI.',
'temperature' => 0.7,
]);
$response = $client->invokeModel('anthropic.claude-v2', [
'prompt' => 'Extract entities from: "John lives in New York."',
'output_format' => 'json',
]);
// Parse JSON response directly.
$router = app(Symfony\AiBedrock\Router\ModelRouterInterface::class);
$modelName = $router->route([
'user_tier' => 'premium',
'feature' => 'chatbot',
]);
// Returns 'anthropic.claude-v3' for premium users.
php artisan ai:bedrock:list
$models = Cache::remember('bedrock_models', now()->addHours(1), function () {
return $client->listFoundationModels();
});
// app/Facades/Bedrock.php
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
class Bedrock extends Facade
{
protected static function getFacadeAccessor() { return 'bedrock.client'; }
}
$response = Bedrock::invoke('amazon.titan-text-express', ['prompt' => '...']);
Macro to extend the client:
$client->macro('generateChat', function ($messages, $model = 'anthropic.claude-v2') {
return $this->invokeModel($model, [
'messages' => $messages,
'anthropic_version' => 'bedrock-2023-05-31',
]);
});
$response = $client->generateChat([['role' => 'user', 'content' => 'Hi!']]);
// app/Http/Middleware/LogAiRequests.php
public function handle($request, Closure $next)
{
if ($request->route()->getName() === 'ai.generate') {
Log::info('AI Request', ['prompt' => $request->prompt]);
}
return $next($request);
}
$response = Cache::remember("ai_{$prompt}", now()->addMinutes(60), function () use ($client, $prompt) {
return $client->invokeModel('amazon.titan-text-lite', ['prompt' => $prompt]);
});
try {
$response = $client->invokeModel('anthropic.claude-v2', $payload);
} catch (\Aws\Bedrock\Exception\BedrockException $e) {
$response = $client->invokeModel('amazon.titan-text-express', $payload);
}
AppServiceProvider:
public function register()
{
$this->app->bind(BedrockClientInterface::class, function ($app) {
return new BedrockClient(
$app['config']['bedrock.aws'],
new \Aws\Bedrock\BedrockClient([
'region' => $app['config']['bedrock.aws.region'],
'version' => 'latest',
])
);
});
}
config/bedrock.php using Laravel’s validator:
use Illuminate\Support\Facades\Validator;
$validator = Validator::make(config('bedrock'), [
'aws.region' => 'required|string',
'aws.credentials.key' => 'required|string',
'models.default' => 'required|string',
]);
ai:bedrock:list command to sync models to a database:
// app/Console/Commands/SyncBedrockModels.php
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class SyncBedrockModels extends Command
{
protected function execute(InputInterface $input, OutputInterface $output)
{
$models = app(BedrockClientInterface::class)->listFoundationModels();
Model::upsert($models, ['model_id'], ['name', 'provider']);
$output->writeln('Synced ' . count($models) . ' models.');
}
}
$this->app->instance(BedrockClientInterface::class, Mockery::mock(BedrockClientInterface::class));
$mock->shouldReceive('invokeModel')
->once()
->andReturn(['content' => 'Mock response']);
AWS Credentials Leaks
config/bedrock.php or environment files.env() with .env files. Never commit .env to version control.php artisan config:clear after changing credentials to avoid caching issues.Model-Specific Parameters
temperature for Claude vs. top_p for Llama).$validator = Validator::make($payload, [
'prompt' => 'required|string',
'max_tokens_to_sample' => 'nullable|integer',
'temperature' => 'nullable|numeric|min:0|max:1',
]);
Rate Limiting
throttle middleware or use a queue:
Route::middleware(['throttle:10,1'])->group(function () {
Route::post('/ai/generate', [AiController::class, 'generate']);
});
Cold Starts
// app/Console/Commands/WarmBedrockModels.php
public function handle()
{
How can I help you explore Laravel packages today?