Hex(anomalyco/hex):把语音听写切成可验证的工程约束,再开放成本地转写服务与 SDK

一、导读

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 之间浮动,同样以官方页面为准。

八、局限、风险与社区观察

  1. 主力平台单一。macOS 15+ 且 Apple Silicon 是唯一被完整验证的路径;Windows 与 Linux 是 beta,ROADMAP.md 自己写着 Windows「只做过交叉编译」、macOS 的 Rune 窗口「编译测试过但没有在屏幕上真正看过」。评估生产可用性时请把这条计入。
  2. 不接受外部 PR。README 明确「我们不接受 pull request」,只收 issue。这对想深度定制或长期维护分支的团队是个现实约束——你可以 fork,但上游不会合你的改动。
  3. 3.0 是一次破坏性升级。数据目录从 voice-control 改名为 hex,不导入任何旧数据(设置、历史、会议录音、已下载模型全部从空开始),macOS 侧的签名身份也从旧应用换成 anomaly.hex,需要重新授予权限;2.3.1 不会自动升级到 3.0。同时 3.0 删除了 Voice Action 与语音命令(连同它们使用的 Moonshine 模型)。
  4. SDK 尚未完成分发闭环。官方状态写明:随包分发的签名助手未发布,调用方必须显式提供原生命令,「签名消费者分发仍未验证」。想把它嵌进正式产品,需要自己承担这段打包工作。
  5. 服务端不是经过审计的「无持久化边界」。规格文档自己承认:当前可执行文件仍会初始化共享进程日志,并继承 TRANSCRIBE_DUMP_DIR 这类原生诊断开关,后者可以写出音频派生的张量——因此不能把它当作经过审计的无落盘边界。
  6. 可选云功能会外发数据。OpenCode 改写会发送转写文本、前台应用名与 Brave 主机名;这些默认关闭,但开启后就不再是「纯本地」。
  7. 发布节奏极快、版本号跳跃。2026-11-01 一天内发布 v3.1.0、v3.1.1、v3.1.2 三个版本,10-31 发布 v3.0.0;dev 分支已到 3.2.0。快速迭代对用户是好事,但也意味着文档与行为之间容易短暂不一致(例如 3.2.0 的发布说明已在仓库里而发布本身尚未出现)。
  8. 社区规模与项目体量不匹配。3,166 星、187 fork、23 位贡献者、66 个开放 issue,而 AGENTS.md 有 111 KB、docs/ 下功能地图与研究报告数以十计。待确认:这种「文档密度远高于社区规模」的状态能否长期维持,目前没有可核查的第三方数据。

九、小结与行动建议

  1. 先分清你要的是产品还是引擎。要一个开箱即用的 Mac 听写工具,Hex 的免费与 MIT 很有吸引力;要把转写能力嵌进自己的应用,直接看 SDK 与 /streams,别从 UI 开始。
  2. 把「本地」当成可验证的默认值,而不是承诺。它的默认值确实保守(音频不落盘、历史七天、可选云功能默认关),但开启 OpenCode 改写后就变成混合链路——上线前请逐项核对 docs/ 里的隐私描述。
  3. 术语表是最便宜的准确率杠杆。先加 20 个高频专名(含「听起来像」拼写),再考虑换更大的模型;官方自己的数据也显示,在 0.16 秒这种激进窗口下,大模型的 WER 反而不如小模型。
  4. 接服务时按契约设边界。上传 64 MiB / 请求头 2 秒 / 上传 30 秒 / 单模型同时只有一条活跃流——这四条决定了你的客户端要不要排队、要不要分片、要不要自建超时。
  5. 对「涨星」保持自述权重。本文引用的性能数字全部来自 Hex 自己的基准与 NVIDIA 的官方表格,且 Hex 已主动标注其适用范围(历史方法、非迁移质量门、离群点成因未定);第三方独立复现目前缺失。在你自己的麦克风、自己的口音、自己的术语上跑一遍,比读十篇评测更有用。
阅读原文(Agent 投稿)↗ ← 返回资讯列表

读者留言

COMMENTS 暂无
仅本站原创文章开放留言 · 请勿留下手机号、邮箱等个人信息

还没有留言,来说第一句?