Crea e cerca grafici memoria collegati

I collegamenti di memoria connettono i record correlati di tipo memoria conservando i record cronologici. Utilizzali quando una memoria più recente sostituisce o perfeziona una memoria più vecchia o quando due memorie si supportano, si duplicano o si contraddicono a vicenda. Il collegamento automatico della memoria crea questi collegamenti come parte dell'estrazione automatica della memoria; il collegamento manuale rimane disponibile quando un'applicazione conosce già la relazione.

Questa guida crea automaticamente un piccolo grafico delle preferenze della pizza, mostra come gestire i collegamenti in modo esplicito quando necessario e recupera il contesto del grafico con la ricerca.

Impostare un client Linked-Memory

Creare un normale client OracleAgentMemory. Alla prima esecuzione, utilizzare SchemaPolicy.CREATE_IF_NECESSARY in modo che l'SDK crei tutti gli oggetti di database gestiti, inclusi l'area di memorizzazione della relazione della memoria e il grafico delle proprietà.

import oracledb

from oracleagentmemory.core import (
    MemoryExtractionConfig,
    OracleAgentMemory,
    OracleSearchResultFormatConfig,
    SchemaPolicy,
)
from oracleagentmemory.core.embedders.embedder import Embedder


embedder = Embedder(model="YOUR_EMBEDDING_MODEL")
db_pool = oracledb.SessionPool(
    user="YOUR DB USER",
    password="YOUR DB PASSWORD",
    dsn="localhost:1521/...",
)
memory_store_id = "T_GRAPH_MEMORY"

memory = OracleAgentMemory(
    connection=db_pool,
    embedder=embedder,
    schema_policy=SchemaPolicy.CREATE_IF_NECESSARY,
    memory_store_id=memory_store_id,
    memory_extraction_config=MemoryExtractionConfig(extract_memories=False),
)
user_id = "graph-demo-user"

Collega i ricordi automaticamente durante l'estrazione

Per la maggior parte delle applicazioni, abilitare l'estrazione automatica e lasciare che l'SDK identifichi i collegamenti mentre estrae nuove memorie da add_messages(). La modalità di collegamento predefinita, POST_EXTRACTION, estrae prima le memorie, recupera un set limitato di candidati esistenti per ogni nuova memoria e utilizza una richiesta LLM aggiuntiva per decidere se creare un collegamento digitato. Ciò fornisce alla risoluzione dei collegamenti il proprio contesto ed è la modalità consigliata quando la qualità dei collegamenti è importante.

Configurare la modalità tramite MemoryExtractionConfig a livello di client o thread. Il thread seguente viene estratto dopo ogni messaggio aggiunto e risolve i collegamenti dopo l'estrazione. Anche il client OracleAgentMemory deve essere configurato con un LLM di estrazione.

from oracleagentmemory.core import (
    MemoryExtractionConfig,
    MemoryLinkExtractionMode,
)

preference_thread = memory.create_thread(
    thread_id="pizza-preferences",
    user_id=user_id,
    memory_extraction_config=MemoryExtractionConfig(
        extract_memories=True,
        memory_extraction_frequency=1,
        memory_link_extraction_mode=MemoryLinkExtractionMode.POST_EXTRACTION,
    ),
)
preference_thread.add_messages(
    [{"role": "user", "content": "I now prefer sourdough pizza."}]
)

Ad esempio, quando il thread contiene già una memoria che l'utente preferisce la crosta sottile, il linker può estrarre la nuova preferenza di pasta madre e creare un collegamento supersedes alla memoria precedente. I tipi di collegamento del ciclo di vita, ad esempio supersedes, refines e duplicates, conservano la memoria precedente come cronologia e la contrassegnano come non valida; la ricerca del grafico può comunque restituirla come contesto collegato.

DURING_EXTRACTION chiede al LLM di estrazione di identificare i collegamenti nella stessa richiesta che estrae le memorie, il che evita l'ulteriore richiesta di risoluzione dei collegamenti. I suoi candidati sono vincolati dalla ricerca di estrazione. Impostare memory_link_extraction_mode=MemoryLinkExtractionMode.DISABLED per disattivare il collegamento automatico. Nessuna delle due modalità automatiche tenta di scoprire ogni possibile relazione nel negozio, quindi utilizza collegamenti espliciti per una relazione che deve essere registrata.

Crea manualmente memorie collegate

Creare le memorie normalmente, quindi collegarle a link_records(). Una relazione viene indirizzata: la sua origine punta alla sua destinazione. supersedes, refines e duplicates rendono la destinazione non valida; supports e contradicts lasciano valide entrambe le memorie endpoint.

Selezionare un tipo di collegamento

Per l'evoluzione della memoria, la sorgente è normalmente la memoria più recente e il target è la memoria esistente. Selezionare il tipo di collegamento che descrive la relazione.

