symfony/ai-platform
Experimental Symfony component offering an abstraction layer for AI models and their providers. It defines common contracts and interfaces, while separate bridge packages add support for platforms like Anthropic, OpenAI, Gemini, Ollama, and Mistral. Install with composer require symfony/ai-platform.
Architecture fit. symfony/ai-platform is a contract layer, not a framework bundle: Platform, Model, Provider, message bags, deferred/streamed results, and one Composer package per vendor bridge. For a Laravel codebase this is the right shape — Laravel already ships and pins a large slice of symfony/* (console, http-foundation, process, routing, translation, error-handler), so the dependency graph is familiar ground rather than a foreign import. The critical caveat is that the abstraction is Symfony-idiomatic in its ergonomics (service contracts, Data Collector tied to the Symfony profiler, bridge registration conventions), even though the runtime objects are plain PHP and can be hand-wired in a ServiceProvider. There is no first-party Laravel package: no auto-discovered provider, no publishable config/ai.php, no facade.
Integration feasibility. High in the mechanical sense (one composer require plus a bridge), medium in the engineering sense. Three concrete frictions:
symfony/http-client ^8.0 will produce an unresolvable graph for a Laravel 11 app. This is the single most likely reason a spike fails outright, and it must be validated in the first hour, not the first sprint.Technical risk. The dominant risk is API instability, not capability. The changelog is candid and instructive: AssistantMessage was reworked, the OpenAI Chat Completions client was replaced by the Responses API client, MultiPartResult was introduced and then re-introduced, ElevenLabs catalog classes were renamed twice, and BinaryResult/DeferredResult gained methods mid-stream. All of that inside six minor versions. Symfony's experimental designation explicitly excludes these features from the BC promise, so every 0.x bump is a potential breaking change by policy. Secondary risks are vendor-truth drift (retired DALL-E endpoints, model catalog corrections across 0.7–0.10) and bridge-specific defects — the releases document dropped parallel tool calls, broken SSE handling for Gemini and Perplexity, and structured-output failures on reasoning models. These are normal maturation bugs, but they land on your production traffic, not the maintainers'.
Key questions to resolve before committing.
Mock test provider (added in 0.11) give us hermetic tests, or does it still require live credentials for meaningful coverage?Signal check. 55 stars and zero dependents is a pre-adoption signal, not a quality signal — the maintainers are Symfony core contributors and the monorepo is active. Treat it as a promising internal beta, not a foundation.
Stack fit. Position the package behind an owned boundary: define App\Contracts\AiClient with the two or three operations we actually need (complete, stream, embed), implement it with symfony/ai-platform, and bind it in a ServiceProvider. Nothing outside that adapter imports a Symfony\AI\Platform symbol. This costs a day and converts a framework-coupling risk into a swappable dependency — the difference between "we adopted an experimental component" and "we adopted a Symfony component."
Migration path. Start single-provider. Install symfony/ai-platform plus exactly one bridge — OpenAI or Anthropic for text, Bedrock if we are already AWS-resident — and run it against an internal, non-customer-facing workload (support summarization, classification, internal search). If we are currently on Prism, the Laravel AI SDK, or raw Guzzle calls, run the new path in shadow mode behind a config flag and diff outputs before switching traffic. Resist installing the failover and cache bridges in phase one; they are the right end state but they compound the debugging surface while the adapter is still settling.
Compatibility discipline. Pin exact versions (0.12.0, not ^0.12) and upgrade deliberately in a branch. Build a CI matrix that runs our test suite against the pinned version plus the latest available, so we learn about breaking changes from CI rather than from a 3 a.m. page. Because the repository is a read-only sub-tree split, bugs and PRs go to symfony/ai — budget for filing upstream issues rather than patching in place, and decide up front whether we will fork a bridge if a blocking defect sits unmerged.
Sequencing.
config/ai.php for provider, model, credentials, timeouts; per-tenant credential resolution via a resolver class; facade optional and thin.Maintenance. Expect an upgrade task roughly monthly while the package is pre-1.0, and staff for it explicitly — a half-day per minor for the adapter plus regression runs is a realistic planning number. The read-only split means issues live in the parent repo; our team must be able to describe defects precisely and, ideally, submit patches. Internal ownership of the adapter is non-negotiable: without it, the component's release cadence becomes our release cadence.
Support. No LTS, no commercial backing, no security-response commitment for experimental features. In practice the maintainer responsiveness visible in the changelog (rate-limit exception surfacing, malformed UTF-8 handling, retryable ServerException) is better than most 0.x packages. Budget for the scenario where a blocking bug has no upstream fix for a release cycle: the answer is the adapter, plus a documented fallback provider client.
Scaling. The component is HTTP-client based with real streaming support (SSE and NDJSON), so throughput scales with worker budget, not with the library. Two Laravel-specific constraints dominate: never hold a PHP-FPM worker for a long completion — push everything to queued jobs with explicit timeouts and retryUntil; and cap tool-call loops, because an unbounded agent loop is unbounded spend. Token-usage extraction exists across completions and embeddings, so per-tenant cost attribution is achievable; make it a first-class metric rather than a later add-on.
Failure modes to instrument for.
ModelNotFoundException on 404 responses helps, but only if we alert on it.Ramp-up. PHP developers will read the API surface quickly; the real learning curve is conceptual — message bags versus prompts, deferred versus streamed results, tool-call semantics, and what "provider-agnostic" actually normalizes versus what still leaks per bridge. Plan a half-day internal walkthrough plus the spike as the onboarding artifact. Team members with Symfony DI experience will be productive fastest; those without will find manual wiring in the ServiceProvider more legible than the bundle conventions, which is an argument for the adapter-first approach.
Bottom line. The abstraction is strategically correct and the maintainers are credible, but at 0.12 with 55 stars and zero dependents, the package is a bet on the Symfony AI initiative rather than on a proven library. Make the bet small, encapsulated, and reversible: one bridge, one use case, one App\Contracts\AiClient between us and it.
How can I help you explore Laravel packages today?