扩展技能(ExtSkill)指南 · iOS

扩展技能(ExtSkill)指南 · iOS

⚠️ 尚未上线:本能力为 v1.5.0-SNAPSHOT 开发中特性,接口与协议可能调整,正式发布前请勿用于生产环境。

v1.5.0 新增能力。ExtSkill = 扩展技能:二开应用把自定义技能挂到智能体上,运行期先 query 拉取该智能体当前可用的扩展技能清单,再 invoke 触发某个技能执行。它与「被动交互 / 主动交互 / 超视距遥操」并列,走独立的事件族与独立的策略枚举 AgentPolicy.extSkill(wire 值 "extskill")。Swift 端 API 与 Java 一一对应。

使用场景

  • 二开应用在灵心平台为智能体配置了若干扩展技能(如天气查询、工单创建、设备控制),需要在运行期动态获取清单并按需触发;
  • 需要旁路对话链路直接调用一个确定性的能力(带结构化入参、拿结构化出参),而不是走 LLM 自由生成;
  • 一次 invoke 分三段收结果:先 onInvokeAck 确认网关已受理,再 onState 收执行期间的状态上报(可选),最后 onInvokeResult 拿到技能真正的执行输出。

调用流程

registerExtSkill 注册后,可任意次 query 拉取清单、invoke 触发执行;不再需要时 unregisterExtSkill 释放。

text
   ┌─────────────────────────────┐
   │  ExtSkillRequest.query       │  拉取可用扩展技能清单
   │    (onQueryResult)           │
   └─────────────────────────────┘

   ┌─────────────────────────────┐
   │  ExtSkillRequest.invoke      │  触发某个扩展技能执行
   │    (onInvokeAck)             │  ← 第一段:网关已受理
   │    (onState)                 │  ← 第二段:执行期间状态上报(0 到多次)
   │    (onInvokeResult)          │  ← 第三段:技能执行输出
   └─────────────────────────────┘
  • query 通过 onQueryResult 一次性回结果;code == 0 时 result 承载技能清单等返回内容;
  • invoke 分三段:先 onInvokeAck(下发确认),再 onState(执行期间技能侧通过 agentsdk.ext_skill.report_state 上报进度,0 到多次),最后 onInvokeResult(执行输出,code == 0 时 param 承载出参);
  • 若发送瞬间 SDK 连接已关闭,query / invoke 回调会在原线程同步以 code == 1000 + msg == "Agentsdk connection is closed" 触发一次失败回执。

Swift 快速代码

swift
import LinksoulAgentSDK

// 1. 创建 SDK
let agentSdk = AgentSdk.create(url: url, appId: appId, appKey: appKey, appSecret: appSecret)

// 2. 注册鉴权
final class AuthCallback: AgentAuthCallback {
    func onAuthState(appId: String, code: Int, msg: String) {
        // code == 0 后再操作
    }
}
agentSdk.registerAuth(AuthCallback())
agentSdk.initialize()
Thread.sleep(forTimeInterval: 2.0)

// 3. 注册扩展技能请求
let requestId = IdGenerator.generateExtSkillRequestId()
let extSkillRequest = ExtSkillRequest(agentSdk: agentSdk, agentId: agentId, requestId: requestId)
agentSdk.registerExtSkill(extSkillRequest)

// 4. 查询可用扩展技能清单
final class QueryCallback: ExtSkillQueryCallback {
    override func onQueryResult(agentId: String, requestId: String, eventId: String,
                                code: Int, msg: String?, result: AgentParam?) {
        print("onQueryResult => code \(code), msg \(msg ?? ""), result \(String(describing: result))")
    }
}
let queryEventId = extSkillRequest.query(queryCallback: QueryCallback(), timeout: 2000)

// 5. 触发某个扩展技能执行
let input = AgentParam.create()
    .setString("city", "shanghai")
    .setInt("days", 3)

final class InvokeCallback: ExtSkillInvokeCallback {
    override func onInvokeAck(agentId: String, requestId: String, eventId: String,
                              code: Int, msg: String?) {
        print("onInvokeAck => code \(code)")
    }
    override func onState(agentId: String, requestId: String, eventId: String,
                          stateName: String?, stateValue: String?) {
        print("onState => stateName \(stateName ?? ""), stateValue \(stateValue ?? "")")
    }
    override func onInvokeResult(agentId: String, requestId: String, eventId: String,
                                 code: Int, msg: String?, param: AgentParam?) {
        print("onInvokeResult => code \(code), param \(String(describing: param))")
    }
}
let invokeEventId = extSkillRequest.invoke(
    extSkillId: "skill_weather", input: input,
    invokeCallback: InvokeCallback(), timeout: 2000)

