本章介绍如何在 Oracle APEX 应用中使用人工智能:先配置应用要调用的生成式 AI 服务,再让用户通过自然语言操作交互式报表,定义能调用工具的 AI Agent,创建 Agent 驱动的聊天机器人,生成可由用户审阅的文本草稿,并使用 Oracle AI Database 26ai 的向量搜索按语义查找结果。

12 应用人工智能#

APEX 的 AI 能力不是单一功能,而是一组可以组合使用的机制。应用可以把用户的自然语言请求转换为报表配置,也可以让 Agent 根据明确目标调用受控工具,读取允许访问的数据或执行业务动作。对于文本生成场景,APEX 可以把应用数据和提示词交给 AI 服务,生成草稿后再交给用户确认。对于搜索场景,向量搜索可以用“含义相近”替代“关键词完全匹配”,帮助用户找到用不同词语描述的相关数据。

学习本章时,请把 AI 功能理解为应用能力的延伸:数据权限、工具契约、提示词边界、用户确认和结果可审计性仍然由应用负责。

12.1 配置生成式 AI 服务#

要在应用中集成 AI,第一步是在工作区中定义一个生成式 AI 服务(Generative AI Service)。这个定义描述应用要调用哪个提供商、REST API 端点、模型名称和凭据。生成式 AI 服务接收自然语言提示词,并根据模型训练结果返回响应。许多服务同时提供多个模型,每个模型通常针对不同用途进行了微调。

在 APEX Builder 中进入 App Builder > Workspace Utilities > All Workspace Utilities > Generative AI 创建服务定义。APEX 支持 Oracle Cloud Infrastructure (OCI)、OpenAI、Cohere、Google Gemini、Anthropic Claude、Mistral AI、Ollama,以及实现 OpenAI 兼容 API 的服务。

  • AI Provider 中选择提供商。
  • 为服务定义填写名称。
  • 设置唯一的 Static ID,后续用 APEX_AI 包进行程序化调用时会引用它。
  • Settings 中,如果希望 App Builder 内置的 APEX Assistant 也使用该服务,开启 Used by App Builder;如果只允许自己的应用使用该服务,则保持关闭。
  • 点击 Test Connection 验证配置,再点击 Create 创建服务。

实践中应把 Web Credential 和服务定义作为受控共享配置维护,避免在页面代码、动态动作或 PL/SQL 中硬编码密钥。上线前还应确认模型版本、数据出境范围、费用、可用性和敏感信息处理策略。

12.2 使用自然语言探索数据#

交互式报表(Interactive Report)已经支持筛选、排序、条件高亮、分组、图表、透视、计算字段和聚合等能力。启用自然语言支持后,用户不必先学会所有菜单,而是可以直接说明想看什么数据。APEX 会调用应用配置的 AI Service 理解请求,并把请求转换为普通交互式报表功能。

关键点在于透明性:Assistant 不会返回一个无法追溯的独立答案,而是把筛选、排序、高亮、图表、分组等配置显示为可检查的 chip。用户可以查看、修改或移除这些设置,也可以继续使用 Actions 菜单手动调整报表。

12.2.1 立即看到自然语言请求的结果#

官方示例使用一个 Movies 应用中的交互式报表。开发者启用了 Natural Language Support,并把搜索框默认体验设置为 Search with AI。普通的 Row Search 仍可从搜索框左侧下拉菜单中选择;当默认使用 Search with AI 时,同一个入口既能做行搜索,也能处理自然语言提示词。

用户 Lucy 可以在搜索框中输入:

List all drama, action, and crime films. [Lucy]

图 12-1 在交互式报表搜索框中输入自然语言请求

报表随即更新为这些类型的影片,并在结果区域上方显示 Genre Name 字段的筛选 chip。点击工具栏中的 Assistant 按钮后,聊天区域会在报表末尾打开,显示 Lucy 的请求和 Assistant 的回复:

I reset the report and filtered it to show only Drama, Action, and Crime films. [Assistant]

