DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

OMSociety /

OMSociety/dsh-xiaoai-bridge

Verified

DSH 插件:把小爱音箱接进 DeepSeek Harness。喊一声唤醒词,答案从音箱里念出来。

★ 1 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@f579f79f
DSH XiaoAI Bridge

小爱音箱桥接器 DSH XiaoAI Bridge

把小爱音箱接进 DeepSeek Harness:喊一声唤醒词,答案从音箱里念出来。

桥接器是本地 Python 服务(源码在 bridge/),由插件当子进程托管;设置页、状态卡、播报纪律都在插件这一半。

version DSH license stars issues

这是什么 • 核心特性 • 功能概览 • 工作原理 • 快速开始 • 模型工具 • 配置项说明 • 数据放在哪 • 排错 • 开发 • 许可证与作者

免责声明:本项目是非官方技术研究项目,与小米及其关联公司没有隶属、合作、授权或背书关系;按「现状」提供,不附带任何保证。刷机与客户端补丁存在设备损坏、数据丢失、账号封禁等未知风险,动手前请读 DISCLAIMER.md。

这是什么

小爱音箱刷成 open-xiaoai 客户端之后,就能在设备上跑自己的语音程序。这个项目把它接进 DeepSeek Harness:

  • 你说唤醒词,音箱开始收音;识别出来的文本被当成一句用户消息,送进 DSH 的一个会话。
  • 会话的回复正文会被念回音箱(念之前先做一次口语化润色,让它听起来像在说话)。
  • 模型也可以反过来主动开口:调 xiaoai_speak,让音箱念出指定的内容。

仓库分两半:根目录是 DSH 插件(Node,lib/),bridge/ 是 桥接器。桥接器负责设备那一侧(TCP 音频、VAD、唤醒词、语音识别、语音合成、播放闸门),插件负责 DSH 这一侧(设置页、运行状态卡、进程托管与看门狗、接口鉴权、随包技能与预设)。插件拉起桥接器进程、渲染它的配置、看住它;桥接器也能脱离插件单独跑。

bridge/ 的源码来自 coderzc/open-xiaoai-bridge(MIT,其上游是 Open-XiaoAI),本仓库在它之上加了 DSH 后端、播报纪律、鉴权与生命周期管理。本仓库独立演进,不跟进上游。

核心特性

特性 说明
唤醒即对话 说唤醒词后直接说话,识别文本交给 DSH 会话;回复正文自动念出来,模型不用显式调工具。
主动说话 xiaoai_speak 工具让 agent 主动播报:提醒到点、任务完成,或者你在电脑上让它读一段原文。
半双工防自问自答 播报期间麦克风通路被播放闸门关掉,音箱不会听见自己。
播报留痕 每句真正念出去的话追加进 spoken.jsonl,随时可回看。
进程托管与看门狗 桥接器是插件拉起的子进程:崩溃按滑动窗口重启,起不来会留诊断;插件退出时先停它。
接口鉴权 /asr 走 bearer 门禁且 fail closed:没有令牌回 503,bearer 对不上回 401,不看来源地址。
状态卡与诊断 设置页里有一张运行状态卡:进程、API Server、令牌、预设,以及最近的错误码。
卸载不留残渣 卸载时删掉可以重建的那一半(渲染配置、pid、缓存),保留你的播报记录。
小爱模式(可选) 随仓库带一个音箱会话专用的 Agent 预设:会说话,能读写文件、查资料、跑命令、记待办,没有子代理与计划模式。

功能概览

唤醒即对话

唤醒词由桥接器在本地用 sherpa-onnx 识别,命中后开始收这句话,过 VAD 判断说完了,再做语音识别,最后把文本 POST 给插件的 /plugin/xiaoai/asr。插件把它投进这台音箱绑定的 DSH 会话(会话不存在就建一个),并把回复写回音箱。一次唤醒说一句,或者打开「连续对话」连着说,直到静默超时或说出退出词。

播报纪律

「什么时候出声、出声说什么」由插件里的一层纪律决定,不是模型想说什么就念什么:

  • 音箱发起的对话:回复正文会自动送进回复器润色后念出来;模型如果已经用 xiaoai_speak 指定了要念的话,就不再念回复正文。
  • 其他会话:默认不出声;打开「任何会话都能让小爱说话」后,桌面与网页会话也能让音箱开口。
  • 工具卡在审批上时念一句固定的提示,审批请求的正文永远不会被念出来。
  • 每次播放都走桥接器的播放闸门,播报期间麦克风通路是关的。