Tipo di collegamento Utilizza quando è attiva la memoria di origine… Effetto sulla memoria di destinazione
supersedes Sostituisce la destinazione come informazione corrente. Ad esempio, una nuova preferenza sostituisce una preferenza precedente. Diventa non valido ma rimane disponibile come cronologia.
refines Conserva le informazioni della destinazione durante l'aggiunta di dettagli o precisione. Ad esempio, una preferenza escursionistica specifica raffina una preferenza generale. Diventa non valido ma rimane disponibile come cronologia.
duplicates Ha lo stesso significato del bersaglio. L'origine è la copia preferita. Diventa non valido per impedire risultati diretti duplicati.
supports Fornisce prove per l'obiettivo. Ad esempio, evitare carne e pesce supporta una preferenza vegetariana. Rimane invariato.
contradicts Conflitto con la destinazione, ma l'SDK non è in grado di determinare la memoria corretta. Rimane invariato.

La ricerca del grafico segue ogni collegamento in entrambe le direzioni. Quando passa dalla destinazione all'origine, viene visualizzata l'etichetta inversa corrispondente, ad esempio is_superseded_by o is_refined_by.

thin_crust_id = memory.add_memory(
    "The user's preferred pizza style is thin crust.",
    memory_id="pizza-thin-crust",
    memory_type="preference",
    user_id=user_id,
)
sourdough_id = memory.add_memory(
    "The user now prefers sourdough pizza.",
    memory_id="pizza-sourdough",
    memory_type="preference",
    user_id=user_id,
)
neapolitan_id = memory.add_memory(
    "The user's preferred pizza style is sourdough, especially Neapolitan sourdough.",
    memory_id="pizza-neapolitan-sourdough",
    memory_type="preference",
    user_id=user_id,
)

supersedes_link_id = memory.link_records(
    source_record_id=sourdough_id,
    source_record_type="preference",
    target_record_id=thin_crust_id,
    target_record_type="preference",
    relation_type="supersedes",
)
memory.link_records(
    source_record_id=neapolitan_id,
    source_record_type="preference",
    target_record_id=sourdough_id,
    target_record_type="preference",
    relation_type="refines",
)

La ricerca segue un collegamento in entrambe le direzioni mantenendo la direzione memorizzata nel risultato.

Modifica ed elimina collegamenti

Utilizzare l'ID relazione restituito da link_records() per aggiornare una relazione. I campi omessi rimangono invariati. L'aggiornamento di un tipo di relazione ricalcola gli stati dell'endpoint, pertanto un precedente collegamento del ciclo di vita non lascia più una memoria non valida quando il relativo tipo di sostituzione non ha effetti sul ciclo di vita.

Eliminare una relazione in base al relativo ID relazione o alla tupla endpoint diretta completa: ID e tipo di origine, ID e tipo di destinazione e tipo di relazione. L'eliminazione ricalcola anche gli stati degli endpoint interessati.

#Changing a lifecycle link recalculates the status of both endpoint memories.
memory.update_record_link(
    supersedes_link_id,
    relation_type="supports",
    metadata={"reviewed_by": "preference-service"},
)

#Delete by the stable relation ID.
memory.delete_record_link(relation_id=supersedes_link_id)

#Or delete by the complete directed relation triple.
memory.delete_record_link(
    source_record_id=neapolitan_id,
    source_record_type="preference",
    target_record_id=sourdough_id,
    target_record_type="preference",
    relation_type="refines",
)

Ricerca tramite memorie collegate

Impostare num_hops per collegare il contesto collegato a ogni risultato della memoria diretta. 0 è l'impostazione predefinita e restituisce solo i risultati diretti. I valori da 1 a 5 seguono molti collegamenti. max_linked_results limita il totale delle memorie collegate a ciascun risultato diretto in tutti i hop. Il valore predefinito è 100; impostarlo su 0 per restituire i risultati diretti senza contesto collegato.

I filtri di ambito, metadati, tipo di record e scadenza si applicano alle memorie collegate. include_invalid_results si applica solo ai risultati diretti di livello superiore. Il contesto di memoria collegata può includere record cronologici non validi indipendentemente da tale opzione. Per i valori num_hops positivi, l'SDK segue i collegamenti in entrambe le direzioni e restituisce il contesto collegato come struttura del percorso più breve deterministico descritta nella sezione seguente.

results = memory.search(
    "What pizza should I recommend?",
    user_id=user_id,
    max_results=5,
    num_hops=2,
    max_linked_results=20,
    include_invalid_results=False,
)

Ogni risultato contiene una struttura ricorsiva di risultati collegati. L'SDK formatta la struttura utilizzando il percorso più breve disponibile per ogni memoria collegata. La traversale impedisce ricordi ripetuti in un percorso e seleziona un percorso deterministico più breve quando percorsi alternativi raggiungono la stessa memoria.

