One AI gateway for every module on the store
Every AI extension arrives with its own API key field, its own vendor lock and its own blind spot on cost. LLM Provider is the shared layer underneath them: your keys, your model choice, your spend log.
ExtensionSooner or later a store wants something a language model is good at: drafting product copy, answering a shopper's question from your own content, checking a merchandiser's input before it goes live. The extensions that do those things each arrive with the same baggage. Each has its own API key field, buried in its own configuration section. Each is welded to one vendor, so the model you liked last year is the model you are stuck with. And none of them can tell you what any of it cost, because none of them can see what the others spent.
Adobe Commerce and Magento Open Source have no shared place for that. There is no notion of "the store's model provider", the way there is a notion of the store's mail transport or its search engine.
What it is for
LLM Provider is that shared place. It is a free, vendor-neutral gateway: one encrypted key store, one model registry, one price table, one call log – and a set of PHP contracts that any module can call instead of talking to a vendor itself.
Seven providers ship with it: Anthropic, OpenAI, OpenRouter, Google Gemini, Ollama, Stability AI and Voyage AI. They are configured once, by you, with your own keys, and shared by every module that consumes the gateway. Ollama runs locally and needs no key at all, which is the answer when the content in the prompt is not allowed to leave the building.
Three capabilities are exposed behind one interface each – chat (with streaming, vision and tool calls), image generation, and text embeddings – so switching a feature from one vendor to another is a dropdown, not a redeployment. Every call is attributed to the module that made it, priced against a per-model table you can edit, and counted against that module's own daily spend cap.
How it can be used
Run the AI features you install. The gateway is the dependency the AI series shares. Install it once, configure the providers you actually use, and every consuming module picks up the same keys, the same models and the same budget discipline.
Change your mind about a vendor. A consuming module names a tier – senior or junior – rather than a vendor. Which model each tier resolves to is admin configuration. Moving a feature from Anthropic to OpenAI, or onto a local Ollama model, changes no consumer code at all.
Keep the data on your own hardware. Ollama is a first-class provider, not an afterthought. For stores where prompts contain customer data, the same consumer code runs against a model on your own server.
See what it costs before the invoice does. Usage is recorded per module, per model and per call, with cost computed from the price table. The daily cap is per consuming module, so one runaway feature cannot spend another's budget.
Building a consumer
This is the part the gateway exists for, and it is three files and one call.
1. Depend on it. In composer.json, and in etc/module.xml so that
configuration and dependency injection load in the right order:
"require": { "webmaster-ramos/module-llm-provider": "^1.0" }
<sequence><module name="WebRamos_LlmProvider"/></sequence>
2. Declare what you were tested with. etc/llm_module.xml is the
compatibility contract. required_features and min_context_tokens are
enforced before any HTTP request happens; the <models> list means "tested with
these" and orders the admin dropdown:
<module name="Acme_AiAssistant" capability="chat">
<required_features>
<feature>json_schema</feature>
</required_features>
<min_context_tokens>100000</min_context_tokens>
<models>
<model id="anthropic:claude-haiku-4-5" tier="junior" recommended="true"/>
<model id="anthropic:claude-opus-4-6" tier="senior"/>
<model id="openai:gpt-5-mini" tier="junior"/>
</models>
</module>
The declaration is opt-in: a module without one is unrestricted. A merchant who wants a model released after your extension can switch on Allow Untested Models for that module, and the gateway admits any registry model that still meets your stated requirements, labelled (untested).
3. Ask for a model, not a vendor. The consumer ships a config group under
webramos_llm/modules/<Vendor_Module>/ and uses the gateway's own backend
model, so an admin cannot pick something your declaration rules out:
<field id="model_senior" translate="label" type="select" sortOrder="10" showInDefault="1">
<label>Senior Model</label>
<source_model>Acme\AiAssistant\Model\Config\Source\SeniorModels</source_model>
<backend_model>WebRamos\LlmProvider\Model\Config\Backend\WhitelistedModel</backend_model>
</field>
4. Make the call. One interface, LlmChatClientInterface, and a request you
build with setters. setCallerModule() is what attributes the cost and the log
entry:
$request = $this->requestFactory->create()
->setCallerModule(Config::MODULE_NAME)
->setMessages([Message::user($prompt)])
->setResponseFormat(ResponseFormat::jsonSchema(self::PAIRS_SCHEMA))
->setMaxTokens(self::MAX_TOKENS);
try {
$response = $this->chatClient->complete($request, $correlationId);
} catch (LlmException $e) {
if (!$e->getErrorCode()->isRetryable()) {
throw $e;
}
$response = $this->chatClient->complete($request, $correlationId);
}
$data = $response->getStructuredContent();
ResponseFormat::jsonSchema() is the part worth knowing about. On OpenAI it
maps to native structured outputs; on Anthropic, which has no such mechanism,
the adapter injects a synthetic tool whose input schema is your schema and
forces it. getStructuredContent() returns a decoded array either way, so the
consumer never learns which vendor answered. Schema validation is the
provider's, by documented contract – if you need a hard guarantee, validate the
decoded array yourself.
The full contract, including streaming, tool calls, images, embeddings and how
to add a provider of your own, is in DEV.md inside the module.
How it compares
Extensions that add an AI feature to Magento usually bundle the integration into the feature. That is the fastest way to ship one feature and the most expensive way to ship four: four key fields, four vendor couplings, four blind spots on cost, and no way to move any of them without touching code.
The other shape sells the model with the extension, metered by the vendor. That removes the setup and replaces it with someone else's price per call, someone else's retention policy for your prompts, and no local record of what was sent.
This one is neither. It is infrastructure: your keys, your provider choice, your price table, your log, on your own servers – and it is free, because the value is in what gets built on top of it. What it does not give you is a feature. On its own it renders nothing to a shopper; it is the layer the features stand on.
What it does not try to be
It is not an AI feature. Installed alone it adds an admin section and a set of contracts, and nothing on your storefront changes.
It does not resell model access. There is no bundled quota and no account with us – you bring keys from the providers you already have, or you run Ollama and bring none.
It does not decide anything about your catalogue. Prompts, schemas and what to do with an answer belong to the consuming module.
And it does not hide the bill. Every call is logged with its module, model, token counts and computed cost, in your own database, where you can query it.