打开终端,敲下一行问题,等 Agent 思考,再把答案复制到编辑器——这是大多数人和 AI Agent 的日常。可一旦你手上正拿着螺丝刀、正在炒菜、正在操作设备,或者单纯觉得“聊天窗口”本身就是一层多余的中介,这种交互方式就立刻显得笨重。人类速度最快的输入方式永远是说话,而 AI Agent 的输出,最终也应当能以说话的方式回到你耳朵里。
Riffn 是 Hacker News 上出现的一个项目,标题非常直接:给 AI Agent 和本地模型加一条“即时语音链路”。这个词值得展开说。它不只是给聊天界面接一个语音转文字插件,而是把“说话”变成 Agent 的一个正式交互入口:你开口,Agent 回应,整个过程低延迟、自然、可打断,而且模型跑在你的机器上,数据不需要绕一圈云端。
这篇文章我会做三件事。第一,分析 Riffn 这类“语音 + Agent + 本地模型”产品到底解决了什么问题,和智能音箱、云语音助手有什么本质区别。第二,拆解一条语音链路的技术骨架:音频采集、语音识别、Agent 调度、本地模型推理、语音合成,每个环节各承担什么职责,哪里最容易卡住。第三,给出一套可复现的最小实现,用开源组件在自己的电脑上搭出这条链路,再配上验证方法、常见问题和工程建议。读完你可以判断:Riffn 的思路适不适合你的场景,以及如果要自己动手,第一步该做什么。
1. Riffn 真正解决的问题:交互接口,而不是语音插件
很多人在接触“给 Agent 加语音”这类产品时,第一反应是:这不就是把 ASR 和 TTS 接上吗?市面上语音助手一抓一大把,区别在哪?
区别在于交互链路的两端不同。传统的智能音箱,背后绑定的是某个固定的云端大模型,你能用的能力是厂商预设好的;云语音助手,语音识别和合成在云端完成,你只是把一段录音换成一个文本回答。而 Riffn 这类产品的核心变化是:语音只是入口,真正干活的是你本地的 AI Agent。Agent 可以调用工具、查数据库、控制设备、执行代码,而语音成为了它和人类之间的实时通道。
这是一个位置上的变化。语音不再是“另一个产品”,而是“Agent 的一个外设”。这意味着你可以完全用自然语言去操作你自己的 Agent 体系:让本地模型总结一份文档,让 Agent 查一下监控数据,让它提醒你某个编译任务的结果。所有交互都不需要你离开手头的工作,也不需要把数据交到第三方服务器。
为什么特别强调“本地模型”?这里有一个工程上的判断。语音交互对延迟非常敏感,人类在对话中能接受的停顿大约在几百毫秒到一两秒之间。云端大模型优势是能力强,但网络往返、排队、流式返回都不可控;本地模型在单机推理下虽然绝对速度不如云端集群,但延迟可控、断网可用、数据不出设备。对于语音这种高频、短句、追求即时反馈的交互场景,本地模型反而是更合理的选择。Riffn 把这两个词放在一起,本质上是在押注一个趋势:Agent 的个人化部署越来越普遍,而语音是这个趋势里最自然的操作界面。
什么人最应该关注这类项目?我认为有三类。第一类是正在做 Agent 应用的开发者,语音可能成为你产品差异化的关键能力。第二类是本地模型爱好者,玩过 Ollama、llama.cpp,但一直觉得“只能打字聊天”差点意思。第三类是做智能家居、桌面助手、硬件设备的工程师,语音是这类场景绕不开的交互方案。
2. 理解链路中的三个关键词:AI Agent、本地模型、语音链路
在展开实操之前,先把概念边界划清楚。这三个词单独看都不难,但组合在一起时常常被混淆。
AI Agent,不是简单的“会聊天的大模型”。Agent 的核心特征是有目标、有计划、能使用工具。它会根据你的指令拆解任务,决定调用哪些函数、读取哪些数据、以什么顺序执行,最后把结果整理成回答。普通模型只做“输入文本 → 输出文本”的映射,Agent 则在模型外面包了一层编排逻辑:工具注册、上下文管理、任务规划、结果校验。语音接入的是这整个编排层,而不是最底层的模型。
本地模型,指的是运行在你自己的电脑或服务器上的大模型,而不是通过 API 访问的云端模型。常见的运行方式有 Ollama、llama.cpp、vLLM 等。本地模型的优势是隐私、离线、成本可控,代价是模型参数规模受限于硬件,通常跑不了几百 B 的顶级模型。所以本地语音 Agent 的设计原则通常是“小模型 + 好调度”:模型不追求穷尽所有知识,而是把工具调用和本地数据利用好,让一个 7B 到 14B 的模型完成 90% 的日常任务。
语音链路,是一条完整的音频处理流水线。它至少包含四段:音频采集(麦克风、声卡驱动)、语音识别 ASR(把声音变成文字)、语音合成 TTS(把文字变回声音),以及隐藏在中间的 VAD 和流式处理。VAD 是语音活动检测,用来判断“人开始说话”和“人说完话”;没有它,系统不知道什么时候该停止录音。流式处理则决定了系统是“录完一整段再处理”还是“边说边处理”,这直接影响使用者感受到的延迟。
| 维度 | 传统云语音助手 | 聊天式 Agent | 语音 + 本地 Agent(Riffn 方向) |
|---|---|---|---|
| 交互入口 | 语音 | 键盘输入 | 语音 |
| 模型位置 | 厂商云端 | 云端 API 或本地 | 本地模型优先 |
| 数据隐私 | 音频和文本都经过云端 | 取决于模型部署位置 | 音频、文本均留在本机 |
| 延迟 | 受网络影响较大 | 打字慢但模型响应直接 | 可控、低延迟、支持打断 |
| 扩展能力 | 厂商预设技能 | 工具调用、代码执行 | Agent 工具链 + 语音入口 |
| 离线可用 | 几乎不可用 | 本地模型时可用 | 完全可用 |
用一句话总结这个表格:Riffn 不是在语音助手里塞了一个 Agent,而是在 Agent 前面加了一条语音链路,然后把模型部署的主动权完全交还给用户。
3. 架构拆解:一条语音链路从哪里开始,到哪里结束
理解了概念,接下来看系统设计。一条“语音 → Agent → 本地模型 → 语音”的链路,从声音进入麦克风到声音从扬声器出来,要经过六个环节。
音频采集。麦克风把模拟声音变成数字采样,常见采样率是 16kHz 或 48kHz,对 ASR 来说 16kHz 单声道通常够用。这个环节最容易被忽略的是设备选择和音量增益,采集到的音频信噪比直接决定下游识别质量。
VAD 与断句。系统需要知道“你开始说了”和“你说完了”。最简单的做法是固定时长录音,但真实产品必须用 VAD 检测语音端点,否则每个回合都会出现半句话或者尾巴被截断的问题。断句策略也影响上下文:一句话是一轮,还是等用户停顿 500 毫秒就切一轮,这需要根据场景调节。
语音识别 ASR。把音频转成文本。当前主流方案有 faster-whisper、Paraformer、FunASR 等。识别结果中的错别字会直接传给 Agent,所以 ASR 准确率是整个链路体验的底板。这里容易出现一个认知误差:觉得大模型能力强,ASR 错几个字没关系。实际上,语音场景里的 ASR 错误会被 Agent 放大,因为语义已经偏离了,后面再强的推理也救不回来。
Agent 调度。转写文本进入 Agent 层。这个环节做三件事:理解指令、决定是否调用工具、组织上下文。对语音场景来说,上下文管理尤其重要。一次会话可能包含多轮语音,每轮都带着历史对话发给模型,既要保证记忆连贯,又要控制 token 数量,避免把七个字的问题膨胀成整个对话历史的长度。
本地模型推理。Agent 决定好之后,调用本地模型完成生成。以 Ollama 为例,它通过 HTTP API 暴露服务,Agent 只需要按接口组装请求。模型大小、量化方式、上下文长度都直接影响这里的延迟和显存占用。
语音合成 TTS。把 Agent 的回答文本转成音频并播放。本地部署可以选择 Piper、ChatTTS 等,也可以调用边缘合成服务。实时场景下,流式 TTS 可以把首字延迟压到几百毫秒,用户听到的不是“整段回答播完”,而是“第一个音节很快就出来”。
把这个流程画成文字链路就是:
麦克风音频 → VAD 检测 → ASR 转写 → Agent 调度 → 本地模型推理 → TTS 合成 → 扬声器播放这个链路里真正的难点,不是某一个环节的单项技术,而是环节之间的衔接。ASR 什么时候把结果交给 Agent?是等整句话结束,还是边识别边送?Agent 在等待模型推理时,TTS 能不能提前把“我在处理”这类反馈播出来?用户中途打断时,系统怎么取消当前生成并重新开始?这些连接处的设计,决定了产品是“能用”还是“好用”。
从 Riffn 的标题里“instant”这个词可以推断,它的设计目标应该就是把这条链路的端到端延迟压到尽量低,让“即时语音连接”成为 Agent 交互的默认体验,而不是一个等待转圈的附加功能。
4. 环境准备与前置条件
先说明一点:Riffn 本身的安装方式、支持平台和具体依赖,请以项目仓库的最新说明为准。本节给出的是搭建这类语音 Agent 链路的通用前置条件,也是自己做最小验证时需要的环境。
硬件方面,最低配置是一台带麦克风的电脑,CPU 能跑动小尺寸模型即可。如果你计划跑 7B 以上的模型,建议有 8GB 以上显存的 GPU,或者至少 16GB 内存供 CPU 推理使用。语音识别模型 tiny、small 级别在 CPU 上也能用,只是速度稍有损失。
软件方面,推荐以下组合:
- 操作系统:Linux 或 macOS 均可,Windows 需要额外处理音频设备权限,建议优先在 Linux 上验证。
- Python 3.10 及以上版本,用于运行 ASR、VAD 和调度逻辑。
- Ollama,作为本地模型运行服务,它把模型下载、加载、推理封装成 HTTP API,是目前最省事的本地模型运行时。
- ffmpeg,音频处理的后备工具,很多 ASR 库在解析音频格式时需要它。
- 音频采集库 sounddevice 或 PyAudio,用于在 Python 中读取麦克风。
- ASR 引擎 faster-whisper,速度快、安装简单,支持 CPU/GPU 推理。
- TTS 引擎 edge-tts 或 Piper,前者调用微软边缘语音服务,后者可以完全本地部署。
版本号这里不写死,因为这类工具迭代很快。你可以用 pip 安装时查看最新版本,本文重点演示通用思路。环境变量方面,Linux 上需要确保当前用户有权限访问/dev/snd音频设备,否则录音会静默失败,这是新手最常遇到的第一道坎。
如果你只是想先感受“语音 + Agent”的交互,最省事的路径是:先装好 Ollama,拉一个中文对话模型,然后把它和你日常使用的语音识别、语音合成串起来。不要一上来追求多模态、实时流式,先跑通“录音 → 识别 → 模型回答 → 合成”这条最笨的四段式链路,再把工程细节逐个加上去。
5. 最小示例:自己搭一条「语音 → Agent → 本地模型 → 语音」链路
前面讲的是架构和准备,这一节给出一个可以直接运行的最小实现。它的定位不是生产级产品,而是用最少的代码让你理解这条链路的每个环节,并作为后续扩展的骨架。
5.1 准备 Ollama 并启动本地模型
先安装并启动 Ollama,拉取一个适合本地运行的对话模型。以 qwen2.5:7b 为例:
ollama serve另开一个终端,拉取模型并验证服务:
ollama pull qwen2.5:7b curl http://127.0.0.1:11434/api/tagscurl 命令返回 JSON 列表,能看到你拉取的模型信息,说明 Ollama 服务正常。这一步是后面所有调用能不能成功的前提,建议在继续之前先确认。
5.2 编写配置文件
项目根目录下创建config.yaml,把 ASR、Agent、TTS 三段的参数集中管理:
# config.yaml asr: model: small # tiny / small / medium,越小越快,越大越准 device: cpu # cpu 或 cuda compute_type: int8 # CPU 推荐 int8,GPU 可用 float16 language: zh agent: endpoint: http://127.0.0.1:11434 model: qwen2.5:7b system_prompt: "你是桌面语音助手。回答要简短、口语化,最多两句话。" tts: voice: zh-CN-XiaoxiaoNeural output_dir: outputs配置拆成独立文件,是为了让你后续切换模型、切换 TTS 音色时不需要改代码。工程上这叫配置与逻辑分离,小项目也值得从第一天养成这个习惯。
5.3 编写主程序
创建main.py,包含录音、识别、调用 Agent、合成语音四段逻辑:
# main.py import asyncio import wave from pathlib import Path import edge_tts import requests import sounddevice as sd from faster_whisper import WhisperModel SAMPLE_RATE = 16000 BLOCK_SECONDS = 4 # 初始化 ASR 模型,small 在 CPU 上是速度和精度比较均衡的选择 asr_model = WhisperModel("small", device="cpu", compute_type="int8") def record(audio_path: Path): print(">>> 开始录音 {} 秒,请说话...".format(BLOCK_SECONDS)) data = sd.rec( int(BLOCK_SECONDS * SAMPLE_RATE), samplerate=SAMPLE_RATE, channels=1, dtype="int16", ) sd.wait() with wave.open(str(audio_path), "wb") as f: f.setnchannels(1) f.setsampwidth(2) f.setframerate(SAMPLE_RATE) f.writeframes(data.tobytes()) def transcribe(audio_path: Path) -> str: segments, _info = asr_model.transcribe(str(audio_path), language="zh") return "".join(seg.text for seg in segments).strip() def call_agent(text: str) -> str: payload = { "model": "qwen2.5:7b", "messages": [ {"role": "system", "content": "你是桌面语音助手。回答要简短、口语化,最多两句话。"}, {"role": "user", "content": text}, ], "stream": False, } resp = requests.post( "http://127.0.0.1:11434/api/chat", json=payload, timeout=60, ) resp.raise_for_status() return resp.json()["message"]["content"] async def speak(text: str): out_dir = Path("outputs") out_dir.mkdir(exist_ok=True) out_path = out_dir / "response.mp3" await edge_tts.Communicate(text, "zh-CN-XiaoxiaoNeural").save(str(out_path)) print(">>> Agent 回复:", text) print(">>> 已保存到:", out_path) def main(): while True: try: audio_path = Path("input.wav") record(audio_path) text = transcribe(audio_path) if not text: print(">>> 没有识别到有效内容,重新开始") continue print(">>> 识别结果:", text) answer = call_agent(text) asyncio.run(speak(answer)) except KeyboardInterrupt: print(">>> 已退出") break if __name__ == "__main__": main()这段代码的逻辑很直白,但有四个地方值得留意。
第一,录音是固定 4 秒的整块录音,它不是真正的语音交互体验。真实产品里,这里应该换成 VAD 流式检测,检测到说话才开始录音,检测到停顿就结束。固定时长只是为了让链路先跑起来。
第二,WhisperModel的初始化放在模块顶层,因为模型加载比较慢,放在循环里会导致每次对话都要重新加载,完全不可用。
第三,调用 Agent 用的是 Ollama 的/api/chat接口,stream设置为false表示等模型完整生成后再返回。实时体验更好的是流式模式,模型每生成一个 token 就推送给客户端,TTS 可以边收边合成。这个改造留到后面的工程建议部分再讲。
第四,TTS 使用了 edge-tts,它会生成 mp3 文件而不是直接播放。你想听声音,可以用任意播放器打开outputs/response.mp3。如果要自动播放,可以加一行subprocess.run(["ffplay", str(out_path)]),但要注意播放会阻塞主流程。
5.4 以服务方式常驻运行
本地工具类项目很容易陷入“关掉终端就没了”的尴尬。如果想让语音链路作为常驻服务,可以写一个 systemd 单元:
# /etc/systemd/system/voice-bridge.service [Unit] Description=Voice Agent Bridge After=network.target ollama.service [Service] User=dev WorkingDirectory=/home/dev/voice-bridge ExecStart=/home/dev/voice-bridge/venv/bin/python main.py Restart=on-failure RestartSec=3 [Install] WantedBy=multi-user.target启用服务:
sudo systemctl daemon-reload sudo systemctl enable --now voice-bridge到这里,一条完整的“说话 → 本地 Agent 回答 → 语音返回”链路已经跑通。虽然简陋,但它包含了语音交互产品的全部核心环节,后续所有优化都是在这个骨架上做加减法。
6. 运行验证:怎么判断链路真的通了
链路涉及多个异步环节,失败的排查比成功更难。所以这里给出一个逐段验证的方法,每一步都有明确预期,任何一个环节出问题都能立刻定位。
第一步,验证 Ollama 服务。运行curl http://127.0.0.1:11434/api/tags,预期返回包含模型列表的 JSON。如果拒绝连接,检查ollama serve是否在运行。
第二步,验证麦克风录音。单独运行录音函数,检查生成的input.wav是否存在、文件大小是否合理。4 秒 16kHz 单声道 16bit 的 WAV 文件大约 128KB。如果文件只有几 KB,说明麦克风没有采集到数据。
第三步,验证 ASR 识别。对录音文件直接调用转写函数,预期得到一个非空字符串。如果返回为空,先用ffplay input.wav确认录音里确实有人声,再检查麦克风音量和识别语言参数。
第四步,验证 Agent 调用。可以用 curl 直接模拟:
curl http://127.0.0.1:11434/api/chat \ -H "Content-Type: application/json" \ -d '{"model":"qwen2.5:7b","messages":[{"role":"user","content":"用一句话介绍你自己"}],"stream":false}'预期返回{"message":{"content":"..."}}结构的 JSON。这一步能排除所有 Python 代码的问题,把范围缩小到模型服务本身。
第五步,验证 TTS 文件生成。检查outputs/response.mp3是否存在,播放是否能听到清晰人声。edge-tts 依赖网络服务,如果生成失败,大概率是网络或服务端限流问题。
所有环节都可以用一条命令启动后观察日志。我在代码里用>>>前缀打印每个阶段的结果,就是希望在链路断裂时,你能从最后一条日志往前倒推,而不是从头猜。
延迟是语音场景的另一个核心指标。你可以用time或 Python 的time.perf_counter()分别测量录音、ASR、Agent、TTS 四段耗时,画出哪一段占比最大。在 CPU 上跑small模型,ASR 通常是最容易成为瓶颈的环节;换tiny模型、改用int8量化、避开峰值负载,都可以明显改善。这个量化意识,比任何调优技巧都重要。
7. 常见问题与排查思路
把最容易遇到、也最容易让人放弃的问题集中列一下。这些问题我在不同语音项目中反复见过,很多不是技术难题,而是环境或配置的坑。
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 录音文件为空或几 KB | 麦克风权限未开 / 设备索引不对 | 用sounddevice.query_devices()查看当前默认输入设备 | 授予终端权限,设置device参数指定麦克风 |
| ASR 识别结果为空 | 音量太低、语言参数错误、ffmpeg 缺失 | 先听录音确认有人声,再单独跑转写 | 调高麦克风增益,检查 ffmpeg 安装,确认language="zh" |
| 连接 Ollama 被拒 | Ollama 服务未启动或端口不对 | curl http://127.0.0.1:11434/api/tags | 启动ollama serve,确认监听 11434 端口 |
| Agent 返回模型不存在错误 | 模型未下载或名字写错 | ollama list查看已拉取模型 | ollama pull qwen2.5:7b,核对配置文件中的模型名 |
| Agent 响应超时 | 模型过大、CPU 推理过慢 | 查看 Ollama 日志中的加载时间 | 切换更小模型、量化模型,或升级 GPU |
| TTS 生成失败 | edge-tts 依赖网络、音频设备不支持 mp3 | 单独测试 TTS 函数 | 更换本地 TTS 引擎 Piper,或检查网络 |
| 系统停顿很久才播报 | 整块录音 + 非流式推理叠加延迟 | 分环节计时,定位耗时大头 | 引入 VAD 提前断句,模型改用流式返回 |
| 程序启动即崩溃 | sounddevice 缺少后端库 | 查看导入错误信息 | Linux 安装libportaudio2,macOS 检查麦克风权限 |
一个通用的排查原则:把链路从中间断开,每次只验证一段。不要在主程序里同时调试麦克风和模型,那会让问题互相掩盖。先把 Agent 调用从语音链路里剥出来,用 curl 验证通,再拼回去。
另外,固定时长录音的断句问题,在演示代码里是刻意保留的“简化”。真实使用时,你会明显感到它很别扭:话说快了会被截断,停顿稍长又会录进大量空白。这个体验问题不是 bug,而是架构简化带来的必然结果,下一步优化就应该从这里开始。
8. 工程落地建议与安全边界
这个最小示例可以跑通,但离“可用”还有一段距离。如果你想把语音 Agent 链路做成真正的产品,下面几条建议值得优先考虑。
第一,把轮询式的“录音 → 识别 → 回答”改成事件驱动的流式架构。我的示例里,录音是固定 4 秒的阻塞操作,这在交互上是不可接受的。生产方案应当是:音频流持续进入,VAD 检测到人声后开始收集,检测到句末或停顿超过阈值就触发 ASR,ASR 结果流式进入 Agent,Agent 输出流式进入 TTS。整个链路应该是数据流,而不是一个接一个的阻塞函数。
第二,加入打断机制(barge-in)。语音交互中,用户经常在 Agent 还没说完时就开口插话。系统需要能识别“用户又开始说话了”,然后停止当前 TTS 播放,清空未执行的生成队列,重新开始一轮识别。没有打断机制的语音助手,体验形同收音机。
第三,认真设计上下文管理。语音对话天然是多轮会话,每次用户说“那后来呢”都依赖前面的语境。你要决定:多轮历史怎么压缩、工具调用结果是否放入对话、系统提示词占多少 token 预算。模型上下文窗口是有限的,语音助手又讲究低延迟,历史越长推理越慢,所以通常只保留最近几轮的关键信息,而不是全量携带。
第四,重视 Agent 工具调用的安全边界。语音入口天然比键盘输入更随意,用户说一句“帮我删除测试环境的数据”,Agent 可能会照做。这在本地开发环境问题不大,但一旦 Agent 能控制真实系统,就必须在工具层增加确认机制和权限校验。更稳妥的做法是:破坏性操作强制走二次确认,敏感命令落到白名单,Agent 能接触的系统接口保持最小暴露面。
第五,关注音频本身的隐私属性。语音比文本更敏感。虽然本地模型解决了推理环节的数据外泄,但你有三条需要注意:ASR 转写文本是否被日志记录、TTS 服务是否将文本发送到云端、麦克风采样是否被不小心写入调试文件。即使模型在本地,工程上仍然可能通过日志、遥测把隐私数据送出去,这个边界需要显式设计。
第六,建立可观测性。语音链路的性能问题经常是“感觉慢”,但说不清慢在哪。建议在每个环节记录耗时、输入输出摘要、错误码,至少能回答三个问题:上一轮端到端延迟多少?哪个环节最慢?失败发生在哪一段?日志是这套体系里成本最低、收益最直接的基础设施。
第七,准备好降级方案。本地模型如果因为资源占用而响应极慢,或 ASR 连续识别失败,系统应该能降级:比如先播一句“网络信号不好,请稍后再说”,而不是让用户对着沉默等待。降级逻辑在容错设计里往往被忽略,但在语音这种实时场景里,沉默比报错更致命。
安全方面再补充一句:如果 Riffn 或类似工具支持让 Agent 调用本地工具,那么在接入前,你应该先梳理 Agent 能触达的系统能力清单。凡是涉及修改、删除、执行、外发数据的操作,默认都应该被拦截或确认。这不仅是安全问题,也是产品信任度的问题——用户敢不敢把语音接到你的 Agent 上,取决于它在关键操作上是否足够克制。
9. 总结与后续学习方向
回到 Riffn 的标题本身。它提出的核心命题是:AI Agent 与本地模型之间,需要一条即时的语音链路作为默认交互方式。从技术上看,这不算颠覆性创新,ASR、Agent、本地模型、TTS 都是成熟组件;但从产品形态上看,它把交互重心从“文本聊天窗口”迁移到了“实时语音通道”,这个迁移会重新定义一批应用场景:桌面助手、开发辅助、智能家居、离线语音交互。
本文没有试图复刻 Riffn 的完整实现,而是把它背后的链路拆到最底层,并给出一条可以自己跑通的最小路径。你如果感兴趣,下一步可以做三件事:一是把固定录音改成 VAD 驱动的自动断句,这是体验提升最明显的一步;二是把 Agent 调用从非流式改成流式,并接入工具调用,让语音真正可以“指挥”Agent 干活;三是把 edge-tts 换成完全本地的 TTS 引擎,做到彻底离线。
最后提醒一句:这类项目最值得学习的地方,往往不在某个单点技术上,而在架构取舍。Riffn 把“即时”放在标题里,意味着它在这个链路的每一处都在和延迟做斗争。你在设计自己的语音 Agent 产品时,也应该把延迟预算从一开始就纳入考量,而不是等功能全部做完再回头优化。先跑通,再变快,最后才谈得上好用。
建议把文章收藏备用,尤其是第 5 节的可运行代码和第 7 节的排查表,动手实践时可以直接对照。语音和 Agent 的结合还在早期阶段,现在入场,正是时候。