Multi-armed bandits, as a service
Search for a multi-armed bandit and you will find papers, libraries, and bandits buried as a checkbox inside somebody’s experimentation suite. What you probably wanted was an endpoint you can call. That is what qbrix is: two calls — select and feedback — and the learning loop runs on our side.
The whole integration
Ask which variant to show, then say what happened. That is the entire runtime surface — everything else is setup you do once. The request_id you get back from a selection is what ties the two calls together: hand it to feedback whenever the outcome lands — a second later, or the next morning.
Reward is just a number. Send 1.0 and 0.0 for a conversion, or an order value, or a dwell time — whatever you are actually trying to maximize.
A library is not a service
The bandit libraries are good. MABWiser is genuinely well built, and Vowpal Wabbit is a serious piece of engineering. But read how MABWiser describes itself — “a research library… for rapid prototyping” — and it is telling you exactly what it is. Prototyping is not the hard part.
The hard part starts after the algorithm works on your laptop. Where do the parameters live once two servers are serving traffic? Who retrains, and how often? What happens on deploy — does the thing forget everything it learned? How do you keep any of it off the request path? None of that is bandit research. It is distributed systems work, and it is where the months go.
| A bandit library | qbrix | |
|---|---|---|
| The algorithm | You get it — this is what a library is for | Same algorithms, already running |
| Where parameters live | You choose, deploy and operate a store | Managed — cached on the selection path |
| Consistency across replicas | Yours to solve once more than one process serves traffic | Handled — one training path, many stateless readers |
| The training loop | You build the queue, the batching and the worker | Runs continuously off your feedback |
| Latency of a decision | Depends what you put on the request path | No database in the selection service — in-memory on a dedicated hot path |
| Restarts and deploys | Cold start unless you persist state yourself | State outlives any single process |
| Scaling out | Re-architect once one box is not enough | Selection scales horizontally by design |
| Time to first decision | Weeks to months | Two API calls |
If bandits are your research — you are tuning the algorithm itself, or publishing — take the library. It is the right tool and you should not pay anyone for an endpoint. This page is for the other case: you want the behavior in production next week, and the algorithm is a means, not the project.
Selection never waits for learning
The reason a bandit is hard to productionize is that it wants to do two things at once: answer instantly, and keep learning. Those pull in opposite directions, so qbrix splits them. Selection and training are separate services that never block each other.
On the serving side the selection service holds no database connection at all. The policy runs in-process against an in-memory cache — no locks, no I/O on the critical path once caches are warm — and that path scales horizontally, so more traffic means more replicas rather than a rewrite. Your feedback goes onto a stream instead, where a single training service consumes it in batches and writes updated parameters back for the selection path to pick up. Nothing on your request waits for any of it.
Read the architecture deep-dive — theory, trade-offs, and what it costsWe benchmarked it against a fixed split
A managed service is only worth the call if it beats what you would have done anyway. So we ran qbrix’s default auto policy against a textbook fixed-split A/B test — twenty runs each, through the full distributed stack, network hops and cache staleness included, on a deliberately hard problem: a 20% relative lift buried under 90% noise.
Worth being straight about the trade: the A/B test found the single best variant 100% of the time, and qbrix found it 95% of the time. A bandit buys you more conversions during the learning, not a cleaner verdict at the end. If a defensible causal readout is the deliverable, run the A/B test. If the traffic you spend while deciding is real money, that is the gap this measures.
Read the full benchmark — methodology and the dollar-scaling mathRead the code you run
The clients are MIT-licensed and on GitHub. The service itself is managed cloud — you cannot self-host it, and we would rather say so plainly than let you find out later — but nothing about the code sitting inside your application is a black box.
Frequently asked questions
What qbrix is, when to use it, how fast it is, and how to connect it to your app.
It is a hosted service that makes the explore-exploit decision for you over HTTP. You call select to ask which variant a given user should see, and call feedback to report what happened. The service keeps the reward estimates for every variant, updates them as feedback arrives, and shifts traffic toward whatever is working. You never implement the algorithm, store its parameters, or run the training loop.
A library gives you the algorithm; a service gives you the running system. With a library you still have to decide where the parameters live, keep them consistent across every process that serves traffic, retrain as feedback arrives, survive restarts and deploys, and keep it all off your request path. That is the part that takes months. qbrix is the algorithm plus the system around it — the library question never comes up. See how qbrix works →
Stochastic policies including Thompson sampling variants, UCB variants, epsilon-greedy and MOSS; contextual policies including LinUCB, LinTS, GLM-UCB and logistic Thompson sampling; and adversarial policies including EXP3, EXP3-IX and FPL. There is also auto, a meta-bandit that picks and tunes the policy for you, so you do not need to choose up front. Browse the policies →
Only if you use a contextual policy. Every select call carries a context object with a stable id — a user or session identifier. Contextual policies such as LinUCB and LinTS also read features from that context: you declare a schema of named properties when you create the experiment, then send values like device or cart value on each request, and qbrix does the encoding. A pre-encoded numeric vector stays available for callers who already hold their own embeddings. Non-contextual policies ignore both. Read about contexts →
Yes. Pools, experiments, and feature gates all have full REST endpoints, and the Python SDK wraps every one of them. The JavaScript/TypeScript SDK is deliberately narrower — it is a small isomorphic client for the runtime hot path, select and feedback, so define your experiments with the Python SDK, curl, or the console. See the API reference →
Feedback is processed asynchronously rather than on your request. It is consumed off a stream and trained in batches, so updated parameters reach the selection path within seconds, depending on batch settings. Your feedback call returns as soon as the event is accepted — it never blocks on training.
No. qbrix is a managed cloud service — that is the point of the product, and it is why there is no infrastructure for you to operate. The Python and JavaScript/TypeScript SDKs are open source under the MIT license, so the client code you run is fully inspectable. See pricing →