1. 端侧语音 Agent 到底在解决什么问题
1.1 从“听懂话”到“办成事”的鸿沟
很多人第一次接触语音助手,体验都差不多:你说一句话,它给你回一段话。问天气、设闹钟、放音乐,这些它都能干,但一旦你想让它“帮我把上周跟张总开会提到的那个方案找出来,改一版发给李经理”,它就开始装傻。这不是语音识别不行,而是从“听懂话”到“办成事”之间,隔着一条巨大的工程鸿沟。
端侧语音 Agent 要解决的核心问题,就是让语音交互从“问答式”变成“任务式”。问答式只需要 ASR(语音识别)加 TTS(语音合成),中间塞一个意图分类就够了。任务式则完全不同:它需要理解上下文、拆解目标、调用工具、处理失败、确认结果,最后还要用自然语言把执行过程讲清楚。这一整套流程跑在端侧设备上,算力、内存、功耗、延迟全是硬约束。
我做过一个统计,在云端做语音 Agent,从用户说完到 Agent 开始执行动作,平均延迟可以控制在 800ms 以内,因为云端有充足的 GPU 和带宽。但同样的逻辑搬到端侧,光是模型加载就可能吃掉 2 秒,更别说多轮推理和工具调用了。所以端侧语音 Agent 的工程细节,本质上是在“能力”和“约束”之间找平衡。
1.2 端侧部署的硬约束与软优势
端侧部署的硬约束很明确:算力有限、内存有限、电量有限、存储有限。以目前主流的端侧芯片为例,NPU 算力大概在 10-40 TOPS 之间,内存 8-16GB,还要分给系统和其他应用。一个 7B 参数的模型,量化到 4bit 后大约占 3.5GB 内存,推理时还需要额外的 KV Cache 和中间激活值,实际占用可能到 5GB 以上。这意味着你不可能同时加载多个大模型。
但端侧也有云端比不了的优势。第一是隐私,语音数据不用上传,敏感信息留在本地。第二是延迟,省去了网络往返,本地推理的响应可以做到更稳定。第三是可用性,没网也能用,这对车载、户外、工业场景特别重要。第四是成本,不用为每次推理付云端费用,长期来看更划算。
所以端侧语音 Agent 的设计思路不是“把云端能力搬过来”,而是“在端侧约束下重新设计能力边界”。哪些任务必须本地做,哪些可以降级处理,哪些干脆不做,这些决策比模型选型更重要。
1.3 适合谁来参考这套工程细节
这篇文章适合三类人。第一类是正在做端侧 AI 应用的工程师,尤其是语音交互方向的,你们会看到很多和云端开发不一样的坑。第二类是做 Agent 框架的开发者,端侧的约束会逼着你重新思考 Agent 的架构设计,很多在云端理所当然的做法在端侧行不通。第三类是对语音交互产品感兴趣的产品经理,理解工程约束才能做出合理的需求取舍。
我不打算讲太多理论,重点放在“我实际怎么做”和“为什么这么做”。涉及模型选型、工具调用、状态管理、延迟优化、失败处理这些环节,我都会给出具体的参数和步骤。有些方案是我踩过坑之后总结的,有些是同行交流得来的,都会标明来源。
2. 整体架构设计与核心思路拆解
2.1 为什么端侧 Agent 不能照搬云端架构
云端 Agent 的典型架构是:用户输入 → 意图理解 → 任务规划 → 工具调用 → 结果生成 → 输出。每一层都可以用独立的大模型或服务来实现,层与层之间通过 API 通信,延迟不敏感,失败可以重试。但端侧完全不是这个逻辑。
端侧的第一个问题是模型加载。你不可能为每个环节加载一个独立模型,内存扛不住。所以端侧 Agent 必须是“单模型多任务”或者“小模型加规则”的混合架构。我的做法是:用一个 3B 左右的量化模型做核心推理,负责意图理解、任务拆解和结果生成;用规则引擎处理高频、确定性的任务,比如“打开空调”“调高音量”;用轻量级的分类模型做路由,决定当前请求走规则还是走模型。
第二个问题是状态管理。云端 Agent 可以把对话历史存在数据库里,每次请求带上完整上下文。端侧不行,内存有限,KV Cache 不能无限增长。我的方案是滑动窗口加摘要压缩:保留最近 5 轮完整对话,更早的对话压缩成一段摘要文本,随对话更新。摘要本身也用模型生成,但只在对话轮次达到阈值时触发,避免频繁推理。
第三个问题是工具调用。云端 Agent 可以调用任意 API,端侧只能调用本地能力,比如文件系统、通讯录、日历、传感器。而且工具调用的结果不能太大,否则会撑爆上下文。我的做法是给每个工具定义严格的输入输出格式,输出结果超过阈值就截断或摘要,确保上下文可控。
2.2 端侧语音 Agent 的分层架构
我实际用的架构分四层。最底层是语音层,负责唤醒词检测、VAD(语音活动检测)、ASR 和 TTS。这一层用专门的轻量模型,不占用主模型资源。唤醒词检测用 10 万参数左右的小模型,常驻内存;ASR 和 TTS 按需加载,用完释放。
第二层是理解层,负责把 ASR 输出的文本转成结构化意图。这一层用主模型加规则引擎。规则引擎处理高频命令,比如“打开XX”“关闭XX”“调高/调低XX”,匹配到就直接执行,不经过模型。匹配不到再走模型,模型输出 JSON 格式的意图和参数。
第三层是执行层,负责工具调用和任务执行。这一层维护一个工具注册表,每个工具定义名称、描述、参数 schema 和执行函数。模型输出的意图会在这里被路由到具体工具。执行结果返回给理解层,由模型生成自然语言回复。
第四层是状态层,负责对话历史、用户偏好、任务状态的管理。这一层不直接参与推理,但为其他层提供上下文。状态层的数据结构设计很关键,既要支持快速读写,又要控制内存占用。
2.3 模型选型:3B 还是 7B,量化到什么程度
模型选型是端侧 Agent 最纠结的环节。我试过 1.5B、3B、7B 三个量级的模型,量化到 4bit 和 8bit 都跑过。结论是:如果只做意图理解和简单任务拆解,1.5B 够用,但生成自然语言回复时明显生硬;3B 是甜点,意图理解准确率能到 90% 以上,回复也还算自然;7B 效果最好,但内存占用和推理延迟都上了一个台阶,只有在高端设备上才跑得动。
量化方面,4bit 量化后模型大小约为原始大小的 1/4,推理速度提升 30%-50%,但精度损失在 5%-10% 之间。8bit 量化精度损失小,但内存占用翻倍。我的选择是 4bit 量化加 LoRA 微调,用少量领域数据把精度补回来。微调数据大概 500-1000 条,覆盖高频意图和常见表达,训练在本地用 LoRA 跑几个小时就能完成。
具体参数上,我用的 3B 模型 4bit 量化后约 1.8GB,推理时 KV Cache 按 2048 上下文长度算,额外占 500MB 左右,总内存占用 2.3GB。在 8GB 内存的设备上,留给系统和其他应用还有 5GB 以上,比较安全。推理速度方面,NPU 加速下首 token 延迟约 300ms,后续 token 约 50ms/token,生成 50 个 token 的回复大约 2.8 秒。这个延迟在语音交互里可以接受,因为用户说完到听到回复,中间有 ASR 和 TTS 的时间,总延迟控制在 3-4 秒。
2.4 工具调用的设计原则:少而精,快而稳
端侧工具调用和云端最大的区别是:云端可以调几百个 API,端侧只能调十几个本地能力。所以工具设计要“少而精”。我实际注册的工具只有 12 个:打开/关闭应用、调节音量、查询天气、设置闹钟、创建日历事件、发送消息、查询通讯录、播放音乐、暂停播放、查询电量、查询时间、执行快捷指令。
每个工具的定义要“快而稳”。快是指执行时间短,不能有阻塞操作;稳是指失败率低,不能依赖外部服务。比如查询天气,端侧不能直接调天气 API,而是读本地缓存的天气数据,缓存由后台服务定期更新。发送消息也是,先存到本地发件箱,由后台服务异步发送,Agent 只负责写入。
工具的参数 schema 要严格定义,用 JSON Schema 描述,模型输出必须符合 schema 才能执行。不符合的让模型重新生成,最多重试 2 次,还不行就返回“我没理解清楚,你能再说一遍吗”。这个重试机制很重要,端侧模型能力有限,一次生成正确的概率大概 85%,重试一次能到 95% 以上。
3. 核心细节解析与实操要点
3.1 唤醒词与 VAD:端侧语音的第一道门槛
唤醒词检测是端侧语音 Agent 的入口,也是最容易被低估的环节。很多人觉得唤醒词就是“小爱同学”“Hey Siri”这种,随便找个开源模型就行。但实际做下来,唤醒词检测的误唤醒率和漏唤醒率直接决定用户体验。误唤醒多了,用户觉得设备“神经质”;漏唤醒多了,用户觉得“叫不动”。
我用的方案是两级检测:第一级用能量检测加过零率做粗筛,判断当前音频帧是否可能是人声;第二级用轻量级神经网络做精筛,判断是否包含唤醒词。粗筛的计算量极小,可以常驻运行;精筛只在粗筛触发时运行,节省算力。唤醒词模型我用的是 10 万参数左右的 CNN,量化到 8bit 后只有 100KB 左右,常驻内存无压力。
VAD 是语音活动检测,用来判断用户什么时候说完。端侧 VAD 不能用太复杂的模型,我用的是基于能量和谱熵的经典算法,加上一个小的神经网络做后处理。参数上,静音阈值设为 -35dB,静音持续时间超过 800ms 就认为用户说完了。这个 800ms 是实测出来的,太短会截断用户的话,太长会让用户觉得反应慢。
注意:唤醒词和 VAD 的模型要分开训练,不要用一个模型同时做两件事。唤醒词要求高召回,VAD 要求高准确,两者的优化目标不一样。
3.2 ASR 与 TTS:端侧语音的输入输出通道
ASR 在端侧的选择比云端少很多。云端可以用 Whisper Large,端侧只能用流式小模型。我试过几种方案,最后用的是基于 Conformer 的流式 ASR,参数量 20M 左右,量化后 20MB,推理延迟在 200ms 以内。识别准确率在安静环境下能到 95%,嘈杂环境下降到 85% 左右。
ASR 的关键参数是采样率和帧长。采样率用 16kHz,帧长 25ms,帧移 10ms,这是语音识别的标准配置。流式识别要处理“部分结果”和“最终结果”,部分结果用于实时显示,最终结果用于后续处理。我的做法是:部分结果只显示不处理,最终结果才送给理解层。这样可以避免模型被不完整的文本干扰。
TTS 在端侧的选择也不多。云端可以用 Azure TTS、Google TTS,端侧只能用本地 TTS 引擎。我用的是基于 VITS 的轻量 TTS,参数量 15M 左右,量化后 15MB,合成 1 秒语音大约需要 100ms。音质肯定不如云端,但胜在离线可用、延迟低。
TTS 的关键参数是语速和音调。语速默认 1.0,用户可以在设置里调 0.8-1.5。音调默认 1.0,调整范围 0.8-1.2。这两个参数对用户体验影响很大,语速太快用户听不清,太慢用户觉得拖沓。我的经验是默认语速 1.1 比较合适,比正常语速稍快一点,用户感觉更利落。
3.3 意图理解:规则引擎与模型的配合
意图理解是端侧 Agent 的核心环节,也是最容易出问题的地方。纯规则引擎覆盖不了所有表达,纯模型又太慢太耗资源。我的方案是规则优先、模型兜底。
规则引擎处理高频命令,用正则表达式和关键词匹配。比如“打开XX”“关闭XX”“调高XX”“调低XX”“查询XX”“设置XX”,这些都有固定的句式,规则匹配准确率接近 100%。规则引擎的响应时间在 10ms 以内,几乎无感。
模型处理规则匹配不到的请求,比如“帮我把上周跟张总开会提到的那个方案找出来”。模型输出 JSON 格式的意图和参数,比如{"intent": "search_file", "params": {"keyword": "方案", "person": "张总", "time": "上周"}}。模型推理时间在 500ms 左右,加上后续的工具调用和结果生成,总延迟在 2-3 秒。
规则和模型的切换逻辑是:先走规则,规则匹配到就直接执行;匹配不到再走模型。规则匹配的阈值要调好,太松会误匹配,太紧会漏匹配。我的做法是用 F1 分数来调阈值,在测试集上跑到 0.95 以上才上线。
提示:规则引擎的规则要定期更新,根据用户实际使用的日志来补充新规则。我一般每两周更新一次,把高频的模型请求转成规则,降低延迟和算力消耗。
3.4 上下文管理:滑动窗口加摘要压缩
端侧 Agent 的上下文管理是个技术活。云端可以把整个对话历史塞进 prompt,端侧不行,内存和算力都扛不住。我的方案是滑动窗口加摘要压缩。
滑动窗口保留最近 5 轮完整对话,每轮包含用户输入和 Agent 回复。5 轮之外的对话压缩成摘要,摘要长度控制在 200 字以内。摘要用模型生成,触发条件是对话轮次达到 10 轮,或者用户主动说“总结一下”。
摘要的生成 prompt 是这样的:“请用 200 字以内总结以下对话的关键信息,包括用户的目标、已执行的操作、待办事项。”这个 prompt 我调了很多次,关键是“关键信息”和“待办事项”这两个词,能让摘要保留对后续对话有用的内容。
上下文的总长度控制在 2048 token 以内,其中滑动窗口占 1500 token 左右,摘要占 300 token 左右,系统 prompt 占 200 token 左右。这个分配是实测出来的,超过 2048 token 推理速度明显下降,低于 1024 token 上下文又不够用。
3.5 工具调用的参数校验与失败重试
工具调用是 Agent “办成事”的关键,也是最容易失败的地方。端侧模型能力有限,输出的参数经常不符合 schema。我的做法是严格校验加有限重试。
参数校验用 JSON Schema,每个工具定义自己的 schema,模型输出必须通过校验才能执行。校验失败的常见原因有:参数缺失、参数类型错误、参数值超出范围。比如“设置闹钟”工具需要time和label两个参数,模型可能只输出time,或者把time输出成“明天早上”这种自然语言而不是 ISO 时间格式。
校验失败后,把错误信息拼回 prompt,让模型重新生成。重试最多 2 次,还不行就返回“我没理解清楚,你能再说一遍吗”。这个重试机制能把工具调用的成功率从 85% 提升到 95% 以上。
注意:重试时要带上原始用户输入和错误信息,不要只带错误信息,否则模型不知道要重新生成什么。
4. 实操过程与核心环节实现
4.1 环境准备与依赖安装
端侧开发环境比云端复杂,因为要交叉编译、要适配不同芯片。我用的开发板是瑞芯微 RK3588,NPU 算力 6 TOPS,内存 8GB,跑 3B 模型够用。开发环境是 Ubuntu 22.04,交叉编译工具链用官方提供的。
依赖安装分三部分。第一部分是推理框架,我用的是 RKNN,瑞芯微官方的 NPU 推理框架,支持 ONNX 和 PyTorch 模型转换。安装命令是pip install rknn-toolkit2,注意版本要和固件匹配,不匹配会报错。
第二部分是语音处理库,ASR 和 TTS 我用的是 sherpa-onnx,支持流式识别和合成,端侧优化做得不错。安装命令是pip install sherpa-onnx,模型文件需要单独下载。
第三部分是 Agent 框架,我没有用 LangChain 这种重型框架,而是自己写了一个轻量级的调度器,大概 500 行代码。核心是一个状态机,管理对话状态和工具调用。自己写的好处是可控,端侧不需要那么多抽象层。
# 安装推理框架 pip install rknn-toolkit2==1.5.0 # 安装语音处理库 pip install sherpa-onnx==1.9.0 # 下载模型文件 wget https://example.com/models/asr-streaming.tar.gz wget https://example.com/models/tts-vits.tar.gz wget https://example.com/models/llm-3b-4bit.rknn4.2 模型转换与量化实操
模型转换是端侧部署最麻烦的环节。PyTorch 模型不能直接在 NPU 上跑,要先转成 ONNX,再转成 RKNN。转换过程中要注意算子支持情况,有些算子 NPU 不支持,需要替换或回退到 CPU。
量化用 RKNN 自带的量化工具,支持 4bit 和 8bit。4bit 量化的命令是rknn.build(do_quantization=True, dataset='calibration.txt', quantized_dtype='w4a16')。w4a16表示权重 4bit、激活 16bit,这是精度和速度的平衡点。
校准数据集很重要,要用真实场景的数据,不能随便找几条。我用了 200 条语音转文本的样本,覆盖不同口音、不同语速、不同环境噪声。校准数据集的质量直接决定量化后的精度,这一步不能省。
转换完成后要验证精度。我的验证方法是:在测试集上跑原始模型和量化模型,对比意图理解的准确率。如果下降超过 5%,就要调整量化参数或增加校准数据。实测下来,3B 模型 4bit 量化后准确率下降在 3% 左右,可以接受。
4.3 语音链路的联调与延迟优化
语音链路的联调是最耗时的环节,因为涉及多个模块的配合。我的联调顺序是:先单独调通 ASR,再单独调通 TTS,再调通唤醒词和 VAD,最后串起来调。
延迟优化的关键是找到瓶颈。我用打点计时的方式,在每个环节加时间戳,记录耗时。实测下来,唤醒词检测 50ms,VAD 800ms(等待用户说完),ASR 200ms,意图理解 500ms,工具调用 100ms,结果生成 800ms,TTS 100ms,总延迟约 2.5 秒。其中 VAD 的 800ms 是固定等待,不算在响应延迟里,实际响应延迟约 1.7 秒。
优化空间主要在意图理解和结果生成。意图理解的 500ms 可以通过规则引擎分流来降低,高频命令走规则只要 10ms。结果生成的 800ms 可以通过流式输出来降低首字延迟,用户听到第一个字的时间可以提前到 300ms 左右。
提示:流式输出要配合 TTS 的流式合成,否则生成一段合成一段,延迟反而更高。sherpa-onnx 支持流式 TTS,可以边生成边合成。
4.4 工具调用的完整实现示例
工具调用的实现分三步:定义工具、注册工具、调用工具。我以“设置闹钟”为例,展示完整实现。
第一步定义工具,用 JSON Schema 描述参数:
alarm_tool = { "name": "set_alarm", "description": "设置闹钟", "parameters": { "type": "object", "properties": { "time": { "type": "string", "description": "闹钟时间,ISO 8601 格式,如 2024-01-01T08:00:00" }, "label": { "type": "string", "description": "闹钟标签,如 起床、开会" } }, "required": ["time"] } }第二步注册工具,把工具加入工具注册表:
tool_registry = {} tool_registry["set_alarm"] = { "schema": alarm_tool, "handler": set_alarm_handler }第三步调用工具,模型输出意图后,路由到对应的 handler:
def set_alarm_handler(params): time = params["time"] label = params.get("label", "闹钟") # 调用系统 API 设置闹钟 system_api.set_alarm(time, label) return f"已设置{time}的闹钟,标签是{label}"这个实现的关键是参数校验。在调用 handler 之前,先用 JSON Schema 校验参数,不通过就重试。校验用jsonschema库,一行代码搞定。
4.5 状态管理与持久化方案
状态管理分内存状态和持久化状态。内存状态包括当前对话上下文、当前任务状态、工具调用结果,这些数据在会话结束后可以丢弃。持久化状态包括用户偏好、常用联系人、历史任务记录,这些数据要存到本地数据库。
我用 SQLite 做持久化,轻量、无需额外服务、支持事务。表结构设计了三张表:user_preference存用户偏好,contact存常用联系人,task_history存历史任务记录。每张表的字段都尽量精简,避免占用太多存储空间。
内存状态用 Python 的 dataclass 管理,定义一个ConversationState类,包含history、current_task、tool_results三个字段。history是滑动窗口加摘要,current_task是当前正在执行的任务,tool_results是最近一次工具调用的结果。
状态更新的时机很关键。用户输入后更新history,模型输出意图后更新current_task,工具调用后更新tool_results。每次更新都要检查内存占用,超过阈值就触发摘要压缩。
5. 常见问题与排查技巧实录
5.1 唤醒词误唤醒与漏唤醒的排查
误唤醒和漏唤醒是唤醒词检测的两大难题。误唤醒的常见原因是环境噪声和相似发音。我遇到过电视里说“小爱同学”导致设备被唤醒的情况,也遇到过用户说“小艾”被误唤醒的情况。
排查误唤醒的方法是看日志。每次唤醒都记录音频片段和置信度,置信度低于阈值的标记为可疑。我一般把阈值设在 0.9,低于 0.9 的不唤醒。这个阈值是调出来的,太低误唤醒多,太高漏唤醒多。
漏唤醒的常见原因是用户发音不清或距离太远。排查方法是让用户在不同距离、不同角度测试,记录唤醒率。实测下来,3 米以内唤醒率 95% 以上,3-5 米下降到 80%,5 米以上基本叫不动。这是硬件限制,软件优化空间有限。
注意:唤醒词不要选太常见的词,比如“你好”“嗨”这种,误唤醒率会很高。选一个三到四个音节的词,误唤醒率会低很多。
5.2 ASR 识别错误的常见原因与修正
ASR 识别错误的原因很多,常见的有:口音、语速、环境噪声、专业术语。我遇到过用户说“打开空调”被识别成“打开空条”的情况,也遇到过说“设置闹钟”被识别成“设置闹钟”的情况(同音不同字)。
修正 ASR 错误的方法有三种。第一种是加热词,把高频词汇加入 ASR 的热词表,提高识别准确率。第二种是加语言模型,用领域数据微调 ASR 的语言模型。第三种是后处理,用规则或模型修正明显的错误。
我主要用热词加后处理。热词表大概 500 个词,覆盖设备控制、常用应用、联系人姓名。后处理用规则修正同音字,比如“空条”改成“空调”,“闹钟”改成“闹钟”。规则不多,大概 50 条,但能解决 80% 的常见错误。
5.3 意图理解失败的排查思路
意图理解失败的表现是:模型输出的意图不对,或者参数不对。排查思路是:先看 ASR 输出对不对,再看模型输入对不对,最后看模型输出对不对。
ASR 输出不对,说明问题在语音层,要调 ASR。模型输入不对,说明 prompt 有问题,要调 prompt。模型输出不对,说明模型能力不够,要换模型或微调。
我遇到过模型把“打开空调”理解成“打开空调”(意图对但参数不对)的情况,原因是模型没有正确提取“空调”这个参数。解决办法是在 prompt 里加 few-shot 示例,给几个正确的输出格式,模型就能学会。
提示:few-shot 示例要覆盖常见场景,不要只给一两个。我一般给 5-10 个示例,覆盖不同意图和不同参数组合。
5.4 工具调用超时与失败的应急处理
工具调用超时和失败是端侧 Agent 的常见问题。超时的原因可能是工具执行时间太长,或者系统资源被占用。失败的原因可能是参数不对,或者工具本身有问题。
应急处理的策略是:超时设 2 秒,超过 2 秒就中断,返回“操作超时,请稍后再试”。失败重试 2 次,还失败就返回“操作失败,请检查后重试”。同时记录失败日志,方便后续排查。
我遇到过设置闹钟失败的情况,原因是时间格式不对。模型输出的是“明天早上八点”,而不是 ISO 格式。解决办法是在 prompt 里明确要求输出 ISO 格式,并加 few-shot 示例。改完之后失败率从 15% 降到 2% 以下。
5.5 常见问题速查表
| 问题现象 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| 误唤醒频繁 | 唤醒阈值太低 | 查看唤醒日志置信度 | 提高阈值到 0.9 |
| 漏唤醒严重 | 用户距离太远 | 不同距离测试唤醒率 | 建议用户靠近设备 |
| ASR 识别错误 | 口音或噪声 | 对比音频和识别结果 | 加热词或后处理 |
| 意图理解错误 | prompt 不清晰 | 检查模型输入输出 | 加 few-shot 示例 |
| 工具调用超时 | 工具执行太慢 | 打点计时找瓶颈 | 优化工具或设超时 |
| 工具调用失败 | 参数格式不对 | 检查参数 schema | 加校验和重试 |
| 响应延迟高 | 模型推理慢 | 打点计时找瓶颈 | 规则分流或流式输出 |
| 内存占用高 | 上下文太长 | 检查 token 数量 | 滑动窗口加摘要 |
这张表是我实际排查问题时总结的,覆盖了 80% 的常见问题。遇到新问题先查表,查不到再深入分析。
6. 端侧语音 Agent 的边界与取舍
6.1 哪些任务适合端侧,哪些不适合
端侧语音 Agent 不是万能的,有些任务适合端侧,有些适合云端,有些干脆不适合语音交互。
适合端侧的任务有三个特征:高频、简单、隐私敏感。比如设备控制、闹钟设置、音量调节,这些任务高频、逻辑简单、不涉及隐私,端侧做最合适。查询天气、播放音乐、发送消息,这些任务中等频率、逻辑中等、涉及部分隐私,端侧做也可以,但需要缓存数据。
不适合端侧的任务也有三个特征:低频、复杂、需要大量外部数据。比如“帮我规划一个三天的旅行行程”,这种任务需要查航班、查酒店、查景点、算预算,端侧做不了,必须云端。再比如“帮我写一份项目报告”,这种任务需要大量上下文和生成能力,端侧模型扛不住。
我的做法是:端侧做不了的任务,明确告诉用户“这个我需要联网处理”,然后走云端。不要硬撑,硬撑的结果是体验更差。
6.2 端云协同的设计模式
端云协同是端侧 Agent 的必然选择。我的设计模式是:端侧优先,云端兜底。端侧能做的端侧做,端侧做不了的走云端。端侧和云端的切换对用户透明,用户不需要知道当前是端侧还是云端。
切换的逻辑是:意图理解后,判断任务复杂度。简单任务走端侧,复杂任务走云端。判断标准是工具数量和上下文长度。工具数量超过 3 个,或者上下文长度超过 2048 token,就走云端。
端云协同的难点是状态同步。端侧的对话历史要同步到云端,云端的执行结果要同步回端侧。我的做法是用一个轻量级的同步协议,只同步关键状态,不同步完整历史。关键状态包括当前任务、已执行操作、待办事项,这些数据量小,同步快。
6.3 隐私与安全的工程考量
端侧 Agent 的隐私优势是相对的,不是绝对的。语音数据在端侧处理,不上传,这是隐私优势。但端侧 Agent 要访问通讯录、日历、文件系统,这些数据如果被恶意利用,隐私风险更大。
我的安全措施有三层。第一层是权限控制,每个工具定义需要的权限,用户授权后才能调用。第二层是数据隔离,Agent 只能访问授权的数据,不能访问其他应用的数据。第三层是审计日志,每次工具调用都记录日志,用户可以查看和删除。
注意:审计日志要加密存储,不能明文存。我用的 AES-256 加密,密钥存在安全芯片里,软件层拿不到。
6.4 后续扩展方向与个人经验
端侧语音 Agent 还在快速演进,后续有几个方向值得关注。第一个是多模态,加入视觉能力,让 Agent 能“看”到屏幕内容,理解更准确。第二个是个性化,用用户数据微调模型,让 Agent 更懂用户。第三个是主动服务,Agent 根据用户习惯主动推荐或执行任务,而不是等用户说。
我个人在实际操作中的体会是:端侧 Agent 的瓶颈不在模型,而在工程。模型能力每年都在提升,但工程细节的积累需要时间。唤醒词调优、ASR 纠错、意图理解、工具调用、状态管理,每个环节都有大量细节要打磨。把这些细节做好,比换一个更大的模型效果更明显。
最后分享一个小技巧:端侧 Agent 的日志要详细,每个环节都打点,包括时间戳、输入、输出、耗时。这些日志是排查问题的唯一依据,没有日志就是盲人摸象。我一般把日志存在本地,保留最近 7 天,方便回溯。