Skip to main content
KaireonAI models retrain on different rhythms depending on what kind of model they are and how you configure them. Two mechanisms are wired end-to-end — continuous (online, per-/respond) and scheduled/evidence-based (offline cron). A third, drift-triggered retrain, ships as primitives but is not auto-scheduled in the default deployment (see §3). This page explains the mechanisms, the per-algorithm defaults, and the API/UI toggles that change the cadence.

TL;DR

Out-of-the-box defaults are conservative. Every new algorithmModel row starts with autoLearn: false, learnMode: "none", learnSchedule: null — so tabular models won’t retrain unless you explicitly turn it on. Bandits and online learners ignore these toggles and always learn on every respond, because that’s the entire point of those algorithm families.

The three retraining mechanisms

1. Continuous (incremental)

For four model types — thompson_bandit, epsilon_greedy, bayesian (when priors are configured), and online_learner — the platform performs an in-place state update on every /respond call that returns a positive or negative outcome. The respond handler reads the current modelState from DB, applies the algorithm-specific update rule, and writes the new state back, all in a single Prisma transaction. Side effects:
  • algorithmModel.modelState advances (e.g. Thompson arm’s α += 1 on positive, β += 1 on negative).
  • algorithmModel.trainingSamples increments by 1.
  • algorithmModel.lastLearnedAt is set to now.
There’s no scheduling involved and no work to do — once the model is live and receiving traffic, it learns in real time. This is the right behavior for these algorithm families because they’re designed for online updates and would be wasteful to retrain in batch.

2. Scheduled offline retrain

For scorecard, logistic_regression, gradient_boosted, and neural_cf, learning is a full pass over accumulated training data. The platform runs a periodic cron (/api/v1/cron/scheduled-retrains) that:
  1. Finds every model with autoLearn: true, learnMode IN ("scheduled", "both"), and status IN ("active", "draft").
  2. For each, retrains if EITHER the schedule elapsed (now - lastLearnedAt >= parseScheduleToMs(learnSchedule || "24h")) OR ~100+ new outcomes have accumulated since the last retrain (evidence co-trigger) — whichever fires first.
  3. If due, runs a retrain pass inline (trainModelFromOutcomes) that recomputes weights / trees / embeddings from accumulated interaction-history rows.
  4. On completion, writes new modelState, metrics, metricsHistory[], predictors[].importance, and bumps both lastTrainedAt and lastLearnedAt.
The default cadence when learnSchedule is null is every 24 hours. Override with any of: "15m", "1h", "6h", "1d", "7d", or a cron expression like "0 3 * * *" (daily at 03:00 UTC).

3. Drift-triggered retrain (primitives only — not auto-scheduled)

The platform ships the building blocks for drift-triggered retraining but does not run them on a schedule today:
  • computePSI / detectDrift (lib/model-governance.ts) compute a Population Stability Index and KL divergence on predictor score distributions. The default PSI trip threshold is 0.25 (PSI < 0.1 = stable; 0.1–0.25 = monitor; > 0.25 = drifted).
  • runScheduledDriftChecks(tenantId) walks active models, compares recent interaction scores against each model’s metricsHistory baseline, and returns the set of drifted models to enqueue for retrain.
The catch: runScheduledDriftChecks is only reachable through checkScheduledRetrains (lib/scoring/auto-learn.ts), and nothing currently calls checkScheduledRetrains. The wired /api/v1/cron/scheduled-retrains cron does its own inline schedule + evidence-threshold retrain and evidence decay — it does not run drift checks. So there is no automatic “retrain on drift” behavior in the default deployment. To approximate drift-aware retraining today, either shorten learnSchedule so the model refreshes often enough to absorb shifts, or invoke /api/v1/cron/scheduled-retrains more frequently — the evidence-threshold co-trigger (below) will retrain after ~100 new outcomes regardless of schedule. Wiring runScheduledDriftChecks into a cron is roadmap work.

Toggling the cadence — API

Every field shown below can be set on POST /api/v1/algorithm-models (model creation) and PUT /api/v1/algorithm-models/{id} (update):

Field reference


Toggling the cadence — UI

In the Studio at Algorithms → Models → , the model-detail panel has a Learning section with the same three controls: an autoLearn toggle, a learnMode dropdown, and a learnSchedule text field with format hints. Changes save via PUT immediately; the new cadence takes effect from the next scheduled-retrains run. Note the retrain cron itself runs daily by default (the in-process maintenance scheduler fires /api/v1/cron/scheduled-retrains on a 1440-minute cadence), so a shortened learnSchedule is only honored as often as the cron runs — point an external scheduler at the endpoint if you need sub-daily retrains.
This is what we’d reach for if you handed us a fresh tenant tomorrow:
  • Cold-start with sparse historical data. Pick a thompson_bandit or epsilon_greedy. The continuous-learning behavior means the model is useful from request #1 — no warm-up needed. Move to bayesian after you have ~10k interactions and want to incorporate predictor features.
  • Steady-state tabular workload with predictable churn. scorecard or gradient_boosted with autoLearn: true, learnMode: "scheduled", learnSchedule: "24h". Nightly is enough for most NBA workloads where the underlying customer behavior doesn’t shift hour-to-hour.
  • Volatile distribution (pricing tests, seasonal pushes, regulatory changes). Same as above but drop to a "6h" (or shorter) cadence so the schedule absorbs sudden shifts. Automatic drift-triggered retrain is not wired today (§3), so a short schedule plus the ~100-outcome evidence co-trigger is how you stay fresh on volatile days. Watch PSI in Model Health to decide when to tighten the cadence further.
  • Catalogs with fast turnover (new offers daily). Drop the schedule lower ("4h") or use drift-triggered exclusively — neural-cf especially benefits from fresh embeddings against the current catalog.
  • Compliance-sensitive deployments where every retrain needs human review. Set autoLearn: false and use the model promotion endpoint (POST /algorithm-models/{id}/promote) to manually advance retrained candidates through draft → shadow → challenger → champion with audit-log review at each step.

Common questions

“My scorecard model’s metricsHistory is empty. Did it train?” Almost certainly not. New models ship with autoLearn: false; the scheduled-retrains cron skips them. Flip autoLearn: true, learnMode: "scheduled" and wait for the next cron tick. Or trigger a one-off retrain via the Studio’s “Retrain now” button (which calls /api/v1/algorithm-models/{id}/train). “My Thompson bandit’s arms aren’t moving.” Three possibilities. First, check that /respond calls actually carry outcomeTypeKey — without a classifiable outcome the bandit can’t update. Second, check lastLearnedAt on the model: if it’s null, no incremental update has fired, which usually means the model isn’t wired into the active decision flow’s score node. Third, check modelState.arms — if it’s {} or missing, the model hasn’t been initialized; either re-create the model (its init path will seed arms from the candidate offers) or set arms explicitly via PUT. “What’s the difference between lastTrainedAt and lastLearnedAt?” lastTrainedAt is set by full offline retraining (the cron-driven flow). lastLearnedAt is set by either offline retraining OR by any incremental update (every respond for bandits / online learners). So a Thompson bandit will have lastLearnedAt advancing every minute and lastTrainedAt permanently null — that’s correct, because Thompson doesn’t have an offline-train concept. A scheduled gradient_boosted will have both fields advance together every 24h. “Can I retrain on-demand for testing?” Yes. POST /api/v1/algorithm-models/{id}/train triggers an immediate offline retrain regardless of schedule. Useful for evaluating data fixture changes before a flow goes live.
See also: Algorithms & Models | Algorithm Models API | Experiments — Shadow vs Champion/Challenger