aiml
SearchMy learning
Menu

Lesson 14 of 19Module 4

Serve a versioned predictor through batch and HTTP

Reuse one validated preprocessing and prediction function across two adapters.

Reuse one validated preprocessing and prediction function across two adapters. A local Rice-classifier lab with explicit failure checks.

Prerequisites

Register and select a content-addressed model; Python dictionaries and basic HTTP requests.

Preparation and term definitions

By the end, you can

  • Reuse one named-feature validation and preprocessing function in batch and HTTP inference.
  • Compare actual HTTP and batch predictions for the same selected model version.
  • Keep malformed-request refusals separate from class predictions and production-serving claims.
Runtime
Python 3.12+
Dependencies
Standard library only

Lab code, tests and fixtures (ZIP, 2.4 MB)Quiz check your understanding

Progress is saved in this browser.

Problem

When you need this. Share one predictor when batch and HTTP callers must apply the same feature contract and preprocessing.

A selected model can produce different answers if one adapter changes feature order, fills missing fields or skips preprocessing. After loading one explicit registered version, you will give batch and HTTP inference the same named-feature contract and compare their actual results.

Concepts

The request names rice-measurements-v1 and supplies exactly the seven Rice measurements. Object field order is irrelevant: the predictor selects values in the bundle’s feature order, applies its retained scaler, and computes the classifier output. Missing and extra features are errors; neither is silently replaced with zero.

Both adapters call the same predictor. Each response includes the model digest, contract, class label and probability for Cammeo. Equality across these adapters checks this local path and input, not model quality or a general performance guarantee. Calibration requires a separate evaluation.

Architecture

One Python process; HTTP runs on a threadNamed features +contractBatch adapterComplete list or errorHTTP adapterPOST /predictValidate + scale+ predictVersion + label+ probabilityInvalid featuresRefuse predictioninvalidOne Python processNamed features +contractBatchadapterHTTP adapterServer threadValidate + scale+ predictVersion + label+ probabilityInvalid featuresRefuse prediction
Batch and loopback HTTP adapters call one predictor in the same Python process. It validates named features, applies the retained scaler and model, and returns the selected version with the prediction. Invalid features produce a refusal.

The batch function and HTTP handler run in the same Python process. The HTTP server runs on a background thread and binds loopback only. Both call predict(); the HTTP adapter additionally checks its route, content type and body size, then maps malformed requests to an HTTP error. The program compares complete JSON results rather than trusting an adapter’s success status.

Working code

Download the complete lab, extract it, and enter mlops-registry-serving/. Use Python 3.12 or later; there are no third-party dependencies. The ZIP includes the candidate, data, source and tests.

Run the focused serve exercise and its regression testsTerminal · bash
python exercise.py serve
python -m unittest -v test_pipeline.py

Submit a complete named-feature request

Run python exercise.py serve. It uses the previously trained candidate and makes real loopback HTTP requests; it does not train a new model. The request below is the actual input selected from the saved run, followed by the actual HTTP response.

Actual POST /predict request bodySource · json
{
  "contract": "rice-measurements-v1",
  "features": {
    "area": 13176,
    "perimeter": 458.3429870605469,
    "major_axis_length": 193.33738708496094,
    "minor_axis_length": 87.44839477539062,
    "eccentricity": 0.8918609023094177,
    "convex_area": 13368,
    "extent": 0.640669047832489
  }
}
Actual HTTP responseRecorded output · json
{
  "contract": "rice-measurements-v1",
  "label": "Cammeo",
  "positive_probability": 0.5836432257994117,
  "version": "a4692350c5e6d1f231eea8c5eb3354c24276870e73a60922a10abb07abffa5f6"
}

Reorder fields, then remove a required measurement

The exercise reverses the request object’s feature order and compares both HTTP responses with batch predictions. The named mapping preserves the computation. It then removes area from a copy and records HTTP 422 with invalid prediction request. The original request remains unchanged.

batch() returns a complete list or raises. It never returns a partial list when a later row is invalid. server.py supplies the actual handler; its body-size check does not replace feature validation in the shared core.

Actual serve exercise report from the previously trained Rice candidate, including its recorded result and refusal case.
Actual local execution using a previously trained candidate. The serving exercise makes real loopback HTTP requests. Full-resolution capture · Raw result · Command and hashes.
Read the actual server.py implementation
server.pySource · pythonDownload
"""Loopback teaching adapter. Not a production HTTP server."""
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from pipeline import decode, encode, predict


