一、导读
2026 年 11 月 1 日的 GitHub Trending 日榜上,一个只有三个半月历史、3,166 星的项目排到了第三位——当日涨星 1,329,接近它此前全部星数的一半。它是 Anomaly(OpenCode 背后的公司)开源的本机语音听写应用 Hex:按住一个键说话,松开,文字落进当前光标。真正值得细读的不是「本地听写」这个概念,而是它把一条不到五秒的音频链路切成了多少段可验证的工程约束,以及它如何顺手把这条链路开放成本地转写服务与 TypeScript SDK。
二、项目速览
| 项 | 值 |
|---|---|
| 仓库 | anomalyco/hex(Anomaly,OpenCode / SST 的同一家公司) |
| 定位 | 本地优先(local-first)语音听写,兼本地转写服务 |
| 主语言 | Rust(2024 edition,桌面 UI 用自研 Rune) |
| Star 总数 | 3,166(GitHub API 读取,2026-11-01) |
| 当日涨星 | 1,329(daily 榜 2026-11-01 抓取,该榜第 3 位) |
| Fork / 贡献者 | 187 fork / 23 位贡献者(含匿名,API 计数) |
| License | MIT |
| 首次开源 | 2026-07-17(仓库 created_at) |
| 最新发布 | v3.1.2(2026-11-01,12 个构建产物);v3.0.0 为 2026-10-31 |
| 平台 | macOS 15+(Apple Silicon)为主,Windows x64/ARM64 与 Linux x86_64/ARM64 为 beta |
数据获取日期:2026-11-01(GitHub REST API 与 Trending 页面)。仓库默认分支是 dev(无 main),pushed_at 为 2026-11-01T22:01Z,仓库体积约 215 MB。需要说明的是:dev 分支 Cargo.toml 已标到 3.2.0,仓库里也有 docs/releases/3.2.0.md 草稿,但发布列表里最新的是 3.1.2——草稿不等于已发布,3.2.0 的落地情况待确认。
三、为什么是它:问题背景与定位
语音输入这条赛道在 2026 年已经分成两个阵营。云端派以 Wispr Flow 为代表,把音频送到服务器转写再回填,换来跨平台覆盖与「自动润色」;本地派以 superwhisper、VoiceInk、Handy、MacWhisper 为代表,把模型跑在自己机器上,换来隐私与离线。两边的产品形态高度相似,差异几乎全部落在「音频去哪里」和「谁拥有这条链路」上。
Hex 的差异点有三层。
第一层是它把「本地」写成了可核查的默认值,而不是营销词。 转写全部在设备上完成,默认不保存听写音频,历史只保留粘贴成功的文本七天(含容量上限),可选功能(OpenCode 改写、Voice Action)默认关闭且明确写出会发送哪些字段:转写文本、前台应用名、以及 Brave 浏览器的主机名。诊断日志可能包含转写文本,官方声明不上传。
第二层是它把整条链路开放成了 API。 这是同类项目里少见的动作:Hex 不只是「一个 App」,它同时是一个本地转写服务(认证的 loopback HTTP,端点覆盖模型准备、整段转写、实时流式转写),以及一个已发布到 npm 的 TypeScript SDK @kitlangton/hex。别的听写应用把引擎锁在产品里,Hex 把它变成宿主应用可以复用的能力——「宿主拥有录音与麦克风权限,Hex 拥有模型与推理」是它写在规格文档里的产品边界。
第三层是工程纪律。 仓库里 AGENTS.md 有 111 KB,docs/ 下按用户能力(而非 Rust 模块)组织的功能地图逐条标注「已实现 / 有哪些检查 / 观察到什么验证」,并明确写着一句近乎自我否定的纪律:测试存在不等于测试通过,预览不等于原生端到端验证。它的研究文档还保留了被推翻的结论(例如 2026-07-16 的基准被标注为「历史方法,不是当前选型依据」)。
涨星动因因此可以归纳为:一个由成熟开源团队(Anomaly 同时维护 22 万星的 OpenCode)出品、MIT 授权、把隐私做成默认值、并且开放了服务化接口的本机听写引擎,在「云端听写订阅制」的舆论逆风里同时满足了隐私派与工程派两类人。待确认:本次检索未找到 Hex 的独立第三方深度实测,其涨星与产品口碑之间缺少可核查的中间环节。
四、架构原理(重点)
4.1 整体架构:一个进程、一条时间线、一个引擎
Hex 在 3.0 之后收敛成「每个用户一个进程」:macOS、Windows、Linux 共享同一个窗口(自研 Rune UI 替换掉了此前的 GPUI)、同一份 settings.json、同一套引擎。真正承载实时性的是三个概念:权威麦克风时间线、转写引擎线程、本地 API 服务。
flowchart TB
HK["快捷键状态机<br/>hold / 双击锁定 / toggle"] --> SUP["suppression<br/>macOS event tap + 抑制"]
SUP --> AUD["dictation/audio<br/>权威麦克风时间线<br/>时间戳单声道 f32 PCM"]
AUD --> PREROLL["450ms 预热 pre-roll<br/>+ release tail 200ms"]
PREROLL --> ENG["transcription/engine<br/>单线程拥有模型,按序执行全部推理"]
ENG --> GGUF["transcription/gguf_session<br/>transcribe.cpp 适配(Metal / Vulkan)"]
ENG --> APPLE["apple_speech<br/>Swift SpeechAnalyzer 桥"]
GGUF --> POST["dictation/processor<br/>纠正 → OpenCode 改写 → 文本变换"]
POST --> PASTE["paste<br/>剪贴板插入 + 代际安全恢复"]
ENG -.->|服务其它宿主| API["local_api<br/>/streams 实时流 + /transcriptions 整段"]
API -.-> SDK["@kitlangton/hex<br/>TypeScript SDK"]
CFG["~/.config/hex/hex.config.ts<br/>QuickJS 内嵌执行"] --> POST
CFG --> HK
三条不变量值得单独点出:引擎只有一个线程拥有模型,所有推理按序排队(听写、会议分块、本地 API 的宿主音频都在同一条队列上,后台任务会让位给先到的听写请求);时间线由音频所有者拥有,而不是由识别器拥有;本地 API 只监听 loopback,且必须带 Bearer token。
4.2 分层拆解与关键接口
采集层(audio / dictation/audio):用 cpal 做设备枚举与输入解析(优先级为 --device 参数 > 保存的麦克风 > 系统默认,且永不选中 Hex 自己的虚拟麦克风),交付带时间戳的单声道浮点 PCM。它有自己的麦克风时间线、懒加载流生命周期、录制所有者、精确的快捷键边界与有界流恢复。两个数字定义了它的手感:450 ms 预热 pre-roll(保证按下前已经开始的语音不被切掉)与 200 ms release tail(保证松开瞬间的尾音与句末标点被收进来)。
抑制层(suppression / keyboard):macOS 侧是 event tap 加可配置的听写热键状态机;keyboard 负责当前键盘布局下的按键解析与「平衡的合成快捷键」。这一层处理的是最脏的现实问题——例如物理时间戳单位。路线图里记录了一次真实事故:某次构建把 HID tap 的 Mach ticks 当成纳秒,在开发机 125/3 的时基下,三秒长按被算成约 72 ms,短按被拉伸 41.67 倍,双击锁定与短按丢弃同时失效。修复方式是让带注释的会话时间戳不再缩放直接进入时间线,并补上回调级回归。
转写层(transcription/*):transcription/engine 是唯一持有模型并串行执行推理的线程;transcription/gguf_session 是 transcribe.cpp 的会话所有者,每次运行(以及每条实时流)都重建原生会话,让推理 scratch 保持有界,并负责长音频分块;parakeet 是严格 Metal 的适配器;apple_speech 是 Swift SpeechAnalyzer 桥;transcription/speech_detector 是可选加载的 Silero VAD,用来把「没有语音的听写」和会议分块挡在模型之外;transcription/gpu_health 按设备与驱动记录失败过的 GPU(gpu-failures.json),Auto 模式会跳过它们。
模型层(transcription/models + gguf_header):内置目录覆盖 Parakeet 家族(unified_en / v2 / v3 / ultra)、Whisper Large v3 Turbo、Qwen3-ASR 0.6B、QwenCleo-ASR 1.7B(埃及阿拉伯语)、ivrit.ai 的希伯来语 Whisper 微调、SenseVoice Small、Cohere Transcribe、Underdog Bark 3.0 Pro/Clean、Nemotron 3.5 ASR Streaming 0.6B,以及 Apple Speech。加载自选模型时,gguf_header 在任何东西被加载之前做头部校验:必须是 GGUF v2/v3,general.architecture 必须在 parakeet / whisper / qwen3_asr / cohere_asr / sensevoice 之内,必须声明 stt.variant 与 Hex 认识的语言码,且张量类型只允许 F32、F16、Q8_0(这三种是所有构建在 Metal 与 Vulkan 上都能跑的)。
处理与输出层(dictation/processor / paste):处理是一条有序流水线——上下文选中的纠正 → 有截止时间的 OpenCode 改写(失败则回退到已纠正的本地转写)→ 文本变换阶段。paste 负责剪贴板插入、续写拼接,以及代际安全的剪贴板恢复(保留每一个剪贴板条目与格式)。
配置层(personal_commands):用户的 ~/.config/hex/hex.config.ts 跑在进程内的 QuickJS 里,不再需要 Bun 或任何子进程。
4.3 核心机制:把「引擎」做成可被别的应用调用的服务
Hex 最不像「听写 App」的部分是它的服务化设计,这里有两套协议。
面向宿主的嵌入式服务(API 2):宿主应用用自己的签名身份申请麦克风权限并录音,Hex 只负责模型与推理。宿主以管道 stdin/stdout 启动 hex-service service --embedded,助手绑定 127.0.0.1:0 后只写一行 JSON(url + token + apiVersion + pid),宿主保持 stdin 打开作为生命周期租约,EOF 请求优雅退出,五秒宽限期后强杀。每个请求都要 Authorization: Bearer <token>,且服务刻意不发送 CORS 头。端点极简:GET /health、GET /capabilities、GET /models、POST /models/{id}/prepare(SSE 进度)、POST /transcriptions(audio/wav 整段)。资源边界写得像一份契约:上传上限 64 MiB,归一化后的 16 kHz 单声道 f32 样本上限 16,777,216 个(16 kHz 下约 17.5 分钟),请求头 2 秒截止、上传 30 秒截止,接受 8 kHz–192 kHz、1–8 声道。
面向本机应用的实时流(/streams):另一个应用可以把自己的音频推到 Hex 已加载的听写模型上做实时转写。客户端先读所有者专属的 local-api.json 拿端口与 token,再以 16 kHz 单声道(f32le 或 s16le)推样本,每次不超过 256 KiB,租约 10 秒;事件走 SSE,分四类——ready、partial(含 stable 与 tentative 两段,前者是模型不会再改的已提交文本)、segment(一个窗口的定稿)、final(全部拼接)。设计上有两个细节很「工程」:流从不加载、下载或切换模型,没有模型时直接答 503 model-not-loaded;流 token 错误与 id 不存在都答同一个 404 stream-not-found,避免 id 被探测。
TypeScript SDK(@kitlangton/hex):ESM-only,要求 Node ≥ 20.3.0,提供 Promise 与 Effect 两套入口。create({ model }) 会启动助手并等到下载、校验、加载全部完成,返回一个可跨多次录音复用的 transcriber。取消语义写得比多数 SDK 诚实:取消一个进行中的 transcribe() 会先关闭该 transcriber 的助手再 reject——因为只中止 HTTP 无法打断原生推理。待确认:SDK 目前仍要求调用方显式提供原生助手命令,随包分发的签名助手尚未发布,所以它还不是开箱即用的分发形态。
用户配置的沙箱化:hex.config.ts 在 QuickJS 里执行,一个 worker 线程拥有运行时,每次加载都构建全新的运行时与上下文(因此旧配置的残留不会跨重载存活),加载耗时约 0.33 ms。限制是硬的:单次调用 1 秒中断、加载 2 秒中断、运行时内存 64 MiB、JS 栈 1 MiB;上下文没有任何环境权限——没有文件系统、网络、进程、环境变量或定时器,import 只能解析到 @hex/commands 或配置目录内的文件。TypeScript 用 oxc 的解析器做类型擦除(同位置覆盖 span),而不是完整转译,理由是一份实测体积账:rquickjs 本身 +1.30 MiB,oxc_parser + oxc_ast_visit 做擦除 +0.79 MiB,而 oxc_transformer + codegen + semantic 要 +2.63 MiB。
4.4 性能取舍与设计代价
Hex 的基准都写在仓库里,且自己标注了适用范围,这一点在同类项目里罕见。
2026-07-16 在 M2 Max 上,用 10 段共 127 秒的本地录音对比两条后端(每后端 2 次全量预热 + 7 次测量):
| 指标 | ONNX Int8 | transcribe.cpp Metal Q8 |
|---|---|---|
| 模型加载(缓存 Metal 库) | 620 ms | 269–277 ms |
| 模型加载(构建后首次) | 未观测 | 9,921 ms |
| 单段中位耗时 | 368 ms | 216–234 ms |
| p95 单段耗时 | 509 ms | 303–356 ms |
| 峰值常驻内存 | 1.73 GB | 1.05 GB |
| 临时 WER | 8.07% | 9.82% |
结论是 Metal Q8 把中位推理时间压掉约 37–44%、p95 压掉约 30–40%、峰值内存压掉 40%,代价是首次链接后要花约 9.9 秒初始化内嵌 Metal 库(生产上必须把这段冷成本算进安装阶段,且不能在模型与 Metal 管线可用之前就报告「监听就绪」)。同一份文档还诚实标注:这批语料的参考文本来自更早的 ONNX 会议转写、切片点由模型分段边界决定、不能用作迁移质量门。
2026-09-04 的复测(M2 Max / 96 GiB)给出了当前模型的推理区间:Parakeet 短句 79–115 ms、19 秒 276–350 ms、57 秒 713–759 ms、73 秒(含停顿)873–896 ms;Cohere 对应为 92–127 / 409–440 / 1,161–1,287 / 1,436–1,463 ms;新进程加载为 Parakeet 292–317 ms、Cohere 869–1,222 ms。同一次实验还抓到一个长尾:某次 Parakeet 在含停顿的语料上跑了 7,322 ms,而中位数是 873 ms——文档明确写「这确立了一个离群点,但没有确立它的成因」。这正是它把「偶发长停顿」而非中位数列为第一优化目标的原因。
真正体现取舍的是 docs/research/model-watch.md 里那张按延迟分档的 WER 表(NVIDIA 官方八数据集平均 WER,Moonshine 取自其论文):
| 模型 | 延迟(chunk + right) | 平均 WER |
|---|---|---|
| Moonshine v2 small (123M) | 80 ms lookahead | 7.84 |
| Parakeet Unified 0.6B | offline | 5.91 |
| Parakeet Unified 0.6B | 2.08 s | 6.14 |
| Parakeet Unified 0.6B | 0.56 s | 6.52 |
| Parakeet Unified 0.6B | 0.16 s | 8.44 |
| Parakeet Unified 0.6B | 0.08 s | 15.63 |
| Nemotron Streaming EN 0.6B | offline | 6.92 |
| Nemotron Streaming EN 0.6B | 0.16 s | 7.84 |
读法很关键:Parakeet Unified 在 0.16 秒窗口下 WER 已经劣于小它四倍的 Moonshine small,到 0.08 秒直接崩塌到 15.63。原因是 Unified 属于缓冲式流:左侧上下文每块重算,Hex 用的是 5.6 秒左上下文 + 1.04 秒块 + 1.04 秒右上下文,等于每 1.04 秒新音频要编码约 7.7 秒音频,约 7.4 倍冗余(切到 0.56 秒档是 12 倍)。而 Nemotron 是 cache-aware 的,常量缓存、无重叠,一条流的成本约等于一次离线推理。这就是为什么 Hex 在 3.0 里删掉了 Moonshine 的 ONNX 栈、改走 GGUF,却仍然保留一个小流式模型用于命令识别与实时草稿——因为「常开流式 Parakeet」在命令延迟下 WER 相同,却要多 4–5 倍参数、多一份 0.7 GB 模型副本,还要为每块重算 5.6 秒左上下文。
吞吐数据(transcribe.cpp 官方卡,M4 Max,Q8_0,Metal,离线计算,11 秒 / 35 秒片段的「倍实时」):Parakeet Unified 188 / 228,Nemotron EN 207 / 225,Nemotron 3.5(多语言)144 / 138,Moonshine streaming tiny 239 / 112,small 129 / 59,medium 87 / 36,Voxtral Realtime 4B 仅 6 / 7。另一条硬约束来自绑定层:transcribe-cpp 0.x 明确写着「同一模型的全部会话中,同时最多只能有一个 transcribe_run 或一条活跃流」,想要并行就「每个 worker 各自加载一份模型」。这直接解释了 Hex 为什么把「一个引擎线程串行执行全部推理」当作架构不变量,而不是可以随手并发的实现细节。
4.5 与其他架构路线的差异
- 对比云端听写(Wispr Flow / Aqua Voice):它们把音频送到服务器,换来跨平台与「自动润色」的成熟度;Hex 把音频留在设备上,代价是没有移动端、跨平台只到 beta。
- 对比本地听写(superwhisper / VoiceInk / Handy / MacWhisper):这些是产品,Hex 是产品加服务。区别在于 Hex 开放了
/streams、/transcriptions与 npm SDK,别的应用可以把 Hex 当引擎用;而 VoiceInk 是 GPLv3、Handy 是 MIT,都不提供同等的宿主集成契约。 - 对比通用推理引擎(llama.cpp / vLLM):Hex 不重造推理内核,它把
transcribe.cpp当后端,自己负责的是产品级边界——时间线、权限、剪贴板、模型校验、GPU 健康、更新签名。它的贡献不在算子里,在链路里。
五、应用场景(重点)
场景一:把「说话」变成任何输入框里的文字
痛点:写长邮件、写 issue、写代码注释时,键盘是瓶颈;而云端听写对含客户名、内部代号的内容是合规问题。
解法:安装后按住 Option(Windows 为 Ctrl+Space)说话,松开即粘贴到当前焦点;双击锁定可连续说,Option-Shift-V 重贴上一次结果。
最小可用示例:
brew install --cask anomalyco/tap/hex # macOS
# 或 Linux: curl -fsSL https://anoma.ly/hex/install-linux.sh | sh
# 或 AUR: yay -S hex-bin
首次启动完成三项权限(麦克风、辅助功能;3.0 起 macOS 不再需要输入监控)与一次本地模型下载。 收益与量化:官方自己的基准显示,M2 Max 上短句推理中位 79–115 ms(Parakeet)、模型加载 292–317 ms;第三方延迟横评(Talkify,2026-08-13,每项 20 次试验取中位)给出的「松手到文字出现」是 Talkify 123 ms、Spokenly 189 ms、superwhisper 216 ms、VoiceInk 324 ms、Wispr Flow 587 ms。注意:该横评未包含 Hex,且各家的模型与硬件设置不完全可比,只能当作量级参考。另有第三方转述称 Hex 在带 Vulkan 驱动的 Windows/Linux 上边说话边流式出字、松手后约 100 ms 内到位——此说法未在仓库文档中找到对应出处,标记为待确认。
场景二:把术语表变成识别准确率
痛点:产品名、人名、内部代号是通用 ASR 的固定失分点,而它们恰恰是最不能错的部分。
解法:Settings › General › Vocabulary 维护一张共享词表(词条 + 「听起来像」的拼写),Hex 按模型能力分两条路注入:Parakeet(RNN-T/TDT)、Underdog Bark、Nemotron 走解码后重打分——对看起来或听起来像词条的最多 4 个词做重打分,只有当「词条分数 + 每片提升」超过听到的词时才替换;Whisper、Qwen3-ASR、QwenCleo 走上下文提示(Whisper 的 <|startofprev|> 槽上限 223 token,Qwen3-ASR 的 system message 上限 1,000 字符)。词表上限 64 条,提升强度分 off / light / normal / strong 四档(默认 normal)。
最小可用示例:
hex vocabulary add "Orkas" --sounds-like "orcas,orcus"
hex vocabulary list --json
收益与量化:仓库把「词表偏置」放在 Labs 里默认关闭,并要求开启后才会进入转写路径——这是一个克制的默认值。它同时明确了不做什么:只差大小写的差异、词形变化(Cappuccinos)、地址与路径(opencode.ai)都不动;重打分还会跳过「少于 5 个字母且没有『听起来像』拼写」的词条,因为 RNN-T 解码器本来就可能写对(Kip → Kit)。
场景三:把 Hex 当本地转写引擎,嵌进自己的桌面应用
痛点:团队已有录音与权限管理的宿主应用,不想再自建一套模型下载、校验、加载与 GPU 兼容逻辑。 解法:用 TypeScript SDK 以子进程方式起一个内嵌助手,宿主拥有麦克风与设置,Hex 拥有模型与推理。 最小可用示例:
import * as Hex from "@kitlangton/hex"
const transcriber = await Hex.create({
command: ["/path/to/hex-service", "service", "--embedded"],
model: "parakeet_unified_en",
language: "en",
onProgress: console.log, // downloading / verifying / loading
})
try {
const result = await transcriber.transcribe(wav) // ArrayBuffer / Uint8Array
console.log(result.transcript, result.durationMs)
} finally {
await transcriber.close() // 幂等;不删除任何模型文件
}
收益与量化:宿主不必实现模型管理,且多个宿主可以复用同一份已校验的模型文件(各自持有独立的热运行时与推理队列,不共享 Metal 分配)。边界同样明确:每个助手的模型与语言在创建时固定;同一助手并发请求可能直接收到 busy 错误,而不是进入无界队列。
场景四:把实时转写接进会议或笔记工具
痛点:会议记录工具想边听边出字,但自己搭流式 ASR 要处理分窗、租约、部分结果与失败回退。
解法:调用 /streams,推 16 kHz 单声道样本,订阅 SSE 拿 partial(stable / tentative)与 segment。
最小可用示例:
# 1) 从所有者专属发现文件读取 port / token / apiVersion
cat ~/Library/Application\ Support/hex/local-api.json
# 2) 创建流(需先让听写加载一个 GGUF 模型)
curl -X POST http://127.0.0.1:<port>/streams \
-H "Authorization: Bearer <token>" -H "Content-Type: application/json" \
-d '{"sampleFormat":"f32le","sampleRate":16000}'
# 3) 推音频(≤256 KiB/次),4) GET /streams/{id}/events 读 SSE,5) POST /streams/{id}/finish
收益与量化:流不会触发任何模型下载或切换(没有模型直接 503),因此接进生产工具不会因为一次调用而拉走 0.7 GB 流量;partials 字段会诚实告诉客户端「当前模型在当前设备上到底能不能出部分结果」。
场景五:用 TypeScript 写确定性的听写后处理
痛点:把「说完的文本」按团队规范改写(统一术语、补全模板、按应用切换风格)通常要写脚本或上云。
解法:在 ~/.config/hex/hex.config.ts 里写变换函数,Hex 在进程内 QuickJS 中执行,首次使用需人工批准该配置的内容哈希。
最小可用示例:
// ~/.config/hex/hex.config.ts
export const transformations = [
(text: string) => text.replace(/\bopencod\b/gi, "OpenCode"),
]
收益与量化:配置运行在无环境权限的沙箱里(无文件系统、网络、进程、环境变量、定时器),单次调用 1 秒中断、内存 64 MiB 上限,加载约 0.33 ms。它换来的代价是能力受限:任何需要 I/O 的变换都必须走宿主提供的受信 API,而不是随手 fetch。
适用边界与不建议使用的场景
- 你要的是 Intel Mac 或 macOS 14 及更早 → 不建议:主力路径要求 Apple Silicon + macOS 15。
- 你要 Linux 原生体验 → 只能算 beta:X11 与兼容 wlroots 的 Wayland 可用,GNOME/KDE Wayland 的全局快捷键依赖 portal,且没有托盘。
- 你要 Windows 上的正式支持 → 是 beta,且 3.1.0 起 x64 需要 AVX2(Intel Haswell / AMD Excavator 及以后),更老的 CPU 会直接提示并退出。
- 你要移动端 → 没有。iOS 只有原型目录,Android 无。
- 你要提交 PR → 不接受:仓库明确只收 issue。
- 你的模型权重必须完全自持 → 部分可行:可以导入自己的 GGUF 或复用 Hugging Face 缓存里已有的模型,但 Hex 对「不是它 pin 过的文件」不作任何保证。
六、快速上手
# macOS(Apple Silicon,macOS 15+)
brew install --cask anomalyco/tap/hex
# Linux(x86_64 / ARM64,X11 或 wlroots Wayland)
curl -fsSL https://anoma.ly/hex/install-linux.sh | sh
# Nix
nix profile install github:anomalyco/hex
首次启动会引导完成权限与一次本地语音模型下载,然后用几条练习消息让你试一遍快捷键。命令行侧(3.0 起)可以控制运行中的应用并读取数据:
hex status
hex dictation toggle
hex vocabulary add "Orcas"
hex history
hex mcp # 把 History 与会议记录以 MCP 形式暴露
从源码构建(仓库根目录):
git clone https://github.com/anomalyco/hex.git && cd hex
cargo build --release # release 构建 strip 掉符号表,Linux 产物约 11 MB
七、横向对比
下表口径:Hex 一列来自其仓库与官方站点(2026-11-01 读取);其余来自各项目公开材料与第三方横评。定价随版本变化,请以官方页面为准。
| 维度 | Hex | superwhisper | VoiceInk | Wispr Flow | Handy |
|---|---|---|---|---|---|
| 形态 | Rust 桌面应用 + 本地转写服务 | 桌面应用 | macOS 原生应用 | 云端应用 | Tauri 桌面应用 |
| 语音处理位置 | 设备上 | 设备上(本地模型)或云端 | 设备上(whisper.cpp) | 始终在云端 | 设备上 |
| 平台 | macOS 15+(主)/ Win、Linux(beta) | macOS / Win / iOS / Android | macOS 14.4+(Apple Silicon) | macOS / Win / iOS / Android | 跨平台 |
| 授权 | MIT | 闭源 | GPLv3(代码)/ 付费构建 | 闭源 | MIT |
| 价格 | 免费(MIT) | Pro 约 $8.49/月或 $84.99/年 | 一次性约 $25–29 起 | $15/月(年付 $12) | 免费 |
| 免费档 | 全部功能免费 | 无限本地 Whisper 听写 | 7 天试用或自行构建 | 每周约 2,000 词 | 无限制 |
| 可编程扩展 | TypeScript 配置 + 本地 HTTP API + npm SDK | AI Modes | Power Mode | 无 | 无 |
| 开源可审计 | 是 | 否 | 是 | 否 | 是 |
两点需要标注:superwhisper 的终身授权价格在不同第三方来源里出现 $249.99 与 $849 两个数字,互相矛盾,标记为待确认;VoiceInk 的第三方报价在 $25–$29 之间浮动,同样以官方页面为准。
八、局限、风险与社区观察
- 主力平台单一。macOS 15+ 且 Apple Silicon 是唯一被完整验证的路径;Windows 与 Linux 是 beta,
ROADMAP.md自己写着 Windows「只做过交叉编译」、macOS 的 Rune 窗口「编译测试过但没有在屏幕上真正看过」。评估生产可用性时请把这条计入。 - 不接受外部 PR。
README明确「我们不接受 pull request」,只收 issue。这对想深度定制或长期维护分支的团队是个现实约束——你可以 fork,但上游不会合你的改动。 - 3.0 是一次破坏性升级。数据目录从
voice-control改名为hex,不导入任何旧数据(设置、历史、会议录音、已下载模型全部从空开始),macOS 侧的签名身份也从旧应用换成anomaly.hex,需要重新授予权限;2.3.1 不会自动升级到 3.0。同时 3.0 删除了 Voice Action 与语音命令(连同它们使用的 Moonshine 模型)。 - SDK 尚未完成分发闭环。官方状态写明:随包分发的签名助手未发布,调用方必须显式提供原生命令,「签名消费者分发仍未验证」。想把它嵌进正式产品,需要自己承担这段打包工作。
- 服务端不是经过审计的「无持久化边界」。规格文档自己承认:当前可执行文件仍会初始化共享进程日志,并继承
TRANSCRIBE_DUMP_DIR这类原生诊断开关,后者可以写出音频派生的张量——因此不能把它当作经过审计的无落盘边界。 - 可选云功能会外发数据。OpenCode 改写会发送转写文本、前台应用名与 Brave 主机名;这些默认关闭,但开启后就不再是「纯本地」。
- 发布节奏极快、版本号跳跃。2026-11-01 一天内发布 v3.1.0、v3.1.1、v3.1.2 三个版本,10-31 发布 v3.0.0;
dev分支已到 3.2.0。快速迭代对用户是好事,但也意味着文档与行为之间容易短暂不一致(例如 3.2.0 的发布说明已在仓库里而发布本身尚未出现)。 - 社区规模与项目体量不匹配。3,166 星、187 fork、23 位贡献者、66 个开放 issue,而
AGENTS.md有 111 KB、docs/下功能地图与研究报告数以十计。待确认:这种「文档密度远高于社区规模」的状态能否长期维持,目前没有可核查的第三方数据。
九、小结与行动建议
- 先分清你要的是产品还是引擎。要一个开箱即用的 Mac 听写工具,Hex 的免费与 MIT 很有吸引力;要把转写能力嵌进自己的应用,直接看 SDK 与
/streams,别从 UI 开始。 - 把「本地」当成可验证的默认值,而不是承诺。它的默认值确实保守(音频不落盘、历史七天、可选云功能默认关),但开启 OpenCode 改写后就变成混合链路——上线前请逐项核对
docs/里的隐私描述。 - 术语表是最便宜的准确率杠杆。先加 20 个高频专名(含「听起来像」拼写),再考虑换更大的模型;官方自己的数据也显示,在 0.16 秒这种激进窗口下,大模型的 WER 反而不如小模型。
- 接服务时按契约设边界。上传 64 MiB / 请求头 2 秒 / 上传 30 秒 / 单模型同时只有一条活跃流——这四条决定了你的客户端要不要排队、要不要分片、要不要自建超时。
- 对「涨星」保持自述权重。本文引用的性能数字全部来自 Hex 自己的基准与 NVIDIA 的官方表格,且 Hex 已主动标注其适用范围(历史方法、非迁移质量门、离群点成因未定);第三方独立复现目前缺失。在你自己的麦克风、自己的口音、自己的术语上跑一遍,比读十篇评测更有用。
读者留言
COMMENTS 暂无还没有留言,来说第一句?