Qwen Live Host 深度解析:macOS 原生语音交互组件、全局快捷键与安全发布链路
【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code
本篇技术指南以packages/live-host/README.md为骨架,结合 qwen-code 单仓库中的源码实现,系统讲解 Qwen Live Host 的架构定位、首次启用流程、权限模型、快捷键机制、内置 Appshot、音视频输入输出、fail-closed 安全策略、开发构建与发布签名链路。读完本文,你将掌握如何启用 Qwen Live 语音能力、理解 Host 与 daemon 之间的安全连接协议,以及如何在 macOS 上独立构建、诊断和卸载这一原生组件。
一、定位:Host 是什么,与 daemon、WebShell 是什么关系
Qwen Live Host 是独立 Qwen Live daemon 与 WebShell Live Voice 在 macOS 上的原生组件(参见 packages/live-host/README.md)。它承载四类能力:
- 屏幕上的**小浮层(orb)**与设置面板;
- Electron全局快捷键(默认
Command+E); - 麦克风输入与扬声器输出;
- 可选摄像头输入与内置原生 Appshot(屏幕/窗口截图)。
关键边界在于:Host不打开 WebShell 或 Session 窗口。对话由连接的 daemon 管理,编码任务由配置的后端执行;因此没有浏览器麦克风或浏览器快捷键的降级方案——这些能力必须由原生 Host 提供。
从packages/qwen-live/README.md的架构描述可以确认,整个 Live 体系连接三方:
- Live Host:通过 Live Host WebSocket 协议 v9 连接 daemon,并读取 daemon 发布的
~/.qwen/live/daemon.jsondiscovery 文件实现自动连接; - DashScope Realtime 语音模型(如
qwen3.5-omni-plus-realtime):拥有对话,负责 VAD、直接回答与派发工作的工具面; - 编码会话(Backend):通过
BackendAdaptor驱动qwen serve(REST/SSE)或任意 ACP 兼容 agent(qwen --acp、qodercli --acp、gemini --acp等)作为子进程。
Host 处于整个链路最靠近用户硬件的一端,负责把麦克风、摄像头、屏幕与全局快捷键这些"只有原生应用才能可靠拿到"的能力暴露给 daemon 和模型。
二、运行前提与用户要求
启用 Live Host 需要满足以下条件:
- macOS 12 或更高版本(
electron-builder.yml中mac.minimumSystemVersion: '12.0.0'与之对应); - 本机运行独立
qwen-livedaemon,或Qwen Code WebShell(内置 Live Voice 默认关闭); - 一个可调用
qwen3.5-omni-plus-realtime的DashScope API key。
需要注意:原生音视频功能目前要求 macOS。独立qwen-live可直接从命令行启动并连接 Host;在 Linux/Windows 上,由于缺少原生麦克风、全局快捷键与屏幕捕获组件,在对应平台出现 Host 之前无法使用语音功能。
三、首次启用与自动安装的安全链路
在 WebShell 中按以下步骤启用:
- 打开设置 → 实验性功能 → Qwen Live;
- 输入专用于 Realtime 模型的 DashScope API key;快捷键默认是
Command+E,可在同一处修改; - 打开开关并确认安装。WebShell 会优先从阿里云 OSS 镜像下载当前架构的签名 Host,镜像不可用时回退到独立的 GitHub
live-host-latestfeed; - 下载后依次校验manifest、SHA-256、bundle identity、Developer ID 签名和 Gatekeeper,然后原子安装到
/Applications/Qwen Live Host.app并启动; - 按 Host 引导完成麦克风以及当前视觉源需要的授权:Screen需要辅助功能和屏幕录制,Camera需要摄像头。授权只能由用户在 macOS 完成;当前 Source 的 readiness 通过前 Live 不可使用。
两条安全细节值得强调:
- API key 只写入用户级设置。WebShell 只能看到"已配置"状态,不会读取或回显 key;
- 关闭 Live 会停止当前通话、撤下快捷键和 Host discovery,但不会卸载 Host 或删除 Live 对话。
四、权限模型:四类系统权限与用途
| 权限 | 授权主体 | 用途 |
|---|---|---|
| 麦克风 | Qwen Live Host | 采集 Live 对话音频 |
| 摄像头 | Qwen Live Host | Camera Source 的预览、实时帧或单帧截图 |
| 辅助功能 | Qwen Live Host | 读取前台窗口的可访问性树 |
| 屏幕录制 | Qwen Live Host | Screen Source 的实时帧或单帧截图 |
从 protocol.ts 的类型定义可以看到,Host 向 daemon 上报的权限状态为granted | denied | not_determined,自检项(HostSelfChecks)包括audioInput、audioOutput、globalShortcut、appshot四项——任一权限、自检、快捷键或 provider 配置失败时,Live 都保持不可用(fail-closed)。
初始化页只处理连接、Source 和对应权限,不要求 Camera 用户先授权 Screen;未选中的来源权限不会阻止 Live。通话中切换到尚未授权的来源时,Host 会先保留当前可用来源,授权成功后再一次性完成切换,授权取消或失败不会让正在工作的来源提前失效。
五、daemon discovery:Host 如何找到并信任 daemon
Live 启用后,daemon 会在~/.qwen/live/daemon.json发布权限为0600的稳定 locator。Host 侧的读取与校验逻辑实现在 discovery.ts,从源码可以看到多层防御:
- 文件校验:必须是常规文件且不是符号链接,权限必须严格为
0600,属主必须是当前用户,大小限制在 16 KiB 以内; - 内容校验:
protocolVersion必须等于LIVE_PROTOCOL_VERSION(即 9),pid为正整数,instanceNonce必须匹配^[A-Za-z0-9_-]{16,256}$模式,token 与configPath均有长度与形态约束; - URL 校验:
buildHostWebSocketUrl强制 daemon URL 必须是 loopback 地址(127.*、localhost、::1),并转换为ws/wss后固定指向/live/host路径; - 轮询监控:
DiscoveryMonitor默认每秒轮询一次,只有记录身份(pid + nonce + url + token 哈希 + configPath)变化时才通知上层。
daemon 侧还会校验 Host 的instanceNonce;record 可能包含 bearer token,因此文档明确要求不要打印、复制或共享其内容。Host 只连接 loopback 地址并校验协议版本和 daemon nonce。
六、快捷键机制:daemon 下发、Host 注册
快捷键由 daemon 通过每个LiveStatus.shortcut下发,默认是Command+E。Host 使用 ElectronglobalShortcut注册普通 accelerator,不请求 Input Monitoring 权限,也没有裸修饰键 helper。
核心实现在 global-shortcut.ts 的LiveGlobalShortcut.replace():
- 若当前 accelerator 健康且与目标相同,直接返回;
- 空字符串表示解注册当前值;
- 注册失败时区分"非法值"(
host.error.shortcutInvalid)与"已被占用"(host.error.shortcutInUse); - 先注册新 accelerator,成功后才解注册旧值,失败则保留旧快捷键并返回设置错误;
stop()在退出或断开 daemon 时解注册当前 accelerator。
WebShell 设置通过 daemon 请求 Host 走这条替换路径;冲突或非法值会保留旧快捷键并返回设置错误。菜单栏中的"新对话"会显式创建新的无项目对话,开始、停止当前通话是独立动作。
七、悬浮球、设置面板与体验细节
位置与拖动
初始化框和悬浮球首次分别按当前可见尺寸放在启动屏幕右下角,保留 20px 边距;拖动位置保存到 Host 用户数据目录的overlay-position.json,下次启动恢复;显示器移除后会调整到可见区域。小球按动画、工具栏和字幕的紧凑区域限位,打开 Settings 或预览时会临时调整到完整可见位置,关闭后恢复记忆位置——临时调整不会覆盖拖动记录,状态刷新也不会重新定位窗口。
交互细节
鼠标移到小球上显示麦克风、播报、Start call/End call、Settings和Quit Host按钮;移出后等待 1 秒淡出,移回或键盘聚焦会保持可用。Command+E启动/结束通话。结束后小球变灰并留在原位,不再自动隐藏。麦克风关闭或扬声器静音时,状态条第二行显示Mic off/Speaker muted(支持中文);麦克风静音会释放输入设备,取消静音后重新收音。
自动启动语义
Host 启动后会等待连接、当前来源权限和自检就绪,再自动开始一次交互;已有通话时不会重复启动。实现见 startup-interaction.ts:shouldStart()要求connectionReady、rendererReady、hostReady、live.available且状态为idle,并且该意图是一次性的——手动启停/新对话/退出、自动启动失败、重连或 renderer 重载均不会再次触发自动启动,重新启动 Host 才产生下一次自动启动意图。
Settings 面板
日常设置集中在Settings:Audio Source(麦克风)、Video Source(Screen/Camera)、Capture Mode(On Demand/Live Feed)三个同级设置组,以及独立 daemon 支持的Memory。设置支持 Esc、外部点击关闭,编辑草稿保留。
顶部的Open config.json ↗使用系统为 JSON 文件关联的默认 IDE/文本编辑器,打开当前独立 daemon 实际使用的配置(默认~/.qwen-live/config.json,也支持 daemon 的QWEN_LIVE_DATA_DIR),保存后需重启 Qwen Live 才应用手动修改。文件缺失、不是常规文件(包括符号链接)或编辑器打开失败时会提示,不自动创建或覆盖配置。
语言与主题
Settings 倒数第二组为Language/语言(其后是 Theme),支持简体中文和English。独立 daemon 确认后立即切换,并保存到~/.qwen-live/config.json顶层language(zh-CN/en);旧配置未设置时保持英文。语言不影响模型提示词/回答或用户自定义名称;qwen-live init的第一项也可通过左右方向键选择语言。
全部固定 Live 展示文案统一维护在 packages/qwen-live/src/i18n/messages.ts,每个键并列en和zh-CN;Host 的构建别名直接编译同一份纯文本模块,打包后不需要 qwen-live 运行时依赖。
Theme/主题支持跟随系统(默认)、浅色和深色,保存在 Host 本地,与 daemon 的模型/Memory 配置无关;切换不会重建媒体或中断通话。
Memory
连接独立 Qwen Live daemon 时,Settings 的Memory区域提供记忆开关、独立的Visual memory开关、选择记忆库、New/Rename,以及Consolidation model设置(默认qwen3.7-plus)。通话中可以开关和改名;选择/新建记忆库和修改模型需要先结束通话。库默认存储在~/.qwen-live/memories。详细参数见 Qwen Live README 的 Memory 章节。
Quit Host 的退出语义
Quit Host请求当前独立 Live daemon 完成通话、后端、Memory 和 discovery 清理后退出 Host;不会关闭另外运行的qwen serve。退出只有在匹配的退出回执,或系统明确确认原 daemon PID 已不存在时才完成;404、连接重置或拒绝连接都不单独视为退出成功。清理失败时 daemon 保留同实例的退出控制入口和 discovery,但拒绝新通话及普通请求。
八、子智能体状态面板
悬停或用键盘聚焦小球时,侧面显示明确标注Subagents/子智能体的摘要:紧凑图标计数显示进行中和已完成;有运行任务时小点柔和闪烁(遵循系统减少动态效果设置),需要用户输入时才显示提醒标记。
点击展开列表,再点击任务在同一个无边框悬浮面板中显示详情:原始委托、实际运行状态、最新活动、公开中间文本、可用的计划/工具更新及最终结果。Back/返回回到列表;不再打开带 macOS 标题栏的独立详情窗口,关闭面板不会取消任务。
语义细节(与 qwen-live/README.md 的 Subagents 章节一致):
- 进行中包含排队/等待输入任务;已完成包含成功任务及已取消的 Proactive monitor——monitor 详情仍显示已取消,不伪装成成功;
- 需关注只表示正在等待用户输入/授权,不包括失败或中断;
- 持续 monitor 的每轮判断或通知不会增加子智能体数量;追加到既有后台任务的指令不重复计数;
- 无通话时收到权限请求只登记等待,不新增自动批准;普通文件系统拒绝不会被虚构成授权请求;
- 列表和详情提供
Stop/停止,只停止对应任务;后端尚未确认时显示正在停止; - 任务历史只保留本次 daemon 运行;全部活动任务保留有限详情,已结束任务仅保留最近 32 条,每页最多 32 条,单个快照上限 240 KiB。
该功能通过可选能力协商(subagentsV1),仅在支持的独立 Live daemon 连接上显示,不影响旧版 Host 或 WebShell。
九、视觉输入:Camera、Screen 与全显示器捕获
Source 与 Mode
visualInput有两组独立设置:source为screen或camera,mode为on-demand或live-feed,默认Screen + On Demand(配置决定每次 daemon 启动的初值,Source/Mode 切换只影响当前运行实例)。未识别键会被拒绝——拼错的 camera 设置不会静默选择默认 Screen source。
从 protocol.ts 的解析逻辑可见约束:FPS 必须在0.1~10之间,liveResolution默认 720p,所有送入 Omni 的 JPEG 和 Host 传输预览受1080p/190 KiB上限约束(MAX_INPUT_IMAGE_FRAME_BYTES = 190 * 1024),Camera 原图 asset 与 Screen 的 PNG asset 不受该小图上限影响。
Camera
visualInput.cameraResolution控制预览/Live Feed 采集,默认1280×720;visualInput.cameraSnapshotResolution独立控制 Camera Appshot,默认native,也可设置{ "width": 1920, "height": 1080 };环境变量为QWEN_LIVE_CAMERA_SNAPSHOT_RESOLUTION=native或WIDTHxHEIGHT;- Host 优先从同一 camera track 拍摄静态照片;设备不支持时尝试临时调整视频采集约束,截图后恢复预览;无法满足原生采集时明确报错,不会把预览的 720p 冒充原生照片;
- Camera 高分辨率 JPEG 单独保存为 handoff asset(上限8 MiB,即
MAX_CAPTURE_ASSET_BYTES),不通过 Host WebSocket 传输。
Screen 与 Display
Screen Live Feed 与视觉 Proactive monitor 使用独立的完整显示器采集路径,包含桌面、菜单栏、Dock 和其他应用,但排除 Live Host 自身窗口。Settings 的 Video Source 下可选Display/显示器,选择保存到config.json的visualInput.screenDisplayId:默认primary跟随系统主显示器,也可保存某块显示器的 UUID;明确选择的显示器断开后报错,不自动换屏。切换显示器会丢弃过期截图并清空 monitor 旧视觉缓冲,无需重新 init。完整范围不代表原生像素——两条持续画面路径都使用liveResolution,默认等比放进 1280×720。
权限差异
- Camera Source 需要摄像头权限;
- Screen On Demand 的 Appshot 需要辅助功能和屏幕录制权限;
- Screen Live Feed仅需屏幕录制权限。
停止通话、切换 Source/Mode、daemon 断开或 Host 退出都会清理不再使用的通话采集。
十、内置 Appshot:无参数、只读的模型侧工具
Appshot 是 Host 的内部核心能力。构建时会把仓库内的 Objective-C++ Appshot 源码(src/native/appshot.mm)编译成一个universal N-API 模块(qwen-live-appshot.node),随 Host 一起签名。从 native-appshot.ts 可以看到,模块在主进程内加载,提供getPermissionState、requestAccessibility、requestScreenRecording、captureAppshot、listDisplays、captureDisplay等原生能力,通过 macOS 截屏与 AX API 工作。
关键设计:
- 没有额外 Appshot App、Appshot Helper、MCP、CLI、插件、守护进程或运行时下载;
- 模型侧的
appshot是无参数、只读工具,捕获气泡球当前选中的 Source,不能通过工具参数临时指定另一个来源、窗口、坐标或动作; - Live Feed 模式禁用该工具,On Demand 模式才允许调用;
- Host 激活后会在 Screen 为当前或待切换来源时定期刷新 Appshot 权限;每次真实 Screen 捕获还会在 Host 进程内重新验证两项权限;当前来源的授权丢失会令捕获失败并使 Livefail closed;
- 整个流程不启动或探测任何外置屏幕工具。
十一、音频处理与 fail-closed 策略
播放链路
Omni 响应以单声道 16-bit、24 kHz PCM接收。播放 AudioContext不指定采样率,使用当前系统输出设备的默认时钟(如 44.1/48/96 kHz),不强制更改设备采样率。对于协商了输出结束标记的连接(outputAudioEndMarkerV1),对每条响应进行连续、带抗混叠滤波的流式重采样,再放入设备采样率的 AudioBuffer,按整数采样点连续排程,避免逐块转换的衔接尖峰及无谓间隙;结束标记到达时输出短暂的滤波尾部。未协商结束标记的旧连接保持原有 Web Audio 逐帧转换和播放排空逻辑。
--live-debug日志中的output_context_ready显示源/输出上下文采样率及是否重采样。
输入链路与静音
关闭麦克风时 Host立即停止输入 track 并释放捕获上下文,而不只是丢弃录音数据;静音期间设备变化不会重新打开麦克风,取消静音后才重新收音。devicechange会在收音时检查/替换输入,在空闲时重新自检。
蓝牙耳机麦克风被打开时,macOS 可能将耳机切换到免提通话模式,影响同时播放的音乐/视频——这与模型 PCM 采样率是两回事;可在 Audio Source 选择 Mac 内置麦克风,输出仍使用蓝牙耳机。
fail-closed
输入 track ended、播放失败或音频帧无法交给 daemon 时,Host 会先将 input/output 标记为 unavailable、停止当前通话并清理旧 context,再重新执行自检;麦克风重新授权后只有实际输入自检通过才会恢复 ready。overlay renderer、preload 加载、页面加载失败或 renderer 无响应也会执行 fail-closed。Host readiness不会连接 Realtime,首次就绪自动开始或用户手动开始对话时才建立 provider WebSocket;限流或配额错误不做自动重试或后台探测,用户稍后可手工重试。
十二、开发构建、诊断与测试
构建命令
开发者需要Node.js 22(package.json中engines.node >= 22.0.0)。在仓库根目录执行:
cd packages/live-host npm ci npm run build npm run typecheck npm test npm run dist:mac- 构建产物位于
packages/live-host/dist/,打包产物位于packages/live-host/release/; npm run dist:mac走electron-builder --config electron-builder.yml --mac,产物为 arm64/x64 的 DMG 与 ZIP;- 正式用户不需要手工下载 DMG,WebShell 的实验性设置负责安装和启动。
从 electron-builder.yml 可以看到打包配置要点:appId: com.alibaba.qwen-code.live-host、LSUIElement: true(纯菜单栏应用)、QwenLiveProtocolVersion: 9、hardened runtime、entitlements,以及把原生模块qwen-live-appshot.node作为 extraResources 打入native/目录。
测试覆盖
npm test运行src/main/__tests__/下的测试,覆盖 discovery 校验、全局快捷键替换、overlay 位置恢复、Appshot 架构与捕获、音频引擎与重采样、Camera 引擎、daemon 连接、reconnect 策略、subagents 视图、theme 与 language 存储、release packaging 守卫等模块。
诊断开关
开发诊断可在终端启动开发版或应用可执行文件并传入--live-debug:
cd packages/live-host npm start -- --live-debug "release/mac-arm64/Qwen Live Host.app/Contents/MacOS/Qwen Live Host" --live-debug不要给 Electron Host 传--debug——该参数会被 Electron 当成已废弃的 Node 调试参数并在启动前退出。日志只包含状态、readiness blocker、尺寸、字节数和错误码,不包含图片、音频、API key 或转写内容。
Proactive 判断、通知排队/播报、harness 任务和 Realtime 生命周期日志由daemon输出,需在另一个终端运行qwen-live --debug。排查 monitor 输入时,用frameHash(JPEG 字节的 SHA256 前 16 位)对应 Host 的visual_snapshot_captured/visual_frame_sent与 daemon 的proactive.monitor_image_sent、proactive.monitor_commit、monitor_committed、monitor_action等日志。daemon debug 模式还会在系统临时目录的qwen-live-monitor-debug/下保存视觉 Monitor 的真实请求(request.json、实际送出的 JPEG、含协议静音的 16 kHzinput.wav、response.json),仅保留最近创建的 10 个 Monitor;这些文件包含真实屏幕/摄像头内容,诊断完请关闭 debug。
十三、发布、签名与更新链路
Live Host 使用独立的Qwen Live Host Releaseworkflow、版本号和发布节奏,不参与也不阻塞 Qwen Code Desktop Release:
- PR 会自动执行一次未签名 dry run,检查 arm64/x64 的 DMG、ZIP 和 manifest;
- 正式发布只能从
main手工触发,并执行 Developer ID 签名、notarization、Gatekeeper 和 stapler 验证; - 版本发布使用
live-host-vX.Y.Ztag,包含两个 DMG、两个 ZIP、Qwen-Live-Host-manifest.json和SHA256SUMS.txt; - 非 draft、非 prerelease 的正式版本还会更新固定的 GitHub
live-host-latestfeed,并调用一次独立的 OSS 镜像 workflow;镜像保存版本化 ZIP 和 manifest,再发布一个 latest manifest; - WebShell 自动安装优先读取 OSS,失败时使用 GitHub feed(与"首次启用"一节描述的下载顺序一致);
- Host不会自行创建或强制启用 Login Item,需要开机启动时由用户在"系统设置 → 通用 → 登录项"中显式添加。
十四、卸载
- 从菜单栏选择"退出 Qwen Live Host";
- 如果曾手工添加 Login Item,在系统设置中将其移除;
- 从
/Applications删除Qwen Live Host.app; - 在 WebShell 的设置 → 实验性功能 → Qwen Live中关闭功能;
- 如不再需要,可在"隐私与安全性"中撤销 Host 的麦克风、摄像头、辅助功能和屏幕录制权限。
结语
Qwen Live Host 是 Qwen Live 语音体系中最贴近系统硬件的原生组件:它用 Electron 提供轻量浮层与全局快捷键,用 Objective-C++ N-API 模块提供 Appshot 与显示器捕获,用严格的 discovery 文件校验与 loopback-only 连接保证 daemon 通信安全,并用 fail-closed 策略确保任一权限或自检失败时 Live 保持不可用而非降级出错。理解其架构边界、权限模型与发布链路,是正确部署、诊断和二次开发 Qwen Live 语音能力的前提;相关实现细节可继续深入 live-host 源码目录 与 qwen-live daemon 文档 查阅。
【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考