能看会说的 Agent:语音交互与 Computer Use 这半年

3 分钟阅读
·

本文是「Agent 开发实践与思考」系列第 12 篇。系列目录:

给工单工具加语音入口时,我原以为要解决的是识别率和首包延迟。后来又在虚拟机里试了几天浏览器自动化,问题变了:模型不是不会理解任务,而是几乎所有系统都假定操作者是人。

人可以看屏幕、记住刚才点过哪里、遇到陌生页面临时判断一下;系统因此把很多能力藏在菜单、表格、弹窗和登录后的页面里。一个模型即使能看图、会说话,想完成「查完数据,填进表格,发给某个人」这样的任务,还是得穿过这一整套专为人准备的界面。

这才是 Computer Use 值得讨论的地方。它不是让模型学会像人一样移动鼠标,而是暴露出一个过渡期:Agent 已经能理解目标,软件世界却还没有普遍提供给 Agent 使用的操作面。

语音入口做完后,聊天框的边界更明显了

语音有两条常见路线。级联方案是 ASR 转文字、LLM 生成文字、TTS 合成语音;端到端方案则由模型直接接收和输出音频。前者每段都能替换、记录和排查,后者在部分模型中能保留更多语气和停顿信息,也可能更快,但中间转写、工具调用和审计能力要看具体接口。

我们最后用了级联。不是因为端到端不够好,而是工单场景必须说清楚发生了什么:用户原话是什么,转写结果是什么,系统根据什么上下文调用了什么能力,操作有没有成功。语音可以是输入,不能成为一条不可追溯的业务链路。

实际最费时间的是流式和打断。ASR 要持续给出中间结果;LLM 的第一个可播报句子要尽早交给 TTS;用户重新说话时,播放器必须清空缓存,正在生成的回复和未提交的动作也必须取消。

这里有一个很容易被忽略的反例。Agent 说「我现在帮你转给一线同学」,用户马上打断:「别转,先问我确认。」如果前端只停掉声音,后端仍把转单请求发出去了,那么这个系统的错误不在语音交互,而在它把一次对话当成一次无状态的文本生成。语音让这个问题更早暴露出来而已。

一次真正的请求需要有身份、任务编号、状态和取消语义。用户可以先用语音发起「把下午冲突的会议整理出来,给改期建议」,系统立即回复「我查完发到手机」,然后在后台继续查日历、生成草稿、发送通知。这样用户不必一直守在通话里,任务也不会因为网络短暂中断而消失。

因此我现在不把语音看作聊天框上的一个按钮。它是一个很自然的任务入口,也会迫使系统从「回答一轮」走向「接住一件事,跑完它,必要时回来找人」。

让模型点屏幕,反而说明屏幕不是答案

我在隔离虚拟机里试过网页检索填表和操作内部旧后台。基本循环很直白:截一张图,模型输出点击、输入、滚动,执行器操作页面,再截一张图。

大按钮和大输入框通常能完成。难的是那些人每天都觉得普通的细节:密集表格里相邻的操作项、遮住半边页面的浮层、没有文字的图标、灰掉但仍显示在列表里的按钮。模型点不到还能再试;点到相邻那行数据,往往已经做了错误操作。

截图的问题不只是坐标不准。浏览器本来就知道哪个元素是按钮、哪个控件可编辑、哪个选项已禁用,这些语义都在 DOM 和无障碍树里。截图把它们压成像素后,模型又要花一次推理把结构猜回来。让模型只看屏幕操作网页,相当于要求它绕开系统已有的结构化接口。

更麻烦的是验证。API 调用可以检查状态码、返回字段和幂等键;命令执行可以检查退出码、输出文件和 diff;屏幕操作常常只能看到一句「提交成功」,再让模型判断这个提示是否可信。几十步以后,等待时间、图像调用成本和错误概率一起累积。

所以我的结论不是「GUI 不可靠,别用」,而是把它放回正确的位置:GUI 是兼容层,不是 Agent 的主执行面。

