扩展技能(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 值 | 说明 |
|---|---|---|
.extSkillQuery | agentsdk.ext_skill.query | 查询可用扩展技能清单(SDK → 网关) |
.extSkillQueryResult | agentsdk.ext_skill.query_result | 查询结果(网关 → SDK) |
.extSkillInvoke | agentsdk.ext_skill.invoke | 触发扩展技能执行(SDK → 网关) |
.extSkillInvokeAck | agentsdk.ext_skill.invoke_ack | 下发受理回执(网关 → SDK) |
.extSkillReportState | agentsdk.ext_skill.report_state | 执行期间状态上报(网关 → SDK) |
.extSkillInvokeResult | agentsdk.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 + teleopId | agentId + requestId |
| 核心动作 | enter / audio / keepalive / exit | query / invoke |
| 结果模型 | 单次 ACK | query 单次结果;invoke 三段(ack + state + result) |