NVIDIANVIDIA-Certified Professional: Agentic AI2026-105.1 Implement memory mechanisms for short- and long-term context retention.
Rank useful memories and retire stale ones
Completed by the knowledge check
Learning objective
Retrieve memories by relevance and recency, and apply decay, expiry, and deletion.
Core idea
Memory retrieval has two different jobs: decide which records are eligible, then rank the eligible records for the question. Relevance measures usefulness to a query; recency measures time. Decay changes ranking as time passes, expiry makes a record ineligible at a deadline, and deletion removes a stored copy. A strong similarity match cannot override an expiry deadline.
The ownership and isolation rules are established in 1.4.2, and 5.1.2 covers supported writes and corrections. Here you implement the read pipeline and its cleanup path. The central failure is operational: returning the nearest few vectors first, then dropping stale records, can leave the agent with no memory even when useful eligible records exist farther down the candidate list.
How it works
Generate candidates with the right score meaning
NeMo Agent Toolkit’s MemoryEditor.search(query, top_k, **kwargs) is the provider seam for retrieval. The automatic wrapper passes search_params to that method. A custom provider can implement candidate selection, eligibility checks, and reranking before returning the final MemoryItem list. MemoryItem.metadata holds application-defined timestamps and lifecycle fields; adding those fields does not itself enforce them.
NVIDIA’s documented RedisEditor.search accepts user_id, top_k, and an optional similarity_threshold. Its score is L2 distance: lower scores mean closer matches, and results above the threshold are filtered out. A comparison written for a similarity score where larger is better reverses this behavior. Calibrate a threshold on representative questions and memories rather than copy one from an unrelated embedding setup.
A LangGraph store offers asearch(namespace_prefix, query=..., filter=..., limit=..., offset=...). Semantic search requires an embedding index. NVIDIA’s existing-graph integration uses workflow._type: langgraph_wrapper, with graph naming the implementation; the store calls belong inside that graph. This is a separate implementation path from a NeMo memory provider, not a promise that all provider keyword arguments are interchangeable.
Filter, rank, and bound the final context
At query time, exclude records that fail the authorized scope, active-status, or expiry checks. Where the backend supports the required filters, apply them during candidate generation. Otherwise retrieve enough candidates for the provider to check and replenish before selecting the final results. Preserve a retrieval work limit: filtering cannot justify unlimited searches on the answer path.
For recency, choose which timestamp expresses the fact’s freshness. created_at measures insertion and updated_at measures store updates in LangGraph’s item model. A bookkeeping update need not mean that a business fact was revalidated. An application-defined verified_at can capture that event explicitly. Do not refresh it merely because retrieval returned the memory; otherwise frequently retrieved mistakes remain artificially young.
A concrete custom reranker can convert a nonnegative L2 distance d to a relevance value 1 / (1 + d) and multiply it by a decay factor 2 ** (-age_days / half_life_days). This is an example application rule, not a RedisEditor scoring option. Record the timestamp basis and half-life per memory category in a retrieval specification. Stable preferences can have a longer half-life than temporary meeting arrangements; validate that choice with retrieval cases containing both relevant distant records and irrelevant recent records.
Return only enough ranked memory to fit the answer’s token allocation. top_k or limit bounds item count, not total text length. A few large records can still overwhelm context. If eligible candidates cannot fill the requested count within the work budget, return fewer and answer from the remaining authoritative context instead of weakening expiry checks.
Candidates pass the eligibility checks before reranking, and a shortfall is replenished only within the work limit.
Expire immediately and delete deliberately
Implement expiry as a read-time predicate, for example now < expires_at in a custom provider’s search. Here expires_at is application metadata, not a portable toolkit setting. A periodic cleanup worker can remove expired keys later, but the predicate prevents that scheduling delay from exposing expired content. Decay alone cannot deliver this guarantee because a sufficiently relevant decayed record can still rank first.
Use LangGraph’s adelete(namespace, key) for targeted store removal, or implement the required selection in a custom MemoryEditor.remove_items. Verify a concrete provider’s deletion semantics before calling it: the abstract interface’s **kwargs does not specify a universal per-record deletion parameter. Track the exact keys to remove rather than infer deletion scope from the method name.
For bulk cleanup through a LangGraph store, asearch supports limit and offset. The stores documentation warns that results beyond limit are truncated without an overflow signal. Enumerate a stable set of affected keys before deleting, or use a backend traversal that tolerates mutations. Increasing an offset while deleting earlier rows can skip records as the result set shrinks.
After cleanup, verify both direct key absence and retrieval behavior. A stored summary may contain the retired fact even when the original record is absent; follow the source and derivative relationships established in 1.4.2. Also exclude a record marked ineligible before cleanup from any in-flight answer assembly. A stale candidate list must not bypass the final eligibility check.
Key distinctions and trade-offs
Choose each operation for its own effect:
| Operation | Deciding condition | Mechanism | Cost or limitation |
|---|---|---|---|
| Relevance ranking | The question needs semantically related facts | RedisEditor.search with L2 distance, or indexed store asearch(query=...) | Requires embeddings and score calibration |
| Recency preference and decay | Eligible facts lose usefulness with age | Custom reranker over a chosen timestamp and half-life | Can suppress useful distant facts; requires retrieval evaluation |
| Expiry | A record must stop influencing answers after a deadline | Custom search eligibility predicate on expires_at | Requires a trustworthy clock and checks on every read path |
| Deletion | The retained record must be removed | adelete(namespace, key) or scoped custom remove_items | Requires key enumeration and verification of affected derivatives |
LangGraph documents backend-dependent default ordering: InMemoryStore uses insertion order, while PostgresStore and AsyncPostgresStore list by descending updated_at. An unqueried store listing is therefore not a portable relevance-and-recency ranking policy. Make ordering explicit when application behavior depends on it.
Architecture / decision scenario
A consulting firm’s research assistant recalls client-meeting arrangements. Its retrieval budget permits 20 candidates and a final context of four memories. Temporary arrangements expire after seven days. The team selects a two-day half-life based on its retrieval tests; both numbers are scenario policy, not toolkit defaults.
One candidate has L2 distance 0.1 and was verified six days ago. Another has distance 0.4 and was verified one day ago. Under the example rule, their scores are approximately 0.909 × 0.125 = 0.114 and 0.714 × 0.707 = 0.505. The less similar but more recent arrangement ranks higher. A third record with distance 0.01 is eight days old: expiry excludes it before scoring, regardless of its excellent relevance.
The tempting design retrieves four nearest vectors and deletes expired records nightly. In a replay, three of those four vectors are already expired, so post-filtering supplies only one memory. The retrieval engineer instead considers up to 20 candidates, checks eligibility, applies the decay rule, and returns at most four within the context allocation. If that bounded candidate pool is insufficient, the response proceeds with fewer memories.
The platform owner snapshots expired keys for targeted deletion and verifies their absence afterward. The product owner checks that a corrected arrangement remains preferred even if the superseded one was retrieved many times. Together these checks exercise ranking, time sensitivity, expiry, and removal rather than accepting “the vector query succeeded” as the result.
Common exam traps
- Reading RedisEditor’s L2 distance as a score where higher means more relevant.
- Assuming a recent record is relevant or a relevant record is still eligible.
- Refreshing factual freshness every time an item is read.
- Using decay as a substitute for expiry or expiry as proof of physical deletion.
- Filtering only the final four candidates when eligible records exist outside that set.
- Deleting one truncated listing and assuming it represented the complete namespace.
What to remember
Filter eligibility, retrieve sufficient candidates within a work budget, rank using explicit relevance and time semantics, then bound the injected context. Decay changes priority, expiry stops use, and deletion removes retained records. Implement these behaviors in the provider or graph that owns memory reads and verify them independently.
Knowledge check
A team moves its memory retrieval to NeMo Agent Toolkit’s RedisEditor and ports a rule from its previous cosine-similarity setup: keep a memory only when its score is at least 0.8. After the move, the agent recalls unrelated memories and misses near-exact matches. What explains this?
top_k value is too small to reach the closest matchesRedisEditor scores by L2 distance: 0.0 is identical and larger values are farther away, so keeping scores of 0.8 and above keeps the distant records and drops the close ones. Recalibrate a similarity_threshold on representative questions and memories. The other explanations do not predict that the closest matches specifically disappear.A scheduling assistant may place at most four memories in its answer context and consider at most 20 candidates per query. Its provider takes the four nearest vectors, then drops those that are expired, out of scope, or inactive. Replays often answer with one memory although eligible matches sit further down the 20-candidate list. Which change fixes this within both limits?
Temporary meeting-room arrangements must stop influencing answers 48 hours after they were made. A proposal gives them a short half-life in the reranker’s decay factor so that old arrangements rank low. Which design meets the requirement?
now >= expires_at in the provider’s searchupdated_at so that recent ones come firstA research assistant’s reranker decays each memory by the age of its verified_at field. A superseded client address keeps outranking its correction, and logs show the provider sets verified_at to the current time whenever it returns a memory. What should change?
verified_at only when the fact is actually revalidatedupdated_at timestamp in place of verified_attop_k so that fewer stale memories are returnedverified_at should move only when the fact is revalidated. A shorter half-life still scores the refreshed record as new, updated_at records store updates rather than revalidation, and a smaller top_k keeps the wrong ordering.A cleanup job must remove expired memories from a LangGraph store namespace that holds about 50,000 items. It calls asearch with limit=100, deletes the expired items on that page, increases offset by 100, and repeats until a page comes back empty. Afterwards, some expired keys remain. Which change makes the cleanup complete?
limit to 1,000 and keep the same paging loopexpires_at at read time in place of deletingupdated_at before paging through itadeletelimit are also truncated without an overflow signal. Enumerate a stable set of keys, delete them, then verify their absence. A read-time check stops use but removes nothing, and a different page size or sort can still skip records.References
- NVIDIA, Adding a Memory Provider
- NVIDIA, Configure the Automatic Memory Wrapper Agent
- NVIDIA, nat.plugins.redis.redis_editor
- NVIDIA, Running Existing LangGraph Agents in NVIDIA NeMo Agent Toolkit
- LangChain, Stores