---
summary: "让机器人与选定的用户加入、移动和离开 Discord 语音通道"
read_when:
- "配置 voice.followUsers 以便机器人在语音通道之间跟踪人员"
- "调试跟随模式连接、插入或回显处理"
title: "使用 Discord 语音关注用户"
sidebarTitle: "通过语音关注用户"
---
跟随模式使机器人在 Discord 语音通道之间移动时跟踪选定的用户。
## 语音关注用户
当您希望 Discord 语音机器人与一个或多个已知的 Discord 用户在一起,而不是在启动时加入固定频道或等待 `/vc join` 时,请使用 `voice.followUsers`。
```json5
{
channels: {
discord: {
voice: {
enabled: true,
followUsersEnabled: true,
followUsers: ["discord:123456789012345678"],
allowedChannels: [
{
guildId: "123456789012345678",
channelId: "234567890123456789",
},
],
},
},
},
}
```
行为:
- `followUsers` 接受原始 Discord 用户 ID 和 `discord:` 值。 OpenClaw 在匹配语音状态事件之前对两种形式进行标准化。
- 配置 `followUsers` 时,`followUsersEnabled` 默认为 `true`。设置为`false`,保留已保存的列表,但停止自动语音跟随。
- `followUsers` 只控制语音驻留。它不会授予发言者权限或所有者权限;请分别配置 `commands.ownerAllowFrom` 以及公会或频道的用户和角色。
- 当被跟随用户加入一个允许的语音频道时,OpenClaw 会加入该频道。当用户移动时,OpenClaw 也会随之移动。当当前被跟随用户断开连接时,OpenClaw 会离开。
- 如果同一公会中有多个被跟随用户,而当前活跃的被跟随用户离开,OpenClaw 会在离开公会前先移动到另一个被跟踪用户所在的频道。如果多个被跟随用户同时移动,则以最新观察到的语音状态事件为准。
- `allowedChannels` 仍然生效。位于不允许频道中的被跟随用户会被忽略,而一个跟随拥有的会话会移动到另一个被跟随用户那里,或者离开。
- OpenClaw 会在启动时以及以受限间隔校正遗漏的语音状态事件。校正会采样已配置的公会,并对每次运行的 REST 查询数量设上限,因此非常大的 `followUsers` 列表可能需要超过一个间隔才能收敛。
- 如果 Discord 或管理员在机器人跟随用户时移动了机器人,OpenClaw 会重建语音会话,并在目标位置允许时保留跟随所有权。如果机器人被移动到 `allowedChannels` 之外,OpenClaw 会离开,并在存在已配置目标时重新加入该目标。
- DAVE 接收恢复在连续解密失败后可能会离开并重新加入同一频道。跟随拥有的会话会在该恢复路径中保留其跟随所有权,因此稍后被跟随用户断开时仍会离开频道。
在加入模式之间选择:
- 对于个人或 operator 设置,如果希望机器人在你进入语音时自动跟随,就使用 `followUsers`。
- `autoJoin`用于固定房间。当机器人仅在人类位于该房间时才应出现时,请添加 `whenOccupied: true`;省略它以获得始终在线的语音状态。
- 对于一次性加入,或自动语音存在会让人意外的房间,就使用 `/vc join`。
Discord 语音编解码器:
- 语音接收日志会显示 `discord voice: opus decoder: libopus-wasm`。
- 实时播放使用相同的捆绑 `libopus-wasm` 包将原始 48 kHz 立体声 PCM 编码为 Opus,然后将数据包传递给 `@discordjs/voice`。
- File 和提供程序流播放使用 ffmpeg 转码为原始 48 kHz 立体声 PCM,然后使用 `libopus-wasm` 将 Opus 数据包流发送到 Discord。
STT 加 TTS 流水线:
- Discord PCM 捕获会转换为一个 WAV 临时文件。
- `tools.media.audio` 负责 STT,例如 `openai/gpt-4o-mini-transcribe`。
- 批量捕获遵循最大的适用[音频输入限制](/nodes/audio),包括配置的模型和CLI回退。过大的捕获会停止并警告说较短的片段;部分音频未转录。此限制不会缓冲或截断直接实时流。
- 转写会通过 Discord ingress 和 routing 发送,而响应 LLM 会使用一个语音输出策略:隐藏 agent 的 `tts` 工具并要求返回文本,因为 Discord 语音负责最终的 TTS 播放。
- `voice.model` 在设置时,只会覆盖此语音频道轮次的响应 LLM。
- `voice.tts` 会覆盖合并到 `tts` 之上;支持流式的 provider 会直接把音频送给播放器,否则生成的音频文件会在已加入的频道中播放。
默认 agent-proxy 语音频道会话示例:
```json5
{
channels: {
discord: {
voice: {
enabled: true,
model: "openai/gpt-6-astra",
followUsersEnabled: true,
followUsers: ["123456789012345678"],
realtime: {
provider: "openai",
model: "gpt-realtime-2.1",
speakerVoice: "cedar",
},
},
},
},
}
```
在没有 `voice.agentSession` 块时,每个语音频道都有自己的路由后 OpenClaw 会话。例如,`/vc join channel:234567890123456789` 会与该 Discord 语音频道对应的会话通信。实时模型只是语音前端;实质请求会交给配置好的 OpenClaw agent。如果实时模型在没有调用 consult 工具的情况下生成了最终转写,OpenClaw 会强制 consult 作为回退,因此默认行为仍然像是在与 agent 对话。
旧版 STT 加 TTS 示例:
```json5
{
channels: {
discord: {
voice: {
enabled: true,
mode: "stt-tts",
model: "openai/gpt-5.4-mini",
tts: {
provider: "openai",
providers: {
openai: {
model: "gpt-4o-mini-tts",
speakerVoice: "cedar",
},
},
},
},
},
},
}
```
实时 bidi 示例:
```json5
{
channels: {
discord: {
voice: {
enabled: true,
mode: "bidi",
model: "openai/gpt-6-astra",
realtime: {
provider: "openai",
model: "gpt-realtime-2.1",
speakerVoice: "cedar",
toolPolicy: "safe-read-only",
consultPolicy: "always",
},
},
},
},
}
```
将语音作为现有 Discord 频道会话的扩展:
```json5
{
channels: {
discord: {
voice: {
enabled: true,
mode: "agent-proxy",
model: "openai/gpt-6-astra",
agentSession: {
mode: "target",
target: "channel:123456789012345678",
},
realtime: {
provider: "openai",
model: "gpt-realtime-2.1",
speakerVoice: "cedar",
},
},
},
},
}
```
在 `agent-proxy` 模式下,机器人会加入配置的语音频道,但 OpenClaw agent 的轮次会使用目标频道的正常路由会话和 agent。实时语音会话会把返回结果重新播回语音频道。监督 agent 仍可根据其 tool policy 使用正常消息工具,包括在合适时发送单独的 Discord 消息。
在实时语音通话期间,要求客服人员列出可用的语音或切换到一种语音。 `talk_voice` 工具更改当前房间的语音并重新连接其实时提供商连接,同时保留 Discord 连接、对话和正在进行的座席工作。更换准备就绪后,代理确认变更。如果切换失败,OpenClaw 保留或恢复之前的语音。如果恢复也失败,会要求您重新加入语音;已接受的代理工作仍可完成。该选择适用于该房间中的后续扬声器,并持续到房间断开连接为止; `voice.realtime.speakerVoice` 仍然是未来调用的默认值。这需要所有者授权的语音转向、代理委派以及对 `talk_voice` 工具的访问。
通话中的更改需要提供商语音目录。 Google Live 支持相同的 `talk_voice` 流程:OpenClaw 打开与所选语音的新连接,并通过 Discord 呼叫保持未完成的座席工作。替换后等待发送的答案。已经提交到先前连接的响应可能会被交换机中断并且不会重播,从而避免重复语音。
当委派的 OpenClaw 运行处于活动状态时,命令授权的 Discord 对话记录在开始另一个座席轮流之前将被视为实时运行控制。诸如“状态”、“取消该”、“使用较小的修复”或“完成后还检查测试”之类的短语被分类为活动会话的状态、取消、转向或后续输入。状态、取消、接受的转向和后续结果都会通过语音通道讲回,以便呼叫者知道 OpenClaw 是否处理了请求。
当 OpenClaw 取消委托咨询时,Discord 记录取消而不是失败,并且不播放通用错误回退。匹配较晚的提供程序工具调用会收到相同的终端取消,而不是重新启动工作。语音会话仍可用于下一个请求;超时和真正的故障保持正常的错误处理。
有用的 target 形式:
- `target: "channel:123456789012345678"` 通过 Discord 文本频道会话路由。
- `target: "123456789012345678"` 会被视为频道目标。
- `target: "dm:123456789012345678"` 或 `target: "user:123456789012345678"` 通过该私信会话路由。
回声较重的 OpenAI Realtime 示例:
```json5
{
channels: {
discord: {
voice: {
enabled: true,
mode: "bidi",
model: "openai/gpt-6-astra",
realtime: {
provider: "openai",
model: "gpt-realtime-2.1",
speakerVoice: "cedar",
bargeIn: true,
minBargeInAudioEndMs: 500,
consultPolicy: "always",
providers: {
openai: {
interruptResponseOnInputAudio: false,
},
},
},
},
},
},
}
```
当模型通过打开的麦克风听到自己的 Discord 播放,但您仍然想通过说话来打断它时,请使用此功能。 OpenClaw 防止 OpenAI 在原始输入音频上自动中断,而 `bargeIn: true` 允许 Discord 扬声器启动事件和已经活动的扬声器音频在下一个捕获的回合到达 OpenAI 之前取消活动的实时响应。 `audioEndMs` 低于 `minBargeInAudioEndMs` 的非常早期的插入信号被视为可能的 echo/noise 并被忽略,因此模型不会在第一个播放帧处中断。
预期的语音日志:
- 加入时:`discord voice: joining ... voiceSession=... supervisorSession=... agentSessionMode=... voiceModel=... realtimeModel=...`
- realtime 开始时:`discord voice: realtime bridge starting ... autoRespond=false interruptResponse=false bargeIn=false minBargeInAudioEndMs=...`
- 有说话者音频时:`discord voice: realtime speaker turn opened ...`、`discord voice: realtime input audio started ... outputAudioMs=... outputActive=...`,以及 `discord voice: realtime speaker turn closed ... chunks=... discordBytes=... realtimeBytes=... interruptedPlayback=...`
- 跳过陈旧语音时:`discord voice: realtime forced agent consult skipped reason=incomplete-transcript ...` 或 `reason=non-actionable-closing ...`
- 实时响应完成时:`discord voice: realtime audio playback finishing reason=completed ... audioMs=... chunks=...`;在此行之后仍然可以播放缓冲的音频。
- 普通播放反压上:`discord voice: realtime audio playback buffering ... bufferedBytes=...`;当 Discord 耗尽缓冲音频时,播放继续。
- Discord 在使用 PCM 后确认范围内的提供者播放标记。 xAI 在开始以下响应之前等待这些确认;清除丢弃的音频不会将其报告为已播放。
- 播放 stop/reset: `discord voice: realtime audio playback stopped reason=... audioMs=... elapsedMs=... chunks=...`
- realtime consult 时:`discord voice: realtime consult requested ... voiceSession=... supervisorSession=... question=...`
- agent 答复时:`discord voice: agent turn answer ...`
- 排队的精确语音时:`discord voice: realtime exact speech queued ... queued=... outputAudioMs=... outputActive=...`,随后是 `discord voice: realtime exact speech dequeued reason=player-idle ...`
- 检测到 barge-in 时:`discord voice: realtime barge-in detected source=speaker-start ...` 或 `discord voice: realtime barge-in detected source=active-speaker-audio ...`,随后是 `discord voice: realtime barge-in requested reason=... outputAudioMs=... outputActive=...`
- realtime 中断时:`discord voice: realtime model interrupt requested client:response.cancel reason=barge-in`,随后会出现 `discord voice: realtime model audio truncated client:conversation.item.truncate reason=barge-in audioEndMs=...` 或 `discord voice: realtime model interrupt confirmed server:response.done status=cancelled ...`
- On 忽略 echo/noise: `discord voice: realtime model interrupt ignored client:conversation.item.truncate.skipped reason=barge-in audioEndMs=0 minAudioEndMs=250`
- 禁用打断:`discord voice: capture ignored: ... reason=protected playback`
- 空闲播放时:`discord voice: realtime barge-in ignored reason=... outputActive=false ... playbackChunks=0`
若要调试音频被截断,请按时间线阅读 realtime 语音日志:
1. `realtime audio playback started` 表示 Discord 已开始播放 assistant 音频。从此时起,bridge 开始统计 assistant 输出 chunk、Discord PCM 字节、provider realtime 字节以及合成音频时长。
2. `realtime speaker turn opened` 标记 Discord 中某个说话者变为活跃状态。如果播放已在进行且启用了 `bargeIn`,这之后可能会出现 `barge-in detected source=speaker-start`。
3. `realtime input audio started` 标记该说话者轮次收到的第一帧实际音频。这里若 `outputActive=true` 或 `outputAudioMs` 非零,表示麦克风在 assistant 播放仍然活跃时正在输入。
4. `barge-in detected source=active-speaker-audio` 表示 OpenClaw 在 assistant 播放活跃时看到实时说话者音频。这有助于区分真正的中断和只是 Discord 说话开始事件但没有有效音频的情况。
5. `barge-in requested reason=...` 表示 OpenClaw 要求实时提供者取消或截断主动响应。 `outputAudioMs`和`playbackChunks`描述生成的音频;随后的 `audioEndMs` 截断字段记录每个本机项目消耗的音频。 Discord 测量 AudioPlayer 准备的 Opus 数据包的本地消耗,粒度为 20 ms;它无法测量远程监听器的播放。
6. `realtime audio playback stopped reason=...` 是本地 Discord 播放复位点。 `player-idle`表示Discord已完成音频消费;仅提供者 `response.done` 和编码器完成并不意味着播放已完成。其他原因包括 `barge-in`、`provider-clear-audio`、`forced-agent-consult`、`stream-close`、`output-audio-overflow` 和 `session-close`。
7. `realtime speaker turn closed` 会总结捕获到的输入轮次。`chunks=0` 或 `hasAudio=false` 表示说话者轮次已打开,但没有可用音频到达 realtime bridge。`interruptedPlayback=true` 表示该输入轮次与 assistant 输出重叠并触发了 barge-in 逻辑。
有用字段:
- `outputAudioMs`:realtime provider 在该日志行之前生成的 assistant 音频时长。
- `audioMs`:OpenClaw 在播放停止前统计的 assistant 音频时长。
- `elapsedMs`:打开和关闭播放流或说话者轮次之间的墙钟时间。
- `discordBytes`:发送到或从 Discord voice 接收的 48 kHz 立体声 PCM 字节数。
- `realtimeBytes`:发送到或从 realtime provider 接收的 provider 格式 PCM 字节数。
- `playbackChunks`:当前响应转发到 Discord 的 assistant 音频 chunk 数。
- `sinceLastAudioMs`:最后一帧捕获到的说话者音频与说话者轮次关闭之间的间隔。
常见模式:
- 立即截断,且 `source=active-speaker-audio`、`outputAudioMs` 很小,并且附近是同一用户,通常说明扬声器回声进入了麦克风。可提高 `voice.realtime.minBargeInAudioEndMs`、降低扬声器音量、使用耳机,或设置 `voice.realtime.providers.openai.interruptResponseOnInputAudio: false`。
- `source=speaker-start` 后接 `speaker turn closed ... hasAudio=false`,表示 Discord 报告了说话开始,但没有音频到达 OpenClaw。这可能是临时的 Discord voice 事件、噪声门行为,或客户端短暂触发麦克风。
- `audio playback stopped reason=output-audio-overflow` 表示持续交付问题超出了有界的待处理音频队列。检查关联的 `Discord realtime audio playback overflow` 错误和前面的提供程序或 Discord 连接诊断;普通播放背压不应产生此错误。
- `Discord voice receive backlog exceeded` 表示身份查找、解码或本地磁盘无法跟上传入的音频。 OpenClaw 将每个接收流限制为 1,000 个待处理数据包和 1 MiB 编码音频;等瓶颈消除后再说话。其他发言者和任何已注册的捕获保持活动状态,不完整的语音不能成为新的对话命令。
- `conversation audio backlog exceeded`、`conversation is busy` 或 `conversation transcript limit exceeded` 表示已达到会话限制。录音继续;等待待处理的请求完成或重复较短的完整请求。
- `Discord voice recording backlog exceeded` 表示待处理的 WAV 文件已达到记录队列的块或字节限制。受影响的话语停止,并且在待处理的音频处理赶上后,注册的捕获仍然可用。
- `audio playback stopped reason=stream-close` 且附近没有 barge-in 或 `provider-clear-audio`,表示本地 Discord 播放流意外结束。请检查前面的 provider 和 Discord 播放器日志。
- `capture ignored: ... reason=protected playback` 表示 OpenClaw 在助理音频处于活动状态时故意保留对话输入。明确开始的捕获仍然记录该演讲。如果您希望语音中断播放,请启用 `voice.realtime.bargeIn`。
- `barge-in ignored ... outputActive=false` 表示 Discord 或 provider VAD 报告了语音,但 OpenClaw 没有可中断的活动播放。这不应导致音频被截断。
凭据按组件进行解析:`voice.model` 的 LLM 路由身份验证、`tools.media.audio` 的 STT 身份验证、`tts`/`voice.tts` 的 TTS 身份验证以及 `voice.realtime.providers` 或提供商的正常身份验证的实时提供商身份验证身份验证配置。