使用 Oracle 代理内存混合搜索

即使查询使用不同的单词,语义搜索也有助于查找相关信息。关键字搜索有助于查找语义搜索可能缺少的确切标识符、名称和短语。

本文介绍了如何将 Oracle Agent Memory 混合搜索与 Oracle Database 一起使用。

混合搜索可帮助 Oracle Agent Memory 按含义和确切文本查找记录。它将 Oracle 管理的文本搜索与基于向量的排名相结合,因此查询可以匹配标识符(如问题代码、产品名称和别名),同时仍然受益于语义检索。

在本指南中,您将:

注:如果语义搜索和关键字搜索都无法提供可靠的检索,请使用混合搜索。当记录包括描述性内容和用户需要查找的准确术语时,混合搜索最有用。

提示:有关软件包设置,请参见 Get Started with Agent Memory 。如果此示例需要本地 Oracle 数据库,请按照 Run Oracle AI Database Locally 操作。

配置 Oracle 混合搜索客户端

创建启用了混合搜索的 Oracle Agent Memory 客户端。客户机将记录存储在 Oracle Database 中,并要求 Oracle 使用托管的混合向量索引进行搜索。

首次启用混合搜索时,请使用 SchemaPolicy.CREATE_IF_NECESSARY。这样,SDK 可以添加托管搜索列,并创建混合索引(如果尚不存在)。

如果希望 Oracle 组合关键字和向量排名,请使用 SearchStrategy.HYBRID。混合搜索需要使用 OracleDBEmbedder 作为客户端的主 embedder,因此存储和 Oracle 管理的混合向量索引共享相同的数据库内模型。

如果只想匹配文本,请改用 SearchStrategy.KEYWORD。下一节显示该设置。

重要提示:本指南要求 oracleagentmemory 26.6.0 或更新版本。如果您的托管方案是由较早的发行版创建的,请使用 SchemaPolicy.CREATE_IF_NECESSARY 启动一次应用程序。此升级支持旧的已发布方案,并添加所选策略所需的搜索对象。第一次升级可能会执行托管 DDL 和数据重写,因此将其视为计划的迁移步骤,而不是廉价的正常启动。方案准备就绪后,可以切换回 SchemaPolicy.REQUIRE_EXISTING 以进行正常启动。

已声明当前发行版配置的开发或部分更新的方案未就地完成;请改为重新创建它们。

如果在升级方案之前使用 SchemaPolicy.REQUIRE_EXISTING,则客户机创建将失败,并告诉您缺少哪些托管搜索对象。

为关键字或混合搜索初始化或升级方案后,请不要使用 SearchStrategy.VECTOR 重新打开它,除非您重新创建方案或运行嵌入回填。由关键字或混合客户机写入的行可能不包含本地嵌入,因此向量搜索可能会丢失记录。

警告:为现有方案创建混合索引可能需要一些时间。Oracle 必须扫描现有的存储搜索文本,并从配置的数据库内模型构建托管的混合索引文本/向量状态。SchemaPolicy.CREATE_IF_NECESSARY 将在客户机启动返回之前等待该 DDL 完成,因此,请将第一次混合升级作为大型方案的计划迁移或维护操作运行。

注:当 SDK 创建托管的混合向量索引时,它还会创建由托管模式命名的 DBMS_VECTOR_CHAIN 向量器首选项。该首选项存储已配置的 OracleDBEmbedder 模型中的向量器配置,预计为轻量级元数据。生成的首选项名称是受管方案的确定性名称,当它符合 Oracle Text 的首选项名称限制时,它遵循配置的表名前缀。您可以使用 Oracle Text 视图(例如 CTX_USER_PREFERENCESCTX_USER_PREFERENCE_VALUES)检查首选项。

注:此示例使用 OracleDBEmbedder。Oracle 在创建混合索引时使用该嵌入器的数据库内模型,因此主嵌入器和混合索引共享一个数据库模型。

