Episode Segmentation and Salience Scoring
How episode boundaries and salience scores shape long-term memory retrieval.
An episodic store needs boundaries that keep one task coherent without burying it inside an entire session. A conversation that moves from authentication debugging to deployment and then retry logging should produce separate retrievable episodes. Salience scoring then controls how strongly each episode influences later recall.
Segmentation signals
The five practical signals, ordered from cheapest to most-sophisticated. Production systems usually hybridize three or four of them; the goal of knowing them individually is to know which signal is failing when the segmentor mis-fires.
1; Fixed-window timeout (the baseline). Every N turns (typically 10-20) or every M minutes of clock-time, emit a boundary. Cheapest possible policy; zero model calls; trivially implementable. The failure mode is the mid-task split. A single coherent sub-task that runs longer than N turns gets cut in half, and the second half loses the context of the first half. Worth shipping as the floor of any segmentation system; it guarantees segments don’t grow unboundedly even when other signals fail.
2; Semantic-shift threshold. Embed each turn (or each user+assistant exchange) and compute the cosine distance to a running representation of the current episode; typically the mean embedding of the last K turns. When the distance exceeds a threshold (commonly 0.3-0.5 with Sentence-Transformers-style embeddings), emit a boundary. Costs one embedding call per turn (~$0.0001 at current rates) and a vector arithmetic op. The failure mode is the gradual drift. A conversation that slowly transitions from one topic to another over five turns never triggers the threshold on any single turn, and the boundary lands in the wrong place or is missed entirely. Mitigation: combine with the fixed-window floor to bound the worst case, and decay the running mean toward the most recent turns to make the threshold more reactive to sustained shifts.
3; Prediction-error boundary. Maintain a one-line running summary of the current episode (kept in working memory). Before each new turn, the model is implicitly predicting “what comes next in this conversation”; when the new turn diverges from that prediction above a threshold, emit a boundary. Concretely: every K turns, run a small-model prompt; “Here’s the current episode summary: <summary>. Here’s the next turn: <turn>. Does this turn continue the episode or start a new one?” The model emits continue|new|sub-episode plus an updated summary. Costs a small-model call every K turns (K=3-5 in practice). This is the closest direct port of the cognitive-neuroscience prediction-error mechanism, and it catches the gradual-drift case that pure semantic-shift misses; by the time five turns have drifted from the summary, the summary is the wrong anchor and the prediction-error flag fires explicitly.
4; Structural turn-type marker. Tag each turn with its type (user-question, user-correction, assistant-answer, tool-call, tool-error, tool-success, system-event) and apply rules: a tool-error followed by a user-question opens a new sub-episode; a system-event (new file uploaded, new tool granted) is always a boundary; a user-correction typically modifies the current episode rather than starting a new one. Costs nothing at runtime if the turn types are emitted by the orchestration layer (which a well-built agent harness already does); costs a small-classifier call per turn otherwise. The failure mode is type-fidelity; if the turn-type tagger is wrong, the structural signal misleads the segmentor; mitigation is to treat structural markers as hints to the higher-level segmentor rather than authoritative boundaries.
5; Agent-emitted marker. The agent itself emits explicit <episode_boundary> or <new_subtask> tokens during its own reasoning, and the segmentor reads them as authoritative. Costs essentially nothing (no separate model call; the agent emits the marker as part of its normal output) and has the highest fidelity because the agent is the closest possible observer of its own task structure. The failure mode is agent forgetting to emit. The agent gets absorbed in a sub-task and never marks the boundary; mitigation is to combine with signals 1-4 as fallbacks, so a missed agent marker is caught by the running prediction-error or semantic-shift detector. This is analogous to the explicit boundaries exposed by Anthropic’s context editing and compaction tooling; letting the agent self-segment is the highest-quality signal when it works, but never the only signal.
The defensible production stack runs all five: a structural-marker fast path (signal 4) catches the easy cases at zero cost; an agent-emitted marker (signal 5) catches the cases the agent self-identifies; a periodic prediction-error check (signal 3) every 3-5 turns catches the gradual drifts; a continuous semantic-shift detector (signal 2) catches sharp shifts the others miss; a fixed-window timeout (signal 1) bounds the worst case. Any single signal alone has a known failure mode; the layered combination handles each other’s blind spots.
Salience scoring
The salience score is the second output of the segmentation pass: once you have an episode, how much should it weigh on future recall? The canonical formulation, from Park et al.’s Generative Agents paper, is the 1-10 poignancy prompt with explicit endpoint anchoring. The exact text from the paper’s §A.1:
“On the scale of 1 to 10, where 1 is purely mundane (e.g., brushing teeth, making bed) and 10 is extremely poignant (e.g., a break up, college acceptance), rate the likely poignancy of the following piece of memory. Memory:
<episode>. Rating:<fill in>.”
The anchoring is the whole architecture. Without it, LLM-rated importance scores cluster at 6-8 regardless of content, the rerank’s importance term becomes near-constant, and the entire α·recency + β·importance + γ·similarity formula collapses to α·recency + γ·similarity; losing one-third of its information. With anchoring, the model has explicit endpoints to calibrate against; “is this more like brushing teeth or more like college acceptance?”, and the resulting distribution is wide enough that the rerank can actually use it. The anchoring works because the model has read enough text to know what a 1 looks like and what a 10 looks like; pinning the scale lets the rest of the range calibrate itself against the named endpoints.
A useful salience scorer needs the following properties.
Pattern 1; Anchor both endpoints with concrete examples. “1 = mundane, 10 = significant” is too abstract; “1 = brushing teeth, 10 = getting divorced” pins the scale. Use endpoints that are vivid enough that the model can’t read them as the same thing. For an agent in a specific domain, replace the Generative Agents’ personal-life endpoints with domain-appropriate ones; “1 = a one-line clarifying question, 10 = a critical production incident root-cause” for an SRE agent; “1 = boilerplate getter method, 10 = the core algorithm of the system” for a coding agent. Domain-specific anchors produce sharper scores than generic ones.
Pattern 2; Make the score deterministic. Run the scorer with temperature=0 and a tightly-constrained output schema (Literal[1, 2, ..., 10] or JSON-schema-constrained). Free-form generation will produce “7-8, depending on context” answers that the downstream pipeline has to parse; structured output forces a single integer and the rerank can rely on it.
Pattern 3; Score at the right unit. Score the episode, not the turn. Per-turn scoring is the most common production mistake; it inflates the rerank’s bias toward whichever turns happened to score high and makes the salience term roughly equivalent to a noisy reweighting of similarity. Per-episode scoring is what the Generative Agents paper actually does, and it’s the unit at which “how much did this matter?” is a well-posed question. The segmentor emits boundaries first; the salience scorer runs once per emitted segment.
A non-obvious refinement from the MemoryBank paper (Zhong, Guo et al., AAAI 2024) and the Generative Agents follow-up work: the salience score is updated at retrieval time. Each successful retrieval of an episode increments a recall-count or resets a recency-decay term; exactly the LRU/LFU hybrid the hierarchical memory piece named. The write-time score is the starting weight; the read pattern adjusts it. An episode written with importance=3 that gets retrieved 50 times has demonstrated more salience than the original score reflects; the maintenance pass should reflect that. Conversely, an importance=8 episode that’s never retrieved is a sign the write-time score was too high or the topic became irrelevant; either way it should decay.
Segment-and-score pipeline in Python
The smallest interesting build: a streaming segmentor that combines signals 1, 2, and 3 (fixed-window, semantic-shift, prediction-error) and a Generative-Agents-style salience scorer. Writes to Chroma for the episodic store. Uses the Anthropic SDK for both the prediction-error check and the salience score, Sentence-Transformers for the embedding-based semantic-shift detector. Install: pip install anthropic chromadb sentence-transformers.
| |
Segments are scoped per user so retrieval can enforce tenant isolation. Prediction-error checks run every few turns because model calls are expensive; fixed-window and semantic-shift checks cover the intervening turns. Salience is normalized to [0, 1] at write time to match the downstream reranker.