Product Decisions This Supports
- Build vs. buy on the LLM integration layer. This package is a bridge, not a platform. It buys you DeepSeek request/response mapping, streaming deltas, function-calling plumbing, and uniform error types behind Symfony AI's provider interface. The decision it informs is narrow but real: do we write and maintain our own DeepSeek client, or adopt a thin vendor bridge and spend our engineering time on product surface instead? For a single-provider, single-endpoint integration, the hand-rolled client is ~a few hundred lines and fully ours; the bridge wins when we expect to add or swap providers.
- Multi-provider / vendor-optionality strategy. The provider abstraction and model routing layer (v0.8.0) is the actual product asset here. It supports a roadmap position of "DeepSeek today, second provider when pricing or latency demands it, no rewrite." That is a cheap hedge to hold — but only if the abstraction is genuinely provider-agnostic, which is a claim to validate in a spike, not accept from a README.
- Cost-per-feature as a first-class product metric.
TokenUsage::model (v0.14.0) means token counts and model identity arrive together, so per-request cost attribution becomes a listener plus a rate card rather than a correlation project. This unlocks the decision PMs actually need: which AI features are worth their marginal inference cost. It enables the measurement; it does not supply the rate card, currency handling, price versioning, or invoice reconciliation — budget that as permanent small maintenance, owned by someone.
- Feature feasibility for the AI roadmap. Chat completions, tool/function calling, and multi-round history cover the standard 2024–2026 feature set: support assistants, structured extraction into app objects, agentic workflows with tools, content generation. Streaming deltas support the real-time UX that users now expect by default. Nothing here is a differentiator; it is table stakes, and the decision is whether to get it cheaply.
- Model catalog as a versioned input, not a constant. The catalog is now machine-updated via CI. That removes a maintenance chore and adds a failure mode: a routine dependency bump can rename or drop a model ID your config, feature flags, or pricing table hardcodes. This is a product-decision input — it argues for validating configured model IDs at boot and treating model choice as configuration with a review path, not a string in a controller.
- Scope decisions this package does not inform. It will not help you decide on prompt strategy, evaluation harness, guardrails, PII policy, or fallback behavior. Those are yours regardless of vendor, and conflating "we adopted the bridge" with "we have an AI platform strategy" is the most likely PM error here.
When to Consider This Package
Consider it when all of the following hold:
- You are on PHP 8.2+ and Laravel 10/11, and you already tolerate Symfony components in your dependency graph (or are prepared to, via something like
spatie/laravel-symfony-components).
- DeepSeek is a deliberate provider choice — cost, reasoning quality, thinking-mode support, or a data-residency requirement — not an incidental one.
- You have a multi-provider or swap-later intention that justifies paying an abstraction tax now.
- You can live with pre-1.0 SemVer: pin to
~0.x and treat every minor bump as a reviewable change with a changelog read, not a routine update. Symfony's BC promise does not apply below 1.0. The 0.13 → 0.14 bump was benign; the next one is not contractually obliged to be.
- Someone owns the integration seams: container bindings for Symfony's
Provider, queue/streaming handling so long responses don't block the request lifecycle, and cost accumulation that commits once at stream termination — including on client disconnect.
- You accept that streaming plus cost capture is nontrivial: token usage must be accumulated across deltas and committed once, and you should confirm
TokenUsage is populated on every path — function-calling round trips and aborted streams included — or spend will be undercounted.
Look elsewhere — or build the thin client — when:
- You need one provider, one endpoint, chat only. The abstraction earns nothing and the Symfony coupling is pure cost.
- Your stack is Laravel-idiomatic first: no existing Symfony components, no appetite for cross-framework container wiring. A native Laravel HTTP client wrapper will be less friction and more debuggable by your team.
- You need vendor support, SLAs, or a security review trail. One star, zero dependents, single-vendor-adjacent maintenance, and no external adopters means you are an early adopter doing diligence the ecosystem hasn't done. That is a legitimate choice; it is not a safe default.
- You need first-party cost governance, observability, or compliance tooling. The package ships none of it, and the retained-data implications (token counts and model IDs persist even though prompt content doesn't) need a policy answer before you build the usage table.
- Your AI workload is long-running or high-volume: performance and backpressure are your problem, and a bridge doesn't help you solve them.
How to Pitch It (Stakeholders)
To executives: We can add DeepSeek's models — chat, tool-calling, streaming — through a small, MIT-licensed adapter rather than a bespoke integration, and keep the door open to a second provider without a rewrite. The cost of the bet is low: the code we'd write anyway is mostly the code this replaces, and the abstraction is the part that pays off if pricing or quality shifts. The risk is maturity, not capability: the package is pre-1.0 with essentially no external adopters, so we pin the version, treat upgrades as reviewed changes, and keep our DeepSeek usage behind our own interface so the bridge is replaceable in a sprint, not a quarter. What we are not buying is a platform — cost tracking, fallbacks, and compliance stay ours. Recommend a time-boxed spike on one real feature, with a go/no-go on the second provider only after we've measured actual token spend per feature.
To engineering: Treat this as a replaceable adapter, not a foundation. Wrap it in our own interface so no application code names a Symfony AI class. Pin to ~0.x; read the changelog on every minor. Two known seams to design for up front: streaming needs to run off the request lifecycle and must commit token usage exactly once, including on abort; and configured model IDs must be validated against the shipped catalog at boot, because that catalog now changes under us via CI. Error handling is a genuine win — uniform API errors and typed exceptions (ModelNotFoundException, ExceedContextSizeException, IncompleteStreamException, retryable ServerException) mean one exception strategy instead of per-provider translation. The cost side is a listener plus a rate card we own and version; it is a forever-small maintenance item, not a launch task. Validate the "swap providers without rewriting" claim with a spike against a second provider before we put it in a roadmap slide.