Weave Code
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 Docker Model Runner Platform Laravel Package

symfony/ai-docker-model-runner-platform

Symfony AI bridge for Docker Model Runner. Connect Symfony apps to local/containerized models via Docker’s Model Runner API. Includes links to official docs and API reference; issues and PRs handled in the main Symfony AI repository.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the Package

    composer require symfony/ai-docker-model-runner-platform
    

    Ensure your project uses PHP 8.2+ and Symfony 7.x (Laravel 10+ compatible).

  2. Configure Docker Model Runner Add Docker Model Runner to your environment (e.g., via docker-compose.yml):

    services:
      model-runner:
        image: docker.ai/model-runner:latest
        ports:
          - "8080:8080"
    

    Update Laravel’s .env:

    AI_DOCKER_MODEL_RUNNER_URL=http://localhost:8080
    
  3. First Use Case: Text Completion Create a Laravel service to wrap Symfony’s ModelClient:

    // app/Services/AiService.php
    namespace App\Services;
    
    use Symfony\Component\Ai\ModelClient;
    use Symfony\Component\Ai\ModelProviderInterface;
    
    class AiService
    {
        public function __construct(
            private ModelClient $modelClient,
            private ModelProviderInterface $provider
        ) {}
    
        public function generateText(string $prompt): string
        {
            return $this->modelClient->completion(
                $this->provider->getModel(),
                $prompt
            );
        }
    }
    
  4. Register the Service Bind dependencies in AppServiceProvider:

    public function register(): void
    {
        $this->app->bind(ModelClient::class, function ($app) {
            return new ModelClient(
                $app->make(ModelProviderInterface::class),
                $app['http_client']
            );
        });
    }
    
  5. Test the Integration Call the service from a controller:

    use App\Services\AiService;
    
    public function chat(AiService $ai)
    {
        $response = $ai->generateText("Hello, world!");
        return response()->json(['response' => $response]);
    }
    

Implementation Patterns

Core Workflows

1. Model Provider Routing

Leverage the Provider abstraction to dynamically route requests to different models:

// app/Providers/AiModelProvider.php
namespace App\Providers;

use Symfony\Component\Ai\ModelProviderInterface;

class AiModelProvider implements ModelProviderInterface
{
    public function getModel(): string
    {
        // Route based on request or config
        return config('ai.models.default') ?: 'ollama/llama3';
    }
}

2. Streaming Responses

Use DeltaInterface for real-time streaming (e.g., chat apps):

use Symfony\Component\Ai\Streaming\StreamedResponse;

public function streamChat(AiService $ai)
{
    $stream = $ai->streamCompletion("What's Laravel?");

    return new StreamedResponse(
        fn () => $stream->toStream(),
        200,
        ['Content-Type' => 'text/event-stream']
    );
}

3. Embeddings with Token Tracking

Extract token usage for cost monitoring:

use Symfony\Component\Ai\Embedding\EmbeddingModelInterface;

public function generateEmbedding(EmbeddingModelInterface $model)
{
    $embedding = $model->embed("Sample text");
    $tokenUsage = $model->getTokenUsage(); // Track costs

    // Log to Laravel's Telescope or database
    \Log::info("Token usage: {$tokenUsage->inputTokens} input, {$tokenUsage->outputTokens} output");

    return $embedding;
}

4. Laravel Facade Wrapper

Create a facade for cleaner syntax:

// app/Facades/Ai.php
namespace App\Facades;

use Illuminate\Support\Facades\Facade;

class Ai extends Facade
{
    protected static function getFacadeAccessor(): string
    {
        return AiService::class;
    }
}

Usage:

use App\Facades\Ai;

Ai::generateText("Hello") // Instead of $aiService->generateText("Hello")

Integration Tips

Symfony HTTP Client in Laravel

Bind Symfony’s HttpClient to Laravel’s container:

// config/services.php
'http_client' => [
    'client' => Symfony\Component\HttpClient\HttpClient::create([
        'base_uri' => env('AI_DOCKER_MODEL_Runner_URL'),
    ]),
],

Docker Orchestration

Use Laravel Forge or Docker Compose for deployment:

