
做天猫精灵带屏技能有一阵子了从纯语音技能转到屏显页面技能最大的体会是这玩意儿不是简单地给语音回复“配个图”那么简单而是要把用户问天气这个动作拆成“语音听得懂、屏幕看得清、卡片排得顺”三层逻辑。这次基于天气查询模板做了个屏显页面技能正好把从建号、配意图、接后端、调卡片到真机排错的全过程捋一遍给准备入坑带屏技能开发的兄弟一个可以直接抄作业的参考。先说清楚这个实验到底做了什么。我在天猫精灵开放平台创建了一个自定义技能选的是平台提供的天气查询模板最终效果是用户对带屏的天猫精灵说“今天天气怎么样”设备不仅会用语音回答温度、风力、空气质量还会在屏幕上弹出一张完整的天气卡片包含城市、日期、最高最低温、天气图标甚至生活指数。这个过程涉及语音交互模型的设计、后端接口的对接、天气数据的获取与加工以及屏显模板的适配。适合刚接触智能音箱技能开发、但又不想从零开始搭语音理解逻辑的开发者。1. 做“屏显技能”前先搞清楚它和纯语音技能差在哪很多从纯语音技能转过来的开发者最容易犯的错就是把屏显当成语音交互的附属品页面随便放张图了事。实际上带屏设备的屏显技能是另一套交互逻辑它有自己的信息层级。1.1 屏显技能到底解决什么问题纯语音技能的信息传递是线性的用户只能“听”到一串文字转语音的播报。比如问天气语音播报可能说“北京今天晴最高气温23度最低气温9度北风3级空气质量良”用户听完得自己在脑子里拆解这些信息。但信息一多比如再加个“明天开始降温”“出门记得戴口罩”用户就很容易记混。屏幕的价值在于把线性信息变成空间信息。同一张天气卡片上温度数字一定比风力大天气图标一定在温度旁边生活指数则放在底部作为补充。用户一眼扫过去优先级就已经分好了。所以开发屏显技能本质上是在做信息架构设计而不是简单的UI套模板。1.2 为什么选“天气查询模板”起步天气是所有技能里最适合练手的场景原因有三。第一天气数据的获取方式成熟不用自己造数据国内外一堆免费的天气API可以直接接。第二用户对天气的提问方式极其多样“今天冷不冷”“明天能穿短袖吗”“周末适合爬山吗”每一种问法背后都对应不同的意图处理和槽位抽取。第三天气信息天然适合视觉化呈现温度曲线、天气图标、生活指数都是现成的图形元素。我这次直接用了平台预置的天气查询模板。这个模板已经帮你把语音交互模型里的基础意图、槽位、以及一部分后端返回模板都搭好了相当于给了一间带装修的房子你要做的是根据自己的需求改布局、换家具而不是从挖地基开始。2. 平台侧准备与技能基础配置先说平台侧的东西。天猫精灵开放平台的入口叫“AliGenie开发者平台”没有单独的APP直接用淘宝或者天猫精灵账号登录就可以进入控制台。整个技能的开发流程是创建技能 - 配置语音交互模型 - 配置后端服务 - 配置屏显模板 - 测试与发布。2.1 账号与开发者资质这里有个容易被忽略的细节个人开发者账号和企业开发者账号在平台上的权限不完全一样。个人账号能创建自定义技能能用自己的服务器做后端也能用平台的模拟器测试。但如果你要做付费技能或者涉及某些特定类目就必须企业资质。好在这个天气查询技能属于标准的自定义技能个人账号完全可以走通全流程。创建技能的时候平台会让你选技能类型自定义技能、内容技能、智能家居技能、个人技能等。这里选“自定义技能”因为我们要自己写后端逻辑自己定义意图和槽位。选完之后填技能名称和调用词我设的调用词是“天气小助手”。之后用户对设备说“打开天气小助手”就能唤起这个技能。2.2 创建技能并选中天气模板平台的控制台里创建自定义技能后会进入技能详情页。这个页面的结构很清晰左侧是导航包含交互模型、配置、测试、发布等模块。创建之后系统会弹出“选择模板”的提示模板库里就有“天气查询模板”。这个天气模板我认真看了一遍它的目录结构它已经包含了一个“查询天气”意图QueryWeather两个槽位城市city、日期date后端服务示例代码Node.js版本屏显页面模板天气卡片的一版基础样式所以当你选了模板其实平台已经帮你生成了一个能跑的最小闭环。我第一次点开它的时候直接去测试台问“北京明天天气”它竟然已经能返回一个基础的JSON响应了。这就是模板最大的价值让你先看到“终点”再反推每一步要改什么。2.3 技能信息与语音交互模型初识在技能配置页面需要先填写技能的基础信息包括技能头像、技能简介、技能详情页的描述等。这些信息会展示在天猫精灵APP的技能商店里。虽然是实验项目我还是认真填了因为后期如果想要申请平台推荐这部分内容直接影响审核通过率。接下来是语音交互模型这是整个技能的灵魂。语音交互模型说白了就是教机器人怎么理解用户的话。它由三部分组成意图Intent、实体/槽位Slot、对话策略。意图就是用户想干什么槽位就是干这件事需要哪些关键信息对话策略则是当信息不完整的时候怎么追问。后面我会单独用一节详细讲这部分因为这里坑最多。3. 语音交互模型配置意图、槽位与对话策略语音交互模型是整个技能里最需要花心思的地方。选好了天气模板按道理这块可以直接用模板现成的。但我建议你一定要自己重建一遍别懒。因为模板给的是最通用的版本生产环境里用户的问法千奇百怪不扩充样本识别率会差到让你怀疑人生。3.1 意图和槽位怎么设计目前这个技能只需要一个核心意图我自己命名为“QueryWeather”用户表达“天气怎么样”“温度多少”“会不会下雨”都属于这个意图。槽位则定义了两个槽位名类型含义示例city内置城市实体用户查询的城市“北京天气”——city北京date内置日期实体用户查询的日期“明天天气”——date明天槽位类型用的是平台内置的 sys.city 和 sys.date这两个内置实体是平台维护好的不需要自己定义词表天然支持全国大部分城市名称和复杂的日期表达。这个设计能省下很多事。比如用户说“北京后天最高温度多少”系统能自动把“北京”抽到city槽位“后天”抽到date槽位并且date槽位的值会被解析成标准格式比如“2025-07-05”后端拿到的就是处理好的结构化数据。但模板案例给的意图和槽位并没有覆盖复杂情况。实测的时候我发现用户不但会说“北京天气”还会说“北京下雨吗”“上海适合穿什么”“广州明天刮风不”。这些句子虽然都在“天气查询”这个大意图下但用户在意的信息点不一样有的人关心温度有的人关心降水概率有的人关心风。如果你把处理逻辑都堆在同一个意图里后端就要做大量条件判断。我后续的做法是拆意图。除了QueryWeather这个主意图我又加了两个子意图QueryPrecipitation查询降水和QueryWind查询风力。这三个意图共用city和date两个槽位但在后端返回时会针对不同意图组装不同的播报文案和卡片字段。这样一来语义理解更准后端逻辑也更清晰。3.2 对话策略与多轮追问当用户说的句子缺槽位时比如只说“今天天气怎么样”没带城市这时候就需要多轮对话来补齐信息。平台支持在意图级别设置“必填槽位”和“追问话术”。我把city设为必填槽位用户没说城市时系统会自动追问“请问您在哪个城市呢”。这里有一个在真机上的体验细节如果用户之前已经授权了设备的城市定位或者设备本身就挂在家庭地址下那么即使他没说城市系统也能通过“用户经纬度”这个内置字段自动补全城市信息。所以做天气技能最好在后端逻辑里做一个优先级判断用户明确说了城市 - 用户授权了定位 - 使用设备默认城市。这个问题在模板默认代码里其实没有处理需要你自己加。对话策略还包括“重听”和“取消”。“重听”就是用户说“再说一遍”需要后端保存上一次的播报文本。“取消”则是用户说“算了不听了”需要结束会话。模板默认没有实现这两个能力但天猫精灵平台的技能协议里是支持这些标准能力的。我建议在真正运营一个技能之前把这两个策略也加进去体验会完整很多。3.3 内置实体与自定义实体除了内置的城市、日期实体天气场景里还有一个非常关键的槽位天气现象比如“晴”“多云”“小雨”等。用户可能问“北京明天是晴天吗”这里的“晴天”就是一个语义实体。我在做方案时发现平台上有一个常用的天气实体类型 sys.weather可以直接用。但为了让识别更精准我建议在自定义实体里再补充一份同义词表把“晴”“晴朗”“晴天”“大晴天”都映射到“晴”这个标准值上。同义词表的作用很直接不管用户说“晴天”还是“大晴天”后端接到的都是标准的“晴”值这样在写天气播报文案时只需要处理一种情况。这些细节单独看不值钱但堆在一起就是识别率的提升。4. 后端服务对接与天气数据加工语音交互模型配置好之后接下来的核心工作就是后端服务。平台的后端对接协议支持两种云函数和自定义HTTP服务。我用的是自定义HTTP服务因为这样调试起来直观代码逻辑也完全可控。4.1 后端接口需要做什么当用户在天猫精灵上说完一句话整个链路是这样的设备端采集语音传给天猫精灵云端。云端基于你配置的语音交互模型做语义理解输出意图、槽位、原始文本等结构化数据。云端将结构化数据封装成JSON请求POST到你配置的后端服务地址。你的后端服务处理业务逻辑这里就是查询天气、组装文案。后端服务返回特定格式的JSON响应给云端。云端解析响应一部分转成TTS语音播报一部分转成屏显卡片渲染。所以后端服务的核心工作就两件解析请求、组装响应。4.2 请求解析与响应组装平台发送到后端的请求核心字段大致是这个结构{ request: { type: IntentRequest, intent: { name: QueryWeather, slots: { city: { value: 北京 }, date: { value: 2025-07-05 } } } }, session: { isNew: false }, context: { device: { location: { longitude: 116.40, latitude: 39.90 } } } }后端拿到这个请求后的任务很明确从slot里拿城市和日期如果缺就触发追问如果齐了就去调天气API把结果整理成规范化数据再返回。返回给平台的响应JSON有一个标准格式。语音播报部分叫“outputSpeech”屏显部分在返回结构里会有特定的卡片字段。一个简化的返回结构长这样{ response: { outputSpeech: { type: PlainText, text: 北京今天晴最高温度二十一度最低温度八度北风三级空气质量优。 }, card: { type: weather_card, data: { city: 北京, date: 2025-07-05, weather: 晴, temperature_max: 21, temperature_min: 8, wind: 北风3级, aqi: 优, tips: 早晚温差较大出门建议加件薄外套 } }, shouldEndSession: true } }这个“card”字段就是屏显页面的数据来源平台会根据技能配置过的模板样式把data里的字段填到对应的视觉组件里。我当时自己写的时候折腾最久的就是这个响应结构。原因是不同版本的平台文档里卡片字段的嵌套层级偶尔有差异有的版本直接叫“card”有的版本要在“response”里多套一层“directives”。现在文档里的协议是稳定版本但如果是从旧项目升级这个字段名变化是最常见的坑。4.3 调第三方天气API的细节天气数据我用的第三方天气服务具体的服务商你可以自由选择国内国外都行关键看免费额度。接入的时候有一个很重要的原则第三方API返回的数据结构和你要展示给用户的数据结构几乎不可能一一对应。比如天气服务商返回的是实时温度“temperature”而播报文案里需要的是当天最高最低温这时候就需要自己做聚合。还有一点要特别小心缓存与时效。天气数据按小时更新很正常但如果你的技能流量比较大每次请求都实时去第三方API拉数据既慢又容易被限流。我当时做了个折中方案在本机做了一层进程内缓存同一个城市同一个日期的查询结果缓存60秒超过60秒才重新拉取。用户体感上几乎无差别但第三方API的调用量直接降了一个数量级。还有一个细节是异常兜底。天气服务商偶尔抽风返回超时或者数据为空。后端一定要做备用逻辑如果天气API5秒内没有返回就返回一个预设的兜底文案“抱歉天气信息暂时获取失败请您稍后再试”。不然用户对着屏幕和音箱干等体验很差。5. 屏显页面实现卡片模板与视觉规范屏显页面是这个实验的重头戏。天猫精灵带屏设备的屏幕尺寸和手机不一样Android平台的布局思路不能直接套用。好在平台提供了一套基于JSON数据驱动的模板引擎开发者不用写HTML或原生View只要配置模板里的数据映射关系页面就能渲染出来。5.1 模板里预置了什么天气查询模板附带的屏显页面已经包含了一套基础的天气卡片设计方案。这套模板的布局大体是这样的顶部是城市和更新时间中间大块区域是天气图标和当前温度左右两侧是最高最低温底部是空气质量、风速、湿度等指标最下方还可以加一行生活建议。这套模板最聪明的地方是它已经帮你把信息层级分好了。我在自己做视觉设计前专门盯着模板样式看了一阵发现它的字号层级和信息权重完全是匹配的。温度数字用超大字号城市名称用中等字号生活指数用弱化的小字。一个小白用户看到这张卡片第一眼一定能看到”21度”而不是“北京”这就是设计规范的力量。5.2 天气卡片数据结构使用模板时后端返回数据的字段名和模板里定义的变量名必须一一对应。我的经验是先看模板的字段定义文档再倒推后端返回的数据结构。以当前天气卡片为例核心字段有这些字段含义示例city_name城市名称北京update_time数据更新时间今天 09:00icon_type天气图标类型sunny / cloudy / raintemp_current当前温度21temp_max最高温度23temp_min最低温度8wind_desc风力描述北风3级humidity湿度45%aqi_desc空气质量描述优有个容易踩的坑是“icon_type”字段。这个字段是模板用来匹配天气图标的不是随便填文字的。它有一套预定义枚举值比如sunny、cloudy、rain、snow、thunderstorm等。后端的天气API返回的往往是“晴”“多云”这类中文描述所以后端要做一次映射转换晴 - sunny多云 - cloudy小雨 - rain。映射没做好卡片上的图标就会是个空白占位这问题在真机上一眼就能看出来。5.3 自定义视觉样式如果模板的样式不能满足需求平台也支持创建自定义模板。官方提供了一套类似手写UI的配置方式可以精确控制每个组件的坐标、宽高、字体大小、颜色等属性。工欲善其事必先利其器这块我花了一下午把文档翻了一遍。自定义模板的核心逻辑是“容器 组件”。你在编辑器里添加各种文本、图片、列表组件然后给每个组件绑定数据字段。开发界面支持实时预览你调一个属性右侧模拟器马上能显示效果。这个实时预览功能对效率的提升非常大避免了上传-真机-查看-修改-再次上传的低效循环。我在自定义模板上做过一次优化实验给天气卡片加了一个未来三天的天气趋势预览用小图标横向排列在卡片底部。这样用户问一次天气看到的是一个“今天为主未来三天”的综合信息而不是只有今天一天。这个改动用模板自带的样式配置就能实现不需要写前端代码但视觉观感明显好很多。6. 真机调试与常见问题排查实录开发环境调通之后真正让人立正挨打的是真机调试。平台提供在线模拟器也能绑定真机调试。我强烈建议用真机因为模拟器和真机在语音识别、屏显渲染上存在细微差异有些问题只在真机上能复现。6.1 模拟器与真机联调在线模拟器通常有两种调试视角一种是文本模拟你手动输入一段用户的query文本系统返回语义理解和技能响应另一种是语音模拟你对着电脑麦克风说话系统走完整的语音识别链路。文本模拟适合快速验证后端逻辑语音模拟适合验证语义理解模型。真机调试需要在技能测试配置里开启“真机调试”模式然后把天猫精灵的固件升级到支持开发者调试的版本。具体来说在天猫精灵APP里需要绑定你的开发者账号技能才能在真机上被唤起。这个流程我第一次走的时候卡了很长时间原因竟然是APP版本太旧没有“开发者调试”入口。所以提醒一句确保APP和固件都是最新版再开始折腾。6.2 常见报错速查表把这两天调试中遇到的问题整理成一张表基本覆盖了新手会遇到的大部分情况问题现象可能原因解决办法技能唤起后无响应后端服务未上线或URL不可访问先在浏览器里直接POST请求后端URL确认HTTP 200用户说“天气”但进入不了技能调用词和意图名不匹配检查技能唤起方式和调用词列表确认“天气”在唤起词内槽位识别不准北京识别成河北某地城市实体未启用或样本不够在交互模型里补充城市说法或使用内置sys.city并大量测试屏显卡片空白返回JSON里card字段的data和模板变量不匹配逐一核对字段名和类型尤其注意icon_type的枚举值语音播报正常但页面无显示技能未勾选“支持屏显设备”在技能配置页面检查设备支持类型勾选带屏设备后端有数据但播报文案很怪TTS对数字的朗读规则不友好温度数字写成中文“二十一度”或用语音标签指定朗读格式6.3 调试中的独家经验最后分享三个调试技巧。第一个是关于城市追问的。真机调试时如果用户没带城市系统的追问机制是正常的但有一个细节追问结束后后端收到的请求里city槽位已经补齐了直接走完整逻辑就行不需要自己维护会话状态。这个我一开始没搞明白还自己写了个会话缓存结果多此一举。第二个是屏显页面的数据隐藏。如果你不想让某个字段显示在卡片上最好的办法不是从JSON里删掉它而是把模板字段留空。我用这个办法把“湿度”从卡片上暂时拿掉了但后续想要的时候只改模板不用改后端调试效率高很多。第三个是关于“查询失败时文案和页面的一致性”。我曾经遇到过一种尴尬情况天气API挂了语音播报已经在说“抱歉获取失败”但卡片还是把上一帧的旧数据渲染出来了用户看到“晴21度”却听到“获取失败”感受很怪异。解决办法是在失败返回的JSON里card字段也要返回一份“失败态”的数据比如图标类型置为unknown、温度字段置为空模板会自动显示一个灰色占位图。语音和页面在异常情况下状态一致这一点很考验细节。技能开发走到这一步基本已经完成了从“能用”到“好用”的跨越。天气查询模板帮我省下了从零搭建脚手架的时间但真正决定最终体验的还是后面那些一个个填平的细节槽位识别准不准、卡片字段对不对得上、异常状态下页面怎么兜底。每一个小坑踩过去技能就往前成熟一点。我个人最大的体会是带屏技能的屏显页面不是“加分项”而是和语音同等重要的核心交互出口把页面当成第一公民来看待很多设计上的取舍自然就清晰了。