OMSociety/dsh-xiaoai-bridge ↗★ 1

dsh-xiaoai-bridge

连接小爱音箱实现语音唤醒、识别与对话 适合拥有已刷机小爱音箱、想通过本地Python桥接器进行语音交互的用户。

套件
dsh-xiaoai-bridge
相容性
待驗證
Harness 依賴範圍
^0.2.0-rc.1
Cordis 依賴範圍
^4.0.4
版本
1.0.0
授權
MIT
最近更新
2026年10月4日

安裝

$npx -p @deepseek-ai/dsh dsh plugin --profile web add github:OMSociety/dsh-xiaoai-bridge

配置项说明

设置页在 DSH 里,分 8 个区,顺序就是下面表格的顺序。页面上的联动(比如关掉「连续对话」后「退出词」收起来)只影响显示,值本身保留。

保存怎么走:设置页保存时提交逐项操作(POST /plugin/xiaoai/config 的 ops,形如 {"op":"set"|"unset","path":[...]},「重置为默认」就是 unset)。写入前会严格校验,不合法直接 400 并说明哪一项不对(dsh-xiaoai-bridge config: ),值不会写进去。

坏值怎么活:运行时读配置会逐条和默认值比,越界或类型不对就回退默认值,并按坏值集合去重只告警一次:dsh-xiaoai-bridge: unusable config repaired with defaults: = ()。插件不会因为一个坏值起不来,但设置页里仍然显示你填的那个值——日志里出现这一行,就说明它没生效。

配置怎么生效

配置有三条通道,改之前先看这一项走哪条:

通道覆盖哪些设置什么时候生效
渲染出的 /config.py唤醒词、对话保持时长、连续对话、退出词、唤醒应答、退出应答、兜底播报文本、会话键、设备名、语音合成方式、豆包 App ID 与音色/音频格式/流式/语速、语音识别后端、行动准则与语音消息附加提示写盘即热重载:桥接器每秒轮询它的 mtime,一般 1 秒内生效
桥接器子进程的环境变量日志级别、静默启动、本地 API 服务的开关与监听地址/端口、音箱名称与音箱地址、音箱连接鉴权(开着时写 DSH_XIAOAI_TOKEN),以及两枚凭据进程启动时快照:改完要重启桥接器(设置页只重渲染配置,不会替你重启)
只影响插件自己的会话会话工作区、Agent 预设、任何会话都能让小爱说话、播报与回复器那一组新会话按新值组建;已经在跑的会话保留它启动时的预设与路由

渲染出的 config.py 是覆盖层,不是模板:它把仓库里的 bridge/config.py 当模块加载,然后只覆盖上面那几个键。文本框留空表示这一项不写,桥接器继续用自己的默认值(而不是写一个空值进去)。插件还故意不碰这些键:dsh.rule_prompt(自动播放与连续对话用的那条约束)、openai.*、asr.doubao.*,以及 vad / kws / audio_input / xiaoai 这些段——要调就直接改仓库里的 bridge/config.py,改完同样会被热重载,见音箱侧的调参。

凭据怎么放:两枚秘密都存在 DSH 的凭据库里,插件启动桥接器时才解析出来放进子进程环境(XIAOAI_API_TOKEN、DOUBAO_ACCESS_KEY)。本地 API 服务的访问令牌在设置页里只填凭据名(字母或下划线开头的标识符,默认 XIAOAI_API_TOKEN),真值由插件在第一次启动时生成并写进凭据库;豆包访问令牌反过来——凭据名固定在 doubaoAccessKeyCredential 里(默认 DOUBAO_ACCESS_KEY),令牌本身直接粘在卡片的密码框里,由插件写进凭据库。同一枚访问令牌在「音箱连接鉴权」开着时还会以 DSH_XIAOAI_TOKEN 交给桥接器,用来校验拨上 4399 的设备。所以设置表和渲染出的 config.py 里都没有明文令牌。换凭据名或换令牌之后都要重启桥接器,新值才会被带上。

两种语音合成方式:

语音合成方式写进配置实际用谁什么时候选
小爱原生(默认)xiaoai音箱自带的合成不想配豆包凭据,音色由设备决定
豆包语音合成doubao火山引擎的豆包语音合成想要固定音色、复刻音色或统一语速

选中的值一定会写进渲染出的 config.py,不存在「留空跟随模板」。以前的「朗读音色」(ttsSpeaker)已经删掉:它和这个开关本来是同一件事的两套入口——桥接器的旧规则就是看那个音色值是不是 xiaoai 来决定走哪条路。豆包音色现在只在选「豆包语音合成」时由「豆包音色」给,插件不再写 dsh.tts_speaker,桥接器模板里那个默认值原样留着。

注意:写一个桥接器不认识的值不会报错:它只记一条 Unknown tts_provider=...,然后按音色回退。「没报错」不等于「接上了」。

基本

配置项类型默认值说明
启用插件 enabled布尔开总开关。关掉后插件不再注册工具与技能,桥接器以 DSH_ENABLE=0 启动(xiaoai_speak 会直接回「插件已在设置中禁用」)。
音箱名称 deviceName文本小爱音箱显示用的名字,会出现在会话标题里,同时作为 XIAOAI_DEVICE_NAME 传给桥接器。它不参与设备绑定:设备键只看音箱地址,改它不会换会话。
音箱地址 deviceHost文本192.168.1.191音箱在局域网里的地址,作为 XIAOAI_DEVICE_HOST 传给桥接器,插件按它区分设备、决定这条语音进哪个会话。它不是插件去拨号的地址(是设备自己连 4399),填错的表现是语音落到别的设备键、会话归属错乱,而不是连不上音箱。
音箱连接鉴权 speakerAuth开关开4399 是设备拨进来的音频通道,开着时要求客户端带上与「本地 API 服务」里「访问令牌凭据名」同一枚令牌,否则握手被拒(桥接器日志报 401)。多数音箱上跑的官方客户端不带请求头,把设备侧 /data/open-xiaoai/server.txt 写成 ws://:4399?token= 就行;coderzc 那个 fork 也可以在设备上加 OPEN_XIAOAI_TOKEN。改完要重启桥接器(它在子进程启动时快照)。关掉它等于允许同一局域网里任何主机往音箱注音、触发「已连接」并顶掉正在用的音箱槽位——只有设备实在带不了令牌时才关。
会话键 sessionKey文本agent:main:dsh-xiaoai-bridge桥接器侧的会话标识(形如 agent::),只喂桥接器(日志前缀、按会话覆盖音色)。DSH 侧的会话由插件按音箱设备区分,所以改这里不会换掉音箱对话所在的会话。
会话工作区 sessionCwd工作区选择不指定(跟随默认工作区)音箱会话归到哪个工作区分组,agent 的工作目录也是它。宿主只服务有绝对 cwd 的会话,所以这里是选择器而不是文本框。改完对新会话生效。
音箱会话的 Agent 预设 agentPreset文本xiaoai音箱那个会话按哪个预设组建。留空用宿主默认预设;填了但没装不是错误:这次回落宿主默认,并留一条 agent-preset-missing 诊断。已经在跑的会话保留它创建时的预设。

唤醒与语音

配置项类型默认值说明
唤醒词 wakeKeywords多行文本你好肥鱼每行一个;逗号、顿号也算分隔符。命中即进入 DSH 对话。它同时写进桥接器的 wakeup.keywords(喂给唤醒词模型)与 dsh.wakeup_keywords(路由到 DSH 后端)。改完 1 秒内热生效。别把全角逗号写进词里:它会被当分隔符切掉,那个词就永远唤不醒。
对话保持时长(秒) wakeupTimeout整数 1-60020一次唤醒之后,这次对话保持多久。
连续对话 continuousConversation布尔关关:一句话一次唤醒。开:一次唤醒可以接着说下一句,直到静默超时或说出退出词。这一项即使关掉也会照写进配置,免得桥接器模板里的默认值反过来压过设置页。
语音识别后端 asrBackend枚举sense_voice另两个选项是 paraformer 与 fire_red_asr。选完后按「后端 + 量化 + 模型目录」重建识别器;选了本机没装模型的后端不会把音箱弄哑:继续用已装好的识别器,只警告一次,并记一条 asr-model-unavailable。识别语言固定为中文(auto 会把短音频判成日文,插件不暴露这个开关)。
语音合成方式 ttsProvider枚举xiaoai(小爱原生)两个选项:小爱原生 / 豆包语音合成,区别见上面那张表。

