Skip to content

接入 AI 实时对话引擎

本文说明如何通过 TiRTC 接入探鸽平台 AI 实时对话引擎。业务服务端负责获取角色、申请连接凭证并下发给设备;设备端负责使用凭证建连、启动会话、收发音频和处理事件。

1. 总体流程

mermaid
sequenceDiagram
    autonumber
    participant D as 设备端
    participant B as 业务服务端
    participant P as 探鸽平台

    B->>P: 创建或查询角色(控制台 / OpenAPI),获取 role_id
    D->>B: 请求发起 AI 实时对话
    B->>B: 校验用户、设备、套餐与业务权限
    B->>P: POST /v1/token/aichat
    P-->>B: peer_id, token
    B-->>D: 下发 peer_id, token
    D->>P: TiRtcWhipConnect(peer_id, token)
    P-->>D: TiRTC 连接建立成功
    D->>P: start_session(device_id, role_id)
    P-->>D: session_id 与音频格式
    D->>P: 上行麦克风音频
    P-->>D: 下行回复音频、字幕、轮次事件

role_id 是 AI 实时对话引擎的必传参数。设备端不要自行拼接 peer_id,也不要持有服务端签名密钥。peer_idtoken 必须由业务服务端向探鸽平台申请后下发。

2. AI 实时对话引擎控制台

接入前,请先进入 AI 实时对话引擎控制台 完成以下配置:

  1. 已在探鸽平台创建应用,并获取 AppIdAccessKeyIdSecretKeyId
  2. 已完成设备注册,以及设备与应用或产品的绑定关系配置。
  3. 已开通 AI 实时对话引擎相关套餐或服务能力。
  4. 已在探鸽开放平台创建并配置智能体。
  5. 已获取本次会话使用的 role_id,或已通过 OpenAPI 建立设备与角色的绑定关系。

角色获取、设备绑定角色、设备角色查询等 OpenAPI 以后续 Apifox 文档 为准。

3. 服务端集成

服务端接入的目标是确定本次会话使用哪个设备和哪个角色,向探鸽平台申请短期连接凭证,并把凭证安全地下发给设备。

3.1 接口鉴权

服务端 API 签名与探鸽云端 OpenAPI 服务端签名一致,详见 服务端API接口签名算法Demo

3.2 申请连接凭证

只有申请 AI 实时对话引擎连接凭证时需要调用 https://api-tirtc.tange365.com 域名:

http
POST https://api-tirtc.tange365.com/v1/token/aichat
Content-Type: application/json
Authorization: TGV1-HMAC-SHA256 ...
X-Tg-App-Id: {AppId}

{
  "device_id": "DEMO_DEVICE_01",
  "role_id": "role_xxx"
}

响应示例:

json
{
  "code": 0,
  "msg": "ok",
  "data": {
    "peer_id": "whips://aichat?device_id=DEMO_DEVICE_01&role_id=role_xxx",
    "token": "v1.{payload}.{signature}"
  }
}

完整说明见 服务端接口

3.3 下发凭证给设备

业务服务端从平台申请到 peer_idtoken 响应后,应通过安全通道下发给设备。设备只需要消费这两个值,不需要知道服务端签名密钥,也不需要自行拼接 peer_id

下发载荷示例:

json
{
  "type": "aichat_join",
  "device_id": "DEMO_DEVICE_01",
  "role_id": "role_xxx",
  "peer_id": "whips://aichat?device_id=DEMO_DEVICE_01&role_id=role_xxx",
  "token": "v1.{payload}.{signature}"
}

安全建议:

  • 不要在日志中打印完整 token
  • peer_idtoken 应尽快使用,避免长时间缓存。
  • 同一设备已有进行中的会话时,服务端应按业务规则拒绝、排队或先结束旧会话。

4. 设备端集成

设备端接入的目标是使用业务服务端下发的 peer_idtoken 建立 TiRTC 连接,发送 start_session 启动会话,然后完成音频上下行、事件处理和会话结束。

4.1 建立 TiRTC 连接

设备收到 peer_idtoken 后,调用 TiRTC SDK 建立连接。

c
#include "tiRTC.h"
#include <stdbool.h>
#include <string.h>

static tirtc_conn_t g_ai_conn = NULL;
static bool g_tirtc_ready = false;

static int ai_tirtc_runtime_init(const char *device_id)
{
    if (g_tirtc_ready) {
        return 0;
    }

    int ret = TiRtcInit();
    if (ret != 0) {
        return ret;
    }

    TIRTCCALLBACKS cbs;
    memset(&cbs, 0, sizeof(cbs));
    ret = TiRtcStart(device_id, &cbs);
    if (ret != 0) {
        TiRtcUninit();
        return ret;
    }

    g_tirtc_ready = true;
    return 0;
}

static void on_ai_whip(int err, tirtc_conn_t hconn, void *user_data)
{
    (void)user_data;
    if (err != 0) {
        /* 建连失败:记录错误码,释放本地会话状态 */
        return;
    }

    g_ai_conn = hconn;
    /* 建连成功后,下一步发送 start_session 命令 */
}

int start_ai_tirtc_connect(const char *device_id, const char *peer_id, const char *token)
{
    int ret = 0;

    if (device_id == NULL || device_id[0] == '\0' ||
        peer_id == NULL || peer_id[0] == '\0' ||
        token == NULL || token[0] == '\0') {
        return -1;
    }

    ret = ai_tirtc_runtime_init(device_id);
    if (ret != 0) {
        return ret;
    }

    /* 返回 0 表示请求已提交,最终是否成功以 on_ai_whip 回调为准 */
    return TiRtcWhipConnect(peer_id, token, on_ai_whip, NULL);
}

