news 2026/9/15 18:21:09

智能定时器与语言理解:基于 LUIS 构建意图与实体解析的完整实战(IoT-For-Beginners)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
智能定时器与语言理解:基于 LUIS 构建意图与实体解析的完整实战(IoT-For-Beginners)

智能定时器与语言理解:基于 LUIS 构建意图与实体解析的完整实战(IoT-For-Beginners)

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

本指南基于 IoT-For-Beginners 开源课程"消费者(Consumer)"路径第 2 课(对应整体课程第 22 课),完整讲解如何为上一课已实现的语音转文字智能定时器注入"理解能力":借助微软 LUIS 语言理解服务,让设备不仅能听到"set a 3 minute timer",还能听懂"set a timer for 3 minutes"这类千变万化的自然表达。读完本文,你将掌握语言理解模型的核心概念(意图与实体)、在 LUIS 门户中创建与训练模型的全流程、通过 HTTP 触发的 Azure Functions 服务端代码调用模型,以及如何把解析结果(秒数)开放给 IoT 设备调用的完整链路。

图片来源:本课官方 sketchnote(作者 Nitya Narasimhan),点击可查看大图。

为什么要"理解"语言,而不是"匹配"句子

在上一课 1-speech-recognition 中,我们完成了从语音到文本的转换。但"听懂文字"是另一回事:如果代码只期待固定句式set a 3 minute timer,那么用户说set a timer for 3 minutes时,程序就会茫然无措——尽管人类一眼就能看出两者表达的是同一个意思。

语言理解(language understanding,也称自然语言理解,natural-language understanding)正是自然语言处理(NLP)这一人工智能领域中的"阅读理解"分支:它负责从文字中抽取关键细节,而不是逐字匹配模板。当你对 Alexa 或 Siri 说"播放 Taylor Swift 的最新专辑"时,背后就是语言理解服务在起作用,它需要从这句话中推导出:

  • 动作是"播放音乐";
  • 歌手是 Taylor Swift;
  • 播放对象是包含多首曲目、按顺序播放的整张专辑;
  • Taylor Swift 有多张专辑,需要按时间排序取最新发布的那张。

💁 需要强调的是:计算机的"理解"远未达到人类沟通的水平。这里说的语言理解,本质是"取一些词,抽取关键信息",而不是真正意义上的语义领悟。

语言理解模型属于 AI 模型,通常先用海量语言数据训练,再通过**迁移学习(transfer learning)**针对具体任务微调——这与你在本课程制造篇中用少量图片训练 Custom Vision 模型的思路如出一辙:拿一个预训练模型,再用你希望它理解的文本去训练它。

创建 LUIS 语言理解模型

LUIS(Language Understanding)是微软 Cognitive Services 中的语言理解服务,本课用它来构建定时器领域的语言模型。

第一步:创建 Authoring 资源

使用 Azure CLI 在smart-timer资源组中创建编写(authoring)资源:

az cognitiveservices account create --name smart-timer-luis-authoring \ --resource-group smart-timer \ --kind LUIS.Authoring \ --sku F0 \ --yes \ --location <location>
  • <location>替换为你创建资源组时使用的区域;
  • --sku F0表示免费层,足够开发使用。

⚠️ LUIS 并非在所有区域都可用。如果出现以下错误,请换一个区域重试:

InvalidApiSetId: The account type 'LUIS.Authoring' is either invalid or unavailable in given region.

第二步:在 LUIS 门户创建应用

  1. 打开 luis.ai,用与 Azure 相同的账号登录;
  2. 按对话框指引选择订阅,然后选中刚创建的smart-timer-luis-authoring资源;
  3. Conversation apps列表中点击New app,命名应用为smart-timerCulture(文化/语言区域)按你的语言设置;
  4. 门户会显示预测资源(prediction resource)字段。虽然可以单独建一个预测资源,但免费编写资源每月已含 1,000 次预测,足以支撑开发调试,此处留空即可;
  5. 阅读创建应用后弹出的新手引导,了解训练语言理解模型的步骤后关闭它。

意图(Intents)与实体(Entities):语言理解的基石

语言理解围绕两个核心概念:

  • 意图(Intent):这句话要做什么,例如播放音乐、设置定时器、取消定时器、下单点餐;
  • 实体(Entity):意图作用的对象,例如专辑、定时时长、食物种类。

模型解释的每个句子至少包含一个意图,可选地包含一个或多个实体。下表是本课给出的典型示例:

句子意图实体
"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 timer
"Order 3 large pineapple pizzas and a caesar salad"order food3 large pineapple pizzas,caesar salad