主动说话

xiaoai_speak 让 agent 不等人问就先开口:任务跑完了、提醒到点了、你要求把某段原文逐字念出来。桥接器没在跑时工具会顺手把它拉起来(「随插件启动桥接器」开着时),再等一会儿(最长约 12 秒)。音箱发起的会话里,工具与技能只注册在这台设备的会话作用域内;打开「任何会话都能让小爱说话」后注册回全局,桌面会话也能用。

进程托管与看门狗

插件负责桥接器的整个生命周期:启动前渲染配置、把设置项转成环境变量、把凭据从 DSH 凭据库解析进子进程环境;运行中收日志、探活、崩溃后按滑动窗口重启;DSH 退出或插件重载时先停子进程,再清掉可以重建的文件(bridge.log、spoken.jsonl 这些记录留着)。

状态卡与诊断

设置页的运行状态卡显示桥接器进程、API Server 是否可达、令牌是否配置、预设是否挂上,以及最近几条错误码(卡片最多显示 3 条,同一编码且详情相同才合并计数)。诊断行也会写进 DSH 日志,前缀是 dsh-xiaoai-bridge:,编码含义见排错。

小爱模式

插件自带的 bundle 里还有一个音箱会话专用的 Agent 预设(显示名「小爱模式」):只有音箱会话用它,能跑命令、读写文件、查资料、记待办,没有子代理、工作流与计划模式——在音箱上这些只会拖慢第一句话。它随插件一起装好,设置页默认已经指向它;宿主读不到这个预设也不会报错,只回落宿主默认预设并留一条诊断。

桥接器 HTTP 接口

桥接器进程里有一个 HTTP API Server(默认 127.0.0.1:9092),插件用它做播报与健康检查,端点见 bridge/docs/openxiaoai-voice-api.md。插件自己的路由挂在宿主 webServer 上,前缀 /plugin/xiaoai:

方法 路径 用途
GET /plugin/xiaoai/health 插件概况(含令牌是否配置)
GET /plugin/xiaoai/config 读设置(供设置页用;保存时带 revision)
POST /plugin/xiaoai/config 写设置(ops 或 patch,二选一)
POST /plugin/xiaoai/asr 桥接器提交一句识别文本(bearer 门禁)
GET /plugin/xiaoai/devices 已绑定的音箱设备与它们的会话键
GET /plugin/xiaoai/bridge/status 桥接器进程状态与日志路径
GET /plugin/xiaoai/bridge/health 经插件访问桥接器的健康检查
GET /plugin/xiaoai/bridge/logs 最近日志(limit 1-400)
POST /plugin/xiaoai/bridge/start 启动桥接器
POST /plugin/xiaoai/bridge/stop 停止桥接器
POST /plugin/xiaoai/bridge/restart 重启桥接器(换了环境变量类的设置后用)
POST /plugin/xiaoai/data/wipe 清空数据目录(body 必须是 {"confirm":"wipe"})

工作原理

flowchart LR
    Spk[小爱音箱] -- 唤醒词 --> Rust
    Rust["Rust 扩展 dsh_xiaoai_server(TCP 4399)"] --> App["bridge/core/app.py"]
    App -- 识别文本 --> Http["插件 lib/http.js(/plugin/xiaoai/asr)"]
    Http --> Session["DSH 会话"]
    Session -- 回复正文或 xiaoai_speak --> Http
    Http -- 播放请求 --> Api["桥接器 API Server(127.0.0.1:9092)"]
    Api --> Rust
    Rust -- 播放 --> Spk

三个端口要分清:4399 是 Rust 扩展固定的音频端口,音箱侧要拨到它(默认要带令牌,见下面的「音箱连接鉴权」);9092 是桥接器的 API Server;插件自己的路由挂在宿主 webServer 上,不额外占端口。

快速开始

前置条件

需要 版本 / 说明
DSH 0.2.0-rc.1 或更新(插件的 peer 依赖就是这条插件线)
Node 20 或更新
pnpm 装插件依赖用(只有一个运行依赖 @deepseek-ai/schemastery)
Python 3.12
uv 建桥接器虚拟环境、装依赖、编译 Rust 扩展
Rust 工具链 uv sync 会用 maturin 现场编译 PyO3 扩展,第一次要十几分钟
小爱音箱 已刷机并打过 open-xiaoai 客户端补丁(这一步在上游,见下)

