摘要
用 Agora Conversational AI 的 translator recipe,搭一个「会说话」的中英双向语音翻译助手的过程------对着麦克风说中文,它实时翻成英文念出来,反过来也行。我先跑通单向(中→英),拆了拆它背后的级联流水线和低延迟机制,再动手把它改成了可切换方向的双向。
一、为什么我想做一个语音翻译助手
1.1 一个真实的场景痛点
去国外玩,点餐、问路全得靠翻译 App------可它得按住说话才能翻:用户对着服务员按住说中文,等它翻成英文念出来;人家回一长串英语,又得赶紧按住让它翻回来。一来一回手忙脚乱,后面排队的人都盯着,场面特别尴尬。
我在想要有个能「自动双向」的:我说中文它翻英文、对方说英文它翻回中文,不用我一直按、一直切。可现有翻译 App 的通病都差不多------延迟高、得按住说话、来回切方向、连珠炮时根本插不上嘴。
1.2 我找到了 translator recipe
目标定了,就缺个趁手的实现。我找到了 Agora Conversational AI 的 translator recipe------它把「语音识别 + 翻译 + 语音合成 + 实时传输 + 打断」这套本来很碎的活打包好了,而且不止能跑通,我后面还把它改成了中英双向。
二、它是什么:先搞懂原理
2.1 一条流水线:STT → LLM → TTS
它做的事用一句话讲:你在浏览器里说话 → 听懂源语言 → 翻译 → 用目标语言念出来。背后是一条经典的三段流水线,在 server/src/agent.py 里就是三个 vendor 串起来:
Python
from agora_agent.agentkit.vendors import OpenAI, DeepgramSTT, MiniMaxTTS
stt = DeepgramSTT(model="nova-3", language=self.source_lang) # 听源语言
llm = OpenAI(model="gpt-4o-mini", system_messages=..., temperature=0.3) # 翻译
tts = MiniMaxTTS(model="speech_2._6_turbo", voice_id=self.tts_voice) # 念目标语言
agora_agent = agora_agent.with_stt(stt).with_llm(llm).with_tts(tts)
最后那行 .with_stt().with_llm().with_tts() 把三段拼成一条流水线。中间 LLM 的翻译指令在 translation_config.py 里,就一句话:
Bash
f"You are a translation assistant. Translate the user's message into {target_lang}. Output only the translation..."
注意 temperature=0.3------翻译要稳,所以特意压低了随机性。中→英时 source_lang=zh、target_lang=English,就是 Deepgram 听中文、OpenAI 翻成英文、MiniMax 用英文念出来。

2.2 最反直觉的一点:零 key
跑之前我以为怎么也得先申请个 OpenAI key 吧------结果完全不用。OpenAI 是 Agora 托管的,你只要注册个 Agora 账号、用 CLI 把凭证写进配置就能跑,不用自己去申请任何模型厂商的 key。
三、动手跑通
3.1 环境准备
要准备三样:Python 3.10+、Bun、Agora CLI。装完分别验证一下版本:
Bash
python --version # 应 ≥ 3.10
bun --version # 1.x
agora --version # Agora CLI(没装的话先:curl -fsSL https://dl.agora.io/cli/install.sh | sh)

Windows 用户:****
agora报找不到命令,多半是C:\Users\<你>\bin没进 PATH,加到用户 PATH 后新开终端。
然后注册 Agora 账号,用 CLI 登录、把凭证写进项目配置
Bash
agora login
agora project use # 选一个 project
agora project env write server/.env.local # 把 App ID + App Certificate 写进配置

3.2 三步启动
Bash
# 1. 装依赖(web + Python venv)
bun run setup
# 2. 登录 + 写凭证
agora login
agora project use # 选一个 project
agora project env write server/.env.local
# 3. 跑起来
bun run dev

Windows 注意:
bun run setup/bun run dev在 Windows 上会踩python3不存在 +venv/bin路径的坑,得手动建 venv(Scripts/)+ 分跑 backend/frontend。
WSL 环境配置
Windows也可以直接在 WSL(Ubuntu) 里跑,能避开
python3不存在、venv/binvsScripts/、PATH 丢失等一堆坑。以下是完整命令。
Bash
wsl # 进入 WSL(Ubuntu)
# 千万别在 /mnt/c/... 下跑,IO 极慢且 venv 容易出问题
cd ~ && mkdir -p code && cd code
git clone <recipe 仓库地址> # 项目放在 ~/code 下
cd <项目目录>
装环境:
Bash
# ------ Python 3.10+ ------
sudo apt update
sudo apt install -y python3 python3-pip python3-venv python3-dev
python3 --version # 若 < 3.10,用 deadsnakes 装新版:
# sudo add-apt-repository ppa:deadsnakes/ppa && sudo apt update
# sudo apt install -y python3.10 python3.10-venv python3.10-dev
# ------ Bun ------
curl -fsSL https://bun.sh/install | bash
source ~/.bashrc # 或按提示 source 那一行
bun --version # 1.x
# ------ Agora CLI ------
curl -fsSL https://dl.agora.io/cli/install.sh | sh
# 脚本结束后会把可执行文件路径写进 ~/.bashrc,source 或重开终端
source ~/.bashrc
agora --version
装依赖 + 写凭证
Bash
bun run setup # WSL 下会正常建 server/venv/bin,不再踩 Windows 的 Scripts/ 坑
agora login
agora project use # 选一个 project
agora project env write server/.env.local # 写入 App ID + App Certificate
bun run dev
在 Windows 浏览器 里打开 http://localhost:3000 → Start Conversation。
3.3 改语言对,先跑通中→英
recipe 默认的语言对是西班牙语→英语(SOURCE_LANG=es),我得先把它改成中→英。改的是 server/.env.local 三个变量:
SOURCE_LANG:Deepgram 的语言码,改成中文(zh,实操时确认 Deepgram 接受的中文码);TARGET_LANG:翻译目标语言,English;TTS_VOICE:MiniMax 的音色名,跟目标语言匹配(英文用English_captivating_female1)。

3.4 第一次对话
- 打开
localhost:3000→ Start Conversation


四、拆解:声音是怎么实时翻译的
跑通之后我好奇:这一来一回到底发生了什么?
5.1 语音 Agent 的四层架构
Agora 把语音 Agent 拆成四层,这个 translator recipe 正好对应上:
- 实时传输:Agora RTC(WebRTC),负责把音频低延迟地搬来搬去。
- Agent 运行时 :Convo AI 托管,管会话生命周期、轮次、打断。代码里就是
AgoraAgent(...)那个对象,带turn_detection、max_history这些配置。 - AI 模型 :Deepgram + OpenAI + MiniMax 这条流水线(
with_stt/llm/tts串起来)。 - 端上体验:那个 Next.js 网页。
5.2 级联式 vs 端到端
它用的是「级联式」三段流水线------先识别(STT)、再翻译(LLM)、再合成(TTS),而不是一个端到端的语音大模型。代码里就是那行 agora_agent.with_stt(stt).with_llm(llm).with_tts(tts),三段清晰可换。好处是每一层都能换、能调(也正是后面做双向的基础);代价是延迟是三层累加的。
5.3 为什么是 WebRTC 不是 WebSocket
传输层为什么非得用 WebRTC、不能图省事用 WebSocket?因为 WebSocket 走 TCP,弱网下一个包丢了,后面所有包都得排队等重传(队头阻塞),对话就卡死了。WebRTC 走 UDP,能直接丢掉过期的音频帧,还自带 3A(回声消除 / 降噪 / 增益),所以才撑得起「边说边听、随时打断」的体验。
5.4 低延迟 + 可打断,代码里都看得见
有意思的是,这两个体验关键词在代码里都有据可查:
Python
parameters = {"audio_scenario": "chorus", ...} # chorus = web 客户端的超低延迟音频 profile
turn_detection = {"config": {"start_of_speech": {"mode": "vad", ...},
"end_of_speech": {"mode": "vad", "vad_config": {"silence_duration_ms": 480}}}}
chorus 是为低延迟选的音频 profile;turn_detection 用 VAD(语音活动检测)判断你说完没(静音 480ms 算一句话结束),这就是「能随时打断、不会乱插话」的底层。
5.5 延迟拆解
官方给的级联架构各环节延迟区间大概是:RTC 150--300 ms、ASR 400--700 ms、LLM 250--1000 ms、TTS 100--350 ms(LLM 通常是最大头)。官方端到端能压到 650ms 左右,靠的是全球 RTC 网络 + 一堆优化(小模型、流式、同区域部署)。
六、进阶:把它改成双向
6.1 单向的局限
recipe 默认是单向的。看代码就知道为什么------语言对是从环境变量读的,在 Agent.init 时就固定了:
Python
self.source_lang = os.getenv("SOURCE_LANG", "es")
self.target_lang = os.getenv("TARGET_LANG", "English")
self.tts_voice = os.getenv("TTS_VOICE", "English_captivating_female1")
也就是说,agent 一启动,源语言、目标语言、音色就绑死了,跑起来后没法在对话中途切换方向。
6.2 改造思路
既然语言对是 agent 启动时绑定的,最直接的思路是:切换方向时,后端停掉当前 agent、换一组新的语言对再启动一个新 agent 。代码里 Agent 已经有现成的 stop(agent_id) 方法,前端加个「中→英 / 英→中」切换按钮,点了就调后端接口:stop 旧 agent → 改 source_lang/target_lang/tts_voice → start 新 agent。
更彻底的改法是让 start() 直接接受语言对参数(而不是从 env 读),切换不用重启、传参即可------但要动 agent.py 的接口。

总结
这次搭下来,最费时间的不是代码,是一个环境变量。SOURCE_LANG 我按直觉填了 English,然后就开始怀疑人生------麦克风明明有声音,Deepgram 那头一片空白,agent 翻来覆去回我「没收到信息」。折腾半天才明白:这里要的是厂商的语言码,不是语言名。
所以填之前先确认一下 STT / TTS 厂商各自的语言码和音色名,翻一眼官方文档,或者直接问 AI,几秒钟的事,能省我这半天。
Agora 这套 Conversational AI Engine 把「搭语音翻译」这件本来很碎的事(传输 + 运行时 + 模型 + 打断)打包得确实到位:
- 零 key 真的开箱即用------不用申请一堆模型厂商的 key,注册 Agora 账号就能跑。
- 延迟低、对话有「呼吸感」------配合 Agora 全球 RTC 网络和官方 650ms 的端到端数据,响应很跟手,不是那种「说完等半天」。
- 打断自然------有 turn detection(语义轮次检测),它知道你这句话说完没,不会轻易被打断或乱插话。