豆包语音合成

这一组只在「语音合成方式」选「豆包语音合成」时显示,选「小爱原生」时整组隐藏(值还留着,切回「豆包语音合成」就原样回来)。它不折叠,也没有自己的标题——上面那个选项已经写着「豆包语音合成」,再给一组标题只是重复。只有在想要豆包音色(固定音色、复刻音色、统一语速)时才要配。

去哪拿:在火山引擎控制台开通豆包语音合成、创建应用,拿到 App ID 与 Access Token(App ID 与 Access Token 的位置见控制台使用 FAQ https://www.volcengine.com/docs/6561/196768 ,可选音色见音色列表 https://www.volcengine.com/docs/6561/1257544 )。App ID 是普通设置项;Access Token 直接粘在设置页的「豆包访问令牌」里,由插件写进 DSH 凭据仓,不进设置文件、不进日志。

配置项类型默认值说明
豆包 App ID doubaoAppId文本空控制台里这个应用的 App ID。留空表示沿用桥接器模板里的占位值(等于没配)。
豆包访问令牌密码输入框(写进 DSH 凭据)未设置粘贴控制台里的 Access Token,点「保存令牌」由插件写进 DSH 凭据仓的 DOUBAO_ACCESS_KEY——凭据名固定在设置项 doubaoAccessKeyCredential 里(默认 DOUBAO_ACCESS_KEY),页面上不再让人填。令牌不进设置文件、不进草稿、不进日志,卡片上只显示「已配置 / 未配置」,旁边有「清除」。保存或清除后要重启桥接器:插件启动桥接器时把凭据解析成环境变量 DOUBAO_ACCESS_KEY,桥接器环境变量优先、取不到才回退渲染配置里的 tts.doubao.access_key。
豆包音色 doubaoSpeaker文本空用豆包时朗读的音色 ID(例如 zh_female_vv_uranus_bigtts);留空沿用桥接器配置里的默认音色。桥接器按音色前缀自动判定资源类型;复刻音色填控制台给的 S_xxxxxxxx。
豆包音频格式 doubaoAudioFormat枚举沿用配置(留空)可选:沿用配置 / 自动 / PCM / MP3 / OGG Opus。留空表示不写,用桥接器模板里的 pcm;「自动」按文本长短在 PCM 与 MP3 之间挑。音箱本地播放用 PCM 首音最快。
边合成边播放 doubaoStream布尔开开:边合成边播,首音更快;关:整段合成完再播。这一项即使关掉也会照写进配置。
豆包语速 ttsSpeed数字 0.5-21豆包朗读速度。只对豆包生效,小爱原生不看它。

注意:App ID 或缺访问令牌时,桥接器会明确报 Doubao TTS credentials are not configured,不会静默换回小爱原生。

应答与兜底

配置项类型默认值说明
唤醒应答 wakeupReplyText文本肥鱼来了唤醒词命中时先念的一句。留空表示不写,用桥接器模板默认(同样是「肥鱼来了」)。
退出应答 exitReplyText文本肥鱼走了连续对话结束时念的一句。
退出词 exitKeywords多行文本退出、停止、再见每行一个,说出任意一个就结束这次对话。只在「连续对话」打开时出现在页面上,值仍然保留。
兜底播报文本 fallbackText文本连不上电脑,请稍后再试桥接器还在跑、但联系不上插件时念的话:DSH 没在运行,或者插件路由不可达。

播报与回复器

音箱念出来的话不是模型的原始回复,而是先经过一次「回复器」调用做口语化润色(关掉「自动念出回复」之后,这一组里只有「任何会话都能让小爱说话」与「审批等待提示语」还有意义)。回复器是一次独立的模型调用,默认跟随该会话的模型路由。

配置项类型默认值说明
自动念出回复 autoSpeak布尔开模型这一轮没调 xiaoai_speak 时,把回复正文交给回复器润色后念出来。关掉后只有模型主动调工具才出声,回复器那一组选项会收起来(值保留)。审批等待提示语不受这个开关影响:审批是工具卡在屏幕上等人处理,这一句照念(见下一行)。
任何会话都能让小爱说话 speakFromAnySession布尔关关:xiaoai_speak 只在音箱发起的会话里可用,工具与技能也只注册在那一层。开:桌面与网页会话也能调它。
播报字数上限 spokenMaxChars整数 40-2000300一条播报最多多少字;超了先让回复器精简一次,仍然超就截断。
审批等待提示语 approvalText文本需要你到电脑上确认一下工具卡在宿主审批流上时念的固定一句,关掉「自动念出回复」也照念(审批意味着有工具正等你到电脑上点一下)。审批请求的正文永远不会被念出来。
回复器模型 replyerProvider / replyerModel下拉(DSH 模型目录)跟随会话默认模型从这台 DSH 已配置的模型里挑一个给回复器用;选项按 provider 分组,选中后写成「provider/model」两个键。选「跟随会话默认模型」等于把两项留空、不指定路由。选项直接读 DSH 的模型目录(读不到、目录为空、当前值已不在目录里,卡片都会写明并给「重试」)。切换只对回复器即时生效——语音会话的 agent 路由在会话创建时就定了,要重启 DSH 才换。
回复器参考轮数 replyerHistoryTurns整数 0-506回复器能看到最近多少轮对话(只用于润色,不影响主会话的上下文)。
回复器失败提示语 replyerFailureText文本回复器调用失败回复器连续失败时改念这一句,免得把没润色的原文念出去。

人格与提示词

这一组都是文本提示词,改完立刻影响下一次播报。「人格设定」「说话风格」与「输出限制」只进回复器请求(只管念出来的话);「行动准则」与「语音消息附加提示」由桥接器追加在每条语音输入后面(影响音箱会话里模型怎么答)。

配置项类型默认值说明
人格设定 personality多行文本内置身份句回复器的身份设定,默认是「你是一个通过小爱音箱和用户说话的语音助手,你的回答会被直接念出来。」改成别的内容后,回复器请求里会多出一行「关于你自己:…」。
说话风格 replyStyle多行文本内置风格句回复器怎么措辞,默认是「用日常、口语化的说法讲出来,就像对着用户说话一样。」
行动准则 behaviorStyle多行文本内置准则渲染成配置里的「行动准则:…」一段,由桥接器追加在每条语音输入后面:约束回答的写法——别用 Markdown、代码、emoji、颜文字、括号动作与 URL,一般 50 字以内、最多不超过 300 字,只有确实要逐字念出的内容才调 xiaoai_speak。提醒「回复会被念出来」的是下面那条「语音消息附加提示」。
输出限制 outputLimits多行文本内置限制写进回复器请求的硬性约束:只输出要念的话,不要 emoji、颜文字、Markdown 标记、括号里的动作或心理描写、URL、@ 提及,不要换行;长度是两档要求——一般 50 字以内、一两句话讲完,只有确实需要长回复时才展开,最多不超过 300 字。
语音消息附加提示 voiceRuleText多行文本内置提示桥接器把它追加在每条语音输入后面,告诉模型这条消息来自音箱、回复正文会被念出来。留空表示不写,用桥接器模板默认。

桥接器进程

配置项类型默认值说明
随插件启动桥接器 autoStart布尔开DSH 启动时顺手把桥接器进程拉起来。关掉后需要桥接器的调用会失败(xiaoai_speak 不会替你拉起进程)。
静默启动 silentStart布尔关开:桥接器连上音箱时不再出声(不发连接提示、不播启动提示音)。只在「随插件启动」打开时出现。
日志级别 logLevel枚举INFO桥接器进程的日志级别:DEBUG / INFO / WARNING / ERROR。走环境变量,改完要重启桥接器。
桥接器目录 bridgeDir文本(高级)空桥接器源码目录;留空用插件包内的 bridge/。指到自己的 checkout 时,虚拟环境与模型都在那边。
Python 解释器 pythonPath文本(高级)空跑桥接器的解释器;留空用 /.venv/Scripts/python.exe(Windows)。桥接器要求 Python 3.12 以上。

本地 API 服务

这一组管桥接器进程里那个 HTTP API Server,插件用它播报与探活(xiaoai_speak 走的就是它)。默认只监听本机。

配置项类型默认值说明
启用本地 API 服务 apiServerEnabled布尔开关掉后桥接器不提供 API,xiaoai_speak 会直接回「桥接器 API Server 已在设置中关闭」。
监听地址 apiServerHost文本127.0.0.1API Server 的监听地址。保持 loopback 最安全:改成 0.0.0.0 等于把音箱的播放与唤醒交给整个局域网。
监听端口 apiServerPort整数 1-655359092API Server 的端口。
访问令牌凭据名 apiServerTokenCredential文本(标识符)XIAOAI_API_TOKEN存放访问令牌的 DSH 凭据名,不是令牌本身。插件用它给 /asr 做 bearer 门禁,并把它交给桥接器。改完要重启桥接器,环境变量在进程启动时快照。

安全边界

能触达 POST /plugin/xiaoai/asr 的调用方,等于拿到了这个 agent 的输入通道:请求正文会被当成一句用户消息。这条路径上插件不做任何语义拦截,也没有给语音轮次单独收窄工具集——一句话得到的权限,等于它落进去的那个会话的权限。

机械保障只有两条:/asr 的 bearer 门禁(fail closed:没配置令牌一律 503,bearer 对不上回 401,且不看来源地址),以及宿主既有的审批流(审批前音箱先念固定的一句提示,审批请求的正文永不念出,决定由宿主做)。其余插件路由(/config、/bridge/*、/data/wipe)按设计不做鉴权:它们和 DSH 在同一台机器、同一个信任边界里。要更强的约束只能靠会话与 agent 层(预设、审批策略、沙箱)。

最小可用配置

{
  "enabled": true,
  "deviceName": "小爱音箱",
  "deviceHost": "192.168.1.191",
  "wakeKeywords": "你好肥鱼",
  "wakeupTimeout": 20,
  "continuousConversation": false,
  "agentPreset": "xiaoai",
  "asrBackend": "sense_voice",
  "ttsProvider": "xiaoai",
  "autoSpeak": true,
  "fallbackText": "连不上电脑,请稍后再试",
  "autoStart": true,
  "silentStart": false,
  "logLevel": "INFO",
  "apiServerEnabled": true,
  "apiServerHost": "127.0.0.1",
  "apiServerPort": 9092,
  "apiServerTokenCredential": "XIAOAI_API_TOKEN"
}

这是设置页里最常改的一组键。页面保存时提交的是逐项 ops,这份 JSON 是同一组键的可读写法;要用 POST /plugin/xiaoai/config 提交就放进 patch 字段(patch 与 ops 不能同时给)。

配置怎么生效

配置有三条通道,改之前先看这一项走哪条:

通道覆盖哪些设置什么时候生效
渲染出的 /config.py唤醒词、对话保持时长、连续对话、退出词、唤醒应答、退出应答、兜底播报文本、会话键、设备名、语音合成方式、豆包 App ID 与音色/音频格式/流式/语速、语音识别后端、行动准则与语音消息附加提示写盘即热重载:桥接器每秒轮询它的 mtime,一般 1 秒内生效
桥接器子进程的环境变量日志级别、静默启动、本地 API 服务的开关与监听地址/端口、音箱名称与音箱地址、音箱连接鉴权(开着时写 DSH_XIAOAI_TOKEN),以及两枚凭据进程启动时快照:改完要重启桥接器(设置页只重渲染配置,不会替你重启)
只影响插件自己的会话会话工作区、Agent 预设、任何会话都能让小爱说话、播报与回复器那一组新会话按新值组建;已经在跑的会话保留它启动时的预设与路由

渲染出的 config.py 是覆盖层,不是模板:它把仓库里的 bridge/config.py 当模块加载,然后只覆盖上面那几个键。文本框留空表示这一项不写,桥接器继续用自己的默认值(而不是写一个空值进去)。插件还故意不碰这些键:dsh.rule_prompt(自动播放与连续对话用的那条约束)、openai.*、asr.doubao.*,以及 vad / kws / audio_input / xiaoai 这些段——要调就直接改仓库里的 bridge/config.py,改完同样会被热重载,见音箱侧的调参。

凭据怎么放:两枚秘密都存在 DSH 的凭据库里,插件启动桥接器时才解析出来放进子进程环境(XIAOAI_API_TOKEN、DOUBAO_ACCESS_KEY)。本地 API 服务的访问令牌在设置页里只填凭据名(字母或下划线开头的标识符,默认 XIAOAI_API_TOKEN),真值由插件在第一次启动时生成并写进凭据库;豆包访问令牌反过来——凭据名固定在 doubaoAccessKeyCredential 里(默认 DOUBAO_ACCESS_KEY),令牌本身直接粘在卡片的密码框里,由插件写进凭据库。同一枚访问令牌在「音箱连接鉴权」开着时还会以 DSH_XIAOAI_TOKEN 交给桥接器,用来校验拨上 4399 的设备。所以设置表和渲染出的 config.py 里都没有明文令牌。换凭据名或换令牌之后都要重启桥接器,新值才会被带上。

两种语音合成方式:

语音合成方式写进配置实际用谁什么时候选
小爱原生(默认)xiaoai音箱自带的合成不想配豆包凭据,音色由设备决定
豆包语音合成doubao火山引擎的豆包语音合成想要固定音色、复刻音色或统一语速

选中的值一定会写进渲染出的 config.py,不存在「留空跟随模板」。以前的「朗读音色」(ttsSpeaker)已经删掉:它和这个开关本来是同一件事的两套入口——桥接器的旧规则就是看那个音色值是不是 xiaoai 来决定走哪条路。豆包音色现在只在选「豆包语音合成」时由「豆包音色」给,插件不再写 dsh.tts_speaker,桥接器模板里那个默认值原样留着。

注意:写一个桥接器不认识的值不会报错:它只记一条 Unknown tts_provider=...,然后按音色回退。「没报错」不等于「接上了」。

最小可用配置

{
  "enabled": true,
  "deviceName": "小爱音箱",
  "deviceHost": "192.168.1.191",
  "wakeKeywords": "你好肥鱼",
  "wakeupTimeout": 20,
  "continuousConversation": false,
  "agentPreset": "xiaoai",
  "asrBackend": "sense_voice",
  "ttsProvider": "xiaoai",
  "autoSpeak": true,
  "fallbackText": "连不上电脑,请稍后再试",
  "autoStart": true,
  "silentStart": false,
  "logLevel": "INFO",
  "apiServerEnabled": true,
  "apiServerHost": "127.0.0.1",
  "apiServerPort": 9092,
  "apiServerTokenCredential": "XIAOAI_API_TOKEN"
}

这是设置页里最常改的一组键。页面保存时提交的是逐项 ops,这份 JSON 是同一组键的可读写法;要用 POST /plugin/xiaoai/config 提交就放进 patch 字段(patch 与 ops 不能同时给)。