Verknüpfte Speicherdiagramme erstellen und suchen
Memory Links verbinden zugehörige speicherähnliche Datensätze und behalten dabei historische Datensätze bei. Verwenden Sie sie, wenn ein neuerer Speicher einen älteren ersetzt oder verfeinert, oder wenn zwei Speicher sich gegenseitig unterstützen, duplizieren oder widersprechen. Die automatische Speicherverknüpfung erstellt diese Verknüpfungen im Rahmen der automatischen Speicherextraktion. Eine manuelle Verknüpfung bleibt verfügbar, wenn eine Anwendung die Beziehung bereits kennt.
Dieser Leitfaden erstellt automatisch ein kleines Diagramm mit den Voreinstellungen für Pizza, zeigt, wie Links bei Bedarf explizit verwaltet werden, und ruft den Diagrammkontext mit der Suche ab.
Linked-Memory-Client einrichten
Erstellen Sie einen normalen OracleAgentMemory-Client. Verwenden Sie bei der ersten Ausführung SchemaPolicy.CREATE_IF_NECESSARY, damit das SDK alle verwalteten Datenbankobjekte erstellt, einschließlich Speicherrelationsspeicher und Eigenschaftsdiagramm.
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"
Erinnerungen automatisch beim Extrahieren verknüpfen
Aktivieren Sie für die meisten Anwendungen die automatische Extraktion, und lassen Sie das SDK Links identifizieren, wenn neue Speicher aus add_messages() extrahiert werden. Der Standardlinkmodus POST_EXTRACTION extrahiert zuerst Speicher, ruft eine begrenzte Gruppe vorhandener Kandidaten für jeden neuen Speicher ab und verwendet eine zusätzliche LLM-Anforderung, um zu entscheiden, ob ein typisierter Link erstellt werden soll. Dies gibt der Linkauflösung einen eigenen Kontext und ist der empfohlene Modus, wenn die Linkqualität wichtig ist.
Konfigurieren Sie den Modus über MemoryExtractionConfig auf Client- oder Threadebene. Der folgende Thread extrahiert nach jeder hinzugefügten Nachricht und löst Links nach der Extraktion auf. Der OracleAgentMemory-Client muss auch mit einem Extraktions-LLM konfiguriert werden.
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."}]
)
Beispiel: Wenn der Thread bereits einen Speicher enthält, den der Benutzer Thin Crust bevorzugt, kann der Linker die neue Sauerteigvoreinstellung extrahieren und einen supersedes-Link zum älteren Speicher erstellen. Lebenszykluslinktypen wie supersedes, refines und duplicates behalten den älteren Speicher als Historie bei und markieren ihn als ungültig. Die Diagrammsuche kann ihn weiterhin als verknüpften Kontext zurückgeben.
DURING_EXTRACTION fordert das Extraktions-LLM auf, Links in derselben Anforderung zu identifizieren, die Speicher extrahiert, wodurch die zusätzliche Anforderung zur Linkauflösung vermieden wird. Die Kandidaten sind an die Extraktionssuche gebunden. Setzen Sie memory_link_extraction_mode=MemoryLinkExtractionMode.DISABLED, um die automatische Verknüpfung zu deaktivieren. Weder im automatischen Modus wird versucht, jede mögliche Beziehung im Speicher zu ermitteln. Verwenden Sie daher explizite Links für eine Beziehung, die aufgezeichnet werden muss.
Verknüpfte Erinnerungen manuell erstellen
Erstellen Sie Speicher normal, und verbinden Sie sie dann mit link_records(). Eine Beziehung wird weitergeleitet: Die Quelle verweist auf das Ziel. supersedes, refines und duplicates machen das Ziel ungültig. supports und contradicts lassen beide Endpunktspeicher gültig.
Linktyp auswählen
Bei der Speicherentwicklung ist die Quelle normalerweise der neuere Speicher, und das Ziel ist der vorhandene Speicher. Wählen Sie den Linktyp aus, der diese Beziehung beschreibt.
| Linktyp | Verwenden, wenn der Quellspeicher… | Auswirkung auf Zielspeicher |
|---|---|---|
supersedes |
Ersetzt das Ziel als aktuelle Informationen. Beispiel: Eine neue Voreinstellung ersetzt eine frühere Voreinstellung. | wird ungültig, bleibt aber als Historie verfügbar. |
refines |
Behält die Informationen des Ziels beim Hinzufügen von Details oder Nachkommastellen bei. Beispiel: Eine bestimmte Wanderpräferenz verfeinert eine allgemeine. | wird ungültig, bleibt aber als Historie verfügbar. |
duplicates |
Hat die gleiche Bedeutung wie das Ziel. Die Quelle ist die bevorzugte Kopie. | Wird ungültig, um doppelte direkte Ergebnisse zu verhindern. |
supports |
liefert Beweise für das Ziel. Zum Beispiel unterstützt die Vermeidung von Fleisch und Fisch eine vegetarische Präferenz. | Bleibt unverändert. |
contradicts |
Konflikt mit dem Ziel, aber das SDK kann nicht bestimmen, welcher Speicher korrekt ist. | Bleibt unverändert. |
Die Diagrammsuche folgt jedem Link in beide Richtungen. Wenn es vom Ziel zur Quelle übergeht, wird das entsprechende Reverse Label angezeigt, wie is_superseded_by oder 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",
)
Die Suche folgt einem Link in beide Richtungen, wobei die gespeicherte Richtung im Ergebnis beibehalten wird.
Verknüpfungen bearbeiten und löschen
Verwenden Sie die von link_records() zurückgegebene Beziehungs-ID, um eine Beziehung zu aktualisieren. Ausgelassene Felder bleiben unverändert. Beim Aktualisieren eines Beziehungstyps werden die Endpunktstatus neu berechnet, sodass ein früherer Lebenszykluslink einen Speicher nicht mehr ungültig macht, wenn sein Ersatztyp keine Lebenszykluseffekte hat.
Löschen Sie eine Beziehung nach ihrer Beziehungs-ID oder nach ihrem vollständigen gerichteten Endpunkttupel: Quell-ID und -typ, Ziel-ID und -typ sowie Beziehungstyp. Beim Löschen werden auch die betroffenen Endpunktstatus neu berechnet.
#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",
)
Verknüpfte Speicher durchsuchen
Legen Sie num_hops fest, um verknüpften Kontext an jedes Direct Memory-Ergebnis anzuhängen. 0 ist der Standardwert und gibt nur direkte Ergebnisse zurück. Die Werte von 1 bis 5 folgen vielen Links. max_linked_results begrenzt die gesamten verknüpften Speicher, die an jedes direkte Ergebnis über alle Hops angehängt sind. Der Standardwert ist 100. Setzen Sie ihn auf 0, um direkte Ergebnisse ohne verknüpften Kontext zurückzugeben.
Geltungsbereich, Metadaten, Datensatztyp und Ablauffilter gelten für verknüpfte Speicher. include_invalid_results gilt nur für direkte Ergebnisse der obersten Ebene. Verknüpfter Speicherkontext kann ungültige historische Datensätze unabhängig von dieser Option enthalten. Bei positiven num_hops-Werten folgt das SDK Links in beide Richtungen und gibt den verknüpften Kontext als deterministischen Shortest-Path-Baum zurück, der im folgenden Abschnitt beschrieben wird.
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,
)
Jedes Ergebnis enthält einen rekursiven Baum mit verknüpften Ergebnissen. Das SDK formatiert diese Baumstruktur mit dem kürzesten verfügbaren Pfad zu jedem verknüpften Speicher. Der Durchlauf verhindert wiederholte Speicher in einem Pfad und wählt einen deterministischen kürzesten Pfad aus, wenn alternative Pfade denselben Speicher erreichen.
Diagrammkontext für einen Prompt formatieren
Jede SearchResult stellt format_content() bereit, um ein direktes Ergebnis und die verknüpften Speicher als strukturierten Prompt-Text darzustellen. Standardmäßig wird die Einstellung include_invalid_results der Suche verwendet, die das Ergebnis erzeugt hat. Eine angegebene Formatierungskonfiguration überschreibt die explizit festgelegten Optionen. Wenn ungültige Inhalte deaktiviert sind, lassen ungültige verknüpfte Speicher ihren Inhalt weg. Ungültige Datensätze, die zu einem gültigen verknüpften Speicher führen, behalten ihren Status und Verknüpfungskontext bei. Nur ungültige Verzweigungen werden ausgelassen.
Verwenden Sie OracleSearchResultFormatConfig, um den gerenderten Baum anzupassen. Dieses Beispiel enthält ungültigen historischen Inhalt, während Zeitstempel, Rollen und Status für eine kompaktere Eingabeaufforderung entfernt werden. Sie können auch Metadaten, Thread-, Benutzer- oder Agent-IDs und die geschätzte Relevanz einschließen. Jedes gerenderte Beziehungslabel beschreibt die angezeigte übergeordnete/untergeordnete Richtung, obwohl RecordRelation die gespeicherte Richtung beibehält.
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))
Vollständiger Code
Das vollständige Beispiel ist in diesem Handbuch enthalten, das Sie kopieren und ausführen können.
#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))