Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Ai Generic Platform Laravel Package

symfony/ai-generic-platform

A generic platform bridge for Symfony AI that connects the framework's AI components to a common platform abstraction, simplifying configuration and enabling interoperable model integrations within Symfony applications.

View on GitHub
Deep Wiki
Context7

Getting Started

First Steps

  1. Installation Add the package via Composer:

    composer require symfony/ai-generic-platform
    

    Ensure your project uses Symfony 7.0+ (or PHP 8.2+). For Laravel, this bridges cleanly into your service container.

  2. Basic Setup Register the bridge in your config/packages/ai.yaml (Symfony) or bind it manually in AppServiceProvider (Laravel):

    framework:
        ai:
            platforms:
                generic: true
    
  3. First Use Case: Embedding Generation Use the AiClient to interact with generic AI platforms:

    use Symfony\AI\Client\AiClient;
    use Symfony\AI\Client\AiClientInterface;
    
    // In a service or controller
    public function __construct(private AiClientInterface $aiClient) {}
    
    public function generateEmbedding(string $text): array
    {
        $response = $this->aiClient->embed([
            'model' => 'generic-embedding-model',
            'input' => $text,
        ]);
        return $response->getEmbedding();
    }
    
  4. Where to Look Next

    • Review the Symfony AI documentation for platform-specific configurations.
    • Check src/Symfony/AI/Client/GenericPlatformClient.php for low-level API details.
    • New in v0.14: Eden AI is now supported as a first-class gateway — see the EdenAI platform config if you want a multi-provider switchboard instead of hitting a single vendor.

Implementation Patterns

Common Workflows

  1. Embedding Generation for Search

    // Generate embeddings for a list of documents
    $documents = ['doc1', 'doc2', 'doc3'];
    $embeddings = collect($documents)->map(fn($doc) =>
        $this->aiClient->embed(['input' => $doc])->getEmbedding()
    );
    
  2. Chat Completions with Context

    // Use chat history for context-aware responses
    $history = [
        ['role' => 'user', 'content' => 'Previous question'],
        ['role' => 'assistant', 'content' => 'Previous answer'],
    ];
    
    $response = $this->aiClient->chat([
        'model' => 'generic-chat-model',
        'messages' => array_merge($history, [['role' => 'user', 'content' => 'New question']]),
    ]);
    
  3. Tool / Function Calling (Stable in v0.14) Tool call handling is now consistent across finish reasons — you no longer need to special-case a stop finish reason to retrieve tool calls:

    $response = $this->aiClient->chat([
        'model' => 'generic-chat-model',
        'messages' => [['role' => 'user', 'content' => 'What is the weather in Paris?']],
        'tools' => [[
            'type' => 'function',
            'function' => [
                'name' => 'get_weather',
                'description' => 'Get current weather for a city',
                'parameters' => [
                    'type' => 'object',
                    'properties' => ['city' => ['type' => 'string']],
                    'required' => ['city'],
                ],
            ],
        ]],
    ]);
    
    // Tool calls are now populated on ANY finish reason (fix #2543, #2551)
    foreach ($response->getToolCalls() as $toolCall) {
        $result = $this->execute($toolCall->getName(), $toolCall->getArguments());
        // Feed back as a tool message in the next turn
    }
    
  4. Batch Processing

    // Process embeddings in parallel (using Symfony Messenger or similar)
    $embeddingTasks = array_map(fn($text) => new GenerateEmbeddingTask($text), $texts);
    $dispatcher->dispatch($embeddingTasks);
    

Integration Tips

  • Laravel Service Providers Bind the AiClientInterface in AppServiceProvider:

    $this->app->bind(AiClientInterface::class, function ($app) {
        return new GenericPlatformClient($app['config']['ai.platform']);
    });
    
  • Configuration Management Use Laravel’s config system to switch between platforms, including the new Eden AI gateway:

    // config/ai.php
    return [
        'platform' => env('AI_PLATFORM', 'generic'),
        'platforms' => [
            'generic' => [
                'endpoint' => 'https://api.generic-ai-provider.com/v1',
                'api_key' => env('AI_GENERIC_API_KEY'),
            ],
            'eden' => [
                'endpoint' => 'https://api.edenai.run/v2',
                'api_key' => env('EDEN_AI_API_KEY'),
            ],
        ],
    ];
    
  • Cost Tracking (New: TokenUsage model) TokenUsage now exposes the model name, so you can attribute cost per model without re-parsing the request payload:

    $response = $this->aiClient->chat([...]);
    $usage = $response->getUsage();
    
    Cost::create([
        'model' => $usage->getModel(),   // New in v0.14
        'input_tokens' => $usage->getInputTokens(),
        'output_tokens' => $usage->getOutputTokens(),
        'cost' => $this->pricing->for($usage->getModel())
            ->calculate($usage->getInputTokens(), $usage->getOutputTokens()),
    ]);
    
  • Carbon Footprint Metadata (Albert) Albert responses now expose carbon footprint data via result metadata — useful for ESG reporting or green dashboards:

    $response = $this->aiClient->chat([...]);
    $carbon = $response->getMetadata()['carbon_footprint'] ?? null;
    if ($carbon) {
        GreenMetric::record($carbon->getGramsCO2e());
    }
    
  • Caching Responses Cache embeddings/chat responses to avoid redundant API calls:

    $cacheKey = 'embedding_'.md5($text);
    return Cache::remember($cacheKey, now()->addHours(1), fn() =>
        $this->aiClient->embed(['input' => $text])->getEmbedding()
    );
    
  • Error Handling Wrap API calls in try-catch blocks:

    try {
        $response = $this->aiClient->embed(['input' => $text]);
    } catch (AiException $e) {
        Log::error('AI Embedding Failed', ['error' => $e->getMessage()]);
        throw new \RuntimeException('Failed to generate embedding', 0, $e);
    }
    

