1. 从「只会听」到「会看画面」:语音 Agent 的下一层能力

RTC 推流加上多模态 LLM,能拼出一个会看画面的语音 Agent:摄像头画面经实时音视频通道推上去,多模态大模型实时理解画面内容,再驱动语音对话把「它看到了什么」说出来。这套东西适合谁?想快速验证多模态语音交互的产品同学、做智能硬件带摄像头的嵌入式团队、以及想给现有语音助手加一双「眼睛」的开发者。我这次用 TaoToken 的统一 Key 把模型接入层收拢到一处,配合 RTC 推流链路,跑通了一个对着摄像头提问、它能用语音描述眼前画面的 Agent。

整条链路拆开看并不复杂:前端拿麦克风和摄像头两路 track,通过 RTC 推流到频道;云端把音频转文字、把视频帧打包成图片;多模态 LLM 同时吃文本和图像,输出回复;TTS 再把回复转成语音推回前端。真正容易卡住的地方在于模型接入——STT、LLM、TTS 如果各用一家厂商,Key 管理、额度、计费、切换成本会迅速堆起来。TaoToken 的价值就在这里:一个统一 Key 覆盖多家模型,配置改一行就能换模型,联调阶段不用来回申请账号。

下面我会给出可复制的 config.toml 与 settings.json 配置骨架、TaoToken 统一 Key 的接入步骤,以及端到端联调的验证动作。技术部分占大头,配置和排障都会写清楚,你可以直接照着改。

2. TaoToken 前置:统一 Key 与接入地址

TaoToken 是一个模型接入聚合层,把不同厂商的模型能力收敛到一套 API 和一份 Key 上。对多模态语音 Agent 这种要同时用到语音识别、多模态理解、语音合成的场景,统一 Key 能省掉大量账号和额度管理的工作。

接入信息如下:

  • 官网:https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=
  • API 基址:https://taotoken.net/api
  • 模型对话入口:https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=models
  • API Keys 管理:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=api_keys
  • 接入文档:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=doc
  • Coding Plan(长期编码/Agent 场景):https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=coding_plan
  • 控制台:https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=console

操作顺序建议这样:先进控制台创建项目,再到 API Keys 页面生成一把 Key,然后把它写进本地环境变量。Key 只放服务端,不要塞进前端代码或提交到仓库。多模态模型的选择可以在模型对话页面先试,确认能正确描述图片后再写进配置。

注意:API 基址统一用 https://taotoken.net/api,不要带查询参数。Key 通过 Authorization: Bearer <你的Key> 传递。

3. 可复制配置:config.toml 与 settings.json 骨架

这一章是全文的核心。我把配置拆成两份:config.toml 管服务端链路(RTC、模型、轮次检测),settings.json 管前端推流和页面行为。两份都给了完整字段和注释,改完就能用。

3.1 config.toml:服务端链路配置

# config.toml —— 服务端语音 Agent 链路配置

[rtc]
app_id = "你的RTC_APP_ID"
app_certificate = "你的RTC_APP_CERTIFICATE"
channel = "vision-agent-demo"
uid = 1001
# 推流角色:publisher 负责推麦克风+摄像头
role = "publisher"

[stt]
provider = "taotoken"
model = "whisper-large-v3"
language = "zh"
# 语音识别走 TaoToken 统一入口
base_url = "https://taotoken.net/api"
api_key_env = "TAOTOKEN_API_KEY"

[llm]
provider = "taotoken"
# 多模态模型,必须支持 image 输入
model = "gpt-4o-mini"
base_url = "https://taotoken.net/api"
api_key_env = "TAOTOKEN_API_KEY"
# 关键:声明输入模态包含图像
input_modalities = ["text", "image"]
system_prompt = """
你是一个会看画面的语音助手。用户会通过摄像头让你看到实时画面,
请根据最新一帧图像,用简短口语化的中文描述你看到的内容,
控制在两句话以内,适合语音播报。
"""