步骤

  1. 停掉正在运行的 DSH,把仓库取回来:
git clone https://github.com/OMSociety/dsh-xiaoai-bridge.git
Set-Location dsh-xiaoai-bridge
  1. 准备桥接器的 Python 侧(在仓库的 bridge/ 下):
Set-Location bridge
uv sync --no-install-project
uv sync
.\.venv\Scripts\python.exe -c "import dsh_xiaoai_server; print('ok')"

第一次 uv sync 会现场编译 Rust 扩展,十几分钟;之后只有改过 bridge/native/**/*.rs 才需要重跑(重跑前先停桥接器,Windows 上扩展文件被占用就删不掉)。

  1. 下模型包。约 470 MB,不随仓库走,必须手动放到桥接器的模型目录:
项目 值
下载地址 https://github.com/coderzc/open-xiaoai-bridge/releases/download/vad-kws-asr-models/models.zip
大小 493,248,891 字节
sha256 8E8A709D6EA011F644F3C5055F536D5E6EB363EEAFBA53CC3232398FD636D273
放到哪里 解压出的内容直接放进 bridge/core/models/

模型包由上游 release 提供,本仓库不再分发;其中的语音模型与运行时组件各按其上游项目的许可使用——sherpa-onnx 系组件为 Apache-2.0,silero-vad 为 MIT,SenseVoice 与 Paraformer 等模型以各自上游项目声明的许可为准,再分发或商用前请先核对。

  1. 装插件并重启 DSH:
dsh plugin --profile desktop add "D:\path\to\dsh-xiaoai-bridge"