// 6. 用完释放
agentSdk.unregisterExtSkill(requestId: requestId)

事件族与协议

AgentEventType 枚举里的扩展技能事件:

Swift 枚举成员wire 值说明
.extSkillQueryagentsdk.ext_skill.query查询可用扩展技能清单(SDK → 网关)
.extSkillQueryResultagentsdk.ext_skill.query_result查询结果(网关 → SDK)
.extSkillInvokeagentsdk.ext_skill.invoke触发扩展技能执行(SDK → 网关)
.extSkillInvokeAckagentsdk.ext_skill.invoke_ack下发受理回执(网关 → SDK)
.extSkillReportStateagentsdk.ext_skill.report_state执行期间状态上报(网关 → SDK)
.extSkillInvokeResultagentsdk.ext_skill.invoke_result执行结果(网关 → SDK)

所有 ExtSkill 消息 wire 结构:

json
{
  "type": "<event type>",
  "agentId": "<目标智能体 agentId>",
  "eventId": "event_xxxxxxxxxxxxxxxxxxxxx",
  "agentMode": "extskill",
  "requestId": "extskill_xxxxxxxxxxxxxxxxxxxxx"
}
  • 与 Teleop 用 sn 不同,ExtSkill 的智能体标识字段用 agentId;
  • requestId 由 IdGenerator.generateExtSkillRequestId() 生成,是一次扩展技能会话的身份,query / invoke 复用同一个;
  • invoke 额外携带 extSkillId(要触发的技能 ID)与 input(扁平的入参键值,对齐 input.dictionary);
  • agentMode 恒为 "extskill"(对应 AgentPolicy.extSkill)。

invoke 入参

invoke(extSkillId:input:invokeCallback:timeout:) 的 input 是一个 AgentParam,承载该技能的结构化入参,具体键由技能定义决定。构造示例:

swift
let input = AgentParam.create()
    .setString("city", "shanghai")
    .setInt("days", 3)
let eventId = extSkillRequest.invoke(
    extSkillId: "skill_weather", input: input,
    invokeCallback: invokeCallback, timeout: 2000)

wire 上以扁平键值下发(input.city / input.days),与 input.dictionary 输出一致。

结果错误码

query / invoke 回调的 code 语义统一:

code含义
0成功(result / param 承载返回内容)
-1服务端返回失败,msg 携带 errorMsg 详情
1000本地失败:发送时 SDK 侧 LinkskyClient 已关闭,SDK 同步在原线程回调该 code,业务侧应视为发送失败

code != 0 时,onQueryResult 的 result、onInvokeResult 的 param 均为 nil。

API 速览

  • 请求类:ExtSkillRequest
  • 回调基类:ExtSkillQueryCallback(onQueryResult)/ ExtSkillInvokeCallback(onInvokeAck + onState + onInvokeResult)
  • 注册:AgentSdk.registerExtSkill(_:) / AgentSdk.unregisterExtSkill(requestId:)
  • ID:IdGenerator.generateExtSkillRequestId()

完整签名见 ExtSkill API。可运行示例见 ExtSkill 示例。

生命周期与清理

  • AgentSdkExtSkillMgr 按 requestId 维护活跃 request;调用 query / invoke 前必须先 registerExtSkill(_:);
  • 每次 request 方法调用会刷新内部 updateTs;超过 7200s 未活动的 request 会被后台清理线程回收;
  • 用完或不再需要时,建议调用 agentSdk.unregisterExtSkill(requestId:) 显式回收;
  • AgentSdk.release() 会连带清理该实例名下的所有 ExtSkill request。

回调线程约定

  • onQueryResult / onInvokeAck / onState / onInvokeResult 在 SDK 的消息分发线程回调(非主线程);如果要更新 UI,请自行切到 DispatchQueue.main;
  • ExtSkillQueryCallback / ExtSkillInvokeCallback 是 open class(不是 protocol),需要继承 + override 使用,方便共享 timeout 等基类字段。

与 Teleop 的区别

维度Teleop(超视距遥操)ExtSkill(扩展技能)
策略AgentPolicy.teleop("teleop")AgentPolicy.extSkill("extskill")
标识字段sn + teleopIdagentId + requestId
核心动作enter / audio / keepalive / exitquery / invoke
结果模型单次 ACKquery 单次结果;invoke 三段(ack + state + result)