◆ Personalization

Personalized
Memory

A global model tells you who a shopper resembles. It can't tell you what just changed for them in the last five minutes.

Personalization is usually framed as a modelling problem: get a big enough network, feed it enough features, and it will know each customer. But however large the model or wide the feature space, a single trained model is still a global model, an average fit over millions of people. It learns the stable structure of demand well, and quietly smooths away the one thing that's most personal: the moment their taste turns.

This piece is about the layer that sits on top of that global model. A small per-customer memory that never really stops listening: it reads the shopper's behavior as a continuous signal in time, updates itself on every event, and keeps tailoring what the global model proposed. No retraining, no waiting for the next batch. The global model is only where it starts cold; from the first few visits each shopper carries their own baseline, and the memory keeps bending that personal baseline toward the moment. It settles down when a session goes quiet, but it settles onto who this shopper is, not back onto the average.

The clean way to think about it is an old one: a State Space model. The global model is the cold-start prior; the running prior is the shopper's own state. The session is the observation. A Kalman gain, set from behavior rather than hand-tuned, is the shrink factor between them.

From global model to personalized memory. On the left a faint cloud of dots is the global model, which learns the many slowly. A steady track runs out of it for two years of her weekly runs: produce, chicken, oat milk. On a Saturday at 9:14am four taps land in one direction - party trays, tortilla chips, queso, soda - and because the four agree, a trust dial opens and the track bends upward into personalized memory, which shifts in minutes. The global model's own path carries straight on, dashed and grey. The two paths end at two different shelves: memory serves guacamole, limes, cups and ice with nothing retrained, while the global model serves oat milk, produce and granola - right about her, wrong about today. If the turn keeps happening, it becomes the prior.
01 · The why

So why isn't the global
model just enough?

It's a fair question. If the model is big enough, with enough features, shouldn't it already know everyone? The catch is a quiet one: making it bigger makes the average sharper. It doesn't make the model yours.

What a global model is good at
Who you resemble
stable taste · category affinity · price tier · life stage · the durable structure of demand
but
▶
What it can't quite hold
What just changed
a sudden turn · a party instead of the weekly run · a nudge from an endcap · intent that flips mid-session
needs
▶
The layer this article is about
A memory for the moment
per-customer · live · training-free · trusts itself only as much as the signal earns

A global model learns the many, over the long run.
A turn happens to one person, right now.

Three reasons the moment slips past it

It isn't the model's fault.
It's just what averaging does.

One
It optimizes the average loss
Training minimizes error across everyone. A signal that's loud for one shopper and absent for the rest is, to the objective, noise to be smoothed. The rarer and more personal the moment, the harder the average pushes back on it.
Two
It moves on a slow clock
A global model refreshes on a batch cadence of days or weeks. The turn you care about happens in minutes. By the time the next training run folds it in, the party is over and the basket is checked out.
Three
The turn is the pivot, not the noise
A local nudge can be the point where a shopper's taste actually changes: a sample, an endcap, a season, a friend's recommendation. Averaged away, it looks like a blip. Caught early, it's the start of a new habit worth serving.
⚠
None of this is an argument against the global model. You want it; it carries everything durable and true about a shopper, and it's the only thing standing between a new customer and a cold start. The point is narrower: the global model just isn't the right tool for a fast, in-session turn, and adding parameters doesn't fix that, because the issue is the averaging, not the size.
02 · The what

What if the model didn't
have to relearn you?

The obvious fix is to train a model per customer. It doesn't really work. Millions of tiny models, each starved of data, each needing its own pipeline. It won't scale. Personalized memory gets to the same place a different way.

The thing that doesn't scale
A trained model per user. Every customer needs data, compute, a training job, a deploy, monitoring. Multiply by millions and you've built an operations problem, not a personalization system. And the customers who'd benefit most, the new and the changing, have the least data to train on.
The thing that does
One frozen global model, shared by everyone, plus a small per-customer memory that carries this shopper's own standing deviation from the average, read and updated at serving time. No gradients, no weight updates; just a few vector operations that re-rank on top of the global model — leaning first on what this shopper has always been, then on what they just did.