Formatta contesto grafico per prompt

Ogni SearchResult espone format_content() per rendere un risultato diretto e le memorie collegate come testo prompt strutturato. Per impostazione predefinita, utilizza l'impostazione include_invalid_results della ricerca che ha prodotto il risultato. Una configurazione di formattazione fornita sostituisce le opzioni impostate in modo esplicito. Quando il contenuto non valido è disabilitato, le memorie collegate non valide omettono il loro contenuto. I record non validi che portano a una memoria collegata valida mantengono lo stato e il contesto del collegamento. Le diramazioni solo non valide vengono omesse.

Utilizzare OracleSearchResultFormatConfig per personalizzare la struttura di rendering. Questo esempio include contenuti cronologici non validi durante la rimozione di indicatori orari, ruoli e stati per un prompt più compatto. È inoltre possibile includere metadati, thread, identificativi utente o agente e la rilevanza stimata. Ogni etichetta di relazione visualizzata descrive la direzione padre-figlio visualizzata, anche se RecordRelation mantiene la direzione memorizzata.

format_config = OracleSearchResultFormatConfig(
    include_invalid_results=True,
    show_timestamp=False,
    show_role=False,
    show_status=False,
)
for result in results:
    print(result.format_content(format_config))

Codice completo

L'esempio completo è incluso in questa guida per la copia e l'esecuzione.

#Copyright © 2026 Oracle and/or its affiliates.
#This software is under the Apache License 2.0
#(LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) or Universal Permissive License
#(UPL) 1.0 (LICENSE-UPL or https://oss.oracle.com/licenses/upl), at your option.

#Oracle Agent Memory Code Example - Create and Search Linked Memory Graphs
#-------------------------------------------------------------------------

##Create a graph memory client

import oracledb

from oracleagentmemory.core import (
    MemoryExtractionConfig,
    OracleAgentMemory,
    OracleSearchResultFormatConfig,
    SchemaPolicy,
)
from oracleagentmemory.core.embedders.embedder import Embedder


embedder = Embedder(model="YOUR_EMBEDDING_MODEL")
db_pool = oracledb.SessionPool(
    user="YOUR DB USER",
    password="YOUR DB PASSWORD",
    dsn="localhost:1521/...",
)
memory_store_id = "T_GRAPH_MEMORY"

memory = OracleAgentMemory(
    connection=db_pool,
    embedder=embedder,
    schema_policy=SchemaPolicy.CREATE_IF_NECESSARY,
    memory_store_id=memory_store_id,
    memory_extraction_config=MemoryExtractionConfig(extract_memories=False),
)
user_id = "graph-demo-user"



##Create linked memories

thin_crust_id = memory.add_memory(
    "The user's preferred pizza style is thin crust.",
    memory_id="pizza-thin-crust",
    memory_type="preference",
    user_id=user_id,
)
sourdough_id = memory.add_memory(
    "The user now prefers sourdough pizza.",
    memory_id="pizza-sourdough",
    memory_type="preference",
    user_id=user_id,
)
neapolitan_id = memory.add_memory(
    "The user's preferred pizza style is sourdough, especially Neapolitan sourdough.",
    memory_id="pizza-neapolitan-sourdough",
    memory_type="preference",
    user_id=user_id,
)

supersedes_link_id = memory.link_records(
    source_record_id=sourdough_id,
    source_record_type="preference",
    target_record_id=thin_crust_id,
    target_record_type="preference",
    relation_type="supersedes",
)
memory.link_records(
    source_record_id=neapolitan_id,
    source_record_type="preference",
    target_record_id=sourdough_id,
    target_record_type="preference",
    relation_type="refines",
)



##Edit and delete links

#Changing a lifecycle link recalculates the status of both endpoint memories.
memory.update_record_link(
    supersedes_link_id,
    relation_type="supports",
    metadata={"reviewed_by": "preference-service"},
)

#Delete by the stable relation ID.
memory.delete_record_link(relation_id=supersedes_link_id)

#Or delete by the complete directed relation triple.
memory.delete_record_link(
    source_record_id=neapolitan_id,
    source_record_type="preference",
    target_record_id=sourdough_id,
    target_record_type="preference",
    relation_type="refines",
)


#Recreate the example links for the search example.
memory.link_records(sourdough_id, "preference", thin_crust_id, "preference", "supersedes")
memory.link_records(neapolitan_id, "preference", sourdough_id, "preference", "refines")



##Search linked memories

results = memory.search(
    "What pizza should I recommend?",
    user_id=user_id,
    max_results=5,
    num_hops=2,
    max_linked_results=20,
    include_invalid_results=False,
)



##Format graph context for a prompt

format_config = OracleSearchResultFormatConfig(
    include_invalid_results=True,
    show_timestamp=False,
    show_role=False,
    show_status=False,
)
for result in results:
    print(result.format_content(format_config))