void stop_ai_tirtc_connect(void)
{
    if (g_ai_conn != NULL) {
        TiRtcClose(g_ai_conn);
        g_ai_conn = NULL;
    }

    if (g_tirtc_ready) {
        TiRtcStop();
        TiRtcUninit();
        g_tirtc_ready = false;
    }
}

TiRtcWhipConnect 返回 0 只表示建连请求已提交;真正成功以回调中的 err == 0 为准。

4.2 发送 start_session

TiRTC 连接建立后,设备端需要通过命令通道发送 start_session。关于详细字段格式和默认值说明,请参考 事件协议

请求示例:

json
{
  "jsonrpc": "2.0",
  "id": "start-session-001",
  "method": "start_session",
  "params": {
    "device_id": "DEMO_DEVICE_01",
    "role_id": "role_xxx",
    "input_audio": {
      "codec": "opus",
      "sample_rate": 16000,
      "channels": 1
    },
    "output_audio": {
      "codec": "opus",
      "sample_rate": 16000,
      "channels": 1
    }
  }
}

收到成功响应后,设备应以响应中的 input_audiooutput_audio 作为本次会话实际音频格式,然后开始持续上行音频。若收到 JSON-RPC error,应停止采集并释放本地会话状态。

4.3 上行设备语音

设备端在采集线程中按固定周期发送音频帧,建议单帧时长控制在 100 ms 以内。

默认约定:

项目推荐值
音频 stream_id1,如探鸽平台或接入包另有约定,以实际约定为准。
采样率16000
声道1
编码opus,也支持 pcm / g711a
帧长100 ms 以内

发送代码示例:

c
#include <stdint.h>
#include <string.h>
#include "tiRTC.h"

static const uint8_t kAiAudioStreamId = 1;

int ai_send_audio_opus(tirtc_conn_t hconn,
                       const void *opus_data,
                       uint32_t len,
                       uint32_t ts_ms)
{
    TIRTCFRAMEINFO fi;
    memset(&fi, 0, sizeof(fi));
    fi.stream_id = kAiAudioStreamId;
    fi.media = TIRTC_AUDIO_OPUS;
    // 重要:必需设置与 input_audio 一致的音频格式 flags
    fi.flags = TIRTC_AUDIOSAMPLE_16K16B1C; 
    fi.ts = ts_ms;
    fi.length = len;
    return TiRtcSendAudioStream(hconn, &fi, opus_data);
}

音频参数映射关系: 必须确保以下三个配置完全对齐,否则将导致平台侧识别失败或解码异常:

  1. start_session.input_audio 中的意图声明。
  2. C 语言层设置的 fi.media
  3. C 语言层设置的采样规格 fi.flags

探鸽平台会做云端 VAD 和语音轮次判断。设备端可以不做本地 VAD;如果为节省带宽自行过滤静音,需要避免截断用户说话的开头和结尾。

需要让智能体理解设备摄像头画面时,在 start_session 成功后继续发送 stream_id = 0 的 H.264 或 H.265 视频帧。视频流第一帧必须是关键帧;完整约定和代码见设备端集成

4.4 播放下行语音

回复音频会通过 TiRTC 音频流下发。设备端应在音频回调中按 start_session 响应的 output_audio 解码并送入播放链路。

处理建议:

  • stream_id 过滤 AI 实时对话引擎音频流。
  • media 和协商的 codec 解码。
  • 播放链路应支持连续流式播放,不要等待整句 TTS 结束后再播放。
  • 如果收到打断或会话结束事件,应及时停止当前播放缓冲。

4.5 处理事件

AI 实时对话引擎的控制消息、字幕和设备能力调用都通过命令通道发送。详见 事件协议

设备端至少需要实现以下事件处理:

method方向说明
start_session设备 -> 平台建连后启动 AI 实时对话会话。
caption平台 -> 设备ASR / TTS 字幕事件。
round_start平台 -> 设备一轮回复音频开始。
round_end平台 -> 设备一轮回复音频结束。
interrupt设备 -> 平台主动打断当前回复。
submit_speech设备 -> 平台手动提交当前上行语音。
end_session双向结束当前会话。

4.6 结束会话

无论触发方是设备端、用户意图还是平台策略,设备端都应保证结束流程可重复调用且不会泄漏资源。建议在用户按键结束、平台通知结束、连接错误、网络断开、业务超时和设备关机时,都调用同一套本地清理逻辑:

  1. 停止采集。
  2. 停止播放。
  3. 释放本地会话上下文,清理音频采集和播放资源。
  4. 断开 TiRTC 连接。

4.7 最小跑通路径

为了快速排查环境与配置问题,建议开发者首先通过以下的端到端最小跑通路径验证:

  1. 服务端请求测试:使用配置好的 AppId/AK/SK,通过 curl 发送 TGV1-HMAC-SHA256 签名的请求到 /v1/token/aichat,确保能稳定返回 HTTP 200 状态码和有效的 peer_idtoken
  2. 设备端连接测试:将拿到的 device_idpeer_idtoken 贴入设备端测试代码的 start_ai_tirtc_connect 方法,观察 on_ai_whip 回调的 err 是否为 0
  3. 会话握手测试:在连接成功的回调中触发发送 start_session 消息。
  4. 验证成功判据:设备端命令回调应当能够收到探鸽平台返回的 JSON-RPC 成功响应(包含 session_id)。如果收到错误响应则需要核对参数拼写。
  5. 音频回路验证:传入一小段事先准备好的 PCM 测试音频(不断循环发送),并验证设备端是否能收到下行的 caption 事件和 TIRTC_AUDIO_OPUS 的回音数据。

AI 实时对话引擎文档