So the personal layer isn't a model in the training sense at all. It's a state: a running estimate of "where this shopper's intent is right now", carried forward from event to event and recombined with the shopper's own baseline on the fly (the global model only fills that baseline in before we know them). It runs as a continuous loop in time; each new event advances the same state a little, so the memory is always current without ever being retrained. This is the training-free online-inference idea, with one thing made explicit: how hard the memory is allowed to pull.

The part I find interesting

How much should we trust the moment?
Let the behavior decide.

Any blend of "global prior" and "personal signal" has a dial: how much do you let the fresh signal move the answer? The nice part is that this dial doesn't have to be a constant. It can rise and fall, per customer per moment, driven by features of the behavior itself.

Prior
This shopper's own state
their standing lean, carried across sessions; global only fills it in cold-start
shrink by
▶
Gain · the dial
Behavior-set weight
consistency · intensity · recency · how far off-prior the signal is
yields
▶
Posterior
What we serve now
prior, nudged toward the moment by exactly as much as the signal earned
●
Clear, consistent signal → trust the memory. Three baskets in a row of party trays, chips and soda: the shopper is telling you something. The dial opens, the personal state moves the ranking hard, and the shelf reflects the turn this session.
◉
Noisy, one-off signal → settle to the standing lean. A single odd click, or two purchases that point in opposite directions: high variance, low confidence. The dial closes, the memory holds back, and you settle to this shopper's own standing state — their baseline, not the global average — rather than chase a blip. Holding back still leaves you personal.

That behavior-set dial is a Kalman gain, with two deliberate changes from the textbook. The prior it leans on is this shopper's own state, not the global average, and the dial has a floor, so even a quiet session still serves something personal. On top of that, the re-rank down-weights what's globally popular, so the personal pick leans into what's distinctive about this shopper instead of echoing the crowd. The rest of this article is one worked example, then the math that makes all three precise.

What continuous memory looks like
Personalized memory as a continuous temporal signal resting on a personal floor above the global baseline A time axis runs left to right. A lower grey dashed line is the global model, the cold-start anchor. Above it sits a second, teal dashed line: this shopper's standing lean, the floor. Behavior arrives as a continuous stream of events along the top. A teal-to-pink curve is the personalized memory: it updates on every event, resting on the personal floor when the signal is sparse or noisy, bending sharply upward when a run of consistent events arrives, then easing back down to the floor. It never drops to the flat global baseline. time → Global model · the cold-start anchor This shopper's standing lean · the floor never collapses to global BEHAVIOR SIGNAL · EVENT BY EVENT consistent run → dial opens Personalized memory · always above global eases back to the floor
The global model is only the cold-start anchor, the lower dashed line. Above it sits a second baseline: this shopper's standing lean, the floor the memory rests on. Behavior is never a single snapshot; it's a stream of events in time. The memory rides that stream, updating on every event, leaning harder when the signal is consistent and easing back to the floor when it isn't — never all the way down to the global average.
03 · A real example

One shopper, one Saturday,
the dial moving

Meet a regular. For two years the global model has her pegged, correctly: health-conscious, budget-aware, a steady weekly run of produce, chicken, oat milk, kids' snacks. Then a Saturday morning looks nothing like that. Watch what each layer does.

SHE
Opens the app. First taps: party trays, tortilla chips (family size), queso, a 24-pack of soda.
session start
GLOBAL
Homepage shelf: organic produce, the usual oat milk, a coupon for the kids' granola bars she buys every week.
serves the average

Nothing here is broken; it's just not the right answer for today. The global model is doing exactly what it was trained to do: serve the durable, two-year pattern. It has no place to put "the last four taps look like a party," so it doesn't.

A global-only system stops here.
MEMORY
Four consecutive off-prior taps, all pointing the same way (entertaining, not the weekly run). Signal is consistent and intense. Open the dial.
gain rises
SERVE
Shelf re-ranks this session: guacamole & salsa, a bag of limes, cups and ice, a game-day dessert. Prior still guards the rails; nothing off-diet-extreme, nothing out of stock.
posterior served
SHE
Adds guacamole and limes. Keeps going.
signal confirmed
◆
The memory didn't retrain anything and it didn't overwrite who she is. It carried the two-year prior intact and bent the ranking toward the moment by exactly as much as the four consistent taps had earned. One inconsistent tap would not have moved it.
Why the dial, not a switch

The same signal, two shoppers,
two different amounts of trust