该示例还使用 SearchIndexSyncMode.ON_COMMIT。这使得混合索引在每次提交写入后保持最新状态,因此新添加的记忆可以立即搜索。当您计划自行运行搜索索引同步时,请使用 SearchIndexSyncMode.MANUAL;如果您希望 Oracle 在后台刷新混合索引,并且可以容忍搜索结果滞后于最近的写入时,请使用 SearchIndexSyncMode.AUTO。此设置适用于存在初始搜索索引之后的持续维护;它不会使第一个索引构建异步。

import oracledb

from oracleagentmemory.core import (
    MemoryExtractionConfig,
    OracleAgentMemory,
    SchemaPolicy,
    SearchIndexSyncMode,
    SearchStrategy,
)
from oracleagentmemory.core.embedders import OracleDBEmbedder


db_pool = oracledb.SessionPool(
    user="YOUR DB USER",
    password="YOUR DB PASSWORD",
    dsn="YOUR DB CONNECT STRING",
)

db_embedder = OracleDBEmbedder(
    connection=db_pool,
    model="YOUR_DB_EMBEDDING_MODEL",
    embedding_dimension=384,
)

memory = OracleAgentMemory(
    connection=db_pool,
    embedder=db_embedder,
    memory_extraction_config=MemoryExtractionConfig(extract_memories=False),
    schema_policy=SchemaPolicy.CREATE_IF_NECESSARY,
    search_strategy=SearchStrategy.HYBRID,
    search_index_sync=SearchIndexSyncMode.ON_COMMIT,
)
API 参考:OracleAgentMemory OracleDBEmbedder SchemaPolicy 搜索策略 搜索索引同步模式

仅使用关键字搜索

如果希望搜索与存储的单词、标识符、别名、产品名称或短语匹配,并且不希望向量排名,请使用 SearchStrategy.KEYWORD。关键字搜索读取混合搜索所使用的相同存储搜索文本,但不使用向量融合。

关键字搜索不需要 Python 嵌入程序。如果 SDK 需要为新的关键字方案创建搜索对象,则会在存储的搜索文本上创建 Oracle Text 索引。SearchIndexSyncMode.ON_COMMITSearchIndexSyncMode.MANUAL 控制关键字文本索引刷新。

keyword_memory = OracleAgentMemory(
    connection=db_pool,
    memory_extraction_config=MemoryExtractionConfig(extract_memories=False),
    schema_policy=SchemaPolicy.CREATE_IF_NECESSARY,
    search_strategy=SearchStrategy.KEYWORD,
)

下面所示的相同 add_memory()search() 调用与 SearchStrategy.KEYWORD 一起使用。区别在于排名:关键字搜索仅基于文本匹配返回记录,而混合搜索将文本匹配与向量排名相结合。

API 参考:OracleAgentMemory 搜索策略

使用兼容的搜索策略

SDK 首次创建或升级托管方案时,会记录存储的检索数据的搜索准备方式。每次启动数据库客户端时都会检查记录的模式。这会阻止客户使用可能无提示丢失记录的策略。

如果所请求的策略与模式兼容,但与所记录的模式不匹配,则 SDK 会发出警告。客户端仍然可以启动,但警告可帮助您注意到差异并确认它是故意的。

警告:由于 Oracle 基于存储的搜索文本构建托管的混合索引状态,因此首次在现有数据上创建混合索引可能会很长时间。SearchIndexSyncMode 控制索引存在后正在进行的索引维护;它不会使第一个构建异步。

当您有意将方案从向量移动到关键字或混合,或者从关键字移动到混合时,请使用 SchemaPolicy.CREATE_IF_NECESSARY。方案就绪后使用 SchemaPolicy.REQUIRE_EXISTING,您希望启动时无需更改数据库对象即可验证方案。

API 参考:SchemaPolicy 搜索策略

存储可搜索的内存

从正常的记忆开始。通过 OracleAgentMemory.add_memory() API,Oracle 将内存内容本身用作可搜索文本。这是最简单的路径,当用户搜索已经出现在内存中的单词或短语时,通常就足够了。

user_id = "user_123"

memory.add_memory(
    "The user calls the Milan outage the renewal blocker.",
    user_id=user_id,
)

API 参考:OracleAgentMemory

存储标识符用户可以搜索