图 12-2 已应用的报表功能显示为 chip,Assistant 按钮打开聊天区域

Lucy 可以继续对当前结果提出细化要求:

Refine to show the films released in the last 5 years, sort on release date, showing the most recent first and only R rated movies. [Lucy]

Assistant 会自动添加新的筛选条件,并按要求应用排序。

图 12-3 用户可在聊天区域继续细化结果

接着,Lucy 要求为不同制片厂添加条件高亮:

Highlight movies from Paramount in light blue and Warner in gold. [Lucy]

图 12-4 可用自然语言配置交互式报表的高亮等功能

为了理解筛选结果,Lucy 还可以要求创建图表:

Create a pie chart of movie count by studio [Lucy]

APEX 会切换到图表视图,并显示表格和图表的工具栏按钮,让用户在两种视图之间切换。

图 12-5 图表和透视也可通过自然语言请求生成

因为底层仍是交互式报表,Lucy 可以把当前报表另存为有意义的名称,以后从已保存报表列表中再次打开这个视图。她也可以改变主意并重置报表,例如输入:

Can you reset the report and include the franchise column, list the films that are part of a franchise and break on that column. [Lucy]

Assistant 会移除原有报表设置,显示指定列,并按 franchise 分组。

图 12-6 通过提示词隐藏或显示列并添加 break 分组

再例如,Lucy 输入:

Reset the report and show all movies from the 80s that have won an Oscar and include the award column after title. [Lucy]

如果开发者提供了足够上下文,Assistant 能把 “the 80s” 理解为 1980 年代,并把 “won an Oscar” 映射到合适的获奖相关列。

图 12-7 开发者提供的上下文帮助 Assistant 把 “80 年代” 和 “奥斯卡获奖” 转换为筛选条件

当请求存在歧义时,Assistant 会要求澄清。例如 Lucy 输入:

Refine and show movies made in the Big Apple and show the location column after Title [Lucy]

Assistant 会询问 “Big Apple” 是否应理解为 Movie City Locations Json 中的 NYC/New York City。Lucy 回答 Yes 后,报表更新为在纽约市拍摄的影片。

图 12-8 必要时 Assistant 会提示用户澄清

在整个对话过程中,用户可以展开或折叠报表功能 chip 区域,检查提示词产生了哪些交互式报表设置。如果用户手动添加、移除或修改报表功能,Assistant 也会感知当前报表设置,并在解释下一条请求时保持同步。

12.2.2 AI 服务会收到哪些信息#

Assistant 调用 AI 服务理解提示词时,会发送当前报表设置、列名、列标签,以及开发者在 Page Designer 中补充的报表上下文和列上下文。它不会把应用数据发送给 AI 服务。它的任务只是理解用户请求、可用列名和上下文,再把请求转换为一个或多个已有交互式报表功能。

因此,用户只能看到自己本来有权限看到的数据,也只能使用自己本来可以手工应用的报表功能。自然语言只是降低了操作门槛,并没有绕过授权或报表能力边界。

12.2.3 启用自然语言支持并补充上下文#

要在交互式报表上启用 Search with AI,在报表属性中开启 Natural Language SupportDefault Search Mode 控制搜索框的初始模式:如果设置为 Row Search,用户可以通过搜索框下拉菜单进入 Search with AI;如果设置为 Search with AI,用户默认看到 AI 搜索,也可以随时切换回 Row Search 或指定字段搜索。

开发者可以添加 Report Context 帮助 Assistant 理解报表用途。官方 Movies 报表示例的上下文说明包括:该报表展示跨越多个年代的电影行业数据,包含票房表现、制作细节、演员信息和财务指标;用户通常会按类型趋势、制片厂表现、导演成功率、预算和收入关系以及时间模式进行分析;数据支持按上映时期、财务阈值、地理市场和分类属性筛选。

图 12-9 报表上下文帮助 Search with AI Assistant 更好地理解用户请求

有时列名和列标签已经足够;如果测试发现某列仍需补充语义,可以添加 Column Context。例如 DIRECTOR_NAME 列可以说明它表示影片主要导演,常用于导演分析、导演表现跟踪和 auteur studios,并提示用户可能只用姓氏称呼知名导演,例如 “Spielberg” 或 “Scorsese”。

也可以选择性定义 Reference Data 发送给 AI 服务。例如 Movies 报表可以用 SQL Query 提供最多 100 个导演名称:

select director_name d, director_name r
from mve_directors
where rownum < 100

注意:请谨慎决定要发送哪些 reference data。与报表和上下文信息一样,reference data 会消耗额外 token。只有当更好的提示词理解确实值得这些成本时,才应发送。

图 12-10 列上下文

12.3 定义完成目标的 AI Agent#

AI Agent 用于完成某个应用相关目标。定义 AI Service 之后,可以创建 AI Agent,让它与配置好的 AI 服务协作,处理来自最终用户或业务逻辑的输入并生成响应。开发者用自然语言系统提示词描述 Agent 的任务。例如 HR Assistant 的目标可以写成:

You are a friendly Woods HR assistant. You only answer questions about Woods HR employees and no others.

APEX 引擎负责与 AI Service 交互;开发者负责定义目标边界、可用工具、工具参数和工具实现。

12.3.1 用工具提供应用数据和允许的动作#

AI Tool 可以让 Agent 更有能力。工具可以用动态数据增强初始系统提示,也可以作为 AI Service 按需调用的回调来生成最终响应。每个工具有名称,也可以有说明和参数。Agent 会在初始交换时运行 Augment System Prompt 工具,并把 On Demand 工具的说明列表提供给 AI Service。

工具可以用 SQL、PL/SQL 或 JavaScript 实现,也可以配置 Server-side condition,让工具只在相关条件下可用。

12.3.2 HR Assistant 的两个工具示例#

第一个示例工具 get_employee_info 允许 AI 服务检索员工信息。它是一个 Retrieve Data 类型的 On Demand 工具,包含两个可选参数 ENAMEJOB,类型都是 VARCHAR2。工具说明应使用自然语言清楚描述它能做什么、参数含义是什么。

图 12-11 定义带可选参数的 Retrieve Data On Demand 工具

Settings 选项卡中,开发者描述工具返回的数据,并提供可以引用参数绑定变量的 SQL。因为参数是可选的,查询只在参数有值时按员工姓名和岗位筛选:

SELECT e.ename, e.job, e.sal, e.hiredate, d.dname
  FROM emp e
  JOIN dept d ON d.deptno = e.deptno
 WHERE ( :ENAME IS NULL OR e.ename = UPPER( :ENAME ))
   AND ( :JOB IS NULL OR e.job = UPPER( :JOB ))
 ORDER BY e.sal DESC

提示:查询也可以像引用工具参数一样,把 APEX session state 中的应用项作为绑定变量引用。

图 12-12 编写 SQL 查询实现 Retrieve Data 工具

第二个工具 give_raise 允许 AI 服务把某位员工薪水提高指定百分比。这个工具类型为 Execute Server-side Code,参数 P_EMPNOP_PCT 都是必填的 NUMBER

图 12-13 定义带必填参数的 Execute Server-side Code On Demand 工具

Execute Server-side Code 工具可以用 PL/SQL 或服务器端 JavaScript 实现。示例 PL/SQL 会检查百分比必须大于 0 且不超过 40,然后更新指定员工的薪水。无论成功还是失败,代码都调用 APEX_AI.SET_TOOL_RESULT 返回工具调用结果:

declare
    l_pct     number := nvl(:P_PCT,0);
    l_new_sal number;
    l_result  varchar2(255);
begin
    if l_pct > 0 and l_pct <= 40 then
        update emp
           set sal = sal * (1 + to_number(nvl(:P_PCT,0)/100))
         where empno = :P_EMPNO
        returning sal into l_new_sal;

        l_result := case
            when sql%rowcount > 0 then 'New salary is '||l_new_sal
            else 'No employee '||:P_EMPNO||' found'
        end;
    else
        l_result := 'Percent must be > 0 and <= 40';
    end if;

    apex_ai.set_tool_result(l_result);
end;
图 12-14 编写 PL/SQL 代码实现 Execute Server-side Code 工具

12.3.3 在 Agent 驱动的聊天机器人中观察工具调用#

Woods HR 应用使用基于角色的授权,只向 HR 代表 Susan 显示导航栏中的 HR Assistant 按钮。点击后会打开 Assistant 聊天机器人对话框,Susan 可以用自然语言询问 Woods 员工相关问题。

Which clerk earns the most? [Susan]

The highest-paid clerk at Woods HR is MILLER, earning $1,300. [Assistant]

Which employee earns the least? [Susan]

The employee who earns the least is SMITH, with a salary of $800. [Assistant]

Raise smith's salary by 10 percent [Susan]

I couldn't apply the 10% raise because the system requires Smith's employee number, and I only have his name/salary - not his ID. Can you provide Smith's employee number, or should I look up Smith again to retrieve it? [Assistant]

图 12-15 在 AI Assistant 聊天机器人中使用 HR Assistant AI Agent

这段对话说明聊天机器人正在使用 HR Assistant AI Agent,并根据需要调用或考虑调用 get_employee_infogive_raise 工具。问题在于 get_employee_info 查询没有返回 EMPNO,所以 Assistant 无法直接执行加薪。把查询改为同时返回 EMPNO,并在 Data Description 中说明 employee id 后,聊天机器人就可以无需额外输入完成任务。

Done - SMITH (EmpNo 7369) received a 10% raise. Salary is now $880. [Assistant]

图 12-16 当 get_employee_info 返回 EMPNO 后,Assistant 可以直接完成任务

12.3.4 Agent 驱动请求的生命周期#

当最终用户在浏览器中提出问题,例如 “Which clerk earns the most?”,APEX 引擎会先运行所有 Augment System Prompt 工具。它们的结果会和 AI Agent 的系统提示词一起,作为第一条消息发送给 AI Service 的大语言模型(LLM)。

如果 AI Service 已经拥有回答所需信息,它可以直接回复;否则,它可能要求调用一个或多个 On Demand 工具。例如 LLM 可能请求调用 get_employee_info,并把工具参数 JOB 设置为 clerk

提示:AI 服务看不到工具的实现方式,只能看到工具返回的数据。APEX 发送的是工具名称、说明和参数定义。这些内容构成 LLM 可调用函数的契约;至于工具返回什么,完全由应用控制。

APEX 会执行 LLM 请求调用的工具,把服务提供的参数传给工具,再把工具结果返回给 APEX。这个 agent loop 会持续到 AI Service 决定给出最终答案。由于 LLM 本身是无状态的,Susan 多轮对话时,APEX 会在每次请求中发送完整对话历史,让模型拥有推理所需上下文。

图 12-17 涉及 AI Agent 的请求生命周期

12.3.5 选择工具执行点#

AI Agent 工具的 Execution Point 决定它何时运行:

  • On Demand:只有当 AI Service 请求调用时,APEX 才执行该工具。
  • Augment System Prompt:在 Agent 向 AI Service 发送初始请求之前运行,结果作为额外系统提示放在用户输入之前。

两种工具都可以配置 Server-side condition。On Demand 工具条件为 false 时,它的说明不会发送给 AI 服务;Augment System Prompt 工具条件为 false 时,该工具会被跳过,不向初始请求添加数据。

任何工具都可以执行检索增强生成(Retrieval Augmented Generation, RAG)。如果 Agent 的目标总是需要某些前置信息才能回答,可以使用 Augment System Prompt。否则,更推荐创建描述清晰的 On Demand 工具,让 LLM 在需要时决定是否调用,并且只返回回答所需的最小信息。

12.3.6 原生工具类型、参数和人工确认#

