IoT-For-Beginners 智能计时器扩展实战:为 LUIS 应用添加「取消计时器」意图并接入 Serverless 处理
2026/9/15 22:10:10 网站建设 项目流程

IoT-For-Beginners 智能计时器扩展实战:为 LUIS 应用添加「取消计时器」意图并接入 Serverless 处理

【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners

导读

本文以微软开源课程《IoT-For-Beginners》第 6 章第 2 课《Understand language》的课后作业(英文原版、保加利亚语翻译版)为核心线索,讲解如何基于 LUIS 语言理解服务为智能计时器 IoT 场景新增「取消计时器(cancel timer)」意图:从理解意图(Intent)与实体(Entity)的关系、在 LUIS 门户中录入示例语句并训练模型,到在 Azure Functions 无服务器代码中以顶层意图(top intent)分支处理并返回响应,最终让你的 IoT 设备能够用自然语言直接取消一个正在运行的计时器。

作业背景:为什么需要「取消计时器」意图

在本课之前的任务中,你已经用 LUIS 训练了一个能够理解「设置计时器(set timer)」的模型,并在无服务器函数中把用户说出的文本转换为秒数。然而,现实中的智能计时器场景不止「设置」一种动作:例如面包已经烤好、需要在计时器到点前把它从烤箱里取出,此时用户需要的是「取消」当前计时器。

作业要求你为 LUIS 应用新增一个cancel timer意图,它具备两个特征:

  • 不需要任何实体(entities)——取消动作本身不携带"时长""单位"等信息;
  • 需要若干示例语句(example utterances)——让模型学会识别各种表达取消意图的说法。

随后,需要在无服务器代码中判断该意图是否为顶层意图,若是则记录(log)"意图已被识别",并返回合适的响应。作业的评分标准(Rubric)也围绕这两点展开:

标准优秀达标待改进
在 LUIS 应用中添加取消计时器意图成功添加意图并训练模型成功添加意图但未训练模型未能添加意图并训练模型
在无服务器应用中处理该意图能将该意图识别为顶层意图并记录日志能将意图识别为顶层意图无法将意图识别为顶层意图

这意味着完整实现需要"LUIS 模型侧"与"无服务器代码侧"两处改动同时完成,缺一不可。

前置知识:LUIS 语言理解模型与意图/实体体系

在动手扩展之前,先回顾本课核心概念。LUIS(Language Understanding)是微软 Cognitive Services 中负责自然语言理解(Natural Language Understanding,NLP 的一个分支)的服务。它的工作方式是:把用户话语转换为结构化信息——意图(Intent)表示用户想做什么,实体(Entity)表示意图所针对的具体对象。本课 README 给出了典型示例:

语句意图实体
"Play the latest album by Taylor Swift"play musicthe latest album by Taylor Swift
"Set a 3 minute timer"set a timer3 minutes
"Cancel my timer"cancel a timerNone
"Order 3 large pineapple pizzas and a caesar salad"order food3 large pineapple pizzas,caesar salad

注意表中第三行:"Cancel my timer" 的意图是cancel a timer,而实体为 None——这正是本次作业的理论依据:取消计时器不需要解析任何时长实体,只需识别意图本身。

模型的训练流程分为三步:

  1. 定义实体:可以是固定词表(List 类型),也可以从文本中学习;LUIS 还提供预置实体(如数字number)。本课为set timer定义了预置实体number和列表实体time unit(normalized value 为minute/second,同义词覆盖单复数形式)。
  2. 创建意图并录入示例语句:模型从你提供的 utterances 中学习。例如set timer意图可以录入set a 1 second timerset a timer for 3 minutes等覆盖数字/文字、分钟/秒组合的多种说法,并标注实体边界(见 sentence-as-intent-entities.png)。
  3. 训练、测试并发布:在门户点击Train,用Test面板验证顶层意图与实体识别,最后Publish到 Staging 或 Production 槽位,供代码通过 REST API 调用。

实现步骤一:在 LUIS 门户中添加cancel timer意图

1. 复用已有的 LUIS 应用

本课前面部分已经完成以下前置工作:

  • 用 CLI 创建了 LUIS authoring 资源:

    az cognitiveservices account create --name smart-timer-luis-authoring \ --resource-group smart-timer \ --kind LUIS.Authoring \ --sku F0 \ --yes \ --location <location>

    ⚠️ LUIS 并非在所有区域可用,若报错InvalidApiSetId: The account type 'LUIS.Authoring' is either invalid or unavailable in given region.,需更换区域。免费层 authoring 资源每月允许 1,000 次预测,足以支撑开发期使用。

  • 在 luis.ai 门户创建了名为smart-timer的对话应用,并已配置number预置实体、time unit列表实体以及set timer意图(示例语句见 README 的 Intents 小节)。