[tts]
provider = "taotoken"
model = "tts-1"
voice = "alloy"
base_url = "https://taotoken.net/api"
api_key_env = "TAOTOKEN_API_KEY"

[turn_detection]
# 轮次检测:判断用户是否说完、能否被打断
mode = "vad"
silence_duration_ms = 480
interruptible = true

[vision]
# 摄像头帧采样与压缩,控制多模态请求体积
enabled = true
frame_interval_ms = 1000
max_width = 640
image_format = "jpeg"
quality = 70

几个字段值得单独说。input_modalities = ["text", "image"] 是让模型「长眼睛」的开关,缺了它模型只会收到文字。frame_interval_ms = 1000 表示每秒抽一帧,太密会推高多模态请求量和延迟,太疏画面变化跟不上,1 秒是对话场景比较稳的起点。silence_duration_ms = 480 决定用户停顿多久算说完,调小更灵敏但容易误判,调大更稳但打断变迟钝。

3.2 settings.json:前端推流与页面配置

{
  "rtc": {
    "appId": "你的RTC_APP_ID",
    "channel": "vision-agent-demo",
    "token": "",
    "uid": 2001
  },
  "media": {
    "publishMicrophone": true,
    "publishCamera": true,
    "cameraResolution": "640x480",
    "frameRate": 15,
    "echoCancellation": true,
    "noiseSuppression": true
  },
  "agent": {
    "backendUrl": "http://localhost:8000",
    "autoStart": false,
    "greeting": "你好,我已经打开摄像头,你可以问我看到了什么。"
  },
  "ui": {
    "showLocalVideo": true,
    "showTranscript": true,
    "language": "zh-CN"
  }
}

publishCamera: true 和 publishMicrophone: true 是两路 track 都推的关键,少推一路画面就进不去。cameraResolution 用 640x480 就够多模态理解用,分辨率越高帧体积越大、上传越慢。echoCancellation 和 noiseSuppression 建议开着,语音 Agent 最怕自己说的话被麦克风收回去形成回环。

3.3 环境变量与 Key 注入

# .env.local —— 不要提交到仓库
TAOTOKEN_API_KEY=sk-你的TaoToken密钥
RTC_APP_ID=你的RTC_APP_ID
RTC_APP_CERTIFICATE=你的RTC_APP_CERTIFICATE

服务端启动时读取这些变量,配置里用 api_key_env 引用变量名而不是写死 Key。这样换 Key 只改环境变量,配置不动。

4. 端到端联调:验证请求与成功结果

配置写完,接下来是把它跑起来并验证。我按「先单点、再串联」的顺序来,每一步都有明确的成功标志。

4.1 先验证 TaoToken 多模态接口通不通

在接 RTC 之前,先用一张图确认多模态模型能正常返回。这一步能排掉大部分 Key 和模型名的问题。

curl -X POST https://taotoken.net/api/v1/chat/completions \
  -H "Authorization: Bearer $TAOTOKEN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-4o-mini",
    "messages": [
      {
        "role": "user",
        "content": [
          {"type": "text", "text": "用一句话描述这张图里有什么"},
          {"type": "image_url", "image_url": {"url": "https://example.com/test.jpg"}}
        ]
      }
    ]
  }'

成功标志:返回 JSON 里 choices[0].message.content 是一句对图片的描述。如果报 401,是 Key 问题;报模型不存在,是模型名写错;报不支持 image,是模型选错了,换支持多模态的型号。

4.2 启动服务端与前端

# 终端 1:服务端
cd server
python -m venv venv
source venv/bin/activate        # Windows 用 venv/Scripts/activate
pip install -r requirements.txt
python src/server.py

# 终端 2:前端
cd web
npm install
npm run dev

服务端起来后日志里应该能看到 RTC 加入频道、STT/LLM/TTS 三段初始化完成。前端打开 http://localhost:3000,页面出现本地摄像头预览,说明推流 track 拿到了。

4.3 端到端验证动作

点开始对话,允许摄像头和麦克风权限,然后按这个顺序验证:

第一,对着摄像头说「你看到了什么」,观察是否在 1 到 2 秒内听到语音回复。成功标志是回复内容和你眼前的画面一致,比如「我看到一个人坐在桌前,桌上有个杯子」。

第二,把摄像头对准另一个物体,再说一次同样的问题,看回复是否跟着画面变化。这一步验证的是多模态帧确实在持续更新,而不是只取了第一帧。

第三,在 Agent 说话中途插话,看它是否停下来听你说。这一步验证 turn_detection 的打断能力。

第四,看服务端日志里每次请求的模态字段,确认 image 确实被带上了。如果只有 text,说明 input_modalities 没生效。

4.4 延迟观测

在服务端给三段各打一个时间戳,能看出瓶颈在哪:

import time

t0 = time.time()
text = stt.transcribe(audio_chunk)
t1 = time.time()
reply = llm.chat(text, image=latest_frame)
t2 = time.time()
tts.speak(reply)
t3 = time.time()

print(f"STT {t1-t0:.2f}s | LLM {t2-t1:.2f}s | TTS {t3-t2:.2f}s")

实测下来,多模态 LLM 那段通常是耗时大头,因为要处理图像。如果 LLM 超过 1.5 秒,先把 frame_interval_ms 调大、max_width 调小试试。

5. 本篇常见错排查

5.1 模型只回文字不描述画面

现象:问「你看到了什么」,回复是「我无法看到画面」之类。原因基本是 input_modalities 没配或模型不支持图像。检查 config.toml 里 input_modalities = ["text", "image"] 是否存在,以及模型名是不是多模态型号。改完重启服务端。

5.2 摄像头设备找不到

现象:前端报 DEVICE_NOT_FOUND。这和权限被拒是两回事,权限问题报的是 PERMISSION_DENIED。台式机、远程桌面、虚拟机经常没有摄像头硬件。解决办法是装一个虚拟摄像头软件,启动虚拟摄像机后完全重启浏览器,让设备列表刷新。注意虚拟摄像头驱动注册有时需要管理员权限,普通权限下会静默失败。

5.3 推流成功但画面不更新

现象:第一帧能描述,之后画面变了回复不变。检查 frame_interval_ms 是否设得过大,或者前端 publishCamera 是否在推流中途被关掉。另外确认 usePublish 里摄像头 track 和麦克风 track 都传进去了,只传麦克风会导致画面缺失。

5.4 语音回环、Agent 听到自己说话

现象:Agent 说完后自己又接话。这是回声消除没生效或 interruptible 配置不当。确认 echoCancellation: true,并把 silence_duration_ms 适当调大,给回声留出衰减时间。

5.5 401 或额度报错

现象:请求返回 401 或额度不足。先确认 TAOTOKEN_API_KEY 环境变量在当前终端可见,echo $TAOTOKEN_API_KEY 能打印出来。再确认 Key 没有多余空格。如果额度问题,去控制台看用量。长期跑编码或 Agent 任务的话,Coding Plan 会比按量更划算。

6. 把统一 Key 用在长期编码与 Agent 场景

这套配置跑通后,你会发现模型接入层被 TaoToken 收拢成了一份 Key 加一个基址。换模型只改 config.toml 里的 model 字段,STT、LLM、TTS 三段可以独立替换,联调时不用重新申请账号。对需要长期迭代语音 Agent 的团队,这种收敛能省下不少维护成本。

如果你接下来要把它接到编码助手或自动化 Agent 里持续跑,可以看 Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=coding_plan

想先单独试多模态模型对画面的理解效果,去模型对话页面直接传图提问最快:https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=models

Key 的创建和管理在 API Keys 页面:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=api_keys

接入参数和字段说明以文档为准:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=doc

最后提醒一句:frame_interval_ms 和 max_width 这两个值直接决定多模态请求的体积和延迟,联调阶段先把它们调保守一点,跑通后再逐步往上加,比一上来就追求高清画面要稳得多。

Logo

邀请您加入社区

更多推荐