首页 / 资讯中心 / 文章详情

智能电视语音助手意图识别实战:7B大模型微调与端侧部署

智能电视语音助手意图识别实战:7B大模型微调与端侧部署 ★ FEATURED ARTICLE
做智能电视语音交互跟我以前做手机助手完全是两个世界。电视场景的意图识别听起来简单翻来覆去不就是“换台”“调音量”“打开应用”嘛可真上手做就会发现用户的话术千奇百怪老人小孩的口音、频道名的简称、连续剧集的表达混在一起再加上电视主板那点“抠门”的算力传统方案很快就顶不住了。去年我负责的智能电视语音助手意图识别模块就是从模板匹配一路干到7B大模型微调落地中间系统性对比过三种主流方案也踩了无数坑。这篇文章把三种方案的对比过程和7B模型微调的完整实战记录下来给正在做端侧或者边缘侧大模型落地的朋友一个参考。1. 智能电视意图识别的业务背景与方案选型逻辑1.1 电视场景为什么比手机场景更难做很多人不理解同样是语音助手电视上的意图识别为啥要做大模型我直接说几个场景差异手机上你说“帮我定个明天早上8点的闹钟”这句话的边界很清楚。电视上你说“我想看那个那个……就是那个谁演的古装剧”这句话里“那个那个”是口语噪声“那个谁”是模糊指代“古装剧”是领域标签真正的槽位是演员名和剧类全部揉在一句话里。你还要结合当前的播放状态去理解用户说“下一个”到底是下一集、下一个节目还是下一个频道没有多轮对话和上下文记忆纯规则根本玩不转。更麻烦的是电视的物理环境。客厅里电视离人两米到五米远场拾音之后ASR的错误率比手机近场高不少ASR一错后面的意图识别全部建立在错误文本上。再加上有些用户是方言口音ASR结果片段化严重经常出现“换到中央”“调到那个五台”“放那个三十而已”这类不完整表达。这些都对意图识别的鲁棒性提出了很高要求。还有一个隐形痛点内容库的更新。电视平台每个月都上新剧、新综艺热门角色名、新梗层出不穷。如果用静态词表加模板每上新一波内容就要维护一批规则项目上线三个月后规则数量翻了一倍维护成本肉眼可见地失控。1.2 三个候选方案的基本盘我们当时圈定了三个候选方案思路完全不同方案一模板规则 关键词匹配 槽位正则抽取这是最传统的做法也是大多数电视厂商在用的基线。方案二用BERT类预训练小模型做意图分类槽位抽取仍然靠规则或序列标注模型。方案三在边缘侧部署经过微调的7B大模型把意图识别和槽位提取合并成一个生成任务一条链路全部搞定。我先把结论放在前面方案一适合只有两三个意图、话术极度固定的场景方案二适合算力有限但意图数量可控的中型场景方案三最适合我们这种意图类型多、话术开放、还要频繁应对新词热词的电视助手。三种方案并不是替代关系我们在最终架构里实际上保留了方案二做快速兜底方案三做主力理解。2. 三种方案深度对比效果、成本与可维护性2.1 模板规则方案快速上线但天花板明显方案一我带了两个实习生花了两周就搭出了第一版。核心是一个意图路由表每个意图对应一组触发词比如“换台”意图对应“换到”“调到”“转到”“切到”这些动词前缀后面跟频道槽位槽位靠正则和词表抽取词表覆盖频道别名、剧名、演员名。这个方案在封闭测试集上的表现其实不差我们的初始评测集里准确率能做到85%左右。但问题全在开放场景。我记得特别清楚的一个bad case用户说“帮我找一下那个湖南卫视七点半播的那个剧”模板里“湖南卫视”是频道词表内的“七点半”是时间槽位“那个剧”完全没法解析最后落到兜底意图体验就是“对不起我还没学会这个操作”。方案的第二个问题是意图描述没有泛化能力。“我想看贼好看的悬疑片”和“给我推荐点烧脑的”语义完全一样但模板只能识别“悬疑片”这种显式词。词表之外的说法统统失效每次上线新内容就要加一批词规则文件越来越大到最后我们光频道别名表就维护了四百多个条目仍然堵不住用户的新说法。2.2 BERT小模型方案在封闭意图集上的性价比之选方案二我们选了一个30层以内的中文BERT类模型做多标签意图分类槽位抽取用另一套序列标注模型。训练数据是历史日志里人工标注的两万条语料把意图从原来的8类扩到了32类包括“点播”“换台”“音量调节”“播放控制”“查询天气”等电视场景常见意图。这个方案的准确率提升很快同测试集上意图分类到了93%槽位抽取F1大约在78%。关键是它有了一定的泛化能力“帮我找点烧脑的”这种说法虽然在训练集里没出现过但因为训练语料里“悬疑”“烧脑”“烧脑子”都标成了同一个意图模型能通过语义相似性做出判断。但BERT方案的短板也很明显。第一它是判别式模型意图和槽位分两段处理槽位的错误会直接传导给下游应用调度整体链路的端到端F1反而比单意图分类低。第二它对新增意图不友好新加一个“会员充值”意图至少要重新标注五百条样本再训练、再评估一个迭代周期两周起步。第三它处理不了“根据上下文判断”的场景比如上一句“放周星驰的电影”下一句“换一个”到底换什么小模型很难利用对话历史。2.3 7B大模型方案开放理解与结构化输出的统一方案三我们选了一个7B规模的中文基座模型用LoRA做指令微调。设计思路很直接把所有电视指令统一转成结构化JSON输出意图、槽位、对话记忆全部由模型一次生成。同样是“帮我找一下那个湖南卫视七点半播的那个剧”模型输出{ intent: 点播, slots: { channel: 湖南卫视, time: 7点半, target_type: 剧集 }, needs_confirm: false }这个方案在开放测试集上意图准确率到了96.5%槽位F1到了85.6%最重要的是bad case率低了很多。让我决定换方案的关键点是它对新词热词天然免疫不需要维护任何词表模型对“热播”“上新”“好看”这类描述性表达的理解远超小模型。还有它天然支持对话记忆把前三轮的用户query拼进prompt模型就能理解“换一个”是换频道还是换剧。代价当然也有。7B模型在纯CPU上跑一次推理可能要七八秒根本没法用量化到4bit之后在带NPU的电视主板上单次推理能压到1秒以内但对系统内存和NPU算力依然有要求。所以我们在架构上做了分层主力场景走本地7B模型超时或低置信度场景再走云端的更大模型这个后面章节细说。2.4 三方案横向评测与最终结论我把三个方案在同样一批测试集上的表现整理成了这张表数据来自我们线上脱敏后的标注样本评测维度模板规则BERT小模型7B大模型(4bit)意图准确率85.2%93.1%96.5%槽位抽取F168.4%78.2%85.6%新说法覆盖比例62%81%95%单次推理延迟15ms45ms900ms内存占用10MB150MB2.1GB新增意图迭代周期3天2周1天规则/词表维护大量少量几乎为零表格能看得很清楚小模型和大模型的差距主要不在意图准确率而在槽位抽取、新说法覆盖和迭代效率上。大模型单次推理的绝对延迟确实高但电视交互对延迟的容忍度比手机要高那么一点900毫秒体感上是“稍微等一下”可换来的是理解能力的明显提升。最后我们选定7B模型作为主力方案一个重要原因就是业务方每周都要上新的内容运营位大模型让内容侧的文案和语音助手的理解保持同步不用再追着维护词表跑。3. 7B模型微调实战数据工程是成败关键3.1 训练数据从哪来标注、日志与合成三条腿走路很多团队做微调失败不是模型不行而是数据不行。7B模型微调对数据的质和量都有门槛我分享一下我们的数据来源历史日志挖掘把线上语音助手的真实交互日志脱敏按session切分筛选出“用户说完话后点按了某个按钮”的样本这代表用户真实的意图准确率非常高。人工标注补盲日志里覆盖不到的长尾说法安排标注团队按话术模板人工扩写。比如“音量”相关的意图我们要求标注员写出各种离谱的说法“声音小点”“听不清了”“你把电视弄小声点”“这声音太大了吵死了”。合成数据增强让GPT类的云端模型基于少量种子样本批量改写生成变体我们在改写时特别要求保留口语化和ASR噪声特征比如加入“那个那个”“呃”这样合成数据跟真实ASR结果分布更接近。三条来源最终汇总成基础数据集规模大约两万条。我强烈建议不要盲目贪多质量差的数据混进来反而会把模型带偏尤其是标注不一致的样本模型会学到错误的映射关系。3.2 Prompt模板与样本格式设计电视场景的微调样本格式我们试过很多种最后稳定下来的是这种统一结构{ instruction: 你是智能电视语音助手请分析用户的指令意图并提取关键槽位。, input: 用户历史指令播放周星驰的电影当前指令换一个。, output: {\intent\: \播放控制\, \action\: \切换下一个节目\, \slots\: {\target\: \周星驰的作品\}, \use_context\: \是\, \confirm\: false} }有个关键细节output里的JSON必须是一段稳定格式不能一会儿带“intent”一会儿带“意图”。我们为所有意图类型定义了统一的JSON schema训练时强制模型按schema输出。你可以把schema理解为给模型的一份“答题卡”模型只要学会填卡推理阶段几乎不需要做后处理。Prompt里带上历史指令极其重要。电视助手的多轮场景是真的多我上面举的“换一个”就是真实日志里高频出现的说法。不带上下文的模型遇到这种指令基本只能回一个“我理解不了”。我们在设计样本时专门把三分之一的数据做成了多轮对话格式确保模型见过带上下文的例子。3.3 数据清洗去重、纠偏与badcase回流数据清洗这步很枯燥但对效果影响是决定性的。我有三个经验意图标签必须做一致性审查。几个人标注“声音大一点”和“把声音调高”容易一个标成“音量调节”一个标成“音量增加”。我们在标注规范里统一了意图粒度然后跑了一个自动交叉验证把冲突样本全部拎出来人工复核。槽位抽取必须严格对齐。比如“湖南卫视”和“湖南台”在标签里必须统一成官方名称“湖南卫视”否则模型会以为这是两个东西。badcase回流机制要建在微调之前。我们把线上测试阶段发现的每一个失败case都补充进训练集重新微调。每轮回流大约补五百条模型下轮就能明显改善。这是我们在实际迭代里效果最好的一条推荐大家直接抄作业。3.4 数据规模与配比的参考值很多刚上手的朋友问“到底要多少条数据”。我的参考值是意图类型不超过40个单意图有效样本不低于300条总量一万到三万条就够用了。低于一万条模型容易过拟合到prompt格式上换个说法就懵高于五万条边际收益已经很小纯浪费训练时间。样本的配比也有讲究。我建议把正负样本比例控制在8:1到10:1负样本太少模型会变得“什么话都能对应到一个意图”这在线上是个灾难。负样本不一定要真实用户说的直接拿一些无关的闲聊语料标成“无法识别意图”塞进去就行。4. 微调落地从LoRA到QLoRA的完整实操记录4.1 硬件需求与显存计算先把账算清楚。一个7B模型参数以float16存储光权重就是14GB。如果用全量微调还需要存梯度和优化器状态Adam优化器的显存开销大约是参数量的12倍以上也就是说全量微调7B没有80GB以上显存根本不现实。绝大多数团队都不会这么干所以LoRA成了事实标准。LoRA的思想是冻结原模型只训练一小部分低秩矩阵。以常见的rank8、作用于三四个目标模块来计算可训练参数量大约只有总参数的0.5%到1%优化器状态可以忽略不计。我们用QLoRA基座模型先量化到4bit再加载模型本体显存占用只有大概4GB到5GB在这个基础上做LoRA训练一张40GB显存的卡不仅能跑还能开到较大的batch size。如果你只有24GB显存同样能跑batch size小一点就行。如果没有自己的GPU云上租一张带4090档位显存的实例也足够。4.2 训练框架与关键超参数详解框架选择上我直接用的开源社区最主流的组合transformers加载模型peft做LoRA再用deepspeed的zero stage2做分布式。这套组合资料多、报错能搜到解决方案比自研训练流程省心太多。下面是我们最终稳定下来的训练配置可以直接参考model_name_or_path: /models/chat-7b torch_dtype: float16 quant_bit: 4 lora: r: 16 lora_alpha: 32 lora_dropout: 0.05 target_modules: [q_proj, k_proj, v_proj, o_proj] training: learning_rate: 2.0e-4 batch_size: 8 gradient_accumulation_steps: 4 num_epochs: 3 warmup_ratio: 0.05 weight_decay: 0.01 max_seq_len: 1024 save_strategy: epoch deepspeed: zero_stage: 2 offload_optimizer: false这里每个参数我都解释一下因为很多人就是乱抄参数翻车的learning_rateLoRA微调的学习率一般比全量微调大常见区间是1e-4到3e-4。我们试过1e-3开头loss直接飞了也试过5e-5训练两轮loss纹丝不动。2e-4是我们跑了十几组实验后的稳定最优值。lora_alpha和r的关系alpha越大LoRA矩阵对原始权重的注入越强。我们固定r16alpha/r控制在2:1到1:1之间实测效果最稳。num_epochs7B模型微调意图识别这种简单任务3个epoch就够。超过4个epoch我基本一定会看到灾难性遗忘模型把原有的通用对话能力忘掉一部分回答变得机械。max_seq_len1024已经覆盖了99%的电视指令因为prompt里除了当前指令还有历史指令。如果只处理单轮512也够还能省显存提速。warmup_ratio0.05的warmup是为了防止训练初期loss暴涨很多新手不设warmup直接训头几十个step就崩了。4.3 训练过程监控与过拟合判断训练过程中我最看重两个东西训练集loss和验证集loss。如果训练集loss还在下降但验证集loss已经回升就是过拟合信号马上停。如果你没有单独留验证集用训练集里抽10%的数据做验证集这步别省。还有个小技巧每个epoch结束保存一个checkpoint然后用固定评测集对每个checkpoint做一次离线评测。我们遇到过训练集loss在第3轮继续降低、但意图准确率反而在第3轮下降的情况说明模型开始死记训练数据了。最终我们用的是第2轮的checkpoint准确率和泛化性最好。别迷信“训练到最后一定最好”以评测结果为准。5. 从服务器到电视主板推理部署的关键问题5.1 智能电视的算力底座到底有多“抠”聊部署之前你得先对电视的硬件有个清醒认知。我们目标平台是一块中高端的电视主板四核CPU带简单NPUNPU算力大概在3到5 TOPS系统可用内存只有2GB左右。这和云端动辄几百GB显存的服务器完全是两个物种。7B模型哪怕量化到4bit参数也有4GB以上模型文件已经超出内存了。所以我们的部署策略分两种情况一是内存相对宽裕的高端机型模型本地推理二是中低端机型只做轻量本地模型加云端兜底。不要幻想一个方案通吃所有机型做电视大模型落地第一课就是学会和硬件妥协。5.2 量化方案对比GPTQ、AWQ与GGUF格式模型量化是端侧部署绕不开的环节我们分别测了三种主流路子GPTQ量化基于二阶信息做校准推理时用反量化矩阵乘。在电视场景下我们把它转成4bit精度损失是我们测过的方案里最小的但推理框架对运行环境有要求低端CPU上性能一般。AWQ量化根据激活值分布找敏感权重做保护量化后精度和GPTQ接近但它针对的是特定推理框架的优化路径跨平台支持不如另外两家。GGUF格式这个方案最大的优势是纯CPU也能跑而且在4bit量化下的推理速度是所有方案里最快的因为它做了大量CPU指令集优化对内存的占用也控制得更好。我们最终在电视端上的主力推理方案就是用GGUF量化格式跑的。这里分享一个量化精度损失的实测数据原始float16模型在评测集上意图准确率96.5%采用GGUF的Q4_K_M量化后降到95.1%槽位F1从85.6%降到84.0%。损失在可接受范围内换来的是内存占用从14GB降到2.1GB推理延迟从2.5秒降到0.9秒。对电视场景来说这个交换非常划算。5.3 本地推理与云端兜底的混合架构我们的线上架构不是简单的一句“模型部署在电视上”而是一个分层协同第一层电视本地跑GGUF的7B模型处理90%的常规指令延迟控制在1秒内。第二层当本地模型的输出置信度低于阈值时把请求转发到云端更大规模的模型做二次理解这部分请求占比大约8%。第三层本地模型完全无法理解、云端也无法识别的指令统一进兜底话术“我还不太明白可以换个说法吗”同时记录badcase回流到训练集。这个架构让平均延迟保持在900ms左右而最难的“疑难杂症”有云端兜底不会直接给用户坏体验。云端兜底的那8%请求是我们的黄金语料来源每周都能捞出一批新说法反哺下一轮微调。推理服务本身的优化还有两个地方值得提。一是prompt拼接要复用缓存同一轮对话里历史部分不动只增量拼最新的指令省掉重复的token化时间。二是输出解析要做容错模型偶尔会输出不合法JSON我们做了两层保障先用正则提取JSON片段解析失败就整个作为纯文本走第二层兜底模型不让用户感知到解析错误。6. 一线路上的踩坑实录常见问题与排查方法6.1 训练阶段loss不降、显存溢出和灾难性遗忘先说loss不降。新手最常犯的错是学习率设置不当和数据格式不匹配。我们排查过一起典型case数据里output字段带了多余的引号转义模型学到的全是字符串噪声loss卡在3.2下不去。做法是把数据打印出来肉眼检查前五十条格式一眼就能发现问题。显存溢出OOM也常见尤其在QLoRA基础上还想开大batch的时候。我的经验是先调gradient_accumulation_steps而不是硬调batch_size小batch多步累积效果完全一样但显存压力小很多。如果24GB卡还爆就把max_seq_len从1024降到768效果影响很小。灾难性遗忘我在4.3节提过再补充一个判断方法训练完成后跑几个通用能力评测项比如让它写一段简单的古诗或者解释一个成语。如果这类通用能力明显变差说明学习率太高或者epoch太多回退到低学习率方案重新训。6.2 推理阶段JSON输出不稳定与重复生成模型在推理时最常出的问题就是输出格式不稳定时不时多一个标点或者漏一个字段。我们做了三件事一是训练数据里加入少量“缺字段”的带错样本让模型知道格式错了会被惩罚二是推理时把温度降到0.1基本消灭了随机性带来的格式漂移三是解析层做字段级别容错缺一个槽位就给一个空值不让整条链路崩溃。重复生成是另一个高频问题。具体表现是输出“换台换台换台换台”然后一直出同一个词。解决办法是给推理参数设置repeat_penalty我们调到1.1到1.2之间基本能压住。如果你的框架没有这个参数就在生成长度上限上做限制最长输出控制在128个token以内因为我们的结构化JSON最多也就一百多个token多出来的基本都是重复。6.3 业务落地误触、空响应与“太慢”的体感上线一段时间后我们发现一个很有意思的问题模型把“我要看电视”识别成了“打开电视电源”结果电视在观看中突然弹了开机引导。这属于真实场景里“意图歧义”问题光靠模型解决不了我们在调度层加了一条规则当用户当前处于播放状态时涉及电源相关的意图统一不执行先反问“您是要关机吗”。这件事给我的教训是大模型解决的是理解问题而业务规则解决的是安全问题两者必须配合不能指望一个模型把所有事情都干了。延迟体感上也有优化空间。九百毫秒的推理时间加上ASR和前端处理用户感知大约是1.5秒确实比小模型慢。我们做了两个改善一是在模型推理期间电视端先播一个短的“嘀”提示音和转场动效用户感知明显变短二是把频道切换、音量增减这类极简单的指令用规则前置拦截根本不给模型处理只有理解类指令才走大模型。这样80%的高频轻操作依旧飞快大模型只处理真正需要理解力的话术用户并不会觉得整体变慢。7. 一些项目层面的经验复盘最后聊点纯工程之外的东西也是我做了这么多轮迭代之后体会最深的几点。第一评测集一定要固化。我们建了一个三千条的线上语义评测集每次微调完都先在评测集上跑分分数达标才允许上灰度。不要相信“感觉模型变聪明了”要用数据说话。我们有一次明显感觉模型变好了评测出来意图准确率反而掉了0.8个百分点查了半天是之前一批badcase回流数据把模型对某个意图的判定带偏了。稳固的评测集就是你的导航仪没有它迭代就像闭眼开车。第二小步快跑的迭代节奏最适合这类项目。我们固定的节奏是每两周一个微调版本每周五灰度发布每次只改一个变量要么只加数据要么只调学习率。有一次我想省时间同时换了基座模型版本又加了数据结果效果下降根本定位不了是哪一步出了岔子。一次只改一件事看起来慢实际上最快。第三微调不是越复杂越好。刚开始我们也想加各种复杂机制比如对比学习、双塔结构、NER联合训练后来发现电视意图识别这个任务本质上没有那么难用最简单直接的LoRA指令微调配合高质量数据效果已经超过了所有花哨方案。很多时候瓶颈是数据质量而不是模型结构把精力花在清洗数据和评测上收益远大于折腾新架构。第四模型落地是硬件、算法、产品三方的事。如果产品侧不能接受大模型的延迟如果你的主芯片内存连4bit模型都塞不下再好的微调结果也只是demo。我们最后能落地是因为提前和硬件团队确认了终端的NPU和内存规格再反过来圈定模型量化的目标规格整个过程是硬件约束倒推出来的而不是算法团队自嗨出来的方案。这个项目做完之后我对“端侧大模型”这件事有了完全不同的理解。大模型不是把云端的东西缩小塞进设备而是在设备能力、用户体感、模型效果之间找到一条可接受的折中路径。每一次量化、每一轮prompt设计都是在为这个折中讨价还价。做技术方案没有银弹只有不断权衡。希望这篇记录能让你少走几步弯路你实际落地时遇到的情况肯定跟我不完全一样但只要数据工程、评测体系和部署约束这三条线抓得住大概率就不会跑偏太多。
阅读完成 · 觉得有帮助?
咨询建站