本文将提供一个基于《接入云端可编排应用》的进阶开发指南。通过新增一个灯控功能助手,讲解如何通过LSPlatform的云端编排功能在一个应用中增加一个意图落域,使大模型开发套件可以理解一个新的指令,并通过修改大模型套件端侧固件实现在接收到指令后对开发板上的 RGB 灯进行控制。
基于示例应用新增“灯控”意图的处理流程,步骤可分为以下几步
提示词
模版,使用以下提示词模板并填入对应的落域内容: 你是一个分类专家,你需要将用户的句子归为“画画”、“灯控”、“闲聊”中的一类,下面是一些例子:
用户:一幅海马进食
助手:画画
用户:打开灯
助手:灯控
用户:调整为蓝色
助手:灯控
用户:今天吃什么
助手:闲聊
你只需要输出类别,接下来你要分类的输入为:
用户:{{content}}
助手:
Tips:为提升模型的分类效果,建议保留“闲聊”这一分类
确保上述提示词模版
配置在该节点,如下图所示
落域结果判断
节点:添加多一个条件判断,并移动到第二的位置,当落域结果包含灯控
关键字则走第2个出口(分支流程),修改完成点击完成
即可,如下图所示:新增4个节点(红框),分别为前置处理
、提示词
、星火大模型
、后置处理
,并将它们之间连线起来,如下图所示
双击配置前置处理
节点:需要新增以下处理代码
/**
* 前置处理节点
*/
//用户提问问题
const asrResult = msg._input.optAsrResult || msg._input.origin_content;
msg._input.content = asrResult;
msg.payload = {}
return msg;
双击配置提示词
节点:
你是一个灯光控制器,根据用户的指令发送控制命令。
响应格式:
开关: <1 表示开,0 表示关,null 表示未描述。>,颜色: <16进制颜色值,null 表示未描述。>
示例:
用户:打开灯光
助手:开关: 1, 颜色: null
用户:调整为蓝色
助手:开关: null,颜色: #0000FF
用户:打开灯光并设置为红色
助手:开关: 1,颜色: #FF0000
请按照上述格式响应用户的指令。
用户:{{content}}
助手:
提示词
节点,选择自定义的方式,将提示词模版内容填入节点中双击配置星火大模型
节点:配置适合的模型版本,取消勾选流式返回
等选项
双击配置后置处理
节点:增加以下代码来解析大模型返回的结果并转换为语音播报内容和NLP结果下发给端侧
//日志打印函数
const printInfo = global.get("PRINT_INFO");
const printErr = global.get("PRINT_ERR");
//设置成功的语音提示
const setSucc = "已完成设置";
//设置失败的语音提示,留空表示使用大模型的回复
const setFail = "很抱歉,我可能还无法理解你想要的指令";
//设置异常的语音提示
const setErr = "很抱歉,我暂时无法完成该操作";
//数据模版,不建议直接修改
const intentTemplate = {
"sub": "nlp",
"nlp_origin": "aiui",
"intent": {
"test": "SET",
"semantic": [{
"slots": [],
"id": "xxx",
"type": "rgb",
"intent": "#0000FF"
}],
"answer": {
"text": "已完成设置",
"type": "T"
},
"service": "AIUI.control"
},
"type": "CUSTOM"
}
//解析后的指令存在此数组
const results = [];
//大模型回复内容
let content = msg.payload.choices[0]?.message?.content || '';
let actions = content.replace(/[\s]+/g, "").split(/[,,]/);
actions.forEach((el, index) => {
let slots = [];
let type = el.startsWith("开关") ? "switch" : "rgb"
let intent = el.split(/[::]/)[1] || "null";
if (intent !== "null") {
results.push({
slots,
id: index + 1,
type,
intent
})
}
});
if (results.length > 0) {
printInfo("匹配到指令:", results);
intentTemplate.intent.semantic = results
//构造tts合成文本,推送语音播报内容给端侧
let ttsMsg = RED.util.cloneMessage(msg);
ttsMsg.payload = {
text: setSucc,
stream: true,
is_last: true
};
//构造灯控指令,推送NLP结果给端侧
let nluMsg = RED.util.cloneMessage(msg);
nluMsg.payload = intentTemplate;
node.send([nluMsg, ttsMsg]);
} else {
printErr("匹配不到指令:", content);
//构造tts合成文本,推送语音播报内容给端侧
let ttsMsg = RED.util.cloneMessage(msg);
ttsMsg.payload = {
text: setFail || content || setErr,
stream: true,
is_last: true
};
//若没有任何指令,只下发语音提示
node.send([null, ttsMsg]);
}
return;
部署
按钮,返回应用界面,打开刚才创建的应用,点击部署生产
就可以在设备上进行体验。按下大模型套件RST
按键,设备重启完成后,体验应用,可尝试使用以下提示词作为语音输入,观察端侧收到的日志报文:
编排相关附件
在第一部分的教程中,我们已经完成了云端新增意图的修改,本章节将修改开发板侧的固件代码,实现接收云端下发的指令后,对开发板上的 RGB LED 进行控制。
示例工程路径:{SDK}\apps\LLM_pic
代码的编译方式可见文档:《大模型语音交互+识图开发指南》
您可以选择将该示例工程拷贝至 SDK目录(duomotai_ap)下的自定义目录内(如 MyAPP)中进行修改和编译,以防止后续更新SDK时丢失已经修改过的代码。
SDK根目录(duomotai_ap)\.sdk\csk\boards\arm\csk6_duomotai_devkit\csk6_duomotai_devkit.dts
是本开发板的设备树文件,在该文件中定义了这个版型的硬件设备节点信息,在aliases
节点中我们可以看到 RGB LED 的节点信息,我们以控制 RGB LED 显示绿色为例,节点名称为 led_rgb_green
。
aliases {
sw0 = &user_button_0;
csk6-exmcu = &csk6_ch32v003;
led-rgb-red = &led_rgb_red;
led-rgb-green = &led_rgb_green;
led-rgb-blue = &led_rgb_blue;
lcd-pwm-ctl = &lcd_pwm_ctl;
camera-ir-led = &camera_ir_led;
led0 = &led_rgb_green;
};
在需要进行 RGB LED 设备控制的.c
文件中,加入以下设备节点的定义,本文以在LLM_pic\src\app_chat\app_music_ctrl.c
增加对 led 的控制为例:
// 增加 gpio 头文件
#include <zephyr/drivers/gpio.h>
//将 LED_G_NODE 定义为 绿色 rgb led 设备节点
#define LED_G_NODE DT_ALIAS(led_rgb_green)
// 通过设备节点创建一个 GPIO 控制结构 leg_g
static const struct gpio_dt_spec led_g = GPIO_DT_SPEC_GET(LED_G_NODE, gpios);
在static void app_player_ctrl_thread
函数中增加对 GPIO 的初始化操作:
int led_ret;
// 检查 led 设备是否就绪
if (!gpio_is_ready_dt(&led_g)) {
return 0;
}
// 将控制 led 的 gpio 初始化为输出
led_ret = gpio_pin_configure_dt(&led_g, GPIO_OUTPUT_ACTIVE);
if (led_ret < 0) {
return 0;
}
RGB LED 以及 GPIO 接口的使用方法可以文档《(外部扩展)GPIO》或 SDK 中的示例
{SDK}\.sdk\csk\samples\driver\exmcu_gpio_led
。
修改文件:LLM_pic\src\app_chat\app_music_ctrl.c
修改以下代码段:
static void app_player_ctrl_thread(void *p1, void *p2, void *p3)
{
…
while(1){
…
else if (msg.event == APP_CHAT_EVT_AIUI_CTRL) {
…
// 新增以下对开灯与关灯的指令处理
} else if (!strcmp(aiui_ctrl_strings, "1")) { // 开灯
LOG_INF("Open LED!");
led_ret = gpio_pin_set_dt(&led_g,1);
} else if (!strcmp(aiui_ctrl_strings, "0")) { // 关灯
LOG_INF("Close LED!");
led_ret = gpio_pin_set_dt(&led_g,0);
} else {
LOG_ERR("unkown AIUI.control cmd: %s", aiui_ctrl_strings);
}
}
}
参照《开发指南》重新编译修改后的代码,将固件烧录至开发板上,即可验证大模型控灯功能。