symfony/ai-ollama-platform
Ollama platform bridge for Symfony AI, connecting your applications to locally hosted Ollama models for chat, embeddings, and NDJSON streaming through the Symfony AI component ecosystem.
HttpClient, Messenger, AI traits) must be abstracted or replaced with Laravel equivalents (e.g., Http facade, Queues, custom interfaces). The Provider abstraction (v0.8.0) and model routing are valuable but need Laravel-specific implementations (e.g., service containers, interfaces). v0.14.0 does not change this posture — it is an additive, non-breaking minor release.gemma:2b) are unique selling points for Laravel apps requiring multimodal AI.TokenUsage now carries a model property, enabling per-model token accounting and cost calculation. This is directly actionable in Laravel: persist TokenUsage rows to a ai_usage table, aggregate via Eloquent, and expose cost dashboards (Nova/Filament) or per-tenant budgets. It also closes the loop on the previously open ROI / self-host vs. cloud question by letting us normalize cost per model across providers behind the Provider abstraction.Messenger, AI traits) would need replacement or abstraction. The package’s dependency on Symfony’s HttpClient remains the biggest hurdle; Laravel’s Http facade or Guzzle can substitute with minimal effort.TokenUsage::model addition is additive, but we must verify: (a) our HTTP-wrapper integration path does not depend on TokenUsage serialization shape, and (b) any custom DTOs mapping usage data are updated to include the new field. Estimated effort: < 1 day, plus test-catalogue refresh.symfony/ai support → Custom facades/services required.Messenger → Laravel Queues/Horizon for async tasks.HttpClient → Laravel’s Http facade or Guzzle.DeltaInterface → Custom Laravel event listeners for streaming.| Risk Area | Severity | Mitigation Strategy |
|---|---|---|
| Symfony Abstraction Leakage | High | Isolate Symfony dependencies behind Laravel interfaces (e.g., OllamaClientInterface). Use adapters (e.g., HttpClientAdapter for Laravel’s Http). |
| Streaming in Laravel | High | Test NDJSON streaming with Laravel’s event system (e.g., broadcasting with Pusher, custom event listeners, or Swoole). Use queues for async streaming. |
| Ollama Infrastructure | Medium | Use Docker/Kubernetes for Ollama; implement health checks and retries in Laravel. Cache models in Laravel’s cache/database. |
| PHP Version Lock | Medium | Use php:8.1 in Docker or upgrade Laravel to 9+. Test with Laravel Pint and PHPStan for compatibility. |
| Pre-1.0 API Churn (now 0.14.x) | Medium | Pin the version in composer.json (e.g., 0.14.*), review changelogs on each 0.x bump, and keep all package touch-points behind our own interface so upstream breaks are absorbed in one adapter. |
| Model Catalog Management | Low | Cache models in Laravel’s cache or database. Implement a Laravel command to sync models with Ollama. |
| Cost Data Integrity (v0.14.0) | Low–Medium | TokenUsage.model must match our internal model keys for accurate cost rollups. Normalize model names at ingest, validate on write, and reconcile streamed vs. non-streamed usage paths. |
| Structured Outputs | Low | Validate JSON/array outputs with Laravel’s validation rules or custom pipes. |
| Audio/Multimodal Support | Medium | Test gemma:2b or other audio models in a staging environment before production. |
AI component in Laravel (high effort) or use this package only for HTTP calls (lower effort)?olliwood/ollama-php) be simpler than this Symfony bridge?TokenUsage (tenant, user, feature, model, prompt/completion tokens, computed cost, timestamp)? Do we persist per-request or aggregate?AI stack stable enough for production? What’s the deprecation policy for this package (still pre-1.0 at v0.14)?olliwood/ollama-php) or Laravel-specific AI packages (e.g., beberlei/ai)?gemma:2b).TokenUsage.model enables per-model cost attribution and quota enforcement).HttpClient with Laravel’s Http facade or Guzzle.use Symfony\Component\AI\Ollama\OllamaClient;
use Illuminate\Support\Facades\Http;
class OllamaService {
public function __construct() {
$this->client = new OllamaClient(
Http::macro('createClient', fn() => Http::client())
);
}
public function chat(string $model, string $prompt) {
return $this->client->chat($model, $prompt);
}
}
ProviderInterface to route models dynamically.interface OllamaModelProvider {
public function getModel(string $name): string;
}
class LaravelOllamaProvider implements OllamaModelProvider {
public function getModel(string $name) {
return config("ollama.models.{$name}");
}
}
AI component in Laravel (e.g., custom AIServiceProvider, interfaces).TokenUsage, reads model, computes cost from a config price table, and records to a Laravel model/job.class MeteredOllamaService {
public function chat(string $model, string $prompt): mixed {
$response = $this->inner->chat($model, $prompt);
$usage = $response->getTokenUsage(); // v0.14.0: includes ->model
AiUsage::create([
'tenant_id' => tenant()->id,
'model' => $usage->model,
'prompt' => $usage->promptTokens,
'completion'=> $usage->completionTokens,
'cost' => config("ai.prices.{$usage->model}.per_1k", 0)
* ($usage->promptTokens + $usage->completionTokens) / 1000,
]);
return $response;
}
}
HttpClient with Laravel’s Http facade.chat, embeddings).OllamaModelProvider / interfaces; move model names into config/ollama.php.ai_usage migration + Eloquent model, price table in config, aggregation command, and a dashboard view.TokenUsage array shape or json_encode output in custom code; the new model property must be handled if we destructure or persist DTOs.model column or backfill default; plan for rows predating the upgrade.| Failure | Blast Radius | Detection | Response |
|---|---|---|---|
| Ollama endpoint down / timeout | AI features degrade | Health check + error-rate alert | Circuit breaker, queued retry, graceful UI degradation, static fallback message |
| Model not pulled / wrong tag | Request fails at runtime | Catalog sync diff, 4xx rate | Scheduled sync command, deploy-time model pull |
| Streaming breaks mid-response | Partial output to user | Client disconnect metrics, incomplete-usage counter | Resume/retry policy, idempotent post-stream usage write |
TokenUsage.model mismatch vs. price table |
Silent zero/mis-costed billing | Reconciliation job comparing distinct models to priced models | Alert on unpriced model; default-deny or flag-and-log |
| Streamed requests missing usage data | Under-counted spend/quota | Compare stream vs. non-stream usage capture rate | Ensure usage captured on stream completion; fallback estimate from prompt length |
| Usage ledger write failure | Billing/quota drift | Queue failure alerts | Dead-letter queue + replay; do not block user response on metering |
| Upstream 0.x breaking change | Integration failure on upgrade | CI on version bump | Version pin + adapter isolation; roll back to previous pin |
0.14.*.How can I help you explore Laravel packages today?