超视距遥操(Teleop)指南

超视距遥操(Teleop)指南

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

v1.5.0 新增能力。Teleop = 超视距遥操(远端操作员在线接管机器人的语音交互,不受本地视距限制)。它是继「被动交互 / 主动交互」之后的第三条交互路径,走独立的事件族与独立的策略枚举 AgentPolicy.TELEOP。

使用场景

  • 机器人在现场无人守卫或光线 / 网络不佳的位置,需要远端操作员对特定请求进行接管应答;
  • 二开应用需要旁路 LLM,直接由人工语音接管一段窗口(例如安抚客诉、精确核对下单信息);
  • 操作员的音频通过 SDK 上行到网关,网关按 agentId 下发到目标机器人执行。

调用流程

严格顺序:enter → 任意次 startAudio / appendAudioDelta / doneAudio → exit。 遥操存续期间可任意频次调用 keepalive 探活(推荐每 10 秒一次,见下文 机器人在线检测(keepalive))。

text
              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_ENTERagentsdk.teleop.enter进入遥操(SDK → 网关)
AgentEventType.AGENTSDK_TELEOP_ENTER_ACKagentsdk.teleop.enter_ack进入回执(网关 → SDK)
AgentEventType.AGENTSDK_TELEOP_AUDIO_STARTagentsdk.teleop_audio.start音频段开始(可携带 param)
AgentEventType.AGENTSDK_TELEOP_AUDIO_DELTAagentsdk.teleop_audio.delta音频增量,audio 字段为 base64 字符串,可选 gain 为音频增益倍数(默认 1.0)
AgentEventType.AGENTSDK_TELEOP_AUDIO_DONEagentsdk.teleop_audio.done音频段结束
AgentEventType.AGENTSDK_TELEOP_KEEPALIVEagentsdk.teleop.keepalive机器人在线探活(SDK → 网关)
AgentEventType.AGENTSDK_TELEOP_KEEPALIVE_ACKagentsdk.teleop.keepalive_ack探活回执(网关 → SDK)
AgentEventType.AGENTSDK_TELEOP_EXITagentsdk.teleop.exit退出遥操
AgentEventType.AGENTSDK_TELEOP_EXIT_ACKagentsdk.teleop.exit_ack退出回执

所有 Teleop 消息 wire 结构:

json
{
  "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 灵敏度:

键类型取值示例说明
roleString"male" / "female"遥操音色选择
thresholdInteger-14 ~ 14VAD 灵敏度阈值,数值越大越不易被截断

Java 端构造示例:

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 秒一次)判断机器人是否仍在线。

接口与回调

java
public String keepalive(TeleopKeepaliveCallback keepaliveCallback, long timeout);

public abstract class TeleopKeepaliveCallback {
    public abstract void onKeepaliveAck(String teleopId, String eventId, int code, String msg);
}
  • timeout:本地占位超时(< 50 clamp 到 50,语义同 enter/exit);
  • 返回本次消息的 eventId;
  • 每次调用发送一条 agentsdk.teleop.keepalive,网关按 teleopId 转发到目标机器人;机器人上线则回 success == true。

code 含义(与 enter / exit 一致)

code含义
0机器人在线且响应正常
-1服务端返回失败,msg 携带 errorMsg——表示机器人已离线,业务侧必须处理该异常
1000SDK 端 WebSocket 已关闭,本次未真正下发

定时探活 + 掉线自动退出

任何一次 code != 0,都应视为机器人已离线——立即停止定时任务、exit 退出遥操、unregisterTeleop 释放资源,避免后续 appendAudioDelta 继续下发无效音频。

java
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。

常见问题

  1. onEnterAck 拿到 code == 1000 但业务侧并未主动关闭? 说明底层 WebSocket 已断开或尚未建立。建议在 AgentAuthCallback.onAuthState(code == 0) 之后再发起 enter;断连场景下 SDK 会自动重连,重连成功后再重新 enter。
  2. appendAudioDelta 每片音频建议多长? 与被动交互侧一致 —— 建议 20ms ~ 40ms 的 PCM/Opus 编码为 base64 后 append;太大容易堵塞 WS 单帧,太小则消息数过多。
  3. enter 之后是否需要立即 startAudio? 不需要。enter 拿到 ACK 只表示遥操会话已就绪,业务侧可以按需要在任意时刻推音频(例如等现场客户开口后再触发)。
  4. 一次遥操可以调用几次 startAudio / doneAudio? 任意多次。每一段讲话都是 startAudio → appendAudioDelta × N → doneAudio,不需要 exit 再 enter。多段之间使用不同的 eventId(startAudio 的返回值)。