训练 LUIS 时先定义实体,再定义意图。实体可以是固定的词条列表,也可以从文本中学习。例如菜单场景可以给出食物清单及每个词的各种变体(同义词),如把egg plantaubergine都归为aubergine的变体。LUIS 还内置了一批可直接使用的预置实体(pre-built entities),如数字 number、位置 location 等。

对于定时器场景,可以用预置的number实体表示时长数值,再自建一个表示单位(分钟/秒)的实体;每个单位需要覆盖单复数变体,如 minute 与 minutes。

意图由模型根据你提供的**示例语句(utterances)**学习。比如set timer意图可以给出:

  • set a 1 second timer
  • set a timer for 1 minute and 12 seconds
  • set a timer for 3 minutes
  • set a 9 minute 30 second timer

然后告诉 LUIS 这些句子中哪些片段对应哪些实体。例如set a timer for 1 minute and 12 seconds的意图是set timer,它包含 2 个实体、每个实体各有 2 个值:

片段数值 time单位 unit
1 minute1minute
12 seconds12second

💁 与任何 AI 模型一样,训练数据越多、越准确,模型效果越好。因此需要提供覆盖"同一件事的不同问法"的多样化示例句子。

实操:为模型添加实体

定时器需要 2 个实体:一个是时间单位(分钟或秒),一个是分钟/秒的数值。

  1. 在 LUIS 门户的Entities标签页,点击Add prebuilt entity,从列表中选择number预置实体;
  2. 点击Create新建时间单位实体:命名为time unit,类型选择List(列表);在Normalized values中添加minutesecond,并在synonyms中补充单复数形式,每输入一个同义词按return确认:
Normalized valueSynonyms
minuteminute, minutes
secondsecond, seconds

实操:为模型添加意图

  1. Intents标签页点击Create,创建名为set timer的意图;

  2. 输入多种设置定时器的写法,混合使用分钟、秒以及分钟+秒的组合,示例可以是:

    • set a 1 second timer
    • set a 4 minute timer
    • set a four minute six second timer
    • set a 9 minute 30 second timer
    • set a timer for 1 minute and 12 seconds
    • set a timer for 3 minutes
    • set a timer for 3 minutes and 1 second
    • set a timer for three minutes and one second
    • set a timer for 1 minute and 1 second
    • set a timer for 30 seconds
    • set a timer for 1 second

    注意将数字的单词写法与数字写法混合(如four4),让模型同时学会处理两种形式;

  3. 每输入一个示例,LUIS 就会开始识别实体,并把识别到的实体加下划线标注。

实操:训练与测试模型

  1. 实体和意图配置完成后,点击顶部菜单的Train按钮,模型会在几秒内完成训练(训练期间按钮置灰,训练完成后恢复);
  2. 点击Test按钮测试:输入如set a timer for 5 minutes and 4 seconds并回车,文本下方会显示检测到的top intent(概率最高的意图),应为set timer,后面跟着该意图的概率;
  3. 点击Inspect查看结果明细:可以看到得分最高的意图及其百分比概率,以及识别出的实体列表;
  4. 测试完成后关闭Test面板。

实操:发布模型

要从代码中调用模型,必须先发布。LUIS 支持发布到Staging(暂存)环境用于测试,或Production(生产)环境用于正式发布;本课使用 Staging 即可。

  1. 点击 LUIS 门户顶部Publish按钮;

  2. 确认选择Staging slot,点击Done,应用发布后会收到通知;

  3. 用 curl 验证发布结果。构建 curl 命令需要三个值——endpoint(终结点)、App ID(应用 ID)和 API key(密钥),三者都可在顶部MANAGE标签页获取:

    • Settings部分复制 App ID;
    • Azure Resources部分选择Authoring Resource,复制Primary KeyEndpoint URL
  4. 在命令行执行:

    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=<sentence>"
    • <endpoint url>替换为Azure Resources部分的 Endpoint URL;
    • <app id>替换为Settings部分的 App ID;
    • <primary key>替换为Azure Resources部分的 Primary Key;
    • <sentence>替换为要测试的句子;
  5. 返回的 JSON 文档包含查询语句、top intent 以及按类型分类的实体列表。以查询set a timer for 45 minutes and 12 seconds为例:

    { "query": "set a timer for 45 minutes and 12 seconds", "prediction": { "topIntent": "set timer", "intents": { "set timer": { "score": 0.97031575 }, "None": { "score": 0.02205793 } }, "entities": { "number": [ 45, 12 ], "time-unit": [ [ "minute" ], [ "second" ] ] } } }

    这份响应的解读:

    • set timer是 top intent,概率高达 97%;
    • 检测到两个number实体:4512
    • 检测到两个time-unit实体:minutesecond

在代码中使用语言理解模型

为什么选择 HTTP 触发器 + 服务端无服务器代码

之前几课中,我们通过 IoT Hub 与云服务通信:发送遥测、监听命令。这种方式非常异步——遥测发出后代码不等待响应,如果云服务宕机也无法感知。而智能定时器需要即时反馈(告诉用户定时器已设置,或提示云服务不可用),因此设备应直接调用 Web 终结点,而不是依赖 IoT Hub 的异步通道。

直接在 IoT 设备上调用 LUIS 可行,但更好的做法是封装一层带 HTTP 触发器的无服务器函数(Azure Functions):函数应用监听 REST 请求并响应,设备只需调用这个 REST 终结点。这样当你想更换 LUIS 应用(例如训练出更好的模型,或增加多语言模型)时,只需更新云端代码,而无需向成千上万台 IoT 设备重新部署代码。

创建无服务器函数应用

  1. 新建名为smart-timer-trigger的 Azure Functions 应用并在 VS Code 中打开;

  2. 在 VS Code 终端执行以下命令添加 HTTP 触发器:

    func new --name text-to-timer --template "HTTP trigger"

    这会创建名为text-to-timer的 HTTP 触发器;

  3. 运行函数应用,输出中会列出终结点:

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

    在浏览器加载http://localhost:7071/api/text-to-timer验证:

    This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response.

接入 LUIS Python SDK

  1. LUIS 的 SDK 以 Pip 包形式提供,在requirements.txt中加入依赖:

    azure-cognitiveservices-language-luis

    仓库中该应用的完整依赖见 code/functions/smart-timer-trigger/requirements.txt,其中还包含azure-functions(注意不要引入azure-functions-worker,以免与 Functions 平台冲突):

    # Do not include azure-functions-worker as it may conflict with the Azure Functions platform azure-functions azure-cognitiveservices-language-luis
  2. 确保 VS Code 终端已激活虚拟环境,执行安装:

    pip install -r requirements.txt

    💁 若安装报错,可先升级 pip:pip install --upgrade pip

  3. local.settings.json中为 LUIS API Key、Endpoint URL 和 App ID 添加配置项(值从 LUIS 门户MANAGE标签页获取):

    "LUIS_KEY": "<primary key>", "LUIS_ENDPOINT_URL": "<endpoint url>", "LUIS_APP_ID": "<app id>"

    完整文件结构参考 code/functions/smart-timer-trigger/local.settings.json:

    { "IsEncrypted": false, "Values": { "FUNCTIONS_WORKER_RUNTIME": "python", "AzureWebJobsStorage": "", "LUIS_KEY": "<primary key>", "LUIS_ENDPOINT_URL": "<endpoint url>", "LUIS_APP_ID": "<app id>" } }
    • <endpoint url>MANAGE标签页Azure Resources部分获取的 Endpoint URL,形如https://<location>.api.cognitive.microsoft.com/
    • <app id>MANAGE标签页Settings部分获取的 App ID;
    • <primary key>MANAGE标签页Azure Resources部分获取的 Primary Key。
  4. __init__.py中加入导入语句:

    import json import os from azure.cognitiveservices.language.luis.runtime import LUISRuntimeClient from msrest.authentication import CognitiveServicesCredentials

    仓库中的完整实现见 code/functions/smart-timer-trigger/text-to-timer/init.py,下文将逐段讲解其逻辑。