Party signal: strengthfour consistent, on-theme taps
HIGH CONFIDENCE
Regular shopper: how far memory moves the shelfstrong, stable prior to lean on
GAIN · MODERATE-HIGH
Brand-new shopper: how far the same signal moves itthin prior, but the signal is all we have
GAIN · HIGH
confidence in the signal gain when the prior is strong gain when the prior is thin

Notice that the gain is relative. For the two-year regular, the prior is trustworthy, so even a strong signal only tilts the shelf. For a first-time visitor the prior is nearly flat, so the same four taps carry almost the whole decision. A single fixed weight can't really do that. A behavior-set gain handles it on its own: the less you already know, the more the moment gets to count.

The other direction

And when the signal is just noise,
the dial closes on its own

What the shopper does
Gain
What gets served
Four taps, all on-theme (party trays → chips → queso → soda)
opens
Consistent & intense → memory moves the shelf toward entertaining.
One party tray, then straight back to oat milk and granola bars
stays low
One off-prior tap, high variance → hold the prior, treat it as a one-off.
Taps that contradict each other: keto items and a birthday cake
stays low
Signal points two ways at once → low confidence, shrink to prior.
The party pattern repeats every Saturday for a month
promotes
No longer a moment; it's a new durable taste. Let it graduate into the global model on the next refresh.
⚑
The last row is the handoff. Personalized memory catches the turn in the moment; if the turn keeps happening, it stops being a moment and becomes prior. The two layers aren't rivals. The memory is the fast loop; the global model is the slow loop; confirmed signal flows from one into the other.
04 · The math

A State Space view:
the shopper as the prior

In this section I'll go a level down into the model behind personalized memory: a state-space model, where a recursive Bayesian update treats this shopper's own carried state as the prior, the session as the observation, and the shrink factor as a Kalman gain set from behavior. The global model is still here — but as the cold-start anchor the personal state starts from, not the thing we fall back to. No global-model re-training anywhere.

Read the customer's current taste as a hidden state x in the global model's embedding space. We never observe it directly; we see behavior, a noisy readout of it, and we track it as it drifts.

x
Hidden state
this shopper's
taste, now
μ₀
Prior
this shopper's
own state
z
Observation
this session's
behavior
R
Obs. noise
set from
behavior features
K
Gain
the shrink
factor
μ₁
Posterior
what we
serve
Step 1 · The prior is the shopper, not the planet

Start from this shopper's own standing state

# the prior is a PERSONAL state: global baseline + this shopper's standing offset μ₀ = μglobal + δ # δ = how this shopper sits apart from the average x ~ N( μ₀ , P₀ ) # cold-start shrinks δ toward 0 (lean on global); as we learn them, δ persists new shopper → P₀ large, δ ≈ 0 # borrow the crowd known regular → P₀ small, δ ≠ 0 # their own baseline, kept

This is the first change from the textbook filter. The prior isn't one shared μ; it's μglobal + δ, where δ is the standing offset this shopper has earned. The global model only sets the baseline before we know someone — a large P₀ pulls δ toward 0. Once we do know them, δ stays, so even a silent session resolves to their baseline, not the average. That one move is most of why the personal answer stops looking like the global one.

Step 2 · Behavior sets the observation, and its noise

Most of the work happens in the variance

# the session is a noisy measurement of the true taste state z = H·x + v , v ~ N( 0 , R ) # z = embedded session behavior # R is NOT a constant; it is a function of behavior features R = R( consistency , intensity , recency , off‑prior distance ) consistent, intense, on‑theme taps → R small # trust the signal contradictory, one‑off, stale taps → R large # distrust it

This is the small choice that makes it feel like personalization and not just a filter. In a textbook Kalman filter R is a fixed sensor spec. Here the "sensor" is human behavior, and how much to trust it changes moment to moment, so we estimate R from features of the behavior itself. Small R when the shopper is speaking clearly; large R when they're not.

Step 3 · The gain is the shrink factor

Prior variance over total variance