2. 新建cancel timer意图

  1. 打开 LUIS 门户,进入smart-timer应用,选择Intents(意图)标签页;

  2. 点击Create(创建),将新意图命名为cancel timer

  3. 在示例语句(utterances)区域录入若干表达"取消计时器"的说法。作业指出它不需要实体,但需要多条示例句子。可参考的示例包括:

    • cancel my timer
    • cancel the timer
    • stop the timer
    • turn off the timer
    • cancel my 3 minute timer

    录入示例后,LUIS 会实时为语句中的数字等部分自动标注已识别的实体(本课set timer意图的标注效果见 luis-intent-examples.png)。对cancel timer而言,实体检测结果通常为空或仅含无关的数字预置实体,不影响意图判定。

💁 训练提示:与任何 AI 模型一样,示例语句越多、覆盖的口语化表达越多样,模型对新说法的泛化能力越强。建议同时混入数字与文字写法、不同语序的说法。

3. 训练并发布模型

  1. 点击顶部Train(训练)按钮,模型会在数秒内完成训练(训练期间按钮置灰);
  2. 点击Test(测试),输入cancel my timer,检查top intent(顶层意图)是否显示为cancel timer及对应概率;
  3. 点击Publish(发布),选择Staging slot(本次作业使用暂存槽位即可)完成发布。

发布后可以先用 curl 验证预测接口:

curl "<endpoint url>/luis/prediction/v3.0/apps/<app id>/slots/staging/predict" \ --request GET \ --get \ --data "subscription-key=<primary key>" \ --data "verbose=false" \ --data "show-all-intents=true" \ --data-urlencode "query=cancel my timer"

其中<endpoint url><app id><primary key>分别取自 LUIS 门户MANAGE标签页的Azure Resources(Authoring Resource 的 Primary Key 与 Endpoint URL)和Settings(App ID)。响应 JSON 中的prediction.topIntent应返回cancel timer

实现步骤二:在 Serverless 代码中处理顶层意图

1. 仓库中的参考实现

仓库在 6-consumer/lessons/2-language-understanding/code/functions/smart-timer-trigger 提供了完整的 Azure Functions HTTP 触发器参考实现,目录结构如下:

  • text-to-timer/__init__.py:函数主逻辑(Python);
  • text-to-timer/function.json:HTTP 触发器绑定定义;
  • local.settings.json:本地运行配置(含 LUIS 三项密钥占位);
  • host.json:Functions 运行时与扩展包版本配置;
  • requirements.txt:Python 依赖清单。

核心逻辑在init.py:

def main(req: func.HttpRequest) -> func.HttpResponse: luis_key = os.environ['LUIS_KEY'] endpoint_url = os.environ['LUIS_ENDPOINT_URL'] app_id = os.environ['LUIS_APP_ID'] credentials = CognitiveServicesCredentials(luis_key) client = LUISRuntimeClient(endpoint=endpoint_url, credentials=credentials) req_body = req.get_json() text = req_body['text'] logging.info(f'Request - {text}') prediction_request = { 'query' : text } prediction_response = client.prediction.get_slot_prediction(app_id, 'Staging', prediction_request) if prediction_response.prediction.top_intent == 'set timer': numbers = prediction_response.prediction.entities['number'] time_units = prediction_response.prediction.entities['time unit'] total_seconds = 0 for i in range(0, len(numbers)): number = numbers[i] time_unit = time_units[i][0] if time_unit == 'minute': total_seconds += number * 60 else: total_seconds += number logging.info(f'Timer required for {total_seconds} seconds') payload = { 'seconds': total_seconds } return func.HttpResponse(json.dumps(payload), status_code=200) return func.HttpResponse(status_code=404)

关键机制说明:

  • 配置注入LUIS_KEYLUIS_ENDPOINT_URLLUIS_APP_ID从环境变量读取,对应 local.settings.json 中的占位项(部署到云端后需在应用设置中配置真实值)。
  • 调用 LUISclient.prediction.get_slot_prediction(app_id, 'Staging', prediction_request)请求 Staging 槽位预测,prediction_request = { 'query' : text }把用户文本作为查询传入。
  • 顶层意图分支prediction_response.prediction.top_intent即预测得分最高的意图。当前实现只有set timer分支:读取numbertime unit两个实体数组,按下标一一对应(实体按说话顺序排列,例如"Set a four minute 17 second timer"会得到number=[4, 17]time unit=[['minute'],['second']]),将分钟数 ×60 累加为total_seconds,最终以{"seconds": 147}形式返回 HTTP 200。
  • 未识别兜底top_intent既不是set timer也不是其他已处理意图时,返回 HTTP 404(Not Found)。

2. 为作业新增cancel timer分支