当用户可以按确切的问题代码、发票号、产品名称或别名进行搜索时,请在存储的内存中包括该文本。然后,混合搜索可以匹配确切的文本,并且仍然使用向量排名进行自然语言查询。

保持内存可读性。通常,包含重要标识符的简短句子就足够了。在此示例中,存储器包括用户以后可能键入的问题和请求标识符。

memory.add_memory(
    "The follow-up fix for the Milan outage is the edge-cluster retry patch, "
    "tracked as ORA-27102.",
    user_id=user_id,
)

memory.add_memory(
    "The renewal request INV-48291 stays attached to the Milan blocker ORA-27102.",
    user_id=user_id,
)

API 参考:OracleAgentMemory

按标识符或短语搜索

使用普通的 search() API。混合搜索在同一 Oracle Agent Memory 搜索界面后面运行,因此您可以像往常一样继续使用范围、结果限制和记录类型筛选器。

第一个查询搜索内存文本中存储的确切问题代码。第二个查询从同一组记忆中搜索自然语言短语。

for query in ["ORA-27102", "renewal blocker"]:
    print(f"\nSearch results for {query!r}:")
    results = memory.search(
        query=query,
        user_id=user_id,
        max_results=5,
        record_types=["memory"],
    )
    print_search_results(results)

注:搜索结果的顺序可能因存储的数据、混合索引配置和 Oracle 评分行为而异。在测试或演示中,检查是否返回了预期记录,而不是依赖于一个精确的排名。

API 参考:OracleAgentMemory OracleSearchResult

小结

在本指南中,您将启用 Oracle 管理的混合搜索,了解何时使用仅关键字搜索,存储常规内存,在内存文本中包括可搜索标识符,以及按确切标识符和自然语言短语查询的内存。

在了解如何在 Oracle DB 中启用混合搜索后,现在可以转至存储和方案

完整代码

#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 - Oracle Hybrid Search
#-------------------------------------------------------

##Configure an Oracle hybrid search client

import oracledb

from oracleagentmemory.core import (
    MemoryExtractionConfig,
    OracleAgentMemory,
    SchemaPolicy,
    SearchIndexSyncMode,
    SearchStrategy,
)
from oracleagentmemory.core.embedders import OracleDBEmbedder


db_pool = oracledb.SessionPool(
    user="YOUR DB USER",
    password="YOUR DB PASSWORD",
    dsn="YOUR DB CONNECT STRING",
)

db_embedder = OracleDBEmbedder(
    connection=db_pool,
    model="YOUR_DB_EMBEDDING_MODEL",
    embedding_dimension=384,
)

memory = OracleAgentMemory(
    connection=db_pool,
    embedder=db_embedder,
    memory_extraction_config=MemoryExtractionConfig(extract_memories=False),
    schema_policy=SchemaPolicy.CREATE_IF_NECESSARY,
    search_strategy=SearchStrategy.HYBRID,
    search_index_sync=SearchIndexSyncMode.ON_COMMIT,
)



##Configure an Oracle keyword search client

keyword_memory = OracleAgentMemory(
    connection=db_pool,
    memory_extraction_config=MemoryExtractionConfig(extract_memories=False),
    schema_policy=SchemaPolicy.CREATE_IF_NECESSARY,
    search_strategy=SearchStrategy.KEYWORD,
)


def print_search_results(results: list) -> None:
    for result in results:
        print(f"- [{result.record.record_type}] {result.content}")



##Store a basic hybrid search memory

user_id = "user_123"

memory.add_memory(
    "The user calls the Milan outage the renewal blocker.",
    user_id=user_id,
)



##Store identifiers users may search for

memory.add_memory(
    "The follow-up fix for the Milan outage is the edge-cluster retry patch, "
    "tracked as ORA-27102.",
    user_id=user_id,
)

memory.add_memory(
    "The renewal request INV-48291 stays attached to the Milan blocker ORA-27102.",
    user_id=user_id,
)



##Search hybrid records by identifier or phrase

for query in ["ORA-27102", "renewal blocker"]:
    print(f"\nSearch results for {query!r}:")
    results = memory.search(
        query=query,
        user_id=user_id,
        max_results=5,
        record_types=["memory"],
    )
    print_search_results(results)