创建和搜索链接的内存图形
内存链接连接相关的类似内存的记录,同时保留历史记录。当较新的内存取代或细化较旧的内存时,或者当两个内存相互支持、复制或矛盾时,使用它们。自动内存链接会在自动内存提取过程中创建这些链接;当应用程序已经知道该关系时,手动链接仍然可用。
本指南将自动创建披萨首选项的小型图形,显示如何在需要时显式管理链接,以及通过搜索检索图形上下文。
设置链接的内存客户端
创建常规 OracleAgentMemory 客户机。首次运行时,请使用 SchemaPolicy.CREATE_IF_NECESSARY,以便 SDK 创建所有托管数据库对象,包括内存相关存储和属性图。
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"
提取期间自动链接内存
对于大多数应用程序,启用自动提取,并让 SDK 在从 add_messages() 提取新内存时识别链接。缺省链接模式 POST_EXTRACTION 首先提取内存,为每个新内存检索一组有边界的现有候选对象,并使用一个额外的 LLM 请求来决定是否应创建键入的链接。这提供了链接解析自身的上下文,并且是链接质量重要的建议模式。
在客户机或线程级别通过 MemoryExtractionConfig 配置模式。以下线程在每次添加消息后提取,并在提取后解析链接。OracleAgentMemory 客户机还必须配置有提取 LLM。
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."}]
)
例如,当线程已经包含用户喜欢薄结壳的内存时,链接程序可以提取新的 sourdough 首选项并创建指向较旧内存的 supersedes 链接。生命周期链接类型(如 supersedes、refines 和 duplicates)将较旧的内存保留为历史记录,并将其标记为无效;图形搜索仍可以将其作为链接上下文返回。
DURING_EXTRACTION 要求提取 LLM 标识提取内存的同一请求中的链接,从而避免其他链接解析请求。其候选者受提取搜索的限制。将 memory_link_extraction_mode=MemoryLinkExtractionMode.DISABLED 设置为关闭自动链接。自动模式都不会尝试搜索存储中的每个可能关系,因此,必须为必须记录的关系使用显式链接。
手动创建链接的内存
正常创建记忆,然后将其与 link_records() 连接。关系被定向:其源指向其目标。supersedes、refines 和 duplicates 使目标无效;supports 和 contradicts 使两个端点内存都有效。
选择链接类型
对于内存演化,源通常为较新的内存,目标为现有内存。选择描述该关系的链接类型。
| 链接类型 | 源内存使用时… | 对目标内存的影响 |
|---|---|---|
supersedes |
将目标替换为当前信息。例如,新首选项将替换较早的首选项。 | 变为无效,但仍可作为历史记录使用。 |
refines |
在添加详细信息或精度时保留目标的信息。例如,特定的远足首选项会细化一般的远足首选项。 | 变为无效,但仍可作为历史记录使用。 |
duplicates |
与目标具有相同的含义。源是首选副本。 | 变为无效以防止重复的直接结果。 |
supports |
为目标提供证据。例如,避免肉类和鱼类支持素食者的偏好。 | 保持不变。 |
contradicts |
与目标冲突,但 SDK 无法确定哪个内存是正确的。 | 保持不变。 |
图形搜索在任一方向上的每个链接后面。当它从目标遍历到源时,将显示相应的反向标签,例如 is_superseded_by 或 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",
)
搜索遵循任一方向的链接,同时在结果中保留其存储方向。
编辑和删除链接
使用 link_records() 返回的关系 ID 更新关系。省略的字段保持不变。更新关系类型会重新计算端点状态,因此当以前的生命周期链接的替换类型没有生命周期影响时,该链接将不再使内存无效。
按关系 ID 或完整的定向端点元组删除关系:源 ID 和类型、目标 ID 和类型和关系类型。删除还会重新计算受影响的端点状态。
#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",
)
通过链接的记忆进行搜索
将 num_hops 设置为将链接的上下文附加到每个直接内存结果。0 是默认值,仅返回直接结果;1 到 5 的值遵循许多链接。max_linked_results 限制在所有跃点中附加到每个直接结果的链接总内存。它默认为 100;将其设置为 0 以返回没有链接上下文的直接结果。
范围、元数据、记录类型和到期筛选器应用于链接的内存。include_invalid_results 仅应用于顶层直接结果。链接的内存上下文可以包括无效的历史记录,无论该选项如何。对于正 num_hops 值,SDK 沿两个方向跟踪链接,并返回链接上下文作为确定性最短路径树,如下节所述。
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,
)
每个结果都包含一个递归链接结果树。SDK 使用每个链接内存的最短可用路径格式化树。遍历可防止路径中的重复记忆,并在备用路径到达同一内存时选择一条确定的最短路径。
设置提示的图形上下文格式
每个 SearchResult 都会公开 format_content() 以将直接结果及其链接的存储器呈现为结构化的提示文本。默认情况下,它使用生成结果的搜索的 include_invalid_results 设置。提供的格式设置配置将覆盖其显式设置的选项。禁用无效内容时,无效的链接存储器会忽略其内容。导致有效链接内存的记录无效,将保留其状态和链接上下文;省略仅无效分支。
使用 OracleSearchResultFormatConfig 定制呈现的树。此示例在删除更紧凑提示的时间戳、角色和状态时包括无效的历史内容。您还可以包括元数据、线程、用户或代理标识符以及估计的相关性。每个渲染的关系标签都描述了显示的父子方向,即使 RecordRelation 保留其存储方向也是如此。
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))
完整代码
本指南中包括了完整的示例,供您复制和运行。
#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))