超视距遥操(Teleop)示例

超视距遥操(Teleop)示例

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

v1.5.0 新增。完整的 Java 端最小示例,展示 enter → startAudio → appendAudioDelta → doneAudio → exit 全流程。示例源码位于仓库 agentsdk_for_java/example/src/main/java/com/agibot/aiem/teleop/TeleopExample.java。

最小示例:TeleopExample.java

java
package com.agibot.aiem.teleop;

import com.agibot.aiem.sdk.AgentAuthCallback;
import com.agibot.aiem.sdk.AgentParam;
import com.agibot.aiem.sdk.AgentSdk;
import com.agibot.aiem.sdk.IdGenerator;
import com.agibot.aiem.sdk.teleop.TeleopEnterCallback;
import com.agibot.aiem.sdk.teleop.TeleopExitCallback;
import com.agibot.aiem.sdk.teleop.TeleopKeepaliveCallback;
import com.agibot.aiem.sdk.teleop.TeleopRequest;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class TeleopExample {

    public static void main(String[] args) throws InterruptedException {

        String url       = "wss://open.agibot.com/api/V1/open-portal/app/wss/agent-sdk";
        String appId     = "您通过灵心开放平台创建的应用获取的appId";
        String appKey    = "您通过灵心开放平台创建的应用获取的appKey";
        String appSecret = "您通过灵心开放平台创建的应用获取的appSecret";
        String agentId   = "您通过灵心平台创建的二开智能体获取的agentId";

        // 第一步:创建 SDK 实例
        AgentSdk agentSdk = AgentSdk.create(url, appId, appKey, appSecret);

        // 第二步:注册验签回调接口
        agentSdk.registerAuth(new AgentAuthCallback() {
            @Override
            public void onAuthState(String appId, int code, String msg) {
                System.out.println("onAuthState => appId: " + appId
                        + ", code: " + code + ", msg: " + msg);
            }
        });

        // 第三步:初始化
        agentSdk.initialize();

        Thread.sleep(2000);

        // 注册遥操请求实例
        String teleopId = IdGenerator.generateTeleopId();
        TeleopRequest teleopRequest = new TeleopRequest(agentSdk, agentId, teleopId);
        agentSdk.registerTeleop(teleopRequest);

        // 进入遥操
        AgentParam enterParam = AgentParam.create();
        teleopRequest.enter(enterParam, new TeleopEnterCallback() {
            @Override
            public void onEnterAck(String teleopId, String eventId, int code, String msg) {
                log.info("onEnterAck => teleopId {}, eventId {}, code {}, msg {}", teleopId, eventId, code, msg);
            }
        }, 2000);

        // 开始说话
        AgentParam startParam = AgentParam.create();
        startParam.setString("role", "male");       // male/female
        startParam.setInteger("threshold", 0);     // -14 - 14
        String eventId = teleopRequest.startAudio(startParam);
        // 持续说话(这里以空字符串占位,实际传 base64 编码后的 PCM/Opus 分片)
        teleopRequest.appendAudioDelta(eventId, "");
        // 结束说话
        teleopRequest.doneAudio(eventId);

        // 检查机器人是否在线(详见「定时探活」小节,遥操期间应每 10s 探活一次)
        teleopRequest.keepalive(new TeleopKeepaliveCallback() {
            @Override
            public void onKeepaliveAck(String teleopId, String eventId, int code, String msg) {
                log.info("onKeepaliveAck => teleopId {}, eventId {}, code {}, msg {}", teleopId, eventId, code, msg);
            }
        }, 2000);

        // 退出遥操
        teleopRequest.exit(new TeleopExitCallback() {
            @Override
            public void onExitAck(String teleopId, String eventId, int code, String msg) {
                log.info("onExitAck => teleopId {}, eventId {}, code {}, msg {}", teleopId, eventId, code, msg);
            }
        }, 2000);

        // 注销并释放(示例省略)
        // agentSdk.unregisterTeleop(teleopId);
        // agentSdk.release();
    }
}

定时探活(keepalive)

enter 拿到 code == 0 之后,业务侧应每 10 秒发起一次 keepalive 探活;onKeepaliveAck 收到 code != 0 即视为机器人离线,需停止定时、退出遥操、注销资源。

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);

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() 停止发送探活。

常见改写要点

想做改哪里
一次遥操中间多次讲话每次讲话都重新 startAudio(startParam) 拿到新的 eventId,appendAudioDelta / doneAudio 使用该 eventId,无需 exit 再 enter
切换音色 / 灵敏度每一段 startAudio 时重新填 AgentParam.role / threshold;不影响前一段音频
中途取消遥操直接 exit(...),不再补发 doneAudio
感知 SDK 鉴权 / 断连在 AgentAuthCallback.onAuthState 里维护一个 authed 标志,enter 前 double check;或在 onEnterAck 收到 code == 1000 后触发重连
多机器人同时遥操每个 agentId 建一个 TeleopRequest;SDK 按 teleopId 索引,互不冲突