AI 基座通道

更新时间:2025-09-16 05:53:30下载pdf

前置准备

开发环境准备

在接入 AI 基座通道前,请先阅读 App SDK 接入文档并完成接入:智能生活 App SDK > 准备工作

完成接入后,在你的工程中引入 AI 基座通道:

// 6.7.0及之后的版本均可用
implementation 'com.thingclips.smart:thingsmart:6.7.6'
// 录音组件
implementation 'com.thingclips.smart:thingsmart-audio-engine-sdk:6.7.0+'
implementation 'com.thingclips.smart:thingsmart-avlogger-sdk:6.7.0+'

智能体准备

为了确保智能体在您的 App 中可用,需要完成以下流程:

  1. 创建智能体:详细操作流程,请参考文档 智能体开发平台

  2. 发布并投放智能体到指定 App:配置完成后,单击页面顶部的 上架
    请记录智能体的 Agent ID,用于后续 SDK 中 创建 session 使用。

    AI 基座通道

  3. 智能体投放 页面,单击 投放 App 将智能体投放到指定 App,确认后,单击 确认投放信息并上架。请记录 小程序 ID 用于后续 SDK 中 创建 session 使用。

    AI 基座通道

注意,小程序 ID 需要使用 v2.0 Beta 小程序,需要点击“更新版本”使用 v2.0 以上小程序,以便启用新版本的智能体。

通道流程

通道连接 (Connection) 管理

通道连接目前有两种连接类型,即:App、代理设备。

  • App 通道:以登录用户身份进行鉴权,一个 App 只有一个通道,可支持多端登录同时使用。
  • 代理设备:以设备身份进行鉴权连接,通常用于无法自主连云的设备(如:单点蓝牙),无法支持多端同时使用同一个设备。
AppSDK选择连接鉴权类型:App or 代理设备获取通道连接状态,判断通道是否连接调用通道连接方法alt[通道未连接]par[通道连接]设置监听对象通道出现异常断开通知业务通道状态变化:被断开自动触发重连逻辑通知业务通道状态变化:连接中通知业务通道状态变化:已连接根据通道状态处理 UI 和业务逻辑par[通道连接状态管理]AppSDK

会话 (Session) 管理

会话是建立在通道之上,一个通道内可以有多个会话 Session,数据流传输需要 Session。

当使用不同智能体、不同配置时,需要使用这些信息请求获取 Agent Token 并创建会话。

AppSDKServer创建会话有两种方式:常规方式、简化方式决定要使用的 AI Solution Code、家庭信息等获取 Agent Token 信息向服务端请求获取返回 Agent Token 结果回调 Agent Token 信息存储 Agent Token使用 Agent Token 创建 Session创建 Session 成功opt[方式1:常规方式]获取 Agent Token 并创建 Session 接口创建 Session 成功opt[方式2:简化方式]AppSDKServer

数据流传输

在数据流传输之前,请先确保已经创建了会话 Session。

