How memory links help long-running agents understand what changed
Companion notebook: Graph-Aware Retrieval for AI Agent Memory
Key takeaways
- Graph-aware retrieval helps Oracle AI agent memory understand how a fact changed, rather than treating every memory as an isolated record.
- Typed links such as supersedes, refines, supports, duplicates, and contradicts make memory relationships explicit.
- Valid and invalid lifecycle states preserve the current answer while keeping older memories available as historical context.
- Automatic linking can support common memory evolution, while num_hops and linked_results keep graph context bounded and inspectable.
An agent can remember a customer’s delivery preference. That is useful. But the more important question is whether it can remember that the preference changed, why it changed, and which version should be trusted now.
That is the problem graph-aware retrieval is designed to address. Oracle AI Agent Memory adds relationships between memories so an agent can retrieve not only a fact, but also the context around that fact: what replaced it, what supports it, what refines it, and what should be treated as historical context.
This article walks through the model behind memory links, the valid and invalid lifecycle states, and the difference between ordinary retrieval and graph-aware search. It also connects those concepts to a working developer flow for Oracle AI Agent Memory backed by Oracle AI Database.
The important shift is that memory stops being only a store of facts. It becomes a small model of change: which record is current, which record was replaced, which record adds evidence, and which record should be kept only as history.
When agent memory needs more than the latest answer
Imagine an agent helping with a support case. In January, a customer says that email is the best way to contact them. In March, they ask to be contacted by phone during business hours. In June, they update the request again because they are traveling.
A flat retrieval system may find all three statements. It may even rank the newest one highly. But ranking alone does not explain the relationship between them. The older memories are not random noise; they tell us that the preference evolved. The June memory is current, the January memory is historical, and the March memory explains the transition between the two.
For an agent, that distinction matters. A response that ignores the history can sound confident but still be wrong. A response that treats every statement as equally current can expose contradictions to the user. A response that understands the links can answer from the current memory while using older memories when the conversation calls for an explanation.
This is especially important for enterprise agents because many business facts are not static. Customer preferences, support status, delivery windows, policy exceptions, and case evidence can all change over time. A memory layer that understands those changes gives the agent a better context package before the next model call.
How memory links improve context engineering for AI agents
A memory link is a typed relationship between two memory records. The type is important because it tells retrieval what the relationship means. A link between two records is not just an edge in a graph; it is a small piece of reasoning that can be used when assembling context for the agent.
| Link type | What it means | Example |
|---|---|---|
| supersedes | A newer memory replaces an earlier answer. | A newer delivery address replaces the previousaddress. |
| refines | A later memory adds detail without replacing the whole idea. | A general delivery preference is narrowed to a specific time window. |
| supports | One memory provides evidence for another. | A case note confirms the customer’s stated preference. |
| duplicates | Two records express substantially the same fact. | A repeated import creates the same memory twice. |
| contradicts | Two records make incompatible claims. | One memory says to call the customer, while another says not to call. |
These link types give the agent more than a collection of similar-looking search results. They provide a vocabulary for how facts relate, which lets an application preserve useful history without confusing historical information with the current answer.
Memory links are directed. For example, if a newer memory supersedes an older memory, the stored relationship is new memory -> supersedes -> old memory. When retrieval traverses the relationship in the other direction, the reverse relationship is exposed as is_superseded_by. The same pattern applies to refines/is_refined_by and supports/is_supported_by.
The graph does not replace the underlying retrieval or search strategy. Oracle AI Agent Memory can use vector, keyword, or hybrid search to find direct memory results, and graph expansion then follows relationships around those results. That is why a linked memory can be useful even when it would not be the highest ranked direct match.
Valid and invalid memory states keep agent memory trustworthy
When a memory is superseded, it does not necessarily disappear. Its lifecycle state can become invalid while the record remains available for historical retrieval. The newer memory becomes the valid answer for current use, and the older one remains available when the agent needs to explain what changed or when a user asks about an earlier interaction.
This is a practical distinction. Invalid does not mean useless. It means the memory should not be treated as the current answer without additional context. The application can still retrieve it through an explicitly scoped historical query, or it can receive it as a linked result when graph-aware search follows the relationship from a current memory.
The lifecycle model also makes memory maintenance easier to reason about. Instead of overwriting a record and losing the trail, the system can keep the record, preserve the relationship, and let retrieval decide how much history belongs in the response.
From memory records to graph-aware retrieval
The retrieval flow has four parts: store a durable memory, connect it to related memories, preserve the lifecycle state, and expand retrieval only when the application asks for linked context.