有授权 API 时先调 API;没有 API 但能读 DOM 或无障碍树时,用元素语义定位;两者都没有,才退回截图、鼠标和键盘。涉及发送、删除、付款、发布或权限变更时,不论走哪条通道,都要有独立于模型的确认和校验。

这套顺序听上去保守,却能解释一个实际现象:很多浏览器自动化 Demo 看起来已经什么都能做,真正进业务后却只能处理最后那一段没有接口的缝隙。它的价值是覆盖空白,不是把已有的可靠接口替换成视觉猜测。

软件大多为人设计,不为 Agent 设计

把语音和 GUI 放在一起看,问题更清楚了。

今天的软件接口大致分两类。一类是给机器的:API、数据库、消息队列、命令行、文件格式。它们结构化、可组合,也可以自动校验。另一类是给人的:网页、App、桌面窗口、表单、菜单和通知。它们擅长降低人的学习成本,但把状态、权限和操作路径藏在视觉交互里。

业务系统过去优先建设第二类很合理,因为真正使用它的人是员工和用户。现在 Agent 开始代替人跨系统办事,缺口就出现了:模型理解「导出本月数据并更新分析表」不难,困难在于数据平台只提供一个网页,分析表又只有另一个网页,两个系统都没有让程序安全地表达这个动作的入口。

Computer Use 选择了最通用的解法:既然系统只给人留了入口,Agent 就暂时扮演人。这是有效的过渡方案,但不是终局。它会把每个系统的交互细节、页面变化、登录态和视觉误差,都变成 Agent 的负担。

真正对 Agent 友好的系统不一定先提供一个「AI 按钮」,而是把已有能力暴露成稳定、窄而可验证的操作接口:能列出资源,能读取状态,能提交变更,能拿到机器可读的失败原因。人仍然可以用漂亮的页面;Agent 不必为了同一件事再去理解页面。

CLI 为什么会重新变重要

这里有一个容易被忽略的中间层:命令行。

API 很理想,但现实中的系统不会突然都补齐 API。网页自动化覆盖面大,但可靠性和成本都差。CLI 恰好落在中间:它比 GUI 结构化得多,比专门 API 更容易临时接上,而且天然适合被模型组合。

上一篇关于 Coding Agent 的文章里,我把「文件系统 + 命令执行」看作通用 Agent 的最小工作台。当时说的是写代码,现在看,这个判断可以再往外推一步:CLI 不只是编程工具,它是 Agent 在尚未 Agent 化的软件世界里最实用的通用适配协议。

原因不在于命令行古老,而在于它有几个模型需要的性质。

它的输入输出是文本或文件,可以被保存、比较和重放;一次操作有退出码和标准错误,失败不是一张「看起来不对劲」的截图;多个命令可以组合为脚本;脚本又能被版本管理、审查、测试和复用。最重要的是,CLI 允许 Agent 在工具缺失时现场造工具。

比如旧配置平台只有网页。让模型反复点页面去导出几百条配置,既慢也无法确认每次导出的范围。更可行的路径是:先在受限环境里观察请求和页面结构,写一个一次性脚本抓取所需数据,导出为 JSON 或 CSV,再用另一个命令做行数、字段和日期范围校验。这个脚本未必值得变成正式产品,但它把一个只能由人操作的页面,临时变成了可重复调用、可验证的命令。

这和我在Agent 如何用代码完成推理、校验、适配与展示里写的「代码当适配器」是同一件事。Agent 不需要等平台团队提前把所有工具准备好。只要它有受控的文件系统、运行环境和命令执行能力,它可以为当前任务生成很薄的一层适配器:解析一个导出文件,包装一个内部接口,抓取一个页面,转换一种数据格式,或生成一个只读报表。

这里的关键不在「让模型随便跑 shell」。恰好相反,CLI 之所以适合做执行面,是因为它可以被严格约束:工作目录白名单、只读凭证、网络出口、命令类别、资源配额、超时和审批,都能在执行器里确定地控制。模型提出动作,执行环境决定动作是否被允许。

一个能长期替人办事的 Agent,应该像一台小型计算机

如果 Agent 只有聊天记录和一组函数调用,它很快会卡住。它需要的不只是更多工具,而是一块属于任务的工作环境。

我倾向于把它想成一台小型计算机,而不是一个更大的聊天窗口。它有一个工作目录,里面放任务输入、下载文件、临时脚本、草稿和结果;有一个进程环境,可以执行受限命令;有一份任务状态,知道自己已经完成哪一步、正在等待什么;还有一个事件入口,允许用户从语音、消息或定时任务继续补充、修改和取消。

例如用户晚上说:「把这周客户反馈里反复出现的问题整理出来,明早给我一页。」Agent 可以把原始数据、筛选脚本和来源链接放进工作目录,先产出草稿,再等到早上通知用户。凌晨用户补一句「不要融资新闻,重点看招聘和产品更新」,它修改的是仍在运行的任务条件,重新执行相关步骤,而不是把两句自然语言连同所有历史对话重新塞给模型猜一遍。

再比如用户要求把旧后台的数据导进分析表。任务环境里应留下下载的原文件、转换脚本、写入前后的校验结果和失败日志。这样即使最后需要人接手,接手的人看到的也不是一句「我已经处理完」,而是一组能检查的中间产物。

这也是为什么我不太认同把 Agent 的记忆简单等同于聊天历史。历史对话适合保留协商过程;事实、文件、脚本、任务状态和执行记录应该在工作区和状态库中保存。模型的上下文可以压缩,任务的证据不能只存在上下文里。

能做和该不该做是两回事

给 Agent 接上语音、命令和屏幕操作后,最容易发生的事是把「它做得到」误认为「可以让它自己做完」。这两件事差得很远。

例如,Agent 能从工单里读到客户信息,不代表它可以把这些信息发到外部;它能把邮件写出来,不代表它可以直接点发送;它能找到删除按钮,也不代表删除这一步该交给它。模型可以负责理解任务、补全参数和处理含糊输入,权限和审批仍然应该由业务系统执行。

实际落地时,我会先看操作有没有留下能核对的结果。发邮件后要拿到发送记录,写入数据后要拿到对象版本,网页导出后要检查下载到的文件。页面弹出一行「成功」或者模型说「已经完成」,都不能算结果。

任务也得能停。用户在语音里改口,未提交的动作应当取消;用户改了目标,原来的计划不该继续跑;要发出去、要删除、要改权限的步骤,系统应该停下来等确认。这样做会少一点「全自动」的感觉,但能把责任留在该负责的人手里。

临时脚本也是一样。一次性取数用完可以删掉;如果一个脚本开始被反复使用,就应该进版本管理,走 review。一个高频、关键的任务长期依赖网页自动化或临时脚本,说明系统仍缺一个正式接口。

收尾

工单语音入口最终上线的是流式 ASR、流式 TTS 和已有 Agent 逻辑的组合。用户最直接的反馈不是它的声音多自然,而是打断后它会不会真的停下、换一个指令后能不能接着办。这比参数指标更接近 Agent 进入真实工作流后的要求。

试玩屏幕操作带来的判断也类似。视觉能力当然重要,它让 Agent 能够进入那些没有接口的旧环境;但如果把它当成主路径,Agent 只是在模仿人使用一个本来就不适合机器使用的系统。

更值得投入的方向是给 Agent 一个受控的执行环境,用文件保存事实,用 CLI 和脚本接住临时需求,用结构化接口完成稳定动作,用 GUI 填补最后的空白。现有系统不会一夜之间变成面向 Agent 的系统,Agent 也不该等待所有系统改造完成。它可以先在这层环境里把碎片化的能力编排起来,同时把那些反复出现的人工界面任务,反推成下一批应该建设的机器接口。


583 字 · 64 段落
xi ming

Written by xi ming You should follow him on Github

评论与讨论