# 通过语音控制设备
本文介绍如何通过输出节点、端插件或云侧插件实现语音控制设备,例如调节音量、拍照识别等。
## 实现方案对比
| **方案** | **通过输出节点传递语音指令** | **端插件** | **云侧插件** |
| --- | --- | --- | --- |
| 适用场景 | 适用于仅需下发指令而无需设备返回数据的单向控制场景,如调节音量、控制设备移动、转人工等。 | 需要从设备端获取数据(如摄像头图像、传感器数据),并根据数据执行后续处理的场景,如拍照识别、获取手机日历等。 | 需要跨设备控制的场景。 |
## 方案一:通过输出节点传递语音指令
通过对话流中的输出节点,可将意图识别后的语音指令传递至设备。适用于简单的、单向的设备控制,例如调节音量或转人工等。具体实现流程如下:
在对话流中分别配置意图识别和输出节点,当意图识别到需要调节音量等设备控制时,扣子编程向设备发送`conversation.message.completed` 事件,例如 `type= "answer", content_type="text", content = {"action": "volume_up"} `,设备根据 `content` 字段获取控制指令并执行相应的设备操作。事件详情请参见[消息完成](https://docs.coze.cn/api/open/docs/developer_guides/streaming_chat_downlink_event#c817e22b)事件。
### 时序图

### 1 搭建对话流
以智能家居场景下,实现语音调节音量与语音闲聊功能为例。对话流的编排详情如下图所示。

各节点的详细配置如下。
| **节点** | **说明** | **示例** |
| --- | --- | --- |
| 开始节点 | **开始节点**的输入参数保持默认值即可。 |  |
| 意图识别(大模型节点) | 通过开始节点中的用户输入进行意图识别。
* **模型**:选择 **doubao 1.5-lite-32k** 或**豆包·角色扮演·Pro** 等支持复杂多轮对话的模型。
* **输入**:引用开始节点的 `USER_INPUT`。建议开启会话历史,确保模型结合上下文判断意图。
* **系统提示词**:根据实际场景调整系统提示词中的意图,本文的系统提示词样例请参见[提示词样例](https://docs.coze.cn/api/open/docs/tutorial/control_device_via_voice#70719ea2)。
* 为了降低大模型的响应时间,建议参考本文通过大模型节点实现意图识别,而不是使用对话流自带的意图识别节点,因为自带的意图识别节点采用直接输出内容的方式,会导致输出的 Token 数量过多,从而增加响应时间。
* 意图识别的输出结果用序号(例如1、2、3)来标识意图,避免让大模型直接返回完整回答,否则,会导致输出的 Token 数量过多,从而显著增加响应时间。具体原理请参见[优化大模型响应时间](https://docs.coze.cn/api/open/docs/tutorial/llm_response_time)。
|  |
| 选择器 | 智能体根据意图识别返回的值,判断进入设备控制节点或闲聊节点。
|  |
| 输出节点-设备控制(输出节点) | 用于下发设备控制指令。
* **输出内容**:根据实际场景调整输出内容中的设备控制指令。例如:`{"action": "volume_up"}`。
* **通话中转语音**:配置音视频通话时是否朗读输出节点的消息内容。若不希望设备控制指令通过TTS 朗读,可关闭此功能。
* **会话历史写入**:设置为不写入。 |  |
| 闲聊(大模型节点) | 实现语音闲聊功能。
* **输入参数**:`input` 参数的值引用开始节点的 `USER_INPUT`。
* **系统提示词**:根据实际情况调整闲聊的回复逻辑和风格。本文的系统提示词请参见[提示词样例](https://docs.coze.cn/api/open/docs/tutorial/control_device_via_voice#70719ea2)。
* **用户提示词**:引用输入参数中的 `input` 参数。 |  |
| 输出节点 | 用于输出闲聊节点的结果,输出变量的值引用闲聊节点的输出参数。 |  |
| 结束节点 | 因为已通过前面的输出节点输出工作流的结果,所以结束节点无需返回变量或文本。 |  |
### 2 测试并发布智能体
1. 试运行并发布对话流。
2. 创建**单 Agent(对话流模式)**的智能体,在智能体中添加对话流,开启语音通话并设置音色。
3. 在智能体右侧的调试页面单击通话图标,语音输入**调大音量**,智能体将返回设备控制指令 `{"action": "volume_up"}`。

4. 将智能体发布到 API 渠道或其他目标渠道。
## 方案二:端插件
本文以 AI 眼镜为例,介绍用户通过语音输入指令后,智能体如何调用端侧插件实现拍照与物体识别。
### 时序图

### 搭建智能体
#### 1 复制智能体模板
1. 打开[AI 眼镜小助手](https://docs.coze.cn/api/open/docs/coze.cn/template/agent/7527496694058139686)智能体,然后单击**复制**。

2. 选择智能体的所属空间并输入一个智能体名称,然后单击**确定**。
3. (可选)在复制的智能体编排页面,单击智能体名称旁的修改图标,修改智能体名称。
4. 根据实际需求,修改开场白文案和预置问题。
#### 2 调整对话流
对话流的编排详情如下图所示。

根据实际场景,在对话流中调整相应的节点和子工作流。本文重点介绍设备拍照分支的实现逻辑,其他子工作流的实现逻辑请参见[搭建低延时语音助手](https://docs.coze.cn/api/open/docs/tutorial/low_latency_voice_assistant)。各节点配置要求如下:
| **节点** | **说明** | **示例** |
| --- | --- | --- |
| 意图识别(大模型节点) | 通过开始节点中的用户输入进行意图识别,判断是否需要调用端插件。每种意图分别对应一个子工作流。
* **模型**:选择 **doubao 1.5-lite-32k** 或**豆包·角色扮演·Pro** 等支持复杂多轮对话的模型。
* **输入**:需要开启会话历史,确保模型结合上下文判断意图。
* **系统提示词**:根据实际场景调整系统提示词中的意图。
* 为了降低大模型的响应时间,建议参考本文通过大模型节点实现意图识别,而不是使用对话流自带的意图识别节点,因为自带的意图识别节点采用直接输出内容的方式,会导致输出的 Token 数量过多,从而显著增加响应时间。
* 意图识别的输出结果用序号(例如1、2、3)来标识意图,避免让大模型直接返回完整回答,否则,会导致输出的 Token 数量过多,从而显著增加响应时间。具体原理请参见[优化大模型响应时间](https://docs.coze.cn/api/open/docs/tutorial/llm_response_time)。
|  |
| 获取当前时间(代码节点) | 通过代码获取实时日期和时间,添加输出参数`current_time` 和 `current_date`,作为后续大模型的输入参数,用于生成当前时间相关的回答。 | ```Python
from datetime import datetime
async def main(args: Args) -> Output:
current_time = datetime.now()
formatted_date = current_time.strftime("%Y-%m-%d")
formatted_time = current_time.strftime("%H:%M")
ret: Output = {
"current_date": formatted_date,
"current_time": formatted_time
}
return ret
```
 |
| 选择器 | 智能体根据意图识别返回的值,进入对应的子工作流,例如设备拍照分支。 |  |
| photograph(端插件) | 通过[设备控制端插件](https://www.coze.cn/store/plugin/7527323690468393014)实现设备拍照,并将图片上传到服务端。 |  |
| 视觉理解(大模型节点) | 接收端插件上传的图片信息,并结合用户原始问题进行多模态理解。
* 输入参数:
* `input` :参数的值引用开始节点的`USER_INPUT`。
* `image` :参数的值引用 photograph 端插件输出的 image。
* `current_date` 和 `current_time` :参数的值引用**获取当前时间**节点的输出。
* 系统提示词:根据实际场景,修改系统提示词中的技能。
* 用户提示词:引用输入参数中的 `input` 和`image`参数。 |  |
| 输出 | 将视觉理解节点的分析结果返回给用户。建议开启流式输出,以提升用户体验。 |  |
### 发布并验证效果
1. 试运行并发布对话流。
2. 将智能体发布到 API 渠道。
3. 验证效果。
1. 访问 [Realtime 智能音视频 Demo](https://www.coze.cn/open-platform/realtime/playground),单击 **Settings**,设置 Token 和对应的智能体。单击 **Connect**。

2. 语音输入指令,例如`这是什么东西`,验证智能体是否能正确触发端插件。例如 Demo 弹出 Function Call 事件对话框表示已触发端插件。
3. 通过[上传文件](https://docs.coze.cn/api/open/docs/developer_guides/upload_files)API 获取图片 ID,并将图片 ID 填入提交端插件执行结果的 `output` 中。

### 端插件实现流程
设备端需要实现完整的事件监听、执行和上报闭环,具体步骤如下:
#### 1. 接收`required_action`事件
当对话流触发端插件时,设备会收到 `conversation.chat.requires_action` 事件,其中包含需要调用的函数信息,如 `photograph`。
下行事件示例:
```JSON
{
"id": "event_15",
"event_type": "conversation.chat.requires_action",
"data": {
"id": "7527500166237***",
"conversation_id": "7527503562080***",
"required_action": {
"type": "submit_tool_outputs",
"submit_tool_outputs": {
"tool_calls": [
{
"id": "5871369658880***",
"type": "function",
"function": {
"name": "photograph",
"arguments": ""
}
}
]
}
}
}
}
```
#### 2. 执行设备能力并上传文件
设备根据 `function.name` 调用本地能力,例如摄像头拍照。调用[上传文件](https://docs.coze.cn/api/open/docs/developer_guides/upload_files) API,将拍照的图片上传至服务端,并获取图片 ID。
上传文件 API 示例:
```Bash
curl -X POST 'https://api.coze.cn/v1/files/upload' \
-H "Authorization: Bearer cztei_qTST5l1tkfumssw***" \
-H "Content-Type: multipart/form-data" \
--form 'file=@"ai_glasses_capture.jpeg"'
```
#### 3. 提交端插件执行结果
设备将获取到的 `file_id` 通过 `conversation.chat.submit_tool_outputs` 事件提交给扣子编程,以驱动对话流继续执行。
`chat_id`、`tool_call_id` 需要与 `conversation.chat.requires_action` 事件中的 ID 保持一致。
上行事件示例:
```JSON
{
"id": "1",
"event_type": "conversation.chat.submit_tool_outputs",
"data": {
"chat_id": "7527500166237***",
"tool_outputs": [
{
"tool_call_id": "5871369658880***",
"output": "{\"image\":\"$file_id\"}"
}
]
}
}
```
## 方案三:云侧插件
需将设备控制相关服务封装为自定义云侧插件,具体实现方法请参见[基于 API 创建插件](https://docs.coze.cn/api/open/docs/guides/services)。
在对话流中添加该云侧插件。当意图识别结果为设备控制时,智能体调用该云侧插件。插件对应的服务端接收请求后,根据请求中的通话 ID 信息,执行相应设备操作。
云侧插件的对话流编排详情如下图所示,各节点的配置和其他方案类似。

时序图

## 提示词样例