下面为您介绍以下概念:

  • 事件(Event
  • 数据通道(DataChannel
  • 数据流通道复用(ReuseDataChannel)
  • 数据包标记(StreamFlag

事件(Event

Event 可以是 App 向服务端发送,也可以是服务端投递给 App。

发送时,主要包含以下事件:

事件 说明
EventStart 标记事件开始,在传递数据流之前,需要先发送该事件。需要传递一个 EventId,直到发送 EventEndChatBreak 之前,都需要使用相同的 EventId
EventPayloadEnd 标记 Event 内某一个数据传递完成,需要传递 DataChannel 数据
EventEnd 标记事件结束。在所有数据流传递完成后,发送该事件。服务端接受到该事件后会将所有数据投递给智能体进行处理
ChatBreak 打断事件。既可以在发送数据流时打断,也可以在接受数据流时打断

接收时,主要包含以下事件:

事件 说明
EventStart 标记事件开始,表示云端即将开始向 App 投递数据,其携带 EventId 与 App 发送时对应
EventPayloadEnd 标记 Event 内某一个数据传递完成
EventEnd 标记事件结束。在所有数据流投递完成后,投递该事件
ChatBreak 打断事件。表示云端打断 App,App 不再需在这个 EventId 上发送或接收数据(需配置开启)
ServerVAD 云端 VAD,即:云端识别到 App 发送的音频片段结束。接收到该事件后,App 无需再继续向该 EventId 投递音频数据(即使投递云端也不再处理);需要配置开启

通道支持多模态,可以在一次 Event 周期内投递多种类型数据流。具体的支持数据类型,详见智能体的配置。

数据通道(DataChannel

在创建会话阶段获取 AgentToken 时中除了返回 Token 以外,还会返回 bizConfig 信息,它包含了 sendDatarevData 两个属性,用于表明传递数据类型。

SDK 会根据 bizConfig.sendDatabizConfig.revData 生成数据通道 sendDataChannelsrecvDataChannels


使用场景示例:
  • 当同类型数据只有单路,发送数据流方法(如 sendAudioDatasendVideoData 等),可以不用关心。
  • 当同类型数据有多路时(比如:双路摄像会有两路视频流),需要注意顺序对应,且需要在发送数据流方法中传递 dataChannel 值,目前暂无该场景。
  • 无论数据类型几路,调用 sendEventPayloadsEnd 方法时,必须传递 dataChannel

数据流通道复用(ReuseDataChannel

在创建会话接口中有 reuseDataChannel 参数,通常情况下是传递 false,即:不启用复用。

用途主要针对实时流数据(比如:实时音频流、实时视频流)场景,当有两个或以上的会话需要对同一份实时数据做不同的处理的时候,就需要用到数据复用,对数据时效性以及传输开销友好。

使用场景示例: 有两个会话分别处理音频翻译和音频生成总结,需要实时采集音频,并将数据共享给这两个会话进行处理。

数据包标记(StreamFlag

数据包传递的标记,用于标记某种数据流的传输起止,有以下四种类型:

  • OnlyOne(0):仅一包,通常发文本、小尺寸图片时可以使用。
  • StreamStart(1):数据流开始,表示开始发送或开始接收。通常第一包数据需要携带数据的额外属性(如:音频流数据需要携带采样率、位深、格式等),此状态数据可以为空。
  • Streaming(2):数据传输中。
  • StreamEnd(3):数据传输结束,此状态数据可以为空。

AI Chat 一轮对话流程样例

AppSDKServer以 App 发送音频 + 图片 配置需要返回 ASR、NLG、TTS 为例已完成通道 Connection 建立, 已完成会话 Session 创建,获得 SessionId假定 DataChhanel 为 Send=["audio", "video", "text", "image"] Recv=["text", "audio", "image", "video"]发送 sendEventStart eventId 可选,不传则由 SDK 自动生成发 event start + eventId发送成功 回调 eventId = "event_***" 接下来所有跟 Event 相关操作都需要使用这个 eventId选择图片记录选择的图片对象开启麦克风采集发送音频首包 sendAudioData, streamFlag = StreamStart, 首包需要携带格式 codecType = PCM, bitDepth = 16, sampleRate = 16000...传递 Event Start 消息回调 Event Start 消息, eventId = "event_***"发送音频中间包 sendAudioData, streamFlag = StreamIng, payload audio data发送 audio 数据包 * n传递 Text 消息,内容为 ASR 通常需要2-3包音频之后回调 Text 消息loop[持续录音并发送(可以与图片同时发送)]发送图片 sendImageData, streamFlag = onlyOne发送 Image 数据包收到包发送 Image data 完成发送 sendEventPayloadsEnd, dataChannel = "image", eventId = "event_***"发 Event payload end 包收到包发送 Event payload end 完成par[发送图片(可以与音频同时发送)]停止麦克风采集发送音频尾包 sendAudioData, streamFlag = StreamEnd发送 Audio 结束包发送 sendEventPayloadsEnd, dataChannel = "audio", eventId = "event_***"发 Event payload end 包所有数据都发完发送 sendEventEnd发 Event end 包处理 Audio + Image 数据传递 Text 消息,内容为 NLG回调 Text 消息传递 Audio 消息,streamFlag == Start, 首包有携带格式 codecType = PCM, bitDepth = 16, sampleRate = 16000...回调 Audio 消息,内容是 TTS 音频传递 Text 消息,内容为 NLG回调 Text 消息传递 Audio 消息,streamFlag == Streaming回调 Audio 消息,内容是 TTS 音频loop[持续传递数据]传递 event payload end, dataChannel = "text", eventId = "event_***"回调 Event payload end 消息传递 Event payload end, dataCeannel = "audio", eventId = "event_***"回调 Event payload end 消息本轮聊天结束 Event end回调 Event end 消息AppSDKServer

接口说明

创建 AI Stream 对象

var aiStream: IThingAiStream = ThingAiStream.newInstance()

监听事件

设置监听 / 移除监听

/**
 * Set stream listener
 *
 * @param listener stream listener
 */
fun setStreamListener(listener: ThingAiStreamListener)

/**
 * Remove stream listener
 */
fun unsetStreamListener()

使用样例:

在连接之前、接收数据之前,需要先设置监听才能收到相关消息

// 连接、创建session之前请先设置监听
aiStream.setStreamListener(streamListener)

连接 & 会话状态变化消息

interface ThingAiStreamListener {
  /**
   * Monitors channel connection state changes
   *
   * @param connectionId The connection identifier
   * @param state The current connection state
   * @param errorCode Error code, if any
   */
  fun onConnectStateChanged(connectionId: String, state: Int, errorCode: Int)

  /**
   * Monitors session state changes
   *
   * @param sessionId The session identifier
   * @param state The current session state
   * @param errorCode Error code, if any
   */
  fun onSessionStateChanged(sessionId: String, state: Int, errorCode: Int)
}

接收事件Event、接收数据流消息

/**
 * Interface for AI Stream event callbacks.
 * Used to monitor and handle various stream data types and connection states.
 */
interface ThingAiStreamListener {

    /**
     * Monitors event data reception
     *
     * @param event The received event data
     */
    fun onEventReceived(event: StreamEvent)

    /**
     * Monitors audio data reception
     * (When flag == start, the audio will be played automatically by the plugin)
     *
     * @param data The received audio data
     */
    fun onAudioReceived(data: StreamAudio)

    /**
     * Monitors video data reception
     * (When flag == start, video playback will begin until completion)
     *
     * @param data The received video data
     */
    fun onVideoReceived(data: StreamVideo)

    /**
     * Monitors image data reception
     *
     * @param data The received image data
     */
    fun onImageReceived(data: StreamImage)

    /**
     * Monitors text data reception
     *
     * @param data The received text data
     */
    fun onTextReceived(data: StreamText)

    /**
     * Monitors file data reception
     * (Currently not supported by the cloud)
     *
     * @param data The received file data
     */
    fun onFileReceived(data: StreamFile)
}

连接 (Connection) 管理

调用流程如下:

AppSDKisConnected()result (Boolean)Not connected, need to connectconnectWithApp(callback)Notify via callbackopt[if connecting as App (simple)]connectWithDevice(deviceId, callback)Notify via callbackopt[if connecting as Device (simple)]Get special connectInfo from Business Logice.g., retrieve complex JSON configconnect(clientType, deviceId, connectInfo, callback)Notify via callbackopt[if has special connection info]alt[Identity Type or Special Info]alt[if connected() == false]AppSDK

相关接口

/**
 * Check if connected to stream service
 *
 * @param clientType client type: 1-as device agent, 2-as App
 * @return true if connected, false otherwise
 * @see com.thingclips.smart.android.aistream.Constants.ClientType
 */
fun isConnected(
    @ClientType clientType: Int,
    deviceId: String? = null
): Boolean

/**
 * Connect to stream service as App
 *
 * @param callback result callback
 */
fun connectWithApp(callback: ConnectCallback?)

/**
 * Connect to stream service as Device
 *
 * @param deviceId device ID
 * @param callback result callback
 */
fun connectWithDevice(deviceId: String, callback: ConnectCallback?)

/**
 * Connect to stream service
 *
 * @param clientType client type: 1-as device agent, 2-as App
 * @param deviceId device ID, required if acting as device agent, otherwise can be empty string
 * @param connectInfo connection info in JSON format
 * @param callback result callback
 */
fun connect(
    clientType: Int,
    deviceId: String?,
    connectInfo: String?,
    callback: ConnectCallback?
)

/**
 * Disconnect from stream service
 *
 * @return operation result code
 */
fun disconnect(): Int

会话(Session)管理

一个 连接(Connection) 下最大可同时保持的 Session 数量为 20,请合理创建/关闭会话。

创建会话

创建会话有两种方式:

  • 方式1 常规用法:先获取 Agent Token Info,再用其创建 Session 会话

由于获取 Agent Token Info 是有一定耗时的,通过该方法可以前置获取,通常情况下有效期是 24 小时。

/**
 * Request agent token
 *
 * @param requestParams  request parameters, you can see [AgentTokenRequestParams] for details, use [AgentTokenRequestParams.Builder] to build
 * @param listener       result listener
 * @see AgentTokenRequestParams
 */
fun requestAgentToken(
    requestParams: AgentTokenRequestParams, listener: ResultListener<ThingAgentTokenInfo>
)

/**
 * Create session with agent token info
 *
 * @param bizTag business tag, 0 for default
 * @param agentToken Agent token, @see [ThingAgentTokenInfo.agentToken]
 * @param bizConfig business config, @see [ThingAgentTokenInfo.BizConfig]
 * @param userDataAttributes user data attributes list
 * @param callback result callback
 * @see requestAgentToken
 */
fun createSession(
    bizTag: Long = 0,
    agentToken: ThingAgentTokenInfo,
    userDataAttributes: List<UserDataAttribute>?,
    reuseDataChannel: Boolean = false,
    callback: SessionCallback?
)
  • 方式2 简化用法:获取 Agent Token Info 并自动创建 Session 会话
/**
 * Create session with request agent token, it's combine requestAgentToken and createSession
 *
 * @param ownerId owner ID
 * @param aiSolutionCode AI solution code
 * @param userDataAttributes user data attributes list
 * @param callback result callback
 */
fun createSession(
    requestParams: AgentTokenRequestParams,
    userDataAttributes: List<UserDataAttribute>?,
    callback: SessionCallback?
)

主动关闭会话
注意:一个 Connection 下最大可同时保持的 Session 数量为 20,请在合适的时候关闭掉不必要的会话

/**
 * Close session
 *
 * @param sessionId session ID
 * @param callback result callback
 */
fun closeSession(sessionId: String, callback: StreamResultCallback?)

Session 创建示例

session 创建需要传 API 和 相关参数,以下是调用示例和参数说明:

String api = "m.life.ai.token.get"; // api name
String apiVersion = "1.0"; // api version
String ownerId = "your_home_id"; // home id
String aiSolutionCode = "your_agent_id"; // agent id

AgentTokenRequestParams params = new AgentTokenRequestParams.Builder()
        .api(api)
        .apiVersion(apiVersion)
        .ownerId(ownerId) // home id
        .aiSolutionCode(aiSolutionCode) // agent id
        .addExtParam("miniProgramId", "your_mini_app_id") // mini app id
        .addExtParam("needTts", "false") // enable tts, default is false
        .addExtParam("onlyAsr", "false") // only ASR or not, default is false
        .build();

aiStream.createSession(params, null, new SessionCallback() {
    @Override
    public void onSuccess(@NonNull String sessionId, @NonNull Map<String, Integer> sendDataCodes, @NonNull Map<String, Integer> revDataCodes) {
        Log.i(TAG, "createSession onSuccess: " + sessionId);
    }

    @Override
    public void onError(int code, String message) {
        Log.e(TAG, "createSession onError: " + code + ", message: " + message);
        runOnUiThread(() -> Toast.makeText(AiChatActivity.this, "Session creation failed: " + message, Toast.LENGTH_SHORT).show());
    }
});

发送事件 Event 接口

可发送的 Event 分为:

  • EventStart:一轮对话开始的标志,可以指定 EventId、也可以由 SDK 自动生成 EventId
  • EventPayloadEnd:告知云端这次对话中某一个数据流传输完成
  • EventEnd:一轮对话结束,发送后 AI 会处理所有传输的数据,并进行回复。
  • ChatBreak:打断某个对话。可以在发送时,也可以在接收时打断

/**
 * Send event start signal with VAD and interrupt options
 *
 * @param options event start options
 * @param callback result callback
 * @see EventStartOptions
 */
fun sendEventStart(
    options: EventStartOptions,
    callback: EventStartCallback
)

/**
 * Send event payloads end signal
 *
 * @param eventId event ID
 * @param sessionId session ID
 * @param dataChannel data channel
 * @param userDataAttributes user data attributes list
 * @param callback result callback
 */
fun sendEventPayloadsEnd(
    eventId: String, sessionId: String, dataChannel: String,
    userDataAttributes: List<UserDataAttribute>?,
    callback: StreamResultCallback?
)

/**
 * Send event end signal
 *
 * @param eventId event ID
 * @param sessionId session ID
 * @param userDataAttributes user data attributes list
 * @param callback result callback
 */
fun sendEventEnd(
    eventId: String, sessionId: String, userDataAttributes: List<UserDataAttribute>?,
    callback: StreamResultCallback?
)

fun sendEventChatBreak(
    eventId: String, sessionId: String, userDataAttributes: List<UserDataAttribute>?,
    callback: StreamResultCallback?
)

发送数据流接口

/**
 * Send audio data
 *
 * @param data audio data
 * @param callback result callback
 */
fun sendAudioData(sessionId: String, data: StreamAudio, callback: StreamResultCallback?)

/**
 * Send video data
 *
 * @param data video data
 * @param callback result callback
 */
fun sendVideoData(sessionId: String, data: StreamVideo, callback: StreamResultCallback?)

/**
 * Send text data
 *
 * @param data text data
 * @param dataChannel customized data channel (optional), using default "text" if not specified
 * @param callback result callback
 */
fun sendTextData(sessionId: String, data: StreamText, callback: StreamResultCallback?)

/**
 * Send image data
 *
 * @param data image data
 * @param callback result callback
 */
fun sendImageData(sessionId: String, data: StreamImage, callback: StreamResultCallback?)

/**
 * Send file data
 *
 * @param data file data
 * @param dataChannel customized data channel (optional), using default "file" if not specified
 * @param callback result callback
 */
fun sendFileData(sessionId: String, data: StreamFile, callback: StreamResultCallback?)

音频实时录制与播放

其中音频数据 Android 支持的是实时录制的音频流,可以使用我们封装的音频流录制+发送方法:

/**
 * Initializes the audio recorder.
 *
 * This method is optional and not required before starting recording. It should be called only when
 * you want to prepare the recorder in advance before actual recording starts.
 * Initializing the audio recorder is a relatively time-consuming operation (about 300ms).
 * Calling this method in advance can eliminate the delay when starting to record.
 * You can call this method while showing a loading state, so that when the user actually starts
 * recording, it can respond immediately.
 * If not called in advance, the startRecordAndSendAudioData method will automatically complete
 * the initialization internally, but this will cause a noticeable delay before recording actually begins.
 *
 * @param callback Operation result callback, reporting initialization success or failure
 */
fun initAudioRecorder(callback: StreamResultCallback?)

/**
 * Starts recording audio and sending data, without triggering events.
 *
 * This method will start recording and transmitting audio data. If initAudioRecorder has not been
 * called for initialization previously, this method will first complete the initialization of the
 * recorder (about 300ms) before starting to record.
 * For better user experience, it is recommended to call initAudioRecorder to complete
 * initialization before displaying the recording button in the UI.
 *
 * @param sessionId Session ID, used to identify the session to which the current audio transmission belongs
 * @param dataChannel Custom data channel (optional), if not specified, the default "audio" channel will be used
 * @param userDataAttributes List of user data attributes, which may contain metadata related to the audio
 * @param callback Operation result callback, reporting whether recording started successfully or failed
 */
fun startRecordAndSendAudioData(
    sessionId: String,
    dataChannel: String? = null,
    userDataAttributes: List<UserDataAttribute>?,
    callback: StreamResultCallback?
)

/**
 * Stop recording audio and sending data, without ending event
 *
 * @param dataChannel customized data channel (optional), using default "audio" if not specified
 * @param userData user data attributes list
 * @param callback result callback
 */
fun stopRecordAndSendAudioData(
    sessionId: String,
    dataChannel: String? = null,
    userData: List<UserDataAttribute>?,
    callback: StreamResultCallback?
)

数据发送示例

一次完整的文本发送示例:

/**
 * 发送文本消息到AI服务
 * @param textMessage 要发送的文本内容
 */
fun sendTextMessage(textMessage: String) {
    // Check if session is valid
    if (TextUtils.isEmpty(currentSessionId) || !aiStream.isConnected(Constants.ClientType.APP, null)) {
        Log.e(TAG, "Cannot send message: session not initialized or connection lost")
        return
    }
    
    // Step 1: Start the event
    val eventStartOptions = EventStartOptions.Builder(currentSessionId).build()
    aiStream.sendEventStart(eventStartOptions, object : EventStartCallback {
        override fun onSuccess(eventId: String) {
            Log.i(TAG, "Event started successfully: $eventId")
            
            // Step 2: Send text data
            val streamText = StreamText().apply {
                text = textMessage
            }
            
            aiStream.sendTextData(currentSessionId, streamText, object : StreamResultCallback {
                override fun onSuccess() {
                    Log.i(TAG, "Text data sent successfully")
                    
                    // Step 3: End text payload
                    aiStream.sendEventPayloadsEnd(eventId, currentSessionId,
                            ThingAiStream.DATA_CHANNEL_TEXT, null, object : StreamResultCallback {
                        override fun onSuccess() {
                            Log.i(TAG, "Text payload ended successfully")
                            
                            // Step 4: End the event
                            aiStream.sendEventEnd(eventId, currentSessionId, null, object : StreamResultCallback {
                                override fun onSuccess() {
                                    Log.i(TAG, "Event ended successfully: $eventId")
                                }
                                
                                override fun onError(errorCode: Int, errorMessage: String) {
                                    Log.e(TAG, "Failed to end event: $errorMessage, code: $errorCode")
                                }
                            })
                        }
                        
                        override fun onError(errorCode: Int, errorMessage: String) {
                            Log.e(TAG, "Failed to end text payload: $errorMessage, code: $errorCode")
                            
                            // Still try to end the event even if payload end fails
                            aiStream.sendEventEnd(eventId, currentSessionId, null, object : StreamResultCallback {
                                override fun onSuccess() {
                                    Log.i(TAG, "Event ended successfully after payload error: $eventId")
                                }
                                
                                override fun onError(code: Int, message: String) {
                                    Log.e(TAG, "Failed to end event after payload error: $message, code: $code")
                                }
                            })
                        }
                    })
                }
                
                override fun onError(errorCode: Int, errorMessage: String) {
                    Log.e(TAG, "Failed to send text data: $errorMessage, code: $errorCode")
                    
                    // End the event if text data sending fails
                    aiStream.sendEventEnd(eventId, currentSessionId, null, object : StreamResultCallback {
                        override fun onSuccess() {
                            Log.i(TAG, "Event ended successfully after text send error: $eventId")
                        }
                        
                        override fun onError(code: Int, message: String) {
                            Log.e(TAG, "Failed to end event after text send error: $message, code: $code")
                        }
                    })
                }
            })
        }
        
        override fun onError(errorCode: Int, errorMessage: String) {
            Log.e(TAG, "Failed to start event: $errorMessage, code: $errorCode")
        }
    })
}

如果有多种数据发送,类似如下流程:

AppSDKCloudsendEventStart()发送事件开始 (sendEventStart)事件开始成功 (eventId: xxx)startRecordAndSendAudioData()开始发送音频数据请求 (startRecordAndSendAudioData, eventId: xxx, dataChannel: audio)开始发送音频数据成功返回ASR数据onTextReceived(dataChannel: text)stopRecordAndSendAudioData()sendEventPayloadEnd()发送数据流结束请求 (sendEventPayloadEnd, eventId: xxx)发送数据流结束响应数据流结束成功sendImageData()发送图片数据请求 (sendImageData, eventId: xxx, dataChannel: image)发送图片数据响应发送图片数据成功sendEventPayloadEnd()发送数据流结束请求 (sendEventPayloadEnd, eventId: xxx)发送数据流结束响应数据流结束成功sendTextData()发送文本数据请求 (sendTextData, eventId: xxx, dataChannel: text)发送文本数据响应发送文本数据成功sendEventPayloadEnd()发送数据流结束请求 (sendEventPayloadEnd, eventId: xxx)发送数据流结束响应数据流结束成功sendEventEnd()发送事件结束请求 (sendEventEnd, eventId: xxx)onAudioReceived(dataChannel: audio)接收到音频数据 (dataChannel: audio)onTextReceived(dataChannel: text)接收到文本数据 (dataChannel: text)onImageReceived(dataChannel: image)接收到图片数据 (dataChannel: image)发送事件结束响应事件结束成功onReceiveEvent(type 2)AppSDKCloud

Demo

您可以访问如下地址获取 Demo:

homesdk_sample

使用说明

  1. 请先阅读本文并完成 前置准备
  2. 使用Android Studio 打开工程后,将生成一个 local.properties文件,在local.properties文件中添加配置
    appKey=your_app_key
    appSecret=your_app_secret
    aiSolutionCode=your_agent_id
    miniProgramId=your_mini_program_id
    
  3. 运行 Demo,登录后,前往 AI Assistant 页面使用

错误码定义

code msg 含义 备注
39001 / 通用错误 用于一些杂项错误
39002
  • deviceId is invalid
  • clientType is invalid
  • api is invalid
  • apiVersion is invalid
  • ownerId is invalid
  • solutionCode is invalid
  • agentToken is invalid
  • bizConfig is invalid
  • sendData/revData is invalid
  • text is blank
参数不合法
  • Agent token 请求参数不合法:solutionCodeownerId 为空
  • Create session 时,请求参数不合法:agentTokenbizConfig 为空
39003 云端错误文案 http 请求失败 Agent token 获取失败:请求 agent token 云端接口返回失败
39004 not connect Connection 未连接 创建/关闭 Session、发送 Data、Event 时
39005 session is invalid SessionId 不存在 关闭 Session、发送 Data、Event 时
39006 eventId is invalid EventId 为空 发送 Event 时
39007 dataChannel is invalid DataChannel 不合法 发送 Data、PayloadEnd
39008 packet is invalid 数据包不合法 发 Data 时,比如:首包/仅一包数据时需要固定的参数,文本内容为空
39009
  • file info get fail
  • file not exist
  • failed to read file data
文件数据读取异常 发送 Data 时,如:图片、文件文件不存在,或读取过程中出现异常
TTT:播放音频所需文件不存在(startPlayAudio
39010
  • send data fail
  • send audio end fail
  • send image fail
  • send text fail
发送数据失败 Socket 发送数据失败,内含 Socket 错误信息
39012
  • socket connection broken
  • close by remote(200/400/401…)
Connection 被远端关闭 详细错误对应云端错误码:200、400、401、404、408、500、504、601、602、603、604、605
对 TTT 来说没有 39012,是通过 onConnectStateChanged 报的详细错误码 200、400…

接收 TEXT 数据格式

本文档详细说明了 AI 聊天组件中处理的各种 JSON 格式及其处理逻辑。

ASR 音频识别文本格式

当用户发送语音输入后,系统会返回 ASR(语音识别)结果,格式如下:

{
    "bizId": "asr-1754380053514",
    "bizType": "ASR",
    "eof": 0,
    "data": {
        "text": "what's the weather today?"
    }
}
字段 字段含义 字段类型 示例值
bizId 业务 ID,用于标识一次交互 string asr-1754380053514
bizType 业务类型,ASR 表示语音识别结果 string ASR
eof 结束标志,0 表示未结束,1 表示已结束 int 0 或 1
data 返回的 ASR 结果对象 object
text 识别出的文本内容 string what’s the weather today?

处理逻辑

  • eof = 0 时,保存临时结果,显示中间识别结果。
  • eof = 1 时,显示最终识别结果并添加到聊天列表中。

NLG 大模型返回格式

AI 模型响应用户查询后,返回的数据格式:

{
    "bizId": "nlg-1754380053514",
    "bizType": "NLG",
    "eof": 0,
    "data": {
        "appendMode": "append",
        "reasoningContent": "思考过程内容",
        "content": "模型回复的文本内容",
        "images": [
            {
                "url": "https://www.tuya.com/image1.jpg"
            }
        ]
    }
}
字段 字段含义 字段类型 示例值
bizId 业务 ID,用于关联同一次交互的消息 string nlg-1754380053514
bizType 业务类型,NLG 表示自然语言生成 string NLG
eof 结束标志,0 表示流式输出中,1 表示结束 int 0 或 1
data 返回的数据对象 object
appendMode 文本追加模式 string append(追加)或其他
reasoningContent 大模型思考过程(思维链) string 思考过程内容
content 大模型生成的实际响应内容 string 模型回复的文本内容
images 大模型返回的图片数据数组 array
url 图片的网址 string https://www.tuya.com/image1.jpg

处理逻辑

  • appendModeappend 时,将新内容追加到已有消息,否则创建新消息。
  • 处理 Images 数组中的图片 URL,展示为图片消息。
  • eof = 1 时,标记该 NLG 流结束。

SKILL 技能返回格式

AI 可调用各种技能,如表情展示等功能。

这里仅举例说明表情类型的技能,其他技能根据智能体的定义 data 有所不同。

表情技能(llm_emo)

{
    "bizId": "skill-1754380053514",
    "bizType": "SKILL",
    "eof": 0,
    "data": {
        "code": "llm_emo",
        "skillContent": {
            "text": "😀",
            "startTime": 1000,
            "endTime": 2000,
            "sequence": 1
        }
    }
}
字段 字段含义 字段类型 示例值
bizId 业务 ID string skill-1754380053514
bizType 业务类型,SKILL 表示技能调用 string SKILL
eof 结束标志 int 0 或 1
data 返回数据 object
code 技能代码 string llm_emo
skillContent 技能内容 object
text 表情符号 string 😀
startTime 表情显示开始时间(毫秒) long 1000
endTime 表情显示结束时间(毫秒) long 2000
sequence 序列号,1 表示序列开始 int 1

处理逻辑

  • sequence = 1 时,清空现有表情步骤列表。
  • 将新的表情步骤添加到列表。
  • eof = 1 时,开始按时间顺序展示表情。

支持的表情枚举

系统支持以下表情类型:

情绪类型 Unicode 表情 显示效果
SAD \uD83D\uDE22 😢
ANGRY \uD83D\uDE20 😠
NEUTRAL \uD83D\uDE10 😐
FEARFUL \uD83D\uDE28 😨
SURPRISE \uD83D\uDE32 😲
CONFUSED \uD83D\uDE15 😕
DISAPPOINTED \uD83D\uDE1E 😞
ANNOYED \uD83D\uDE21 😡
THINKING \uD83E\uDD14 🤔
HAPPY \uD83D\uDE00 😀