Gotchas and Tips

Pitfalls

  1. Platform-Specific Quirks

    • The "generic" bridge assumes a standard API schema. If your provider deviates (e.g., non-standard response formats), extend GenericPlatformClient:
      class CustomGenericClient extends GenericPlatformClient {
          protected function decodeResponse(array $data): mixed {
              // Override to handle custom responses
              return $data['custom_key'] ?? parent::decodeResponse($data);
          }
      }
      
  2. Tool Call Finish Reasons (Fixed in v0.14)

    • Prior to v0.14, tool calls could be silently dropped when the provider returned a stop finish reason instead of tool_calls. Upgrade to v0.14 to get consistent tool-call extraction across all finish reasons. If you pinned an older version, guard your parsing logic explicitly by inspecting getFinishReason().
  3. Rate Limiting

    • Generic platforms may throttle requests. Implement exponential backoff:
      use Symfony\Component\AI\Exception\RateLimitExceededException;
      
      try {
          $response = $this->aiClient->chat($prompt);
      } catch (RateLimitExceededException $e) {
          sleep(2 ** $this->retryCount++);
          retry();
      }
      
  4. Cost Management

    • Embedding generation can be expensive. Validate input lengths:
      if (strlen($text) > 5000) {
          throw new \InvalidArgumentException('Input too long for embedding');
      }
      
    • New in v0.14: use TokenUsage::getModel() when persisting usage so cost aggregation is accurate even when you route across multiple models.
  5. Dependency Conflicts

    • Ensure symfony/ai and symfony/http-client versions are compatible. Avoid:
      composer require symfony/ai:^1.0 symfony/http-client:^6.4
      
      (Check Symfony’s docs for version pairs.)
  6. Eden AI Gateway Caveats (New in v0.14)

    • Eden AI proxies many vendors behind one endpoint. Model IDs and response shapes can vary per underlying vendor — verify the usage block and metadata keys returned for your chosen combination before relying on TokenUsage or carbon footprint fields.

Debugging Tips

  • Enable API Logging Configure HTTP client logging in config/packages/http_client.yaml:

    framework:
        http_client:
            logging: true
    
  • Validate API Responses Use dd() to inspect raw responses:

    $response = $this->aiClient->embed(['input' => $text]);
    dd($response->toArray()); // Debug raw data
    
  • Mocking for Tests Use Symfony\AI\Client\MockAiClient in PHPUnit:

    $mockClient = new MockAiClient();
    $mockClient->expects('embed')->andReturn(new EmbeddingResponse([1, 2, 3]));
    $this->app->instance(AiClientInterface::class, $mockClient);
    

Extension Points

  1. Custom Platform Clients Extend GenericPlatformClient for provider-specific logic:

    class OpenAIPlatformClient extends GenericPlatformClient {
        protected function getEndpoint(): string {
            return 'https://api.openai.com/v1';
        }
    }
    
  2. Middleware for AI Requests Add request/response modifiers:

    $client = new GenericPlatformClient($config, [
        new AddAuthHeaderMiddleware('Bearer %env(AI_TOKEN)%'),
        new RetryMiddleware(),
    ]);
    
  3. Event Listeners Subscribe to AI events (e.g., AiClientEvent):

    $dispatcher->addListener(AiClientEvent::PRE_REQUEST, function (AiClientEvent $event) {
        if ($event->getRequest()->getUri() === 'embed') {
            $event->setRequest($event->getRequest()->withHeader('X-Custom-Header', 'value'));
        }
    });
    
  4. Laravel Scout Integration Use embeddings with Laravel Scout for vector search:

    use Laravel\Scout\Searchable;
    
    class Post extends Model implements Searchable {
        public function toSearchableArray() {
            return [
                'title' => $this->title,
                'embedding' => $this->aiClient->embed(['input' => $this->content])->getEmbedding(),
            ];
        }
    }
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
stevenay/myanfont
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc
animalyoung/laravel-influxdb
onix-solutions/sms-telera
lonely-lights/prosetta
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge