让「大肥鱼」在群里开口说话:NapCat + AstrBot + GPT-SoVITS 语音机器人搭建实录

引子

文字聊天机器人已经很不稀奇了,但如果你想让自己的人设角色在群里用特定的声音说话,链路会突然长出一大截:协议端、机器人框架、大模型、语音合成,少一环都不行。

最近「大肥鱼」人设和「鲸鱼娘」桌宠在 DeepSeek 生态里火了一把,很多人第一次意识到:这些角色如果只会打字,乐趣少一半;真让它们用自己的声音在群里接话,才算「活过来」。

这篇文章是完整的一次搭建实录:从技术选型、端口规划,到语音编码绕不开的坑,再到把默认 TTS 换成支持零样本音色克隆的 GPT-SoVITS;最后还包括跑起来之后的那些问题------消息上下文怎么隔离、群消息历史留多少条、怎么让它主动接话又不招人烦、以及延迟该从哪一层下手。全程本地部署,不依赖任何商业语音服务。


一、先把架构拆成四层

语音聊天机器人不是「接个 LLM 就行了」,它是一条四段式的流水线:

markdown 复制代码
QQ 客户端
   │  (QQ 协议)
   ▼
① 协议端  ── OneBot 11 ──▶  ② 机器人框架  ──▶  ③ 大模型
                                    │
                                    ▼
                              ④ 语音合成 ──▶ 转码 ──▶ 回传
层 职责 常见实现
协议端 收发 QQ 消息,暴露标准接口 NapCat(对外提供 OneBot 11)
机器人框架 事件分发、插件、人设、会话管理 AstrBot
大模型 生成回复文本 任意兼容 OpenAI 协议的服务
语音合成 文本转音频 Edge-TTS / GPT-SoVITS / 云端 TTS

理解这条链路的价值在于:出问题时要能判断是「收不到消息」「消息没被处理」还是「处理了但发不出去」。这三类故障的现象完全不同,排查入口也完全不一样。

从桌宠到群成员:差的不只是「会不会发声」

最近 DeepSeek 生态里最出圈的两样东西,一个是「大肥鱼」人设,一个是「鲸鱼娘」桌宠。前者是一份人设插件,决定它怎么说话、什么语气、什么口头禅;后者是本地桌宠,负责在桌面上晃、冒泡、偶尔吐槽。

这两类插件都是社区产物,共同点是观赏向、单人向:只有你一个人看、一个人对话,没有并发、没有社交压力、也没有「什么时候该闭嘴」的问题。

但一旦把它搬进群里,性质就变了:

维度 桌宠 / 本地人设 群机器人
受众 只有你 一群人,且各有偏好
记忆 单一会话 私聊按人隔离、群聊共享
说话时机 你点它才动 需要 @、关键词或主动插话策略
表达形式 文字气泡 文字 + 语音,会有「像不像」的问题

所以「大肥鱼能不能在群里说话」这件事,真正难的不是接一个大模型,而是把它的人设、记忆边界和发言节奏搬到多用户场景里------这也是后面几节要解决的东西。


二、选型:官方路线还是第三方协议端

2026 年的 QQ 机器人基本是两条路:

官方开放平台

  • 优点:合规、无封号风险、官方已放开语音收发能力;
  • 缺点:权限和场景受限,很多群能力拿不到,个性化程度低。

第三方协议端(如 NapCat)+ 开源框架

  • 优点:能力完整、可以做到高度个性化的角色扮演;
  • 缺点:属于模拟登录,存在风控与封号风险,需要自己承担。

如果只是做「群里的个性化 AI 角色」,第二条路几乎是唯一选择。但必须配套几条纪律:

  • 用不常用的小号,绝不拿主号跑;
  • 控制发言频率,别做主动刷屏;
  • 不加入大群、不群发;
  • 私聊优先验证,稳定后再考虑群聊。

这些不是「建议」,是这条路线能否长期跑下去的前提。


三、连接方式:反向 WebSocket

协议端和框架之间用 OneBot 11 标准接口通信。推荐反向 WebSocket:由协议端主动连到框架,框架只监听本地端口。

好处是配置更简单,也不需要在协议端做鉴权白名单。端口规划建议提前定好,避免和本机其他服务打架:

yaml 复制代码
# 框架侧(示意)
platform:
  type: aiocqhttp          # OneBot 11 适配器
  ws_reverse:
    host: 127.0.0.1
    port: 6199
    path: /ws
  webui:
    port: 6185             # 管理后台

协议端侧填同一个地址:

arduino 复制代码
ws://127.0.0.1:6199/ws

连上之后,日志里出现适配器连接成功的记录,就说明「协议端 → 框架」这一段通了。

排查提示:私聊不需要 @,群聊必须 @ 才会触发回复。很多人第一次测试收不到回复,是因为在群里直接说话没 @ 机器人。另外二维码登录有有效期,过期重新生成即可,不要反复重启进程。


四、语音:绕不开的 SILK v3

这是整条链路上最容易卡住的一步。QQ 的语音消息不是普通的 mp3/ogg,它要求 SILK v3 编码。框架生成的是 wav/mp3,直接塞进语音接口大概率发不出去或者对方听不到。

所以链路上必须有一个转码环节,通常依赖 ffmpeg:

scss 复制代码
文本 → TTS(返回 wav/mp3) → ffmpeg 转 SILK v3 → 语音消息发送

配置层面要做两件事:

  1. 确认 ffmpeg 在 PATH 里,且框架能调用到(容器/守护进程环境下经常是这一条没满足);
  2. 明确开启语音输出,让框架走「语音消息」而不是「音频文件」的发送通道。

调试顺序建议从简到繁:先让机器人回文字,再让它回语音,最后才调音色。一次只改一个变量,出问题才定位得动。


五、音色不达标:从 Edge-TTS 换到 GPT-SoVITS

Edge-TTS 的优点是零配置、开箱可用、延迟低;缺点是音色是固定的。它只能在你选定的声音里挑一个,没有办法复刻某个特定角色的声线。

问题就出在这里。「大肥鱼」之所以是「大肥鱼」,一半靠语气和口头禅,另一半靠那个辨识度极高的声线;「鲸鱼娘」桌宠也是同理------文字能模仿,声音模仿不了,人设就散了。你可以在提示词里写满「说话慢一点、尾音拖长一点」,但只要输出是 Edge-TTS 那几个标准播音腔,听起来就不是那个角色。

这条需求没法靠调参数解决,只能换引擎:需要能克隆音色的 TTS 。GPT-SoVITS 是目前本地部署里比较成熟的选择,关键优势是零样本推理:

  • 不需要训练模型;
  • 只需要 3~10 秒干净的参考音频 + 对应的文本;
  • 推理后即可得到接近参考音色的输出。

资源上,一台 64GB 统一内存的 Apple Silicon 机器满速跑是够的,这也是本地部署相对云端方案的优势------没有额度、没有延迟抖动、隐私可控。

部署成一个本地 HTTP 服务后(默认端口 9880),在框架里把 TTS 提供商切过去就行:

yaml 复制代码
tts:
  provider: gsv_tts
  endpoint: http://127.0.0.1:9880
  ref_audio: ./voices/ref.wav      # 3~10s 干净人声
  ref_text: "参考音频对应的文本"
  prompt_language: zh
  text_language: zh

准备参考音频时,有三条经验值得提前知道:

  • 干净比长更重要:有背景音乐、混响、多人说话的素材,克隆出来会「串味」;
  • 文本要对得上:参考文本和音频内容不一致,韵律会明显跑偏;
  • 情绪要一致:用平静语气做参考,就别指望它输出激动语气,想覆盖多情绪就准备多份参考。

六、TTS 接上之后,为什么还是收不到回复

把本地 TTS 服务接进来、模型权重也加载成功之后,遇到的问题很典型:链路看起来全绿,但发消息就是没回复。

这时候最忌讳的是「到处改配置」。正确做法还是分层验证,只是这次要验证到「消息有没有走到合成那一步」:

  1. 协议端 → 框架:日志里有事件推送记录;
  2. 框架 → 大模型:有请求发出、有文本返回;
  3. 文本 → TTS:本地服务是否收到请求、返回的音频是否非空;
  4. 音频 → QQ:转码后的 SILK 文件大小是否正常(几十字节基本就是失败)。

这次最后落在第 3、4 步之间,重连后恢复,本质是TTS 加载完成与消息通道就绪之间存在时序差:服务已经起来了,但语音通道还没真正可用,此时进来的消息会被直接吞掉。稳定之后的表现就是秒回。

还有一个容易忽略的「假成功」:参考音用的是占位音频。链路全通、语音也能发出去,但听起来完全是另一个人的音色。这不是 bug,是素材没换------先跑通链路,再替换 3~10 秒无背景音的干音,这个顺序不要颠倒,否则音色不对和链路不通会混在一起排查。


七、上下文与记忆:私聊是独立房间,群聊是大厅

这一点直接决定了机器人「记不记得事」,也最容易出现「怎么突然失忆了」的困惑。

框架的上下文划分规则可以概括成三段式键:

复制代码
平台 : 消息类型 : 会话 ID