def server(bundle, version, port=0):
    class Handler(BaseHTTPRequestHandler):
        def log_message(self, *_):
            pass

        def reply(self, status, value):
            data = encode(value)
            self.send_response(status)
            self.send_header('Content-Type', 'application/json')
            self.send_header('Content-Length', str(len(data)))
            self.end_headers()
            self.wfile.write(data)

        def do_POST(self):
            if self.path != '/predict':
                self.reply(404, {'error': 'unknown route'})
                return
            try:
                size = int(self.headers.get('Content-Length', '0'))
                if not 0 < size <= 4096:
                    self.reply(413, {'error': 'body must be 1..4096 bytes'})
                    return
                if self.headers.get_content_type() != 'application/json':
                    self.reply(415, {'error': 'application/json required'})
                    return
                data = self.rfile.read(size)
                self.reply(200, predict(bundle, decode(data), version))
            except (ValueError, TypeError, OverflowError):
                self.reply(422, {'error': 'invalid prediction request'})
    service = ThreadingHTTPServer(('127.0.0.1', port), Handler)
    service.timeout = 2
    return service
Read the complete recorded serve output
Recorded local serve exerciseRecorded output · textDownload
{
  "execution_mode": "local exercise using a previously trained candidate",
  "candidate_sha256": "a4692350c5e6d1f231eea8c5eb3354c24276870e73a60922a10abb07abffa5f6",
  "request": {
    "contract": "rice-measurements-v1",
    "features": {
      "area": 13176.0,
      "perimeter": 458.3429870605469,
      "major_axis_length": 193.33738708496094,
      "minor_axis_length": 87.44839477539062,
      "eccentricity": 0.8918609023094177,
      "convex_area": 13368.0,
      "extent": 0.640669047832489
    }
  },
  "response": {
    "contract": "rice-measurements-v1",
    "label": "Cammeo",
    "positive_probability": 0.5836432257994117,
    "version": "a4692350c5e6d1f231eea8c5eb3354c24276870e73a60922a10abb07abffa5f6"
  },
  "reordered_fields_match": true,
  "batch_http_match": true,
  "missing_feature_status": 422,
  "missing_feature_response": {
    "error": "invalid prediction request"
  }
}

The exercise driver shows each operation and cleanup. The fresh-training driver and training run record document how the saved candidate was created. Adding --record to an exercise deliberately replaces its result and generated report; it does not refresh the screenshot automatically.

Failure cases

Trigger Required boundary and test
Missing or extra features test_missing_extra_boolean_and_nonfinite_features_refused rejects a wrong feature set, null, Boolean and nonfinite values.
Duplicate JSON keys test_duplicate_json_keys_refused prevents a repeated field from silently replacing an earlier one.
Nonfinite computation test_nonfinite_computation_refused checks finite inputs whose arithmetic overflows.
Invalid HTTP input test_real_http_matches_batch_and_rejects_bad_json exercises malformed JSON, wrong fields and an oversized body through actual HTTP.
Incomplete batch test_incomplete_batch_never_returns_partial_results rejects a batch with an invalid later row.

The recorded missing-feature response is a request refusal, not a negative class prediction. Keep that distinction in clients: an error cannot be counted as a successful model answer.

Deployment

The exercise starts a temporary loopback server, performs its requests and shuts it down in a finally block. Python’s HTTP server is a teaching adapter, not a production deployment. There is no authentication, concurrency admission control or connection deadline here. A public service needs those controls and an appropriate production server before exposure.

Scaling

Batch size is limited to 64 requests and an HTTP body to 4096 bytes. These bounds do not limit active HTTP threads, connection duration or total memory. No throughput or tail-latency benchmark was run. Measure the intended workload before choosing serving infrastructure; release rollout and monitoring remain separate work.

Key takeaways

The HTTP request contains all seven measurements but its fields arrive in a different order. What should this predictor do?

The HTTP request contains all seven measurements but its fields arrive in a different order. What should this predictor do?

Choose one answer, then check your reasoning.

Read the explanation

Named-feature validation makes object field order irrelevant while preserving the model’s expected order.

Best practices

Share one core predictor across adapters. Validate feature names and numeric values before arithmetic. Return model identity with each prediction, and distinguish request refusal from a valid negative classification.

References

Written by Arjun Prabhulal.

Module 4

Validate, register and serve a candidate