插件也发布在 npm 上(包名就是插件名 dsh-xiaoai-bridge),装法三选一:本机 checkout 用上面的绝对路径(进 profile 是 link:,改代码即时生效)、npm 用 dsh plugin --profile desktop add dsh-xiaoai-bridge、或从 GitHub 用 dsh plugin --profile desktop add "github:OMSociety/dsh-xiaoai-bridge#1.0.0"(换成 #main 即跟随开发分支)。npm 与 GitHub 两条都只带源码资产,没有 bridge/ 的虚拟环境与模型包,需要自己补一份并把设置页的「桥接器目录」指过去。

  1. 音箱侧(属于上游):刷机、打客户端补丁,并确认设备侧的拨号地址。

  2. 打开设置页确认几项:启用插件(开)、音箱名称、音箱地址(音箱在局域网里的 IP)、会话工作区。「音箱连接鉴权」保持默认开——设备侧要么按下面那条提示带上令牌,要么把它关掉(关掉等于允许同一局域网里任何主机往音箱注音)。

  3. 对着音箱说唤醒词,然后说话;回复会从音箱里念出来。

提示:刷机教程见 open-xiaoai 的 flash.md,客户端补丁见 client-rust 的 README。设备侧还要确认音箱上 /data/open-xiaoai/server.txt 指向 ws://<这台电脑的局域网 IP>:4399?token=<访问令牌>——那是设备自己的拨号地址,不在本仓库里;多数音箱上跑的官方客户端不带任何请求头,只认 URL 里这个令牌(coderzc 那个 fork 也可以改成在设备上加 OPEN_XIAOAI_TOKEN)。地址或端口指错了的表现是音箱完全没反应、本地日志里什么错都不会有;地址对但没带令牌的表现是桥接器日志里报 401、音箱同样没反应。

提示:「小爱模式」预设就写在插件的 cordis.patch.yml 里,随插件一起装好,不用单独安装。设置页的「音箱会话的 Agent 预设」默认就是 xiaoai;宿主读不到它不会报错,只会回落宿主默认并留一条 agent-preset-missing 诊断。

注意:装完必须重启 DSH。保存设置只会重新渲染桥接器的配置文件(桥接器 1 秒内热重载),但写在子进程环境变量里的那几项——日志级别、静默启动、本地 API 服务的开关与监听地址、两枚凭据(API 访问令牌与豆包访问令牌)——要重启桥接器才生效,见配置怎么生效。

模型工具

工具 用途 关键参数
xiaoai_speak 让音箱念出一段文字 text(必填):要念的原话,逐字念
  • 音箱发起的对话本来就会把回复正文念出来(念之前先做一次口语化润色),所以模型通常不用调它:直接写回复正文就行。只有要逐字念出的原文(口令、验证码)、提醒与通知、任务完成的结论,或者用户明确要求出声时才调。
  • 一轮只念一次:同一轮里第二次调用会被忽略;这一轮已经调过工具时,回复正文不会再被念一遍。
  • 调用在把播放交给音箱之后立刻返回(桥接器的同步播放路径在这台设备上不可靠,插件一律用异步)。
  • text 会被逐字念出来,别放 Markdown、代码块、列表和 URL。
  • 默认只在音箱发起的会话里可用;打开「任何会话都能让小爱说话」后,桌面与网页会话也能调它。
  • 桥接器没在跑时工具会顺手拉起它(「随插件启动桥接器」开着时),并等它起来(最长约 12 秒)。
  • 模型侧还有一份随插件注册的技能 xiaoai-speak,讲的是同一套纪律:什么时候该出声、什么时候不该。

配置项说明

设置页在 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://<电脑 IP>:4399?token=<令牌> 就行;coderzc 那个 fork 也可以在设备上加 OPEN_XIAOAI_TOKEN。改完要重启桥接器(它在子进程启动时快照)。关掉它等于允许同一局域网里任何主机往音箱注音、触发「已连接」并顶掉正在用的音箱槽位——只有设备实在带不了令牌时才关。
会话键 sessionKey 文本 agent:main:dsh-xiaoai-bridge 桥接器侧的会话标识(形如 agent:<agentId>:<其余>),只喂桥接器(日志前缀、按会话覆盖音色)。DSH 侧的会话由插件按音箱设备区分,所以改这里不会换掉音箱对话所在的会话。
会话工作区 sessionCwd 工作区选择 不指定(跟随默认工作区) 音箱会话归到哪个工作区分组,agent 的工作目录也是它。宿主只服务有绝对 cwd 的会话,所以这里是选择器而不是文本框。改完对新会话生效。
音箱会话的 Agent 预设 agentPreset 文本 xiaoai 音箱那个会话按哪个预设组建。留空用宿主默认预设;填了但没装不是错误:这次回落宿主默认,并留一条 agent-preset-missing 诊断。已经在跑的会话保留它创建时的预设。

唤醒与语音

配置项 类型 默认值 说明
唤醒词 wakeKeywords 多行文本 你好肥鱼 每行一个;逗号、顿号也算分隔符。命中即进入 DSH 对话。它同时写进桥接器的 wakeup.keywords(喂给唤醒词模型)与 dsh.wakeup_keywords(路由到 DSH 后端)。改完 1 秒内热生效。别把全角逗号写进词里:它会被当分隔符切掉,那个词就永远唤不醒。
对话保持时长(秒) wakeupTimeout 整数 1-600 20 一次唤醒之后,这次对话保持多久。
连续对话 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-2 1 豆包朗读速度。只对豆包生效,小爱原生不看它。

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

应答与兜底

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

播报与回复器

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

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

数据放在哪

插件的数据目录是 $DSH_HOME/xiaoai-bridge(没有设 DSH_HOME 时是 ~/.dsh/xiaoai-bridge)。

内容 位置 说明
渲染出的桥接器配置 <数据目录>/config.py 覆盖层,模板是仓库里的 bridge/config.py;每次保存设置重写一次,删掉也会在下次启动时重新渲染
桥接器日志 <数据目录>/bridge.log 桥接器进程的 stdout/stderr,加上插件自己追加的诊断行;GET /plugin/xiaoai/bridge/logs 读它。文件超过 8 MiB 时轮转一次,旧的那份是 bridge.log.1(只留一个槽位)
播报留痕 <数据目录>/spoken.jsonl 每念一句追加一行;到 5 MiB 轮转一次,旧的那份是 spoken.jsonl.1(只留一个槽位)
进程文件 <数据目录>/bridge.pid 记着当前桥接器进程,启动时重写
设备与会话映射 <数据目录>/devices.json 音箱设备到 DSH 会话的绑定;绑定的会话被归档后会自动重开一个
桥接器设备标识 <数据目录>/device.json 桥接器自己持久化的设备 ID(device_id),写在配置文件同目录
桥接器源码与虚拟环境 仓库的 bridge/(或「桥接器目录」指向的地方) .venv 由 uv sync 生成,Rust 扩展的编译产物也在里面
模型文件 bridge/core/models/ 约 470 MB,不入库、不随插件走,按快速开始那一节下载
设置值与令牌真值 DSH 的设置库与凭据库 设置值不在 config.py 里;令牌只以 DSH 凭据存在(bridge/config.py.rendered、**/devices.json、**/device.json、*.token、credentials.json 都在 .gitignore 里,绝不入库)

提示:bridge.log 会逐字记下音箱这侧说的话与桥接器回的话(日志行前缀是 我说: 与 DSH:),把它贴出去排障前,先确认里面没有不想公开的内容;上一段日志在 bridge.log.1 里,同样含原文。

DSH 退出、插件重载与 dsh plugin remove 跑的是同一套清理,它只删可以重建的那一半(config.py、bridge.pid、*.tmp、__pycache__),留着 bridge.log、spoken.jsonl、devices.json、device.json 这些记录——播报记录本来就是为了跨重启活下来。要连记录一起清,卸载前调 POST /plugin/xiaoai/data/wipe(body {"confirm":"wipe"}),或者卸载后直接删掉整个数据目录。

排错

状态卡编码

设置页的运行状态卡会列出最近的错误。编码含义如下(卡片最多显示 3 条;同一编码且详情相同才合并计数):

编码 什么时候出现
bridge-unreachable 桥接器没响应:进程挂了,或者监听地址与端口不对
bridge-rejected 连上桥接器了,但令牌被它拒绝
plugin-rejected 插件的 /asr 拒绝了调用方:没有令牌回 503,bearer 对不上回 401
bridge-error 桥接器返回了错误状态
bridge-timeout 调用桥接器超时
start-failed 桥接器进程没起来(解释器路径、依赖、Rust 扩展缺失都会走到这里)
watchdog-gave-up 崩溃次数超过重启预算,看门狗不再重启
port-held 旧进程本该被杀掉,但端口还在应答
token-not-applied 桥接器启动早于令牌写入,只能走 loopback;重启桥接器即可
scope-registration-unavailable 宿主不支持按会话注册工具,xiaoai_speak 这次没有注册(不会退回全局注册)
scope-registration-failed 把工具注册进会话作用域时抛错
agent-preset-missing 设置里指定的预设没装,这次回落宿主默认预设
agent-preset-broken 预设装不上(清单本身有问题)
agent-preset-mount-failed 预设挂到音箱会话时失败
session-archived-rebound 绑定的会话被归档了,插件为这台音箱新开了一个
asr-model-unavailable 设置页选的语音识别后端在本机用不了,继续用原来那个

日志与状态在哪

  • 状态卡:设置页里,看进程、API Server、令牌、预设与最近错误。
  • 插件日志:DSH 自己的日志,诊断行以 dsh-xiaoai-bridge: 开头。
  • 桥接器日志:<数据目录>/bridge.log,或调 GET /plugin/xiaoai/bridge/logs?limit=200 看最近若干行。
  • 播报留痕:<数据目录>/spoken.jsonl——「音箱到底念了什么」看这里,它记的是真正播出去的话。

常见症状

  • 音箱完全没反应,本地不报错:检查设备侧的拨号地址(音箱上 /data/open-xiaoai/server.txt 里的 ws://<电脑 IP>:4399)与 4399 端口,再看状态卡有没有 bridge-unreachable。
  • 音箱连不上,桥接器日志里是 401:设备侧没带令牌。把 /data/open-xiaoai/server.txt 改成 ws://<电脑 IP>:4399?token=<访问令牌>(或在支持令牌的客户端上加 OPEN_XIAOAI_TOKEN)后重启音箱上的客户端;实在改不了就去设置页关掉「音箱连接鉴权」,代价是同一局域网里任何主机都能往音箱注音。
  • 每句话都被拒:看 plugin-rejected 与 token-not-applied;令牌在 DSH 凭据库里,桥接器要带着它重启一次。
  • 唤醒没反应:确认模型包放对了位置(bridge/core/models/);桥接器启动后加载模型要几十秒;唤醒词换成更好识别的说法。
  • 音箱自己接自己的话:有播报路径没走播放闸门,属于代码问题——请报 issue 并附上 bridge.log(它含对话原文,贴之前先看一眼)。
  • 设置改了没生效:先看配置怎么生效那张表(环境变量那一档要重启桥接器),再在日志里找有没有 unusable config repaired with defaults:。

音箱侧的调参

下面这些键在桥接器的模板 bridge/config.py 里,插件不渲染它们。要改就直接改那份模板(渲染产物把它当模块加载,改完 1 秒内热重载),改动前先看 AGENTS.md 的「桥接器(bridge/)」一节:

  • 唤醒词不灵:换更好识别的词;kws.keywords_threshold(默认 0.2)调低会更灵敏;启动后模型加载要几十秒。
  • 话没说完就被抢答:调大 vad.min_silence_duration(默认 500 毫秒,可以先试 1000)。
  • 麦克风收得小:调 audio_input.gain(默认 1.0,从 2.0 试着加,过高会失真)。
  • 想打断播报:直接对小爱喊「小爱同学」。

卸载

dsh plugin --profile desktop remove dsh-xiaoai-bridge

插件会先停掉桥接器子进程,再删掉可以重建的文件;bridge.log、spoken.jsonl、devices.json、device.json 会留在数据目录里,想一起清掉就按数据放在哪那一节的说明处理。

开发

# 插件侧(仓库根):九个离线检查,全绿会打印 [check-all] 全部 9 个检查通过。
npm run check

# 也可以逐条跑
node scripts\check-client.mjs      # 客户端 bundle
node scripts\check-config.mjs      # 配置渲染
node scripts\check-keywords.mjs    # 唤醒词 / 退出词
node scripts\check-session.mjs     # 会话与设备路由
node scripts\check-supervisor.mjs  # 进程托管与看门狗
node scripts\check-speak.mjs       # 播报纪律与工具
node scripts\check-diagnostics.mjs # 错误库与失败分类
node scripts\check-http.mjs        # HTTP 层(鉴权、体积上限、同源、路由)
node scripts\check-cleanup.mjs     # 数据目录切分与端口探测

# 桥接器侧
Set-Location bridge
.\.venv\Scripts\python.exe -m pytest -q

代码放在哪:

lib/index.js         插件入口:设置卡片、生命周期、session/event 转发
lib/process.js       子进程托管:启动、停止、日志、看门狗、环境变量
lib/render-config.js 设置项 → 渲染出的 config.py
lib/tools.js         xiaoai_speak 工具
lib/auto-speak.js    播报纪律(谁在什么时候出声)
lib/bridge.js        桥接器 HTTP 客户端与失败分类
lib/diagnostics.js   错误库
lib/session.js       设备与会话绑定
lib/speech-log.js    播报留痕
lib/cleanup.js       数据目录切分与卸载
lib/client.js        设置页与运行状态卡
skills/xiaoai-speak/ 模型用的技能
cordis.patch.yml     bundle 声明(插件本体 + 「小爱模式」预设)
bridge/              Python 桥接器(DSH 后端在 core/dsh*.py)
scripts/             自检脚本(九个 check-*.mjs 与聚合入口)

动了插件行为就补对应的 checker,动了桥接器就补 bridge/tests/;npm run check 与 pytest 全绿是提交前的底线。环境、约定与与上游的关系见 CONTRIBUTING.md,给编码 agent 的硬规则见 AGENTS.md。

更新日志

逐条变更记在 CHANGELOG.md:当前版本 1.0.0,CHANGELOG.md 现在只有文件头,1.0.0 的条目与日期在打 tag 那天补(仓库里的 tag 都属于上游桥接器,插件版本号没有单独打 tag)。

支持与致谢

  • 问题与需求走 Issues,改动走 PR;顺手点个 Star 也行。
  • 桥接器的源码来自 coderzc/open-xiaoai-bridge(MIT),它受 Open-XiaoAI 启发;刷机与客户端补丁都在上游:
    • 刷机教程:https://github.com/idootop/open-xiaoai/blob/main/docs/flash.md
    • Client 端安装:https://github.com/idootop/open-xiaoai/blob/main/packages/client-rust/README.md
    • 豆包 TTS 音色列表:https://www.volcengine.com/docs/6561/1257544
  • 还用到 sherpa-onnx、onnxruntime、aiohttp、PyO3 与 maturin 这些开源项目。

许可证与作者

MIT。bridge/ 的原始版权行(Del Wang、coderzc)原样保留,本仓库新增部分的版权行追加在其后(© 2026 OMSociety)。第三方组件的许可见各自项目。

—/ 5

No ratings yet

Verified DSH bundle

Commit f579f79f3dd7

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout