通过技能让 RMI ADK 智能体具备领域专业知识

概览

大语言模型拥有广泛的通用知识,但并不了解您网域中的特定指标、数据库架构或计算公式。如果没有此上下文,模型会进行猜测,从而导致 SQL 不正确和分析有缺陷。

RMI ADK 代理通过技能来解决此限制。假设用户询问“昨天 Storrow Drive 的拥堵情况如何?”。为了回答这个问题,代理必须知道 RMI 将拥堵表示为出行时间指数 (TTI),即 historical_travel_time 表中实时 duration_in_seconds 与畅通 static_duration_in_seconds 的比率。没有技能的代理可能会虚构一个 average_speed 列(RMI 报告仅包含分类速度,从不包含 km/h),或者应用错误的公式,从而生成自信但错误的答案。

虽然代理需要这些领域知识,但将每个指标定义、表架构和 SQL 注意事项都放入单个系统提示中效率低下。

大型系统提示的限制

将所有网域规则和架构都放入单个系统提示中会导致以下几个问题:

  • 成本更高,响应更慢:在每个回合中发送大量提示会浪费令牌并增加延迟时间,即使对于不需要这些规则的问题也是如此。
  • 指令遵循能力变差:随着提示变得越来越长,包含的极端情况也越来越多,模型更有可能忽略或忘记特定规则。
  • 维护难度更大:将所有内容都整合到一个提示中,很难在不破坏其他规则的情况下更新或测试单个规则。

技能

智能体技能将领域知识整理到模块化文件夹中,智能体仅在需要时才加载这些文件夹。每项技能都是一个目录,其中包含一个 SKILL.md 文件(带有 Markdown 说明和 YAML 标头)。

智能体不会预先加载所有内容,而只会将每项技能的简短 description 保留在其基本提示中。当用户提出的问题与技能相关时,代理会加载该轮对话的完整指令。这样可以使提示保持较小的大小,并为实际对话记录节省上下文空间。

技能还可实现清晰的关注点分离:您可以单独编写、测试和更新各项功能,而不会在不相关的领域中产生意外的副作用。生产代理通常使用多个专注的技能,而不是一个巨大的提示。

技能详解

SKILL.md 文件包含两部分:用于路由的 YAML 标头和用于说明的 Markdown 正文。

1. YAML 标头

---
name: rmi-traffic-metrics-grounding
description: >
  Standard traffic performance metrics computable from RMI BigQuery
  tables. Covers congestion severity (TTI), delay, travel time
  reliability (LOTTR, BTI, PTI, CoV), congestion frequency, speed
  breakdowns, and network-wide congestion rates. Use when the user asks
  about traffic conditions, congestion, reliability, delay, or network
  health.
---

模型使用 description 来决定是否加载技能。由于模型仅在决定加载技能之前看到此说明,因此请确保其中清楚列出了涵盖的主题、典型的用户措辞以及触发技能的时间。

2. Markdown 正文

正文提供模型加载后遵循的特定领域指导。 RMI 指标技能主体包含确切的 TTI 公式 (duration_in_seconds / static_duration_in_seconds)、每个指标的经过验证的 BigQuery SQL 模板,以及将用户意图映射到正确指标的触发短语。提供结构化且经过验证的指令可确保模型保持可靠性,并防止其猜测架构或公式详细信息。

使用 ADK 注册技能

将技能分组到 SkillToolset 中,然后将其添加到智能体的工具列表中:

from google.adk import skills
from google.adk.tools import skill_toolset

rmi_skill_toolset = skill_toolset.SkillToolset(
    skills=[
        # TRAFFIC_METRICS_SKILL_DIR points to the skill's SKILL.md folder.
        skills.load_skill_from_dir(TRAFFIC_METRICS_SKILL_DIR),
    ],
)

# root_agent = llm_agent.Agent(..., tools=[*bq_tools, rmi_skill_toolset])

在此示例中,TRAFFIC_METRICS_SKILL_DIR 指向包含流量指标基础技能的目录。

将工具与技能捆绑在一起

由于技能是基于文本的指令,因此仅依靠模型来解读和执行复杂的逻辑可能会导致不一致。将可执行工具附加到技能可提供确定性:代码处理严格的计算、验证和 API 交互,而技能则指示模型何时以及如何使用这些工具。

捆绑工具还可以避免全局上下文膨胀。工具不会预先全部公开,而是仅在相应的领域技能处于有效状态时加载。

您可以在技能的 YAML 标头中直接附加特定工具:

metadata:
  adk_additional_tools:
    - calculate_custom_metric

这样可确保模型及时收到工具架构及其使用说明,从而保持精简的基本工具集。

示例:根据上下文信息回答拥堵查询

  1. 用户询问“Storrow Drive 在晚高峰时段的拥堵程度如何?”
  2. 基本系统提示仅宣传每项技能的名称和说明,因此代理会看到 rmi-traffic-metrics-grounding 涵盖“拥堵”,并调用 load_skill 来获取此查询的完整指令。
  3. 加载技能后,智能体应用 TTI 定义和它提供的经过验证的 SQL 模板,计算与 historical_travel_time 的比率,而不是猜测公式。

由于技能的正文仅在查询需要时才会被提取,因此智能体从未使用过的技能永远不会进入上下文,从而使基本系统提示保持较小的规模。

要点总结

  • 根据网域指导进行接地:提供明确的指令、限制和业务逻辑,而不是依赖于一般的模型假设。
  • 使用模块化技能:将知识拆分为专注的技能,而不是一个庞大的系统提示,以节省 token、缩短延迟时间并提高准确性。
  • 撰写清晰的说明:在每项技能的说明中添加具体的触发短语和关键字,以便代理可靠地加载相应技能。
  • 添加具体示例:向技能主体添加经过验证的示例和参考工作流,以确保输出内容的一致性和准确性。
  • 捆绑工具以实现确定性:将可执行工具附加到技能,以处理严格的验证和执行,同时保持基本工具集的精简。

后续步骤

贡献者

Nathaniel Thomas | Google Maps Platform 软件工程实习生