编写预测与解析逻辑

  1. 清空main方法原有内容,加入客户端初始化代码。它从环境变量(即local.settings.json中的值)加载配置,用 API key 创建 credentials 对象,再创建与 LUIS 应用交互的客户端:

    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)
  2. 本 HTTP 触发器接收的请求体为 JSON,待理解的文本放在text属性中。从请求体取值并打印日志:

    req_body = req.get_json() text = req_body['text'] logging.info(f'Request - {text}')
  3. 构造预测请求(一个包含待预测文本的 JSON 文档),并发送到应用发布所在的 Staging 槽:

    prediction_request = { 'query' : text } prediction_response = client.prediction.get_slot_prediction(app_id, 'Staging', prediction_request)
  4. 预测响应包含 top intent 和实体。如果 top intent 是set timer,则从实体中读取定时所需时长:

    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
    • number实体是数字数组。例如"Set a four minute 17 second timer."会得到[4, 17]
    • time unit实体是字符串数组的数组,每个时间单位是一个内层数组。同上示例会得到[['minute'], ['second']]

    这两类实体组合后的 JSON 形态:

    { "number": [4, 17], "time unit": [ ["minute"], ["second"] ] }
  5. 实体之间没有显式关联,但可以合理假设:它们按说话顺序排列,因此用数组下标即可确定哪个数字对应哪个时间单位。例如:

    • "Set a 30 second timer":1 个数字30、1 个单位second,一一对应;
    • "Set a 2 minute and 30 second timer":2 个数字230,2 个单位minutesecond,第一个数字对第一个单位(2 分钟),第二个数字对第二个单位(30 秒)。

    用如下循环按序提取值(放在if块内):

    for i in range(0, len(numbers)): number = numbers[i] time_unit = time_units[i][0]

    "Set a four minute 17 second timer."会循环两次:

    循环次数numbertime_unit
    04minute
    117second
  6. 在循环内按单位换算总秒数:每分钟加 60 秒,秒则直接累加:

    if time_unit == 'minute': total_seconds += number * 60 else: total_seconds += number
  7. 循环结束后打印定时器总时长:

    logging.info(f'Timer required for {total_seconds} seconds')
  8. if块末尾,把秒数包装成 payload,转为 JSON 字符串并以 200 状态码返回(200 表示调用成功):

    payload = { 'seconds': total_seconds } return func.HttpResponse(json.dumps(payload), status_code=200)
  9. if块之外处理意图未被识别的情况——返回 404(not found)状态码:

    return func.HttpResponse(status_code=404)

触发器配置说明

仓库中 code/functions/smart-timer-trigger/text-to-timer/function.json 定义了触发器绑定:

{ "scriptFile": "__init__.py", "bindings": [ { "authLevel": "function", "type": "httpTrigger", "direction": "in", "name": "req", "methods": [ "get", "post" ] }, { "type": "http", "direction": "out", "name": "$return" } ] }

其中authLevelfunction(函数级密钥鉴权),methods支持 GET 与 POST。宿主配置见 host.json,其extensionBundle声明使用 Azure Functions 扩展包版本[2.*, 3.0.0)

用 curl 验证整个链路

运行函数应用,然后用 curl 发起 POST 请求:

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

<text>替换为请求文本,例如set a 2 minutes 27 second timer。函数应用侧会输出类似日志:

Functions: text-to-timer: [GET,POST] http://localhost:7071/api/text-to-timer For detailed output, run func with --verbose flag. [2021-06-26T19:45:14.502Z] Worker process started and initialized. [2021-06-26T19:45:19.338Z] Host lock lease acquired by instance ID '000000000000000000000000951CAE4E'. [2021-06-26T19:45:52.059Z] Executing 'Functions.text-to-timer' (Reason='This function was programmatically called via the host APIs.', Id=f68bfb90-30e4-47a5-99da-126b66218e81) [2021-06-26T19:45:53.577Z] Timer required for 147 seconds [2021-06-26T19:45:53.746Z] Executed 'Functions.text-to-timer' (Succeeded, Id=f68bfb90-30e4-47a5-99da-126b66218e81, Duration=1750ms)

curl 返回的响应中,"seconds"字段即定时器秒数:

HTTP/1.1 200 OK Date: Tue, 29 Jun 2021 01:14:11 GMT Content-Type: text/plain; charset=utf-8 Server: Kestrel Transfer-Encoding: chunked {"seconds": 147}

把 REST 终结点开放给 IoT 设备

IoT 设备要调用 REST 终结点,必须知道 URL。此前访问用的localhost只是本机快捷方式,要开放给设备,有两种方式:发布到云端,或获取本机 IP 供局域网访问

⚠️ 若使用 Wio Terminal,建议在本机运行函数应用:部分库依赖会导致无法按此前方式部署函数应用。此时请本地运行函数应用并通过电脑 IP 访问;若确实要部署到云端,后续课程会给出方法。

方式一:发布到云端

按前序课程的指引把函数应用发布到云端。发布后 URL 为https://<APP_NAME>.azurewebsites.net/api/text-to-timer<APP_NAME>为函数应用名),同时记得发布本地设置。

HTTP 触发器默认受函数应用密钥(function app key)保护。获取该密钥:

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

复制functionKeys部分default条目的值:

{ "functionKeys": { "default": "sQO1LQaeK9N1qYD6SXeb/TctCmwQEkToLJU6Dw8TthNeUH8VA45hlA==" }, "masterKey": "RSKOAIlyvvQEQt9dfpabJT018scaLpQu9p1poHIMCxx5LYrIQZyQ/g==", "systemKeys": {} }

该密钥需作为查询参数拼入 URL,最终为https://<APP_NAME>.azurewebsites.net/api/text-to-timer?code=<FUNCTION_KEY>

💁 可通过 function.json 中的authLevel设置调整 HTTP 触发器的鉴权级别。

方式二:本机运行 + 局域网 IP 访问

获取电脑在本地网络的 IP 地址:

  • Windows 10:查看"查找 IP 地址"相关指南;
  • macOS:查看"如何在 Mac 上查找 IP 地址";
  • Linux:查看私网 IP 地址的获取方法。

得到 IP 后,即可通过http://<IP_ADDRESS>:7071/api/text-to-timer访问,例如http://192.168.1.10:7071/api/text-to-timer

💁 注意使用端口 7071,IP 地址后必须加:7071

💁 该方式仅当 IoT 设备与电脑处于同一网络时才可用。

最后用 curl 验证终结点可访问。

动手挑战:扩充训练语料

"设置定时器"有无数种等价说法(例如不同语序、不同数字写法、夹杂语气词等)。请思考更多表达方式,把它们作为示例加入你的 LUIS 应用并重新训练,测试模型面对多种请求方式时的泛化能力。

课程作业:实现"取消定时器"

阅读 6-consumer/lessons/2-language-understanding/assignment.md:为 LUIS 应用新增一个cancel timer意图(无需实体,但需要若干示例语句);在无服务器代码中检测该意图是否为 top intent,若命中则记录日志并返回合适响应。参考评分标准:能添加意图并训练模型、能检测 top intent 并记录日志,即为满分表现。

回顾与延伸

  • 本课完整示例代码位于 code/functions/smart-timer-trigger,其中__init__.py是解析核心、function.json定义触发器、local.settings.json存放 LUIS 连接配置;
  • 想深入理解语言理解(自然语言理解)的理论背景,可查阅自然语言理解相关公开资料;
  • 想进一步了解 HTTP 触发器的更多配置项,可查阅 Azure Functions HTTP 触发器文档中关于authLevel、绑定方向的配置说明;
  • 下一课 3-spoken-feedback 将把本课解析出的定时器秒数转换为语音反馈,形成完整的"听懂—执行—回话"闭环。

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

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/15 18:20:50

固定电话验证:从正则到前后端实现,避开这些坑

前几天有个同事跑过来问我&#xff1a;“固定电话验证不就一个正则吗&#xff1f;你帮我写一个就行。”我没急着回答&#xff0c;而是打开工作邮箱翻出一份客户导入记录&#xff0c;屏幕上几条真实数据让他沉默了几秒&#xff1a;010-62245678转801 0755-12345678#666 &#xf…

作者头像 李华
网站建设 2026/9/15 18:20:12

CSS if()函数:原生条件计算与暗色模式实践指南

1. 这不是“CSS 写 if”&#xff0c;而是 CSS 终于拥有了条件计算能力2026 年初&#xff0c;Chrome 137 正式发布后&#xff0c;前端圈炸了锅。朋友圈、技术群、掘金热榜反复刷屏一句话&#xff1a;“2026年了&#xff0c;CSS 终于能写 if 了”。我第一时间打开 DevTools&#…

作者头像 李华
网站建设 2026/9/15 18:20:00

4 步完成抖音无水印下载:douyin-downloader 新手实操指南

4 步完成抖音无水印下载&#xff1a;douyin-downloader 新手实操指南 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback su…

作者头像 李华
网站建设 2026/9/15 18:19:29

SpringBoot外卖跑腿系统:智能调度与高并发实践

1. 项目概述与背景外卖跑腿配送系统是近年来随着本地生活服务数字化浪潮兴起的关键基础设施。我们团队基于SpringBoot框架开发的这套系统&#xff0c;核心解决了三个行业痛点&#xff1a;订单流转效率低、配送资源调度不均衡、商户与骑手协同困难。在实测中&#xff0c;相比传统…

作者头像 李华
网站建设 2026/9/15 18:19:18

基于MAX V 5M570的CPLD实现I2C RTC(PCF8563)驱动设计

简介&#xff1a;面向CPLD/FPGA开发者和硬件设计学习者&#xff0c;这套MAXV 5M570 CPLD开发板原理图与PCF8563高精度温补RTC芯片的Verilog驱动源码&#xff0c;以完整的Quartus 13.0工程形式提供&#xff0c;可直接打开分析或二次开发。核心模块pcf8563以mclk和reset作为输入&…

作者头像 李华