DSH 插件:把小爱音箱接进 DeepSeek Harness。喊一声唤醒词,答案从音箱里念出来。
31.5/100
综合分
2
GitHub 星标
86
npm 周下载
—/5
用户评分
数据截至 2026/10/19 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add dsh-xiaoai-bridgenpm 源 · dsh-xiaoai-bridge 的发布者账号已校验与本仓库一致
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:已验证
是什么
dsh 原生插件 · security
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 13 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查✓ 自动检查通过展开查看检查明细 ↓
以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。
✓npm 包dsh-xiaoai-bridge @ 1.0.0
✓Node 引擎要求 >=20 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明
验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/12 21:21:42
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 42 处,展示前 42 条)
- 读取本地文件lib/index.js:527
bridgeDirIsDirectory = existsSync(paths.bridgeDir) && statSync(paths.bridgeDir).isDirectory(); - 读取本地文件lib/index.js:527
bridgeDirIsDirectory = existsSync(paths.bridgeDir) && statSync(paths.bridgeDir).isDirectory(); - 读取本地文件lib/index.js:615
pythonExists: existsSync(paths.pythonPath), - 读取本地文件lib/index.js:616
modelsDirExists: existsSync(paths.modelsDir), - 读取本地文件lib/index.js:617
skillFileExists: existsSync(join(SKILL_DIR, 'SKILL.md')), - 发起网络请求lib/client.js:1143
return fetch(CREDENTIAL_URL, { headers: { accept: "application/json" } }) - 发起网络请求lib/client.js:1166
fetch(CREDENTIAL_URL, { - 发起网络请求lib/client.js:1319
return fetch(CONFIG_URL, { headers: { accept: "application/json" } }) - 发起网络请求lib/client.js:1349
return fetch(HEALTH_URL, { headers: { accept: "application/json" } }) - 发起网络请求lib/client.js:1464
fetch(CONFIG_URL, { - 读取本地文件lib/skill.js:45
const raw = readFileSync(SKILL_FILE, 'utf8').trim(); - 读取本地文件lib/process.js:102
if (statSync(logPath).size <= MAX_LOG_BYTES) return; - 写入本地文件lib/process.js:103
renameSync(logPath, `${logPath}.1`); - 写入本地文件lib/process.js:273
mkdirSync(dataDir, { recursive: true }); - 读取本地文件lib/process.js:314
raw = readFileSync(pidPath, 'utf8').trim(); - 写入本地文件lib/process.js:430
writeFileSync(tempPath, `${JSON.stringify(payload)}\n`, 'utf8'); - 写入本地文件lib/process.js:431
renameSync(tempPath, pidPath); - 删除本地文件lib/process.js:472
unlinkSync(pidPath); - 读取本地文件lib/process.js:490
entries = readdirSync(dir, { withFileTypes: true }); - 读取本地文件lib/process.js:502
const mtime = statSync(full).mtimeMs; - 读取本地文件lib/process.js:526
pidMtime = statSync(pidPath).mtimeMs; - 读取本地文件lib/process.js:533
const mainMtime = statSync(join(bridgeDir, 'main.py')).mtimeMs; - 执行外部命令来自配置/变量lib/process.js:872
proc = spawn(pythonPath, ['main.py'], { - 执行外部命令固定命令lib/process.js:1015
const killer = spawn('taskkill', args, { windowsHide: true, stdio: 'ignore' }); - 发起网络请求lib/bridge.js:187
const response = await fetch(url, { - 读取本地文件lib/session.js:254
if (!existsSync(storePath)) return; - 读取本地文件lib/session.js:256
const parsed = JSON.parse(readFileSync(storePath, 'utf8')); - 写入本地文件lib/session.js:295
mkdirSync(dataDir, { recursive: true }); - 写入本地文件lib/session.js:301
writeFileSync(tmp, `${payload}\n`, 'utf8'); - 写入本地文件lib/session.js:302
renameSync(tmp, storePath); - 读取本地文件lib/speech-log.js:67
bytes = (await stat(path)).size; - 删除本地文件lib/speech-log.js:79
await unlink(rotatedPath).catch(() => {}); - 写入本地文件lib/speech-log.js:80
await rename(path, rotatedPath); - 写入本地文件lib/speech-log.js:96
await mkdir(dirname(path), { recursive: true }); - 写入本地文件lib/speech-log.js:110
await appendFile(path, line, 'utf8'); - 读取本地文件lib/cleanup.js:75
return readdirSync(root); - 读取本地文件lib/cleanup.js:88
const info = lstatSync(path); - 删除本地文件递归lib/cleanup.js:90
rmSync(path, { recursive: true, force: true }); - 删除本地文件lib/cleanup.js:95
rmSync(path, { force: true }); - 写入本地文件lib/render-config.js:59
renameSync(from, to); - 删除本地文件lib/render-config.js:65
unlinkSync(from); - 写入本地文件lib/render-config.js:296
writeFileSync(tmp, source, 'utf8');
扫描于 2026/10/31(0 天前) · 范围 入口闭包 + 全包扫描 · 来源 npm 发布包
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
依赖的 DSH / Cordis 模块
@deepseek-ai/schemastery@deepseek-ai/cordis@deepseek-ai/dsh-agent@deepseek-ai/dsh-api-remotes@deepseek-ai/dsh-client-ui-plugin-manager@deepseek-ai/dsh-client-ui-primitives@deepseek-ai/dsh-client-ui-slots@deepseek-ai/dsh-credentials@deepseek-ai/dsh-host-webserver@deepseek-ai/dsh-llm@deepseek-ai/dsh-session@deepseek-ai/dsh-settings给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- 接入小爱音箱
- 唤醒词触发
- 语音播报答案
最近更新
在 GitHub 查看全部 →v1.0.12026-11-01
· 修复
· xiaoai_speak 的作用域注册不随插件卸载撤销。 lib/exposure.js 把工具与技能注册进各会话 agent 自己的 ctx,disposer 只留在局部变量里,dispose() 仅关全局层;agent 作用域比插件活得久,禁用之后新会话仍带着这两个条目,重新启用会在同一作用域里再注册一份(同名注册二次抛错,事件监听静默双份)。现在注册包在 agentCtx.effect 里——宿主提供该座椅时条目随 agent 一起收回——同时把 unwinder 存进插件自己的 scopedUnwinders,dispose() 一并清空;两侧谁先跑都幂等,不会重复撤销。
· 客户端样式表在插件停用后残留。 lib/client.js 的 ensureStyles() 直接往 document.head 插 、不返回 disposer,apply() 又是裸调用,禁用后规则留在宿主页面上。现在返回移除该节点的 disposer,并由 apply() 交给 ctx.effect。
· Fixed
· The scoped xiaoai_speak registration outlived a disabled plugin. lib/exposure.js registered the tool and its skill into each speaker session's own agent context but kept the disposers in a local array, so dispose() only dropped the global layer. An agent scope outlives the plugin, so new sessions kept both entries after a disable, and re-enabling registered a second copy in the same scope (a duplicate named registration throws; event listeners just doubled). The registration now runs inside agentCtx.effect — with that seam the entries go away with the agent — and its unwinder is held in the plugin's own scopedUnwinders, which dispose() drains; whichever side runs first wins, and running twice is a no-op.
· The client stylesheet survived a disabled plugin. ensureStyles() in lib/client.js inserted a into document.head without returning a disposer, and apply() called it bare, leaving the rules on the host page after a disable. It now returns a disposer that removes the node, which apply() hands to ctx.effect.
v1.0.02026-10-18
· 新增
· 插件本体:唤醒词收音 → DSH 会话 → 回复念回音箱的完整链路;设置页可调唤醒词、退出语、回复器提供商与模型、TTS 提供商与音色、语速、会话工作目录、日志级别等,并带一张运行状态卡与最近的错误码。
· xiaoai_speak 工具与播报纪律:模型可以主动开口;音箱发起的对话自动把回复正文念出来;工具卡在审批上时只念一句固定提示,审批请求的正文永远不会被念出来;每句真正念出去的话追加进 spoken.jsonl。
· 豆包 TTS 与凭据:Access Token 存在 DSH 凭据仓的固定凭据名 DOUBAO_ACCESS_KEY 下,在设置卡片里粘贴保存即可,令牌不进设置文件、不进日志。
· 桥接器:插件托管的本地 Python 子进程,负责设备那侧(TCP 音频、VAD、sherpa-onnx 唤醒词、语音识别、语音合成、播放闸门)与 API Server;Rust 原生侧完成 4399 握手与播放器状态三态;崩溃按滑动窗口重启,插件退出时先停它。
· 随包资产与验收底线:skills/xiaoai-speak 技能、音箱会话专用的 Agent 预设、locale/ 中英文案,以及仓库根的 npm run check(九条)与 bridge/tests/(pytest)作为提交前底线。
· 变更
· 版本从 1.0.0 起算,本文件从这个版本开始记录。
· xiaoai_speak 的发言权交还收紧:只有桥接器明确答复(HTTP 非 2xx,如 503/401)才把本回合交还给自动播报;超时、连不上、抛异常都保持占用本回合——宁可这一轮不响,也不冒同一轮播两次的风险。
· 作用域注册(registerScoped)与全局逃逸门一样收集 disposer:中途失败会回滚已经注册的那一层,不再留半注册状态。
· 设置卡片的模型列表提示分层:「列表为空」优先于「部分条目读取失败」,只有确实读到部分条目时才说列表可能不完整。
· 修复
· 播放链路:后台播报任务创建失败会释放队列槽位并返回 503;/api/interrupt 同时取消排队与在播任务;原生唤醒词在播放期间仍能打断。
· 回复器:流中断(aborted 或超时)时不再丢掉已经生成、且已经说完一句的文本,并把 degraded 记进播报记录。
· 配置层:校验覆盖 DEFAULTS 的全部 44 个键(原先只有 12 条显式规则,其余键的坏类型会原样进运行时);空串仍然表示「用内置默认」。
· 暴露层:把「宿主没有 scoped seam」这个事实与告警去重拆成两个闩锁,逃逸门开关不再谎报 seam 是否存在。
· 设置卡片:保存遇到 409 冲突时保留草稿、只换版本号;取回配置失败不再丢已有快照;挂载与刷新按钮在草稿脏时不再悄悄重播表单。
· 桥接器:Rust TTS 拿到空音频流时按错误处理(不再静默成功);ASR 模型加载与 4399 握手加固(鉴权提示、重试退避、超时可配)。
· Added
· The plugin itself: wake word capture → DSH session → reply spoken back to the speaker, with a settings page for the wake word, the exit phrase, the replyer provider and model, the TTS provider and voice, the speaking rate, the session working directory and the log level, plus a status card with the most recent diagnostic codes.
· The xiaoai_speak tool and the speaking discipline: the model can speak on its own; speaker-initiated turns have their reply text spoken automatically; a tool card waiting on approval speaks one fixed line and never the approval text itself; every line that was really spoken is appended to spoken.jsonl.
· Doubao TTS and its credential: the access token lives under the fixed DSH credential name
数据来自仓库的 GitHub Release,可能与插件实际版本不一致。
README
由 DeepSeek 最新模型翻译生成小爱音箱桥接器 DSH XiaoAI Bridge 把小爱音箱接进 DeepSeek Harness:喊一声唤醒词,答案从音箱里念出来。
桥接器是本地 Python 服务(源码在 bridge/),由插件当子进程托管;设置页、状态卡、播报纪律都在插件这一半。
这是什么 • 核心特性 • 功能概览 • 工作原理 • 安装方式 • 模型工具 • 配置项说明 • 数据放在哪 • 排错 • 开发 • 许可证与作者
免责声明:本项目是非官方技术研究项目,与小米及其关联公司没有隶属、合作、授权或背书关系;按「现状」提供,不附带任何保证。刷机与客户端补丁存在设备损坏、数据丢失、账号封禁等未知风险,动手前请读 DISCLAIMER.md。
这是什么
小爱音箱刷成 open-xiaoai 客户端之后,就能在设备上跑自己的语音程序。这个项目把它接进 DeepSeek Harness:
- 你说唤醒词,音箱开始收音;识别出来的文本被当成一句用户消息,送进 DSH 的一个会话。
- 会话的回复正文会被念回音箱(念之前先做一次口语化润色,让它听起来像在说话)。
- 模型也可以反过来主动开口:调 xiaoai_speak,让音箱念出指定的内容。
仓库分两半:根目录是 DSH 插件(Node,lib/),bridge/ 是 桥接器。
展开完整文档(README 剩余 1 节)
小爱音箱桥接器 DSH XiaoAI Bridge 把小爱音箱接进 DeepSeek Harness:喊一声唤醒词,答案从音箱里念出来。
桥接器是本地 Python 服务(源码在 bridge/),由插件当子进程托管;设置页、状态卡、播报纪律都在插件这一半。
这是什么 • 核心特性 • 功能概览 • 工作原理 • 安装方式 • 模型工具 • 配置项说明 • 数据放在哪 • 排错 • 开发 • 许可证与作者
免责声明:本项目是非官方技术研究项目,与小米及其关联公司没有隶属、合作、授权或背书关系;按「现状」提供,不附带任何保证。刷机与客户端补丁存在设备损坏、数据丢失、账号封禁等未知风险,动手前请读 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 让智能体不等人问就先开口:任务跑完了、提醒到点了、你要求把某段原文逐字念出来。桥接器没在跑时工具会顺手把它拉起来(「随插件启动桥接器」开着时),再等一会儿(最长约 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. 把仓库取回来:
git clone https://github.com/OMSociety/dsh-xiaoai-bridge.git
Set-Location dsh-xiaoai-bridge
2. 准备桥接器的 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 上扩展文件被占用就删不掉)。
3. 下模型包。约 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 等模型以各自上游项目声明的许可为准,再分发或商用前请先核对。
4. 装插件并重启 DSH:
先停掉正在运行的 DSH(运行中的服务会锁住依赖,装完再起)
dsh plugin --profile <profile> add "dsh-xiaoai-bridge"
包内只有源码资产,不含 bridge/ 的虚拟环境与模型包,需要自行补一份并在设置页把「桥接器目录」指过去。
5. 音箱侧(属于上游):刷机、打客户端补丁,并确认设备侧的拨号地址。
6. 打开设置页确认几项:启用插件(开)、音箱名称、音箱地址(音箱在局域网里的 IP)、会话工作区。「音箱连接鉴权」保持默认开——设备侧要么按下面那条提示带上令牌,要么把它关掉(关掉等于允许同一局域网里任何主机往音箱注音)。
7. 对着音箱说唤醒词,然后说话;回复会从音箱里念出来。
提示:刷机教程见 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,json { "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 试着加,过高会失真)。
- 想打断播报:直接对小爱喊「小爱同学」。
卸载 powershell
dsh plugin --profile <profile> remove dsh-xiaoai-bridge
插件会先停掉桥接器子进程,再删掉可以重建的文件;bridge.log、spoken.jsonl、devices.json、device.json 会留在数据目录里,想一起清掉就按数据放在哪那一节的说明处理。
开发 powershell
插件侧(仓库根):九个离线检查,全绿会打印 [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)。第三方组件的许可见各自项目。预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
OMSociety/dsh-xiaoai-bridge
DSH 插件:把小爱音箱接进 DeepSeek Harness。喊一声唤醒词,答案从音箱里念出来。
相关插件 · 安全 / 权限
智能体逆向工程morluto/rea
用智能体逆向工程任何东西,从应用行为到原生二进制。
★ 415,267已汉化DSH
73.3
智能体集群框架ruvnet/ruflo
面向 Claude Code 与 Codex 的智能体元基座meta-harness。
★ 80,414已汉化MCP
71.9
WorkBuddy 模型接入corrinehu/dsh-workbuddy-connect
2026 年 10 月 20 日起,WorkBuddy…
★ 1,604已汉化DSH
71.7
破甲一键通z91772524-ai/pojia-next
十五个 AI…
★ 967已汉化DSH
71.6
AI 代理虚拟终端strukto-ai/mirage
Mirage 是给 AI 智能体用的虚拟终端:一层 shell,统管数据、命令行和运行时。Unix…
★ 3,756已汉化DSH
70.8
Agent 操作层agentic-os-org/ANOLISA
ANOLISA(Agentic Nexus Operating Layer & Interface System Architecture)|智能体操作系统,带运行时、安全、可观测性,以及 Tokenless 响应压缩,降低 token 用量与成本。
★ 649已汉化DSH
70.7