APEX 提供三种原生工具类型:

  • Retrieve Data:基于 SQL Query、返回 CLOB 的 Function Body 或静态文本返回数据。
  • Execute Server-side Code:使用 PL/SQL 或 JavaScript (MLE) 在服务器端执行业务逻辑,可用 APEX_AI.SET_TOOL_RESULT 覆盖默认成功结果。
  • Execute Client-side Code:在异步上下文中请求最终用户输入或调用浏览器 API,也可以通过返回字符串覆盖默认成功结果。

On Demand 工具可以使用所有工具类型。用于 Augment System Prompt 时,只能选择 Retrieve Data 或 Execute Client-side Code。

On Demand 工具可以声明命名参数,设置说明和是否必填。支持的数据类型包括 VARCHAR2CLOBNUMBERBOOLEAN。SQL 或 PL/SQL 工具用绑定变量引用参数值,例如 :PERSON_ID;JavaScript 工具通过 this.data.PERSON_ID 访问。

如果某个工具涉及敏感操作,可以在工具定义的 User Approval 区域开启 Requires Confirmation。开启后,当 LLM 请求调用该工具时,最终用户会收到提示;只有用户批准后,工具才会执行。

声明式使用时,Show AI AssistantGenerate Text With AI 动态动作,以及 Generate Text with AI 页面进程或 workflow activity 都可以引用 AI Agent。程序化使用时,把 AI Agent 的 Static ID 传给 APEX_AI 包 API。如果 AI Service 调用 Agent 工具,APEX 会自动执行它们。由浏览器发起的 Show AI Assistant 或 Generate Text With AI 动态动作可以使用客户端工具。

如果内置工具类型不够,可以使用 Generative AI Tool 插件类型创建可复用的自定义工具。

12.4 创建由 Agent 驱动的聊天机器人#

要创建聊天机器人,可以使用 Show AI Assistant 动态动作。这个动态动作通常在页面加载时执行,或由按钮点击触发。它可以打开独立对话框,也可以指向页面中的 Static Content 区域作为内嵌显示区域。

运行时,最终用户会看到欢迎消息,并可以开始提问。显示形式类似常见聊天应用:用户和机器人以交替时间线展示问答气泡,每条消息都有头像图标。

在动态动作的 Generative AI 区域中选择一个 Agent 来处理对话,并决定 Display As 是对话框还是内嵌区域。Agent 的提示词和工具可以为用户提供更完整的体验。如果聊天机器人只需要固定提示词,也可以让动态动作直接使用 Generative AI Service,而不选择 Agent。

提示:如果要配置 AI 服务和最终用户的头像图标或图片,进入应用中的 Shared Components > Component Settings > Show AI Assistant 调整相应设置。

图 12-18 使用按钮触发动作显示 AI Assistant 对话框

如果需要完全自定义聊天体验,可以用 APEX_AI 包中的 CHAT() 函数调用 AI 服务,用 APEX_COLLECTION 包把问题和回复存入 collection,再结合 Comments region 和 APEX_COLLECTIONS 视图显示对话。

12.5 生成文本以节省时间#

当应用需要为用户起草、改写、总结、分类或解释文本时,可以使用 Generate Text with AI 动态动作、页面进程或 workflow activity。例如诊所应用可以根据选中的建议生成患者出院说明,销售应用可以在客户通话前总结近期活动。

如果请求需要通过工具读取允许访问的应用数据或执行操作,请选择 AI Agent;如果固定提示词已经足够,也可以直接使用 Generative AI Service。自定义代码中可以调用 APEX_AI 包的 GENERATE() 函数。

官方示例中,Woods Clinic 员工在 Complete Procedure 表单中填写病人术后说明。表单列出医生常用的恢复建议,也允许员工填写非处方止痛建议和医生开具的药物。

图 12-19 输入患者出院说明相关信息

在同一个对话框的 Discharge Letter 选项卡中,员工点击 Generate Initial Letter 生成出院信初稿。按钮上的第一个触发动作是 Execute Server-side Code,它把员工输入赋值给一组应用项:PATIENTPROCEDUREGENERAL_RECSPAIN_RECPRESCRIPTIONS。第二个触发动作是 Generate Text with AI,关联到一个 Generate Discharge Letter Draft AI Agent,并把生成的草稿填入页面上的 Rich Text Editor 页面项。

该 Agent 的系统提示词使用模板指令,按条件插入部分应用项值:

You are a friendly nurse at a medical clinic named "Woods Clinic".
Your task is to write a succinct letter in a professional style as discharge
instructions for a patient #PATIENT# who underwent a #PROCEDURE# procedure
at the clinic today. Using a gender-neutral greeting, start by thanking the
patient for trusting Woods Clinic for their healthcare needs and summarize
the procedure.

{if GENERAL_RECS /}
Include general recommendations like: #GENERAL_RECS#.
{endif/}

{if PAIN_REC /}
For any pain experienced, recommend: #PAIN_REC#.
{endif/}

{if PRESCRIPTIONS /}
Summarize prescribed medicines: #PRESCRIPTIONS#
{endif/}

生成结果会显示在页面中。诊所员工可以审阅草稿、做必要修改,然后打印并交给患者带回家。生产应用中,建议把 AI 生成内容作为“待人工确认的草稿”,不要直接发送或保存为最终文档。

图 12-20 使用 AI Agent 准备出院信

12.6 使用向量搜索按语义查找#

向量搜索让用户可以按含义查找结果,即使用户输入的词和表中存储的词不一致,也能返回相关记录。APEX 可以结合 Oracle AI Database 26ai Vector Search 与 Search Configuration,为页面提供语义搜索体验。

12.6.1 关键词搜索带来的挫败感#

用户知道自己想找什么,但他们使用的词可能和表中的词不同。如果搜索没有结果,体验会很差。官方示例中,Lucy 白天参加拉斯维加斯会议,晚上想带家人参加适合孩子的活动。你已经为 Vegas Family Nights 应用创建了一个带 Search region 的页面,使用 Activities Search Configuration 搜索 AIW_ACTIVITIES 表中的亲子活动。该标准搜索配置会搜索 TITLEDESCRIPTIONIMAGE_DESCRIPTIONTAGS 等列。

图 12-21 Activities 表列上的标准搜索配置

但当 Lucy 搜索 “place with sea life swimming around us” 时,没有任何活动匹配。

图 12-22 Lucy 使用的词没有找到匹配活动

她再搜索 “location where we can see illuminated old hotel signs”,仍然没有结果。问题不是数据不存在,而是用户表达和数据中的词没有直接匹配。

12.6.2 用向量捕获词语含义#

AI 模型会根据训练数据理解新的文本或图像输入。它会评估大量特征,并为每个特征分配一个分数。以亲子活动为例,特征可能包括活动类型、适合年龄、室内或室外、体力要求、教育价值、耗时、费用、距离 Strip 的远近、无障碍情况、噪音水平、餐饮供应、天气敏感性等。每个特征都可以用 0 到 1 之间的数字表达强弱。

这些按顺序排列的数字就是向量(vector)。Oracle AI Database 26ai 支持 VECTOR 数据类型,可以把这种“语义得分卡”存入表列,并高效索引向量,快速找出与用户搜索意图最接近的记录。

12.6.3 在现有表中加入向量列#

示例数据库中已有 AIW_ACTIVITIES 表。可以修改该表,新增 SEMANTIC_CONTENT 列,类型为 VECTOR,用于存储 AI 模型为每项活动推断出的特征分数列表。这个向量编码的是模型对活动完整画像的理解。

图 12-23 在 Object Browser 中为现有表添加 VECTOR 列

12.6.4 在数据库中安装模型#

用于编码数据语义的 AI 模型可以是外部 AI 服务、外部程序,也可以是直接加载到 Oracle 26ai 数据库中的行业标准 ONNX(Open Neural Network Exchange)模型。使用外部 AI 服务时,必须把数据发送到外部进行编码;使用数据库内模型时,可以在数据库中就地完成语义编码。

安装模型的前提是 APEX 工作区的解析 schema 具备 CREATE MINING MODEL 权限。官方示例使用以下 PL/SQL 加载 ONNX 模型,请把 TODO 替换为博客文章中模型文件的 URL:

begin
    dbms_vector.load_onnx_model(
        model_name => 'DOC_MODEL',
        model_data => apex_web_service.make_rest_request_b(
            p_http_method => 'GET',
            p_url         => 'TODO'
        ),
        metadata => json(q'~
        {
            "function" : "embedding",
            "embeddingOutput" : "embedding",
            "input":{"input": ["DATA"]}
        }~')
    );
end;

12.6.5 定义 Vector Provider#

向量 embedding 是模型把输入内容理解为多维特征空间坐标后的表示。APEX 通过 Vector Provider 简化了外部模型或数据库内模型的使用。进入 Workspace > All Workspace Utilities > Vector Providers 定义向量提供方。定义后,可以在 APEX_AI.GET_VECTOR_EMBEDDINGS 函数中引用它,也可以在 Search region 使用的 Search Configuration 中引用它。

图 12-24 基于数据库内 ONNX 模型创建 Vector Provider

12.6.6 为数据生成向量 embedding#

要为文本输入生成向量,可以调用 APEX_AI.GET_VECTOR_EMBEDDINGS,传入要编码的文本和 Vector Provider 的 Static ID,例如 vegas-family-nights。下面的 UPDATE 语句把活动标题、描述、图片描述和标签组合成文本,为每行生成 SEMANTIC_CONTENT 向量:

begin
    apex_util.set_workspace('COMPANION');

    update aiw_activities
       set semantic_content = apex_ai.get_vector_embeddings(
           p_value => 'Title: ' || title || chr(13) ||
                      'Description: ' || description || chr(13) ||
                      'Feature Image Description: ' || image_description ||
                      'Tags: ' || tags,
           p_service_static_id => 'vegas-family-nights'
       );
end;

12.6.7 在页面中启用语义搜索#

要让最终用户使用 Vector Search 按含义搜索,先在 Shared Components 下定义 Activities Vector Search Configuration,类型选择 Oracle AI Vector Search。对于 AIW_ACTIVITIES 表,向量列就是前面添加并填充的 SEMANTIC_CONTENT

注意:搜索配置中选择的 Vector Provider 必须和生成现有数据语义向量时使用的提供方一致。只有这样,数据库才能把用户搜索向量和表中已有向量进行可比的距离计算。

图 12-25 在 Activities 表上定义 Vector Search 类型的搜索配置

随后,把页面上已有 Search region 的 Search Source 切换为 Activities Vector 搜索配置。

图 12-26 配置 Search region 使用支持向量的搜索配置

现在,运行时 APEX 会把用户输入转换为表示搜索含义的向量,再查询与该搜索向量最接近的活动。Lucy 搜索海洋生物相关表达时,Shark Reef Aquarium 会作为第一个结果出现。

图 12-27 即使词语不同,Lucy 也能找到语义相关结果

12.6.8 理解向量距离#

用户输入搜索词后,APEX 先计算表示这些词含义的搜索向量。然后查询 AIW_ACTIVITIES 表,并使用 Oracle 26ai 的 VECTOR_DISTANCE() 函数计算用户搜索向量与活动向量之间的距离。距离越小,含义越接近。配合 FETCH FIRST N ROWS ONLY,APEX 可以只返回最相似的前 N 条结果。

为了临时观察结果的向量距离,可以在 Search region 的 Attributes 选项卡中临时开启 Custom Layout,并在布局中引用 &DISTANCE.。当 Lucy 搜索 “location where we can see illuminated old hotel signs” 时,Neon Museum 会以 0.464 的语义距离排在第一位。

图 12-28 临时显示结果向量距离以研究另一条搜索

结果中也可能出现语义距离更远、但仍有某些关联的活动。例如 Sphere 是内外都有投影的巨型球形屏幕,某种程度上也像发光标志;Twilight Zone Mini Golf 的描述中也有 glow-in-the-dark 和 backlight-lit。这类结果可能让用户困惑,因此可以进一步限制只显示与最佳结果足够接近的记录。

12.6.9 使用 best-score proximity cutoff#

best-score proximity cutoff 的思路是:先找到最接近用户搜索的结果距离,再只保留距离落在最佳结果合理阈值范围内的其他结果。假设用 10% 作为阈值,且 p_search_text 是用户搜索文本,可以先计算最小向量距离再乘以 1.10:

select min(
           vector_distance(
               apex_ai.get_vector_embeddings(
                   p_value => p_search_text,
                   p_service_static_id => 'vegas-family-nights'
               ),
               a.semantic_content
           )
       ) * 1.10 /* 10% more than minimum */
  from aiw_activities a

为了让这个计算更容易复用,可以创建标量 SQL macro BEST_ACTIVITY_DISTANCE。它返回一段可在标量位置使用的 SQL 表达式:

create or replace function best_activity_distance (
    p_search_text in varchar2,
    p_factor      in number default 1.10
) return varchar2 sql_macro(scalar) is
begin
    return q'[
        (select min(
                    vector_distance(
                        apex_ai.get_vector_embeddings(
                            p_value => p_search_text,
                            p_service_static_id => 'vegas-family-nights'
                        ),
                        a.semantic_content
                    )
                ) * p_factor
           from aiw_activities a)
    ]';
end;

提示:虽然标量 macro 返回 SQL 文本,但它不会把用户搜索文本或系数值拼接进 SQL。返回的表达式引用 macro 参数 p_search_textp_factor,Oracle 会在调用 SQL 展开时处理这些引用。绑定参数仍是绑定参数,字面量或 SQL 表达式仍是字面量或表达式;数据库照常解析、类型检查和执行展开后的表达式。

定义好 BEST_ACTIVITY_DISTANCE 后,可以结合 APEX_SEARCH.SEARCH 函数过滤结果。下面的查询返回指定 Search Configuration 的搜索结果,并只保留距离不超过最佳结果 10% 范围的记录:

select primary_key_1,
       title,
       description,
       icon_blob,
       icon_mimetype,
       distance
  from table(
       apex_search.search(
           p_search_expression => :P5_SEARCH,
           p_search_static_ids => apex_t_varchar2('activities-vector')
       )
  )
 where distance <= best_activity_distance(:P5_SEARCH)

官方图示中,这个查询用于 Results Content Row region。用户在 Breadcrumb bar 的 Search Field slot 中输入 P5_SEARCHWhen Enter Pressed 动态动作在用户按 Enter 时刷新 Results region。因为查询引用了 P5_SEARCH 绑定变量,Page Items to Submit 也必须设置为 P5_SEARCH。同时,Content Row region 的 Order By Clause 配置为静态列 distance,让向量距离最近的结果排在最前。

图 12-29 在 Content Row 中对 Search Configuration 结果应用 best-score proximity cutoff

使用这个策略后,Lucy 只会看到最相关的结果。

图 12-30 Lucy 只看到最相关的结果

当 Lucy 搜索 “dangle from a wire flying between buildings high in the air” 时,应用会返回 Fly LINQ Zipline 这个明显匹配的周六家庭活动。

图 12-31 Lucy 通过语义搜索找到确切目标

结果并不一定只有一条。如果 Lucy 想找 “swing around on a giant mechanical arm high above the city”,两个高度相关的结果会出现在阈值范围内。孩子们可以先从 Observation Wheel 的高处视野开始,再尝试更刺激的活动。

图 12-32 多个活动落在 best-score proximity cutoff 范围内

关于 Search region 和 Search Configuration 的更多内容,可继续对照官方文档中的 “Unified Search Results Across Sources”。