由此得到两条结论:

场景 会话 ID 上下文表现
私聊 对方账号 每人一个独立对话,互不影响
群聊 群号 整群共用一个上下文,所有人共享记忆

几个实践要点:

  • 私聊和群聊的记忆完全不互通,不会跨场景传递;
  • 清空上下文是在对应会话里发 /reset,只清当前会话,不影响别人;
  • 群聊里可以开「每人独立记忆」,但代价是机器人会明显变健忘------每个人只有极短的上下文窗口,人设连续性反而变差。一般不建议开,宁可用一个共享上下文 + 更长的保留条数。

如果群聊只有被 @ 的消息才进历史,那机器人自然「只记得别人点它说过的话」。想让它在群里更连贯,需要把群消息历史打开,并把保留条数调到一个合理值(几百条量级),否则上下文太短,接话会显得突兀。


八、主动发言:三种机制,别混为一谈

「让机器人自己说话」有完全不同的三种实现,选错方向会白折腾很久:

机制 触发条件 特点 适用
概率插话 群里有消息时按概率接话 原生能力,配置简单 群聊里有存在感
定时主动 cron 定时任务 可控、可预测 早晚问候、定时播报
事件触发 插件 hook 响应事件/关键词 精准、零延迟误触 入群欢迎、关键词唤醒

8.1 概率插话的「节制」比概率更重要

一个常见的错误配置是:概率设得很低(比如 0.1)就觉得「已经很克制了」。但群里消息一多,0.1 的累计触发率其实相当高,一晚上能接话几十次。

真正让拟人感成立的,是这几项配套约束:

  • 活跃时段:夜里不接话,否则很像「一直盯着屏幕的机器人」;
  • 冷却时间:一次发言后强制静默 N 分钟;
  • 白名单:只在指定群生效,别全局打开;
  • 上下文长度:至少留几十上百条,否则接话会答非所问;
  • 人设一致性:大肥鱼会在你加班时阴阳你两句,鲸鱼娘会突然冒出气泡吐槽------这种「性格」来自人设提示词和语音的双重叠加。如果文字像、声音不像,或者反过来,拟人感立刻垮掉,所以人设和音色必须一起调。

顺带说一句:同一个插件生态里也有做「自动刷视频、自动评论」那一类的东西。它们和桌宠、人设不是一回事,属于典型的滥用型自动化,别碰。能力越大,越需要克制,这句话在群机器人上尤其成立。

8.2 需要 100% 触发时,用关键词而不是调概率

测试阶段经常需要「发消息必回」。把概率调到 1.0 是最差的做法------它会让机器人对每条消息都插话,既吵又难验证。

更合适的是关键词唤醒:插件里维护一个关键词元组,命中才回,同时把概率插话关掉避免重复回复。

python 复制代码
# 关键词唤醒插件(示意)
KEYWORDS = ("机器人昵称", "自定义暗号")

def match(event) -> bool:
    text = event.message_str or ""
    return event.is_at_bot or any(k in text for k in KEYWORDS)

两个必须知道的细节:

  • 改完要重启才生效,热改配置不会重新加载模块;
  • 关键词要和「@ 机器人」并列判断,否则群里没人 @ 时永远不触发。

九、延迟:先调推理强度,再换模型

语音机器人的延迟是叠加的:LLM 首字延迟 + TTS 合成耗时 + 转码 + 网络。很多人第一反应是换更小的模型,但往往第一步该调的是推理强度。

现在不少模型支持多档 reasoning effort(low / high / max),默认值常常是 high。这在写代码、做分析时是好事,放到群聊闲聊里就是纯延迟:

yaml 复制代码
provider:
  model: deepseek-flash
  reasoning_effort: low   # 群聊闲聊场景,改 low 通常质量损失很小

经验判断:

  • 一对一的深度问答 :保持 high,值得等;
  • 群聊接话、语音回复 :改 low,用户对「快」的感知远大于对「多思考两秒」的感知;
  • 语音链路:TTS 合成本身就是固定开销,给 LLM 留的预算要更紧。

调完之后再看是否换模型,顺序反了会浪费很多时间。


十、聊天记录去哪了:审计与复盘

机器人跑起来之后,很快会需要回答「它昨天在群里说了什么」。记录其实不止一处,按用途选:

途径 位置 适用
框架 WebUI 会话管理 图形界面 快速翻看、单条定位
本地数据库 data/data_v4.db 的 platform_message_history 表 批量导出、做分析
协议端接口 OneBot 拉取 QQ 侧原始消息 需要原始数据结构
QQ 客户端 聊天窗口 只做肉眼确认