# the Kalman gain: the fraction of the update you keep — but floored K = max( Kmin , P₀·Hᵀ / ( H·P₀·Hᵀ + R ) ) # scalar: K = max(K_min, P₀/(P₀+R)) # the posterior is the prior, shrunk toward the observation by K μ₁ = μ₀ + K·( z − H·μ₀ ) # innovation = how far behavior is off this shopper's baseline P₁ = ( I − K·H )·P₀ # and we got more certain # the two limits — note the floor changes the bottom one R → 0 ⇒ K → 1 # follow the moment R → ∞ ⇒ K → Kmin # settle to μ₀ = μ_global + δ, this shopper's own state

K is the "dial" from §02, but it rides between Kmin and 1 — not 0 and 1. When behavior is noisy it settles to the floor and you serve μ₀ = μglobal + δ, the shopper's own standing state; when behavior is crisp it moves toward 1 and you serve the moment. The floor is the small piece that stops a quiet session from ever collapsing the personal answer back onto the global average.

Step 3b · Serve the distinctive, not the popular

Divide out what everyone already buys

# at serving time, score by the personal state DOWN-weighted by global popularity score(item) = ⟨ μ₁ , item ⟩ / popglobal(item)β # β in (0, 1] # popular-everywhere items get discounted; personally-distinctive ones surface popglobal high → pushed down popglobal low, personal fit → lifted

A global model is an average, so its top picks are the globally popular ones — which is exactly why a naive personal re-rank keeps agreeing with it. Dividing by global popularity (a TF-IDF-style move) makes the personal layer index the long tail the average smooths away. β tunes how hard you push; a little exploration on top keeps it from always serving the greedy pick. This is the third change, and it's the one that makes the difference visible on the shelf.

Estimation termIn this systemWhat it controls
μ₀, P₀this shopper's carried state (μ_global + δ); global only seeds it coldthe personal baseline you settle to
zembedded in-session behaviorthe fresh signal
Rlearned from behavior features (consistency, intensity, recency)how far the dial can open
Kthe floored shrink factor (Kmin…1)how much of the moment reaches the shelf, and the floor that keeps it personal
μ₁re-ranking at serving time, down-weighted by global popularitywhat the customer actually sees
Step 4 · Why there's no training loop

Each event is just a small update

# each event just advances the same recursion: O(d) vector ops, no backprop predict : μ ← F·μ , P ← F·P·Fᵀ + Q # taste drifts a little between events (Q) update : μ ← μ + K·( z − H·μ ) # fold in the new behavior # the per-customer "memory" is just the carried pair memory(customer) = ( μ , P ) # i.e. (μ_global + δ, P): kilobytes, not a model

No gradient descent, no per-user weights, no retraining. The "memory" is a small carried state (μ, P) advanced by two cheap steps per event. That is what makes it scale to every customer: the expensive, shared thing (the global model) is trained once; the personal thing is a few vector operations at inference.

◆
The drift term Q matters too. It's the admission that taste moves even when we're not looking, so certainty decays between sessions and the memory stays willing to be surprised. Set Q too low and you get a stubborn shopper who can never change; too high and yesterday is forgotten by lunch. It's the memory's forgetting rate.
Where I might be wrong

The parts I'd want to double-check

1
the Gaussian / linear picture is a convenience. Real taste lives on a nonlinear manifold; the honest versions are an EKF/UKF or a learned recurrent state, and they're harder to keep stable
2
everything rests on R. If the behavior-to-variance map is bad, the dial opens on noise or stays shut on real turns, and that map has to be learned and monitored
3
a fast loop that re-ranks on four taps is also a fast loop that can be gamed or can chase a misclick into a bad spiral. Guardrails (margin, stock, compliance) must stay above the memory, not under it
4
if turns are rare and shallow for most shoppers, the global model was already enough and this is complexity you don't need. Measure lift over a strong averaged ranker before building it
5
the floor, δ, and the popularity de-weight are new knobs. Set the floor too high and you over-personalize thin, cold users; push β too hard and you bury things people genuinely want. Both need the same lift test, not a guessed constant
⚖
How I'd check it. Stand the memory up on one surface behind the existing guardrails, and check three things: does in-session relevance rise on the sessions where behavior departs from the baseline; does the gain settle to its floor (not shoot to zero) on the sessions where it doesn't; and on quiet sessions, does the served shelf still differ from the global pick in a way shoppers actually engage with? If the dial won't open when it should, won't rest on the personal floor when it shouldn't, or the floor just serves novelty nobody wants, the model is wrong and nothing downstream will save it.