超视距遥操(Teleop)指南
超视距遥操(Teleop)指南
⚠️ 尚未上线:本能力为 v1.5.0-SNAPSHOT 开发中特性,接口与协议可能调整,正式发布前请勿用于生产环境。
v1.5.0 新增能力。Teleop = 超视距遥操(远端操作员在线接管机器人的语音交互,不受本地视距限制)。它是继「被动交互 / 主动交互」之后的第三条交互路径,走独立的事件族与独立的策略枚举
AgentPolicy.TELEOP。
使用场景
- 机器人在现场无人守卫或光线 / 网络不佳的位置,需要远端操作员对特定请求进行接管应答;
- 二开应用需要旁路 LLM,直接由人工语音接管一段窗口(例如安抚客诉、精确核对下单信息);
- 操作员的音频通过 SDK 上行到网关,网关按
agentId下发到目标机器人执行。
调用流程
严格顺序:enter → 任意次 startAudio / appendAudioDelta / doneAudio → exit。
遥操存续期间可任意频次调用 keepalive 探活(推荐每 10 秒一次,见下文 机器人在线检测(keepalive))。
enter exit
┌──────────────────────┐ ┌──────────────────────┐
│ TeleopRequest.enter │ │ TeleopRequest.exit │
│ (onEnterAck) │ │ (onExitAck) │
└──────────┬───────────┘ └──────────┬───────────┘
│ 任意次 (fire-and-forget) │
▼ │
┌──────────────────────┐ │
│ startAudio(param) │ │
│ appendAudioDelta(*) │───────────────────┘
│ doneAudio │
└──────────────────────┘
┌──────────────────────┐
│ TeleopRequest.keepalive │ ← 建议每 10 秒一次;code != 0 视为机器人离线
│ (onKeepaliveAck) │
└──────────────────────┘
enter/keepalive/exit都有 ACK 回调;相应on*Ack收到code == 0视为成功;startAudio/appendAudioDelta/doneAudio是 fire-and-forget,本地不排队等 ACK;- 若发送瞬间 SDK 连接已关闭,
enter/keepalive/exit回调会在原线程同步以code == 1000+msg == "Agentsdk connection is closed"触发一次失败回执。
事件族与协议
| Java 枚举成员 | 事件类型字符串 | 说明 |
|---|---|---|
AgentEventType.AGENTSDK_TELEOP_ENTER | agentsdk.teleop.enter | 进入遥操(SDK → 网关) |
AgentEventType.AGENTSDK_TELEOP_ENTER_ACK | agentsdk.teleop.enter_ack | 进入回执(网关 → SDK) |
AgentEventType.AGENTSDK_TELEOP_AUDIO_START | agentsdk.teleop_audio.start | 音频段开始(可携带 param) |
AgentEventType.AGENTSDK_TELEOP_AUDIO_DELTA | agentsdk.teleop_audio.delta | 音频增量,audio 字段为 base64 字符串,可选 gain 为音频增益倍数(默认 1.0) |
AgentEventType.AGENTSDK_TELEOP_AUDIO_DONE | agentsdk.teleop_audio.done | 音频段结束 |
AgentEventType.AGENTSDK_TELEOP_KEEPALIVE | agentsdk.teleop.keepalive | 机器人在线探活(SDK → 网关) |
AgentEventType.AGENTSDK_TELEOP_KEEPALIVE_ACK | agentsdk.teleop.keepalive_ack | 探活回执(网关 → SDK) |
AgentEventType.AGENTSDK_TELEOP_EXIT | agentsdk.teleop.exit | 退出遥操 |
AgentEventType.AGENTSDK_TELEOP_EXIT_ACK | agentsdk.teleop.exit_ack | 退出回执 |
所有 Teleop 消息 wire 结构:
{
"type": "<event type>",
"agentId": "<目标机器人 agentId>",
"teleopId": "teleop_xxxxxxxxxxxxxxxxxxxxx",
"eventId": "event_xxxxxxxxxxxxxxxxxxxxx",
"agentMode": "teleop"
}
其中 teleopId 由 IdGenerator.generateTeleopId() 生成;agentMode 恒为 "teleop"(对应 AgentPolicy.TELEOP)。
startAudio 参数
startAudio(AgentParam) 支持在每一段音频开始时携带一份 AgentParam,主要用于告诉服务端本段音频的音色 / VAD 灵敏度:
| 键 | 类型 | 取值示例 | 说明 |
|---|---|---|---|
role | String | "male" / "female" | 遥操音色选择 |
threshold | Integer | -14 ~ 14 | VAD 灵敏度阈值,数值越大越不易被截断 |
Java 端构造示例:
AgentParam startParam = AgentParam.create();
startParam.setString("role", "male");
startParam.setInteger("threshold", 0);
String eventId = teleopRequest.startAudio(startParam);
wire 上会以 param.extParam.role / param.extParam.threshold 的形式下发(与其他 AgentParam 一致)。
机器人在线检测(keepalive)
遥操会话通常持续较长,期间机器人可能因网络中断 / 电量耗尽 / 现场断电等原因掉线。SDK 提供 TeleopRequest.keepalive(...) 一次性探活方法,业务侧应定时调用(建议 每 10 秒一次)判断机器人是否仍在线。
接口与回调
public String keepalive(TeleopKeepaliveCallback keepaliveCallback, long timeout);
public abstract class TeleopKeepaliveCallback {
public abstract void onKeepaliveAck(String teleopId, String eventId, int code, String msg);
}
timeout:本地占位超时(< 50clamp 到 50,语义同enter/exit);- 返回本次消息的
eventId; - 每次调用发送一条
agentsdk.teleop.keepalive,网关按teleopId转发到目标机器人;机器人上线则回success == true。
code 含义(与 enter / exit 一致)
code | 含义 |
|---|---|
0 | 机器人在线且响应正常 |
-1 | 服务端返回失败,msg 携带 errorMsg——表示机器人已离线,业务侧必须处理该异常 |
1000 | SDK 端 WebSocket 已关闭,本次未真正下发 |
定时探活 + 掉线自动退出
任何一次 code != 0,都应视为机器人已离线——立即停止定时任务、exit 退出遥操、unregisterTeleop 释放资源,避免后续 appendAudioDelta 继续下发无效音频。
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
ScheduledExecutorService keepaliveScheduler = Executors.newSingleThreadScheduledExecutor(r -> {
Thread t = new Thread(r, "teleop-keepalive");
t.setDaemon(true);
return t;
});
AtomicBoolean robotOnline = new AtomicBoolean(true);
// enter 成功后启动定时探活;每 10 秒发一次
keepaliveScheduler.scheduleAtFixedRate(() -> {
if (!robotOnline.get()) return;
teleopRequest.keepalive(new TeleopKeepaliveCallback() {
@Override
public void onKeepaliveAck(String teleopId, String eventId, int code, String msg) {
if (code == 0) return;
// 机器人离线:停止定时、退出遥操、释放资源
if (!robotOnline.compareAndSet(true, false)) return;
log.warn("robot offline => code={}, msg={}", code, msg);
keepaliveScheduler.shutdown();
teleopRequest.exit(new TeleopExitCallback() {
@Override
public void onExitAck(String teleopId, String eventId, int code, String msg) {
agentSdk.unregisterTeleop(teleopId);
}
}, 2000);
}
}, 2000);
}, 10, 10, TimeUnit.SECONDS);
调用 exit 后应主动 keepaliveScheduler.shutdown(),避免继续发送探活消息。
API 速览
- 请求类:
com.agibot.aiem.sdk.teleop.TeleopRequest - 回调基类:
com.agibot.aiem.sdk.teleop.TeleopEnterCallback/TeleopKeepaliveCallback/TeleopExitCallback - 注册:
AgentSdk.registerTeleop(TeleopRequest)/AgentSdk.unregisterTeleop(String teleopId) - ID:
IdGenerator.generateTeleopId()
完整签名见 Teleop API。可运行示例见 Teleop 示例。
生命周期与清理
- SDK 内部按
teleopId维护活跃 request;调用enter前必须先registerTeleop(...); - 每次 request 方法调用会刷新内部
updateTs;超过 7200s 未活动的 request 会被后台清理线程回收; - 调用完
exit或不再需要遥操时,建议调用agentSdk.unregisterTeleop(teleopId)显式回收,避免依赖 7200s 超时清理; AgentSdk.release()会连带清理该实例名下的所有 Teleop request。
常见问题
onEnterAck拿到code == 1000但业务侧并未主动关闭? 说明底层 WebSocket 已断开或尚未建立。建议在AgentAuthCallback.onAuthState(code == 0)之后再发起enter;断连场景下 SDK 会自动重连,重连成功后再重新enter。appendAudioDelta每片音频建议多长? 与被动交互侧一致 —— 建议 20ms ~ 40ms 的 PCM/Opus 编码为 base64 后 append;太大容易堵塞 WS 单帧,太小则消息数过多。enter之后是否需要立即startAudio? 不需要。enter拿到 ACK 只表示遥操会话已就绪,业务侧可以按需要在任意时刻推音频(例如等现场客户开口后再触发)。- 一次遥操可以调用几次
startAudio/doneAudio? 任意多次。每一段讲话都是startAudio → appendAudioDelta × N → doneAudio,不需要exit再enter。多段之间使用不同的eventId(startAudio的返回值)。