两个配置层面的坑:

  • 默认只存被 @ 的群消息,所以「没存到」往往不是 bug,是本来就没开;
  • 打开全群历史后要注意存储增长,几百人的群一天能堆出可观的记录量,定期清理或加个保留天数。

十一、排查清单

把这次踩过的坑整理成一份顺序清单,按这个顺序走基本不会绕路:

  1. 框架能起来吗 ------ WebUI 能打开,说明服务和配置没问题;
  2. 协议端连上了吗 ------ 日志里能看到反向 WS 连接成功;
  3. 能收到事件吗 ------ 私聊发一条消息,框架日志里是否有事件记录;
  4. 能回文字吗 ------ 先把 LLM 链路跑通,别急着上语音;
  5. 能回语音吗 ------ 检查 ffmpeg、SILK 转码、语音通道;
  6. 音色对不对 ------ 前五步全通之后再动 TTS 参数;
  7. 延迟能接受吗 ------ 先降推理强度,再考虑换模型;
  8. 是否在说话太多 ------ 检查概率插话的冷却、时段和白名单。

另外几个高频细节:

  • 人设配置放在框架侧,不要写死在代码里,方便热更新;
  • 测试用小号、控制在私聊,确认稳定再放进群,避免频繁触发风控;
  • 框架的 WebUI 有默认初始账号,首次登录第一件事就是改密码,别让管理后台裸奔在本地端口上。

十二、合规与风险,必须写在前面

第三方协议端模拟登录这件事,本质上是踩在平台规则的边缘。技术上能做,不代表可以随便用。几个底线:

  • 只用小号,主号不参与;
  • 不做主动营销、不群发、不刷屏;
  • 不进大群,控制消息频率;
  • 主动发言能力要慎用:它是最容易从「有个机器人」滑向「骚扰」的功能,冷却和时段限制不是可选项;
  • 随时准备停用,不做依赖它运转的业务。

如果这些前提不能接受,那还是老老实实走官方开放平台,牺牲一部分能力换取稳定性。


结语

这条链路的价值不只是「让机器人说话」,而是它把几个平时割裂的领域串起来了:即时通讯协议、事件驱动的机器人框架、LLM 接入、语音合成与音频编码。每一段都不算深,但拼在一起就会冒出各种「看起来该通却不通」的问题。

回过头看,真正花时间的往往不是「让它说话」,而是「让它记得」和「让它少说」------上下文按私聊/群聊怎么隔离、群消息历史留多少条、主动接话的冷却怎么配,这些都不属于任何单个组件的文档,只能自己一层层试出来。

而「像不像」这件事,最后拼的也不是某个单点技术:人设插件给了性格,桌宠给了陪伴感,GPT-SoVITS 给了声线,机器人框架给了记忆和分寸。四样凑齐,大肥鱼或鲸鱼娘才算真正从你的桌面走进了群里。

最容易踩的坑反而不是大模型,而是最不起眼的那一层:语音编码格式 。同样地,第二常见的坑是时序------服务起来了不等于通道就绪,重连一次往往比改十行配置有效。搭复杂链路时,先按层验证,再谈效果。

相关推荐
Rocky Ding*6 小时前
REPA-E技术深度解析:解冻 VAE 之后,扩散模型为什么需要选择梯度
论文阅读·人工智能·深度学习·机器学习·aigc·ai-native·repa-e
DQQzero7 小时前
0.16 元/秒的短剧流水线:即梦短剧工作室把 AI 视频生产改成了什么样
人工智能·ai·aigc·视频生成
硅谷秋水10 小时前
从VLM规划器到机器人智能体:面向依赖历史信息的操控任务自演化框架
人工智能·机器学习·语言模型·机器人
Vex2une10 小时前
AI 渲染正在重写游戏美术的账本:提效、外包与新的门槛
人工智能·aigc·游戏美术·神经渲染·dlss 5·ai 渲染·游戏开发门槛
西安小哥10 小时前
给 Agent 堆上下文,不如把缓存命中率抬上去
aigc·ai编程
liferecords10 小时前
不训练一个参数,把图像编辑器变成视频编辑器:EditVid 的局部-全局拆解术
人工智能·llm·aigc·多模态
LV技术派10 小时前
我的《成为 AI Native Builder》开源小册,全量开放了!
aigc·openai·ai编程
小虎AI生活1 天前
REA(rea.tools) 接入 WorkBuddy 实操:Electron ASAR 免解压静态分析到零代码复刻
aigc·ai编程
狼爷1 天前
AI 这么强,笔记还有意义吗?结合 AIED 2026 研究,一套可落地的原子笔记工作流
aigc