作业要求的代码改动,本质上就是在上述if分支结构中追加一个cancel timer的顶层意图分支。可参照如下模式扩展(示意,需结合你的实际代码调整):

if prediction_response.prediction.top_intent == 'set timer': # ... 原有的设置计时器逻辑(解析 number / time unit 并计算 total_seconds)... elif prediction_response.prediction.top_intent == 'cancel timer': logging.info('Cancel timer intent recognized') payload = { 'status': 'timer cancelled' } return func.HttpResponse(json.dumps(payload), status_code=200) return func.HttpResponse(status_code=404)

注意作业的三个硬性要求:

  1. 识别为顶层意图:必须使用prediction_response.prediction.top_intent判断(与set timer分支同级),而非在意图列表里做模糊匹配;
  2. 记录日志:用logging.info(...)输出"意图已识别"的日志,例如Cancel timer intent recognized
  3. 返回合适响应:返回 HTTP 200 与一个 JSON payload,供 IoT 设备端解析,告诉设备执行取消计时器的动作。

3. 依赖与绑定配置核对

新增分支不需要修改依赖,因为取消意图与设置意图共用同一套 LUIS 运行时客户端。仓库中的 requirements.txt 已声明所需依赖:

azure-functions azure-cognitiveservices-language-luis

function.json 定义了 HTTP 触发器绑定,authLevelfunction(表示调用需要函数键),同时允许getpost方法。若希望放宽/收紧访问权限,可通过修改authLevel实现。

实现步骤三:本地运行、验证与设备接入

1. 本地运行并用 curl 验证

先按 README 的指引安装依赖(确保虚拟环境已激活):

pip install -r requirements.txt

若安装报错,可先执行pip install --upgrade pip。然后在 VS Code 中运行 Functions 应用,终端会输出:

Functions: text-to-timer: [GET,POST] http://localhost:7071/api/text-to-timer

用 curl 发起 POST 请求验证新增的取消意图:

curl --request POST 'http://localhost:7071/api/text-to-timer' \ --header 'Content-Type: application/json' \ --include \ --data '{"text":"cancel my timer"}'

期望看到:函数日志中出现意图识别记录(如Cancel timer intent recognized),并返回 HTTP 200 与 JSON 响应。对照 README 中set timer的示例输出,{"seconds": 147}这类 payload 结构同样适用于你为cancel timer设计的响应。

2. 让 IoT 设备可访问该 REST 端点

智能计时器设备需要直接调用该 HTTP 端点(而非经 IoT Hub 异步通信),以获得即时响应。有两种接入方式:

  • 部署到云端:将 Functions 应用发布到 Azure,URL 形如https://<APP_NAME>.azurewebsites.net/api/text-to-timer?code=<FUNCTION_KEY>。其中函数键用以下命令获取:

    az functionapp keys list --resource-group smart-timer \ --name <APP_NAME>

    从输出functionKeys段的default字段复制函数键,作为 URL 的code查询参数。注意发布云端时也要把local.settings.json中的 LUIS 配置发布为应用设置。

  • 本地运行 + 局域网 IP:获取本机局域网 IP 后,端点地址为http://<IP_ADDRESS>:7071/api/text-to-timer(端口必须保留:7071)。此方式要求 IoT 设备与电脑处于同一网络;若使用 Wio Terminal,官方建议采用此方式,因为其依赖库与云端部署方式存在冲突。

评估标准与验收清单

对照作业的 Rubric 做最终自检:

  1. LUIS 侧smart-timer应用中已存在cancel timer意图,且已录入多条示例语句并完成训练(只添加不训练只能算"达标");
  2. 代码侧:无服务器函数在top_intent == 'cancel timer'时进入独立分支,既记录日志又返回响应(只识别不记录只能算"达标");
  3. 端到端验证:用curl或真实设备说一句cancel my timer,确认模型识别、日志输出、HTTP 200 响应三条链路全部打通。

延伸思考:让模型泛化得更好

本课 README 的课后挑战(Challenge)鼓励思考同一件事的不同说法并录入为示例,测试模型的泛化能力。对cancel timer意图同样适用:尝试录入cancel the 3 minute timerstop counting downturn the timer off等多样表达,观察 Top Intent 的概率变化。这类扩展可以直接沿用本作业建立的"意图 + 顶层分支"模式,无需改动代码结构。

小结

本文围绕《IoT-For-Beginners》第 22 课的课后作业,完整梳理了在 LUIS 应用中新增cancel timer意图并接入 Serverless 处理的实现路径:从意图/实体概念出发,在门户中添加意图、录入示例语句、训练与发布,再到基于仓库参考实现 text-to-timer/init.py 追加顶层意图分支、记录日志并返回响应。掌握这套模式后,你可以继续为智能计时器扩展"暂停""延长"等更多自然语言指令,验证 LUIS 模型的泛化边界。

【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询