创建和搜索链接的内存图形

内存链接连接相关的类似内存的记录,同时保留历史记录。当较新的内存取代或细化较旧的内存时,或者当两个内存相互支持、复制或矛盾时,使用它们。自动内存链接会在自动内存提取过程中创建这些链接;当应用程序已经知道该关系时,手动链接仍然可用。

本指南将自动创建披萨首选项的小型图形,显示如何在需要时显式管理链接,以及通过搜索检索图形上下文。

设置链接的内存客户端

创建常规 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))