# docker-compose.yml
version: '3.8'
services:
  app:
    build: .
    depends_on:
      - model-runner
  model-runner:
    image: docker.ai/model-runner:latest
    environment:
      - MODELS=ollama/llama3,baai/bge

Error Handling

Map Symfony exceptions to Laravel’s problem details:

use Symfony\Component\Ai\Exception\InvalidArgumentException;
use Symfony\Component\HttpFoundation\JsonResponse;

try {
    $ai->generateText("Invalid prompt");
} catch (InvalidArgumentException $e) {
    return new JsonResponse([
        'error' => 'Invalid input',
        'details' => $e->getMessage(),
    ], 400);
}

Testing

Mock the ModelClient in PHPUnit:

use Symfony\Component\Ai\ModelClient;

public function testAiService()
{
    $mockClient = $this->createMock(ModelClient::class);
    $mockClient->method('completion')->willReturn("Mocked response");

    $service = new AiService($mockClient, $this->createMock(ModelProviderInterface::class));
    $this->assertEquals("Mocked response", $service->generateText("Test"));
}

Gotchas and Tips

Pitfalls

1. Docker Dependency Hell

  • Issue: Docker Model Runner requires a running Docker daemon. Local development may fail if Docker isn’t available.
  • Fix: Use Laravel Sail with Docker-in-Docker (DinD) for CI/CD:
    # .github/workflows/test.yml
    services:
      docker:
        image: docker:dind
    

2. Symfony Abstraction Leakage

  • Issue: Laravel developers may struggle with Symfony’s ModelClient API.
  • Fix: Create a Laravel-specific facade or DTO layer to hide complexity:
    // app/Dtos/AiRequest.php
    namespace App\Dtos;
    
    class AiRequest
    {
        public function __construct(
            public string $prompt,
            public ?string $model = null,
            public array $options = []
        ) {}
    }
    

3. Streaming Quirks

  • Issue: DeltaInterface may not play well with Laravel’s StreamedResponse if not configured properly.
  • Fix: Ensure the stream is properly closed:
    $stream = $ai->streamCompletion($prompt);
    $response = new StreamedResponse(
        fn () => $stream->toStream(),
        200,
        ['Content-Type' => 'text/event-stream']
    );
    $response->send(); // Critical for cleanup
    

4. Token Tracking Gaps

  • Issue: Token usage extraction (v0.7.0+) may not cover all models.
  • Fix: Extend the EmbeddingModelInterface for custom models:
    use Symfony\Component\Ai\Embedding\TokenUsage;
    
    class CustomEmbeddingModel implements EmbeddingModelInterface
    {
        public function embed(string $text): array
        {
            $result = $this->callDockerModel($text);
            return [
                'embedding' => $result['embedding'],
                'tokenUsage' => new TokenUsage(100, 50), // Mock values
            ];
        }
    }
    

5. Configuration Overrides

  • Issue: Docker Model Runner URLs may differ across environments.
  • Fix: Use Laravel’s config caching with environment overrides:
    // config/ai.php
    return [
        'models' => [
            'default' => env('AI_DEFAULT_MODEL', 'ollama/llama3'),
        ],
        'docker' => [
            'url' => env('AI_DOCKER_MODEL_RUNNER_URL', 'http://localhost:8080'),
        ],
    ];
    

Debugging Tips

1. Log Docker Requests

Enable Symfony’s HTTP client logging:

// config/services.php
'http_client' => [
    'client' => HttpClient::create([
        'base_uri' => env('AI_DOCKER_MODEL_RUNNER_URL'),
        'logger' => function () {
            return new \Monolog\Logger('ai_docker', [
                new \Monolog\Handler\StreamHandler(storage_path('logs/ai_docker.log')),
            ]);
        },
    ]),
],

2. Validate Model Responses

Check for malformed JSON or unexpected types:

use Symfony\Component\Ai\Exception\RuntimeException;

try {
    $response = $ai->generateText("Test");
    if (!is_string($response)) {
        throw new RuntimeException("Invalid response type: " . gettype($response));
    }
} catch (RuntimeException $e) {
    \Log::
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.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky