如何设计一个 Skill 的描述 元信息结构,使 Agent 能够自动理解和选用合适的 Skill?

面试官:“如果要让 Agent 自动理解和选用合适的 Skill,你会怎么设计 Skill 的描述或元信息结构?”

候选人:

“这是个很实际的问题。Skill 元信息就像给 Agent 看的‘岗位说明书’,写得太简陋 Agent 看不懂,写得太复杂又难以维护。我觉得设计这套结构时,核心要回答三个问题:这个 Skill 能干什么(能力声明)、它需要什么输入(参数语义)、在什么情况下该用它(触发与约束)。

下面是我在实践中总结的一套分层元信息结构。


第一层:基础身份 —— 唯一标识与分类

{
  "name": "book_flight",
  "version": "1.2.0",
  "category": "travel/transportation",
  "tags": ["flight", "booking", "payment", "travel"],
  "owner": "travel-team"
}
  • name:唯一标识,Agent 内部通过它来调度。

  • version:版本号,支持多版本共存、灰度上线。

  • category / tags:分类和标签,方便 Agent 做粗粒度的意图筛选。比如用户问旅行相关的问题时,优先在 travel 分类下找 Skill。

  • owner:维护团队,方便出问题时快速找到责任人。


第二层:意图与描述 —— 让 Agent 知道“什么时候该用我”

这是最关键的一层,直接决定了 Agent 能否正确匹配 Skill。

{
  "description": {
    "short": "预订国内国际机票",
    "long": "根据出发地、目的地、日期、乘客人数等条件,查询可用航班并完成机票预订,支持经济舱/商务舱/头等舱筛选。",
    "trigger_keywords": ["订机票", "买机票", "航班", "出行", "飞往"],
    "trigger_examples": [
      "帮我订一张明天去上海的机票",
      "查询北京到深圳的航班",
      "我要买下周三去成都的头等舱"
    ],
    "semantic_vector": "0x4a7b..."
  }
}

这里有几个设计要点:

  • 分层描述:short 用于快速筛选,long 用于精确匹配,Agent 在粗筛时看 short,锁定候选 Skill 后再比 long。

  • 触发关键词与示例:这不是简单的字符串匹配,而是给 Agent 做语义相似度计算用的种子样本。Agent 拿到用户输入后,会用嵌入模型分别计算用户输入与 trigger_examples 的相似度,超过阈值就激活这个 Skill。

  • 语义向量:把长描述预计算成向量存起来,运行时直接做向量相似度搜索,比每次实时编码快得多。这在 Skill 数量超过几十个时尤其重要。


第三层:输入输出 Schema —— 让 Agent 知道“该给我什么”

{
  "parameters": [
    {
      "name": "departure",
      "type": "string",
      "required": true,
      "description": "出发城市名称",
      "default": null
    },
    {
      "name": "destination",
      "type": "string",
      "required": true,
      "description": "到达城市名称",
      "default": null
    },
    {
      "name": "date",
      "type": "string",
      "required": true,
      "description": "出发日期,格式 YYYY-MM-DD",
      "default": null
    },
    {
      "name": "cabin_class",
      "type": "enum",
      "enum_values": ["economy", "business", "first"],
      "required": false,
      "description": "舱位等级,默认经济舱",
      "default": "economy"
    }
  ],
  "output": {
    "type": "object",
    "description": "返回符合条件的航班列表及预订状态",
    "schema": { "flights": "array", "booking_id": "string", "status": "string" }
  }
}

设计要点:

  • 必填 vs 可选:Agent 看到 required: true 的参数如果缺失,就会触发澄清流程,主动反问用户。

  • 枚举约束:像 cabin_class 这种有限值的参数,直接用枚举定义,防止 Agent 自己发明不存在的值。

  • 默认值:降低用户输入负担,也减少 Agent 追问的次数。

  • 输出描述:不仅让人看,也让 Agent 知道调用完能拿到什么,方便它规划后续步骤(比如预订成功后是否需要调用“发送行程邮件”Skill)。


第四层:前置条件与约束 —— 让 Agent 知道“什么时候不能乱用”

{
  "preconditions": {
    "required_capabilities": ["payment_authorized", "user_logged_in"],
    "rate_limit": { "max_calls_per_minute": 10, "max_calls_per_user_hour": 3 },
    "timeout_ms": 30000,
    "retry_policy": { "max_retries": 2, "backoff": "exponential" }
  },
  "side_effects": ["creates_order", "charges_payment"],
  "rollback_skill": "cancel_flight"
}

设计要点:

  • 前置条件:Agent 在触发 Skill 前会先检查这些条件是否满足。比如用户没登录,就先把“登录”Skill 激活,再回来继续。

  • 频率限制:防止 Agent 或用户在短时间内疯狂触发同一个 Skill,保护后端服务。

  • 超时与重试:声明这个 Skill 的预期响应时间,Agent 可以根据它来设定等待策略。

  • 副作用声明:明确告诉 Agent “这个 Skill 会产生订单、会扣款”,这样 Agent 在规划时会把它放在关键路径上,也方便事后审计。

  • 回滚 Skill:如果后续出错需要补偿,Agent 知道该调用哪个 Skill 来做撤销。


第五层:依赖与协作 —— 让 Agent 知道“我和谁有关系”

{
  "dependencies": {
    "requires": ["user_profile", "payment"],
    "optional": ["travel_insurance", "hotel_booking"],
    "conflicts_with": ["refund_processing"]
  },
  "composition": {
    "can_be_subtask_of": ["travel_planning"],
    "can_use_as_subtask": ["payment", "send_invoice"]
  }
}

设计要点:

  • 必须依赖:比如“支付”Skill 挂了,那“订机票”就不能执行。Agent 在规划时会检查依赖的可用性。

  • 可选协作:如果用户也需要订酒店,可以在订机票后顺带推荐,这是提升体验的机会点。

  • 冲突声明:有些 Skill 不能同时跑(比如“退款”和“下单”),Agent 会做互斥判断。

  • 组合声明:声明这个 Skill 可以作为哪些大任务的一部分,以及它可以调用哪些小 Skill。这让 Agent 在规划复杂任务时能自动拼装多个 Skill 形成一条链。