mixle.inference.production.serving module¶
Production scoring with activity + computation logging and health/problem reporting.
A Service wraps a fitted model (loaded directly or from a Registry alias) and
scores production batches, recording every computation – record count, wall time, mean log-likelihood,
how many records were unscorable (outside the model’s support), and how many were unavailable (the
model could not be reached to ask) – to an in-memory activity log (and optionally a JSONL file).
health() summarizes recent activity so problems (rising unscorable rate, model unavailability,
falling log-likelihood, slow batches) are visible; with a reference sample set it can also flag drift.
Unscorable and unavailable are deliberately kept distinct. A record legitimately outside the model’s
support scores as a non-finite log-density that the model itself computes and returns, no exception
involved. A configured availability exception raised while asking the model – by default a failed
network call or backend timeout – means the model was unavailable: an outage, not a scored observation.
Service.score() isolates only that explicit failure mode as "model_unavailable" so an outage
is never silently folded into an ordinary -inf indistinguishable from a genuine one. Other
exceptions propagate as implementation or request errors instead of being masked by compatibility
retries.
The batch call failing is itself a distinct, separately-tracked degradation (mode
"batch_unavailable"). When seq_log_density raises a configured availability exception, every
record in that call is retried individually – and a record can recover (score normally through the
per-record path) even though the batch path failed for it. Left untracked, that retry would be invisible
on precisely the calls where it matters most: a batch endpoint that fails on every call but whose
per-record fallback always succeeds would leave no trace in the activity log or health() at all,
since every record still ends up scored and finite – nothing looks unscorable or unavailable, even
though every call is silently paying for a full per-record retry. n_batch_unavailable /
batch_unavailable_rate count records exposed to that fallback regardless of whether the retry
itself succeeded, so a degrading batch endpoint is visible before it starts actually losing data –
which is what unavailable_rate covers.
- class Service(model, *, name=None, reference=None, log_path=None, keep=1000, availability_errors=(ConnectionError, TimeoutError))[source]
Bases:
objectA deployed model that scores batches and logs each computation for monitoring.
- Parameters:
- classmethod from_registry(registry, name, *, alias=None, **kw)[source]
Load the model an alias points at in
registryand serve it (carrying its provenance header).aliasfollowsRegistry.current()exactly: naming one requires it to exist (an absent or misspelled alias raises rather than serving an unpromoted version), while omitting it takes the promotedproductionmodel if there is one and the latest registration otherwise.
- score(records)[source]
Return per-record log-densities and log the computation (timing, mean log-lik, unscorable count, unavailable count, batch-unavailable count).
Records affected by a
model_unavailablefailure (see module docstring) still score-infin the returned array – preserving its shape/dtype contract for callers – but are counted separately asn_unavailablein the logged event and surfaced asunavailable_ratebyhealth(), rather than being indistinguishable from a genuinely-scored-inf.The batch call itself failing is tracked separately again, as
batch_unavailable: every record in a batch whoseseq_log_densitycall raised is retried individually, and is counted inn_batch_unavailable/batch_unavailable_rateregardless of whether that per-record retry recovers a real score or itself fails inton_unavailable– so a batch endpoint that is failing over to the (much slower) per-record path on every call remains visible even when every individual retry happens to succeed and no record is actually lost.- Raises:
ValueError – if the model’s batch output does not have exactly one log-density per input record – a cardinality mismatch is a contract violation to reject, not a shape to silently accept. Raised only for a batch call that succeeded with the wrong shape; it is not itself treated as a reason to retry per-record.
- Parameters:
records (Any)
- Return type:
- check_drift(records)[source]
Drift of
recordsversus the service’s reference sample (requires areference).
- health(*, window=100)[source]
Summary of the most recent
windowscoring events – throughput, mean log-likelihood, the unscorable rate (the production problem signal), the unavailable rate (the subset of unscorable records caused by the model being unreachable – an outage – rather than legitimately scored), and the batch-unavailable rate (records whose batch call failed and had to be retried per-record, whether or not that retry itself recovered a score – always>=the unavailable rate; seescore()).mean_loglikis the mean over RECORDS, not over events: it is the total finite log-density divided byscored_records, so it does not move when the same scores arrive in differently sized batches. Averaging each event’s own batch mean made one record with log-likelihood 0 followed by 100 records averaging -10 report -5.0 instead of the true -9.901, which let batch shape alone manufacture or mask a degradation. Unscorable records are excluded from both the numerator andscored_records(they are counted byunscorable_rateinstead); an all- unscorable window reportsmean_loglik=Nonerather than a number derived from no evidence.- Parameters:
window (int) – how many of the most recent scoring events to summarize; an exact positive integer.
0used to select the whole history ([-0:]is a full slice) and a negative value selected a surprising suffix, both silently.- Raises:
TypeError – if
windowis not an exact integer (boolincluded).ValueError – if
windowis not positive.
- Return type: