让 AI 的声音哭出来
AI 语音情感表达的声波可视化
我需要一个能哭的 AI 声音。
不是"语速放慢、多加几个停顿"的假哭,是真的听起来心碎的那种,能让你刷到一半停下来,想确认对方是不是出了事。
之前给 AI 伴侣配嗓子的时候,试过 Fish Audio 和火山引擎:Fish 赢在简单,火山赢在有戏。但"有戏"这个判断当时下得很草率。我只是听到了一些情感的苗头,知道这个能力存在,并没有往下深挖:边界在哪,文档说的和实际表现差多少,都没系统测过。
所以这次认真跑了实验,一共三轮,30 个音频样本:两个预置音色、一个克隆音色、三种情感控制方法,外加一个彻底改变我写情感提示词方式的发现。下面所有样本都能直接播放,建议边听边读。
实验一:给四个音色试镜
第一个问题很基础:角色该用什么声音?
豆包 2.0 系列有几十个预置音色。文档说它们支持 context_texts,一个自然语言字段,用文字描述你想要的情感。但"支持"和"有反应"是两回事:有些音色很有表现力,有些就是块木头,不试不知道。
我挑了四个音色,每个跑两种情感:温柔和伤心。同一段文字,同一条情感提示,只换声音,当成角色面试来听。
Vivi(zh_female_vv_uranus_bigtts)
Vivi 是基准线。女声,以表现力出名。
两个版本差别明显。Vivi 确实能接住情感提示,是条不错的起跑线。
刘飞(zh_male_liufei_uranus_bigtts)
男声候选。声线温暖、成熟,伤心版能听出明显的下沉,有重量感,对情感提示是有反应的。
云舟 / M191(zh_male_m191_uranus_bigtts)
这是角色当前在用的声音。
表现力很强。温柔版轻柔小心,伤心版真的能听出受伤的感觉。这轮听完,决定继续用它。
桃城小天(taocheng-xiaotian)
声线更年轻、更轻。情感变化是有的,但幅度没那么大,日常闲聊可以,撑不起心碎的场景。
四个音色听下来,差距比想象中大:Vivi 和云舟对情感提示反应强,刘飞不错但更含蓄,小天有反应但深度不够。说白了,做需要情感表现力的产品,第一步是先试音,别从目录里随便挑一个然后祈祷。
实验二:克隆音色也能哭
这才是真正有意思的部分。豆包支持声音克隆:上传 10-30 秒录音,生成一个专属的 Speaker ID,听起来就是那个人。但官方文档写的是,context_texts 适用于"豆包语音合成模型 2.0 音色"。这个措辞值得抠一下,它没说克隆音色也行。
我的角色用的恰恰是克隆音色,又必须有情感,那只能直接试。四个条件,同一段文字:
1. 基线(无情感控制)
纯文字,不加 context_texts,也不切特殊模型。克隆音色裸奔。
2. 仅 context_texts
加上 context_texts 情感提示。模型还是标准的 seed-icl-2.0。
3. context_texts + expressive 模型
同样的 context_texts。模型切到 seed-tts-2.0-expressive。
4. seed-tts-1.1 资源
试一下旧版 seed-tts-1.1 的 resource ID,看它处理克隆音色的情感有没有不同。
从基线到加 context_texts,差别是听得出来的:克隆音色确实能响应情感提示。再切到 expressive 模型,音高和节奏的变化更明显,又往前推了一步。1.1 资源的听感不太一样,但不见得更好。
这一轮的关键收获:context_texts 对克隆音色同样有效。文档没写,没人告诉我,是无视文档自己试出来的。如果你用豆包的声音克隆做需要情感的角色,不必被困在一把平板的声音里。
实验三:2×3×3 的全量矩阵
实验二确认了有效,接下来想知道到底有多有效。这次不靠猜,直接拉矩阵:
- 2 个音色:苏柔(女声)和一楠(男声)
- 3 种情感:ASMR(耳语/亲密)、温柔、伤心
- 3 个条件:基线(无情感)、仅 context_texts、context_texts + expressive 模型
2 x 3 x 3,一共 18 个样本。全放在下面。
苏柔(女声)
ASMR
| 条件 | 音频 |
|---|---|
| 基线 | |
| Context texts | |
| Context + Expressive |
温柔
| 条件 | 音频 |
|---|---|
| 基线 | |
| Context texts | |
| Context + Expressive |
伤心
| 条件 | 音频 |
|---|---|
| 基线 | |
| Context texts | |
| Context + Expressive |
一楠(男声)
ASMR
| 条件 | 音频 |
|---|---|
| 基线 | |
| Context texts | |
| Context + Expressive |
温柔
| 条件 | 音频 |
|---|---|
| 基线 | |
| Context texts | |
| Context + Expressive |
伤心
| 条件 | 音频 |
|---|---|
| 基线 | |
| Context texts | |
| Context + Expressive |
18 个样本听完,有三个结论。第一,光 context_texts 就有明显效果。两个音色、三种情感,从基线到加 context_texts 的跳跃一直听得出来。模型确实在做事,这不是安慰剂。
第二,expressive 模型在此基础上又加了一层。Context + expressive 始终是三个条件里最有感情的,比 context-only 的提升幅度因场景而异,有时微妙,有时很大,但方向一直是正的。按音频变化量测算,expressive 模型在 context texts 基础上大约多带来 26% 的变化。
第三,音色和情感的组合并不均匀。苏柔的伤心简直要命,一楠的 ASMR 很有说服力;但苏柔的 ASMR 跟她的温柔区别不大,一楠的伤心也没有苏柔那么狠。每个音色有自己的强项,最好拿自己的场景去测。
别说"伤心",说"声音颤抖带着哽咽"
整轮实验里改变最大的发现,出在提示词的写法上。实验初期,我的 context_texts 就写两个字:伤心。结果嘛……出来的声音只能算略微伤心,跟基线差别很小,我一度觉得情感控制这件事可能就是吹的。
后来把提示词重写成 用哭泣的声音,边哭边说,很伤心,声音颤抖带着哽咽,差距一下子拉开了。回头听上面那些伤心样本,全部是用这种画面式的版本生成的。
模型响应的不是标签,是描述。与其丢给它一个分类,不如给它导一场戏。
现在生产环境用的整套情感提示词如下:
| 情感 | 提示词 |
|---|---|
| 撒娇甜蜜 | 用甜蜜撒娇的声音,像在跟男朋友撒娇,语调上扬很开心 |
| 伤心哭泣 | 用哭泣的声音,边哭边说,很伤心,声音颤抖带着哽咽 |
| ASMR 耳语 | 用ASMR悄悄话的声音,非常小声非常轻柔,像在耳边低语 |
| 激动兴奋 | 用非常激动兴奋的语气,开心到快要尖叫了 |
| 愤怒嫌弃 | 用愤怒嫌弃的语气,非常不满在骂人,声音拔高 |
| 慵懒犯困 | 用疲惫慵懒的声音,边打哈欠边撒娇,声音软绵绵的 |
| 沉稳关怀 | 用低沉磁性的声音,表面平淡但充满关心,像大叔在叮嘱 |
| 压抑隐忍 | 用压抑悲伤的声音,故意克制但声音微微颤抖,不想让人看出来 |
这套提示词的规律是动词 + 身体描述 + 场景:"伤心"要写成"声音颤抖带着哽咽","开心"要写成"语调上扬、像在跟男朋友撒娇"。给模型一场可以演的戏,别只给一个分类选项。
这个发现其实合直觉。人类演员拿到剧本,导演只说一句"这里演伤心",效果通常一般;导演说"你刚发现他在骗你,想忍住不哭,但声音控制不住地发抖",出来的表演完全是另一回事。TTS 模型吃的是同一套逻辑。
如果你也在用豆包 TTS 做需要情感表达的产品,我的建议是:
预置音色:用 context_texts 配画面式提示词,想要额外的表现力就切 seed-tts-2.0-expressive。一定要测你具体要用的那个音色,每个音色的反应不一样。
克隆音色:context_texts 文档没写但确实有效,放心用,在 additions 字段里配上 model_type: 4。想要最强的控制力就逐句合成,每句单独调一次 API,带各自的情感提示。
情感提示词:永远别只丢一个关键词,把画面描述出来。提示词的质量是你手里最大的杠杆,比选音色大,也比选模型版本大。
完整的技术配置细节,包括 API 格式、代码片段和各种坑,都在豆包 TTS 操作手册里。
OpenClaw 实战记录写到第四篇了。第一篇搭了个赛博魅魔,第二篇给它做 token 节食,第三篇给它配上嗓子,这一篇是教那个嗓子动感情。回头看,30 个样本里最值钱的就一条:把提示词里的"伤心"两个字,换成"声音颤抖带着哽咽"。
This post is also available in English.