Cet article est publié en anglais.
Model Serving Architecture: Why the API Is Only the Front Door
A guide to the platform behind an inference endpoint: routing, scaling, versioning, observability, security, and calling served models from Spring AI or LangChain4j.
Think about what a diner at a restaurant sees: someone takes the order, disappears toward the kitchen, and comes back with a plate. The part you can't see matters more. Orders get coordinated, stock gets checked, cooks prepare dishes, many tables get served at once, and each plate has to land in front of the right person.
Serving a machine learning model has the same shape. From the outside, an application sees an HTTP endpoint that takes a request and returns a prediction. Behind it there may be routing, authentication, feature lookup, preprocessing, the model runtime itself, resource management, version selection, monitoring and failure handling. The endpoint is the waiter. The serving architecture is the restaurant.
Leaving the notebook
A model can behave perfectly in a notebook and still be painful to operate once other systems depend on it. During development, a data scientist loads the model, prepares inputs, runs inference and checks results, all in a controlled setting. Production breaks each of those comforts. Several applications ask for predictions at the same moment, traffic rises and falls, versions must be swapped without interrupting callers, and an answer may depend on data owned by other services.
At that point the model stops being a standalone artifact and becomes one component of a distributed system. The question shifts from how to call it to how to offer inference as a dependable production service.
The API is the front door, nothing more
An API gives applications a controlled way to ask for predictions, yet it's a small slice of the whole. Imagine a payment moving through an online banking app. Before a decision can come back, the request may need to be authenticated, enriched with customer features, validated, preprocessed, matched to a model version, scored and then post-processed.
Each of those steps can alter the outcome. The model may answer in milliseconds while feature retrieval drags. A healthy model may become unreachable because the compute under it is exhausted. A fresh model version can behave differently without the API contract changing at all.
So treat the API as the entry point into a serving system, the same way the waiter stands for the visible side of the restaurant.
What happens during a single inference
A production request typically crosses several responsibilities before an answer reaches the business application. A gateway may deal with authentication, authorization, routing and rate limits. The serving layer then fetches features or context, runs preprocessing, picks a model version and calls the runtime. Afterward, the output may need post-processing before it's returned.
The path looks like this: client application, then API or gateway, then the serving layer, then feature and context retrieval, then the model runtime, then post-processing, then the response.
Seeing the whole path helps with diagnosis. If a call takes two seconds when it should take two hundred milliseconds, the model may be innocent. Feature retrieval, network hops, contention for resources or an overloaded worker could be to blame. For that reason, treat serving as one system from the client down to the runtime, and measure it that way.
The architecture behind it
Mature setups divide responsibilities instead of cramming everything into one service. The business application owns the interaction with the customer or process. The serving layer handles inference requests. The model runtime executes the model. Around them sit platform capabilities for deployment, scaling, security, observability and resource management.
The key point is that model serving belongs to the platform, in between applications and runtimes. It can hook into feature stores, model registries, gateways and infrastructure without making any of them part of the model. As models and consumers multiply, this split pays off: platform teams can change deployment and runtime details without making every application team learn them.
One model is rarely enough
The first deployment may involve a single model, but enterprise platforms seldom stay that tidy. Different business functions need different models, and one model may exist in several versions while it's being evaluated and rolled out.
That makes routing a design concern. The platform must decide which model and version answers a request and where it runs, especially when models differ in resource needs or share hardware.
A model registry gives you a trustworthy catalog of what exists and which versions are available. Rather than scattering deployment details through application code, the serving layer reads lifecycle information from the registry. This separates building models from consuming them, so a model can evolve without forcing callers to change on every release.
Scaling inference
Scaling inference isn't always like scaling an ordinary web service. A stateless API often grows by adding instances. Model servers face extra limits, because models can eat large amounts of memory, GPU capacity or startup time.
A big model may need specialized hardware, while a small one may handle thousands of requests per second. Some workloads gain from batching requests to keep hardware busy. Others can't tolerate even a small increase in response time.
So scaling choices have to weigh model size, traffic, concurrency, hardware, latency goals and cost together. Adding instances may fix one bottleneck and create another if loading time or GPU supply becomes the constraint.
Synchronous, asynchronous and batch
Not every use case demands an immediate answer. A fraud check during payment authorization needs one now. Document processing can accept a job and hand back results later.
Batch inference is a third pattern. Scoring millions of customers overnight is about throughput, not the latency of a single request.
Each pattern has its own architectural traits, so start from the business process and not from habit with REST. Ask how soon the prediction is needed and where it fits in the surrounding workflow.
Versioning is a production issue
Shipping a model isn't the same as shipping an application release. A new model can shift predictions and performance even when the serving infrastructure hasn't changed, so controlled rollout matters.
A common approach sends a small share of traffic to the new version while the old one handles the rest. The platform watches technical and business signals, raises the share step by step, and can roll back if the newcomer misbehaves.
Observability
Classic monitoring says whether infrastructure is healthy. Serving needs a wider view: inference latency, throughput, failures, model versions, resource use and the condition of dependencies such as feature services.
A system can look technically healthy and still produce odd results if the model receives inputs unlike those it was built on. Observability should therefore join infrastructure metrics with suitable model-level signals, while respecting how sensitive the data is. The goal is confidence that the right model is running, and running dependably within the limits you expect, beyond a mere reply from the endpoint.
Security and isolation
Serving endpoints expose valuable business capabilities and handle sensitive data, so security belongs in the design from the start. Authentication, authorization, request validation, rate limiting, network boundaries and access control should surround inference instead of arriving after deployment.
Isolation matters just as much when models share infrastructure. A single high-volume workload shouldn't be able to starve unrelated models of compute or memory, particularly when GPUs are involved. Handling serving as a platform feature lets these controls be applied consistently, instead of every application team solving the same problems alone.
Using it from Java
From a Java application, calling a model can look deceptively easy. A framework such as Spring AI offers a clean programming abstraction, and the work of deploying, scaling, routing and running models stays outside the app. That split is valuable in a company, where application teams shouldn't own the infrastructure decisions needed to operate every model.
With Spring AI, an app uses a ChatClient to call the AI capability while the model itself is exposed by the serving infrastructure:
@Service
public class RiskAssessmentService {
private final ChatClient chatClient;
public RiskAssessmentService(ChatClient chatClient) {
this.chatClient = chatClient;
}
public String assess(String transactionContext) {
return chatClient.prompt()
.system("""
You are a transaction risk assessment assistant.
Analyse the supplied transaction context.
""")
.user(transactionContext)
.call()
.content();
}
}
The code doesn't know whether the model sits in a local container, a Kubernetes cluster, a dedicated inference server or GPU hardware. That's the platform's business. The application consumes the capability through whatever interface it's given.
The idea gets more useful when the model needs structured context. Instead of letting each application fetch and assemble inputs by itself, move that job into an application or platform service:
public String assess(String customerId, Transaction transaction) {
String context = featureService
.getCustomerContext(customerId);
return chatClient.prompt()
.system("Assess the transaction using the customer context.")
.user("""
Customer context:
%s
Transaction:
%s
""".formatted(context, transaction))
.call()
.content();
}
The Java application orchestrates the business interaction, a feature service supplies current context, and the serving layer remains responsible for inference. As more applications use the same model, this division becomes more valuable.
LangChain4j offers a similar application-level abstraction. The enterprise app defines an interface that represents the AI capability, which keeps model-specific infrastructure out of business code:
public interface RiskAssistant {
@SystemMessage("""
Assess the transaction risk using the supplied
customer and transaction context.
""")
String assess(String context);
}
The app then uses that capability through the framework, and the endpoint behind it is managed independently:
String context = featureService
.getCustomerContext(customerId);
String assessment = riskAssistant.assess(context);
The boundary that counts isn't Spring AI against LangChain4j. Either can serve as the integration layer. What matters is the separation of business code, AI orchestration and serving infrastructure. It lets the platform change on its own: a model can move to another runtime, capacity can grow, a new version can roll out, and none of that forces a redesign of the Java applications consuming it. This is the real benefit of treating serving as a platform capability and not just a model hidden behind an HTTP endpoint.
Choosing an architecture
No single design fits every workload. A small model used by a low-traffic internal tool may run fine inside the application. A model shared by several business apps may justify a dedicated serving layer.
Containers give consistent deployment and scaling, and Kubernetes offers stronger orchestration for larger model portfolios. Specialized inference platforms make sense once you need GPUs, very high throughput, advanced batching or finer resource control.
Weigh model characteristics, traffic profile, latency requirements, business criticality, operational maturity and cost. The fanciest platform isn't automatically the right one. Aim for the smallest architecture that reliably meets the workload's needs and leaves a sensible path to grow.
The endpoint is just the start
Back in the restaurant, the customer sees the waiter, but that's a thin part of a large operation. The order has to be taken correctly, sent to the right station, cooked with available resources, coordinated with other tables and delivered without bringing the kitchen to a halt.
Model serving works the same way. An endpoint makes a model reachable, and reachability is only the beginning. Dependable inference rests on what surrounds it: routing, context retrieval, versions, compute, scaling, failure handling, observability, security and operational controls.
The model may stay at the center of the capability, but the serving architecture decides whether that capability can support real business decisions. Serving isn't about exposing a model. It's about building the system that lets a model support those decisions reliably.
Further reading
For the Java side, see the LangChain4j and Spring AI docs. On the platform side, the Kubernetes docs, KServe and NVIDIA's Triton Inference Server are good starting points.