A graph-aware result can then include the current memory and the linked records that explain where it came from.
Conceptually, this is the difference between retrieval as ranking and retrieval as context assembly. Ranking answers the question: which memory is closest to the query. Context assembly asks which related memories help the agent use that answer correctly.
Use Oracle AI Database as the durable memory boundary
Graph-aware retrieval depends on durable state. The memory records, their lifecycle state, and the links between records need to live somewhere that survives a single chat session or application process. In this workflow, Oracle AI Database provides that boundary.
For Autonomous AI Database, the runtime can use the service name and wallet/client credentials supplied by the database connection setup. For Oracle AI Database or a local validation environment, the same store can use the appropriate DSN or connect descriptor. The notebook keeps passwords and API keys in environment variables or a private .env file rather than embedding them in the article or notebook output.
The next developer decision is schema policy. A fresh validation environment can create the managed objects when necessary; a production startup path should make upgrades deliberate and reviewable.
from oracleagentmemory.core import OracleDBMemoryStore, SchemaPolicy
store = OracleDBMemoryStore(
**store_kwargs,
schema_policy=SchemaPolicy.CREATE_IF_NECESSARY,
)
This is the line that connects the release story to the database. The graph-aware memory features depend on the managed schema that stores memory links, lifecycle information, and the graph representation used by retrieval. In a shared production environment, teams can use REQUIRE_EXISTING after migration review, so application startup does not silently change the schema.
For developers, the schema policy is not just a setup ceremony. It controls how much authority the application has at startup. That matters when agent memory becomes part of a shared production system rather than a local experiment.
Model changing facts as durable memories
A graph-aware memory example does not need a large synthetic graph to be useful. A small support scenario is enough: the first record captures a broad delivery preference; later records add a replacement preference, a more precise time window, and supporting workflow context. This gives the reader a clear before-and-after view of what the graph adds.
The records are durable memories, not temporary Python variables. Once they have been stored, the application can connect them with typed relationships and ask retrieval to return the current answer with the surrounding evidence.
Keeping each version as its own memory also avoids a common failure mode: overwriting the old fact and losing the reason the answer changed. With linked records, the current answer can stay clean while the historical path remains available.
Automatic linking for production-ready agent memory
An application may know that one event supersedes another and create the link explicitly. That is useful for workflows with a clear business event, such as a profile update or a case-status transition. But many applications do not have a clean event boundary. The relationship is visible only when the new message is interpreted alongside existing memories.
This explicit path is useful when the application has confirmed the relationship. A replacement-order workflow may know with confidence that a new delivery promise supersedes an earlier one. The record link makes that workflow fact durable and available tolater retrieval.
That is where automatic linking during memory extraction becomes useful. The extraction process can identify that a new memory supersedes, refines, duplicates, supports, or contradicts an existing memory. The agent developer can focus on the conversation and the memory policy while the system builds the relationship graph as part of the memory workflow.
memory_extraction_config = MemoryExtractionConfig(
memory_extraction_frequency=1,
memory_link_extraction_mode=(
MemoryLinkExtractionMode.POST_EXTRACTION
),
)
The release exposes POST_EXTRACTION, DURING_EXTRACTION, and DISABLED modes. POST_EXTRACTION is the default path shown in the release material: extracted memories are written first, then candidate memories are retrieved, and related links are identified. DURING_EXTRACTION presents candidates inside the extraction step, while DISABLED preserves extraction without automatic relationship discovery. The companion notebook uses DURING_EXTRACTION for the local runnable flow so extracted memories and candidate links can be inspected in one deterministic example.
For a developer walkthrough, explicit links make the behavior easy to inspect and reproduce. Automatic linking is still the experience most applications should aim for: explicit links are best when the application already knows the relationship, while automatic links help general-purpose memory workflows discover relationships during extraction.
Graph-aware retrieval with num_hops and linked_results
A normal memory search asks which records are most relevant to the query. Graph-aware retrieval asks that question and then considers the connected memories. The num_hops setting controls how far retrieval follows those relationships.
Think of num_hops as a context budget for relationships. A value of 0 behaves like direct retrieval. A value of 1 lets the search bring back immediate linked context without opening the door to an unbounded graph traversal.
With num_hops=0, the result is limited to the directly matched memories. With num_hops=1, retrieval can include memories connected by one link. This makes it possible to compare a direct answer with an answer that includes its surrounding context.
query = "What delivery window should I use for replacement shipment RMA-8842?"
search_options = { "max_linked_results": 5, "include_invalid_results": True, }
direct_results = await memory.search_async( query=query, user_id=USER_ID, agent_id=AGENT_ID, num_hops=0, **search_options, )
graph_results = await memory.search_async( query=query, user_id=USER_ID, agent_id=AGENT_ID, num_hops=1, **search_options, )
The direct result may identify the current preference. The graph-aware result can also expose the memory that it superseded, a supporting case note, or a refinement that adds the delivery window. The comparison keeps the query and the other search options the same, so the difference in returned context is caused by graph expansion rather than by lifecycle filtering or a different prompt.
max_linked_results bounds the amount of related context returned. include_invalid_results controls the top-level direct results, so an application can keep the current answer focused while still allowing historical memories to appear as linked context when they explain how the answer evolved.
Build a context package for future agent responses
Graph-aware retrieval is most useful when the relational information is easy to consume. The linked_results field provides that bridge. It lets an application distinguish the primary matches from the connected records and assemble a compact context package for the next model call.
A production application can use the same pattern to build a prompt-ready summary: start with the valid memory, include the linked historical or supporting context, and preserve the relationship label so the language model does not have to infer the connection from raw text alone. The result is a response grounded in both the fact and the path that led to it.
This is different from generic GraphRAG over a document corpus. The graph here is built from agent memories and their lifecycle relationships, so it can represent how the agent’s own durable context evolved over time.
linked_rows = []
for parent_rank, result in enumerate(graph_results, start=1):
for linked_rank, linked in enumerate(result.linked_results or [], start=1):
relation, linked_result = linked
linked_rows.append(
{
"parent_rank": parent_rank,
"linked_rank": linked_rank,
"relationship": relation.relation_type,
"linked_memory": linked_result.record.content,
}
)
display(pd.DataFrame(linked_rows))
A tabular inspection is useful while developing the workflow because it makes the graph expansion auditable. The application can later replace this display with a compact prompt context, a trace record, or a user-facing explanation of why a related memory was included.
Production considerations for Oracle AI agent memory
Memory links make retrieval more useful, but they do not remove the need for application-level decisions. Teams should decide which memories are allowed to be current, how invalid memories are scoped, and which relationships should be created automatically versus explicitly.
- Define a memory scope that matches the user, tenant, case, or workflow boundary of the application.
- Treat valid and invalid as retrieval behavior, not as a reason to destroy the underlying history.
- Use explicit links for deterministic business events and automatic linking for relationships discovered during extraction.
- Keep graph traversal focused. One hop is often enough to add useful context; deeper traversal should be justified by the workflow.
- Do not claim benchmark improvements until approved results are available for the exact release and configuration being described.
Conclusion
Persistent memory is often described as giving an agent a longer memory. That is only part of the story. The harder requirement is giving the agent a better sense of time: which fact is current, which fact was replaced, which detail supports the answer, and which contradiction needs attention.
Graph-aware retrieval provides that structure. With typed links, lifecycle states, controlled traversal, and linked_results, Oracle AI Agent Memory can preserve the history around a fact while still helping the agent answer from the right version. The companion notebook shows the mechanics. The larger payoff is a memory layer that can explain change instead of hiding it.
Frequently asked questions
What is graph-aware retrieval?
Graph-aware retrieval is a retrieval pattern that starts with the memories that match a query, then follows selected relationships to bring back related context. In Oracle AI Agent Memory, those relationships can show whether a memory supersedes, refines, supports, duplicates, or contradicts another memory.
Do I still need agent memory if my application already uses RAG?
Yes, for many agentic applications. RAG is usually about retrieving external knowledge for a task. Agent memory is about preserving durable context from the agent’s own interactions, tool results, user preferences, and workflow history so future turns can use what changed over time.
How is this different from a general knowledge graph?
A general knowledge graph often models broad domain entities and relationships. Graph-aware agent memory is narrower and more operational: it connects memories created by an agent workflow so retrieval can understand which facts are current, historical, supporting, repeated, or conflicting.
Does invalid mean the memory is deleted?
No. In this workflow, invalid means the memory is no longer the current answer. It can remain available as historical context or through a deliberately scoped retrieval request.
Do applications have to create every link themselves?
No. Explicit linking is useful when an application already knows that an event supersedes or supports another memory. Automatic linking during extraction is the more transparent option when the relationship must be inferred from new content and existing memory.
Why not always retrieve every connected memory?
Because extra context is not automatically useful context. num_hops gives the application a way to control graph expansion, and scope rules keep the returned context relevant to the current user or workflow.
