Creación y búsqueda de gráficos de memoria enlazados
Los enlaces de memoria conectan registros similares a los de la memoria al tiempo que conservan registros históricos. Utilícelos cuando una memoria más reciente reemplace o refine una más antigua, o cuando dos memorias se apoyen, se dupliquen o se contradigan entre sí. El enlace automático de memoria crea estos enlaces como parte de la extracción automática de memoria; el enlace manual permanece disponible cuando una aplicación ya conoce la relación.
Esta guía crea automáticamente un pequeño gráfico de preferencias de pizza, muestra cómo gestionar enlaces explícitamente cuando es necesario y recupera el contexto del gráfico con la búsqueda.
Configuración de un cliente de memoria enlazada
Cree un cliente OracleAgentMemory normal. En la primera ejecución, utilice SchemaPolicy.CREATE_IF_NECESSARY para que el SDK cree todos los objetos de base de datos gestionados, incluido el almacén de correlación de memoria y el gráfico de propiedades.
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"
Enlazar memorias automáticamente durante la extracción
Para la mayoría de las aplicaciones, active la extracción automática y permita que el SDK identifique enlaces a medida que extrae nuevas memorias de add_messages(). El modo de enlace por defecto, POST_EXTRACTION, extrae primero las memorias, recupera un juego limitado de candidatos existentes para cada nueva memoria y utiliza una solicitud de LLM adicional para decidir si se debe crear un enlace escrito. Esto proporciona a la resolución de enlaces su propio contexto y es el modo recomendado cuando importa la calidad de los enlaces.
Configure el modo mediante MemoryExtractionConfig en el nivel de cliente o thread. El siguiente thread se extrae después de cada mensaje agregado y resuelve los enlaces después de la extracción. El cliente OracleAgentMemory también se debe configurar con un LLM de extracción.
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."}]
)
Por ejemplo, cuando el subproceso ya contiene una memoria que el usuario prefiere de corteza fina, el enlazador puede extraer la nueva preferencia de masa de origen y crear un enlace supersedes a la memoria anterior. Los tipos de enlace del ciclo de vida, como supersedes, refines y duplicates, conservan la memoria antigua como historial y la marcan como no válida; la búsqueda de gráficos aún puede devolverla como contexto enlazado.
DURING_EXTRACTION solicita al LLM de extracción que identifique enlaces en la misma solicitud que extrae memorias, lo que evita la solicitud adicional de resolución de enlaces. Sus candidatos están limitados por la búsqueda de extracción. Defina memory_link_extraction_mode=MemoryLinkExtractionMode.DISABLED para desactivar el enlace automático. Ninguno de los modos automáticos intenta detectar todas las relaciones posibles en el almacén, por lo que debe utilizar enlaces explícitos para una relación que se debe registrar.
Crear memorias enlazadas manualmente
Cree memorias normalmente y, a continuación, conéctelas con link_records(). Se dirige una relación: su origen apunta a su destino. supersedes, refines y duplicates hacen que el destino no sea válido; supports y contradicts dejan ambas memorias de punto final válidas.
Seleccione un tipo de enlace
Para la evolución de la memoria, el origen es normalmente la memoria más reciente y el destino es la memoria existente. Seleccione el tipo de enlace que describe esa relación.
| Tipo de Enlace | Usar cuando la memoria de origen... | Efecto en la memoria de destino |
|---|---|---|
supersedes |
Sustituye el destino como la información actual. Por ejemplo, una nueva preferencia sustituye a una anterior. | Se convierte en inválido, pero permanece disponible como historial. |
refines |
Mantiene la información del destino al agregar detalles o precisión. Por ejemplo, una preferencia de senderismo específica refina una general. | Se convierte en inválido, pero permanece disponible como historial. |
duplicates |
Tiene el mismo significado que el objetivo. El origen es la copia preferida. | Se convierte en no válido para evitar resultados directos duplicados. |
supports |
Proporciona pruebas para el objetivo. Por ejemplo, evitar la carne y el pescado apoya una preferencia vegetariana. | Permanece sin cambios. |
contradicts |
Conflictos con el destino, pero el SDK no puede determinar qué memoria es correcta. | Permanece sin cambios. |
La búsqueda de gráficos sigue cada enlace en cualquier dirección. Cuando pasa del destino al origen, muestra la etiqueta inversa correspondiente, como 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 búsqueda sigue un enlace en cualquier dirección mientras mantiene su dirección almacenada en el resultado.
Editar y suprimir enlaces
Utilice el identificador de relación devuelto por link_records() para actualizar una relación. Los campos omitidos permanecen sin cambios. Al actualizar un tipo de relación, se vuelven a calcular los estados de punto final, por lo que un enlace de ciclo de vida anterior ya no deja una memoria no válida cuando su tipo de sustitución no tiene efectos de ciclo de vida.
Suprima una relación por su ID de relación o por su tupla de punto final dirigida completa: ID y tipo de origen, ID y tipo de destino y tipo de relación. La supresión también vuelve a calcular los estados de punto final afectados.
#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",
)
Buscar a través de recuerdos enlazados
Defina num_hops para asociar el contexto enlazado a cada resultado de memoria directa. 0 es el valor por defecto y devuelve sólo los resultados directos; los valores de 1 a 5 siguen muchos enlaces. max_linked_results limita el total de memorias enlazadas asociadas a cada resultado directo en todos los saltos. El valor por defecto es 100; defínalo en 0 para devolver resultados directos sin contexto enlazado.
Los filtros de ámbito, metadatos, tipo de registro y caducidad se aplican a las memorias enlazadas. include_invalid_results solo se aplica a los resultados directos de nivel superior. El contexto de memoria enlazada puede incluir registros históricos no válidos, independientemente de esa opción. Para los valores num_hops positivos, el SDK sigue los enlaces en ambas direcciones y devuelve el contexto enlazado como árbol de ruta más corta determinista descrito en la siguiente sección.
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,
)
Cada resultado contiene un árbol recursivo de resultados vinculados. El SDK formatea ese árbol mediante la ruta de acceso más corta disponible a cada memoria enlazada. El recorrido evita recuerdos repetidos en un camino y selecciona un camino más corto determinista cuando los caminos alternativos alcanzan la misma memoria.
Formato de contexto de gráfico para una petición de datos
Cada SearchResult expone format_content() para representar un resultado directo y sus memorias enlazadas como texto de petición de datos estructurado. Por defecto, utiliza el valor include_invalid_results de la búsqueda que ha producido el resultado. Una configuración de formato proporcionada sustituye sus opciones definidas explícitamente. Cuando el contenido no válido está desactivado, las memorias enlazadas no válidas omiten su contenido. Los registros no válidos que conducen a una memoria enlazada válida conservan su estado y contexto de enlace; se omiten bifurcaciones de sólo no válidas.
Utilice OracleSearchResultFormatConfig para personalizar el árbol representado. Este ejemplo incluye contenido histórico no válido al eliminar registros de hora, roles y estados para una petición de datos más compacta. También puede incluir metadatos, threads, identificadores de usuario o agente y relevancia estimada. Cada etiqueta de relación representada describe la dirección de principal a secundario mostrada, aunque RecordRelation conserva su dirección almacenada.
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))
Código Completo
El ejemplo completo se incluye en esta guía para que pueda copiar y ejecutar.
#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))