
在 Mac 上用 yomiscript 与 Kokoro 生成读音准确的日语语音
在 Mac 上用 yomiscript 与 Kokoro 生成读音准确的日语语音
日语 TTS 最常见的失败不是音色,而是读错音:同一个写法有多种读法,引擎只能靠词典猜。yomiscript 把「决定读音」交给写句子的 LLM,把「发声」交给本地运行的 Kokoro-82M。本教程讲清它的分工模型、MCP 与 CLI 两种用法、环境变量配置、YomiScript 写法,以及长句上限等已知限制。
日语语音合成最常出问题的地方不是音色,而是读错音。「一日」既可以读作「ついたち」,也可以读作「いちにち」;「上手」既可以读作「じょうず」,也可以读作「うわて」。同一个写法对应多种读法的词在日语里非常多,而传统 TTS 引擎只能靠词典和规则去猜,遇到需要上下文才能判断的词就会出错。
yomiscript 换了一个思路:让写出这句话的 LLM 顺便把读音也写出来。因为 LLM 知道自己在写什么,所以它清楚这里的「一日」指的是哪一天。真正发声的是公开的语音合成模型 Kokoro-82M,它跑在本地 Mac 上,不需要语音合成服务的 API 密钥,也不产生语音合成费用。负责写读音的 LLM(例如 Claude Code)沿用你平时在用的那一个,这部分费用照常计算。
这篇教程面向在 Mac 上做日语语音输出、又对读音准确性有要求的开发者,讲清 yomiscript 的分工模型、MCP 与命令行两种接入方式、可调的环境变量、YomiScript 的写法,以及目前已知的限制。文中涉及版本号、模型体积、性能数字等易变信息,请以官网与包管理器显示的当前信息为准。
准备工作
理解三个角色
yomiscript 把传统 TTS 引擎一个人干的活拆成了三段:
- Yomite(読み手,读音决定者):把日文句子转换成 YomiScript 的角色。实际承担这个角色的是你调用的那个 LLM,也就是写出原句的那一方。
- YomiScript:一种描述「怎么发音」的记法。发音用国际音标(IPA)书写,并用
<t:…>附上对应的原文字符。句末下降用 ↘ 表示,上升(疑问)用 ↗ 表示。 - Katarite(語り手,发声者):把 YomiScript 变成声音的角色,这里是 Kokoro-82M。它不解析句子,只按写好的发音去读。
正因为决定读音的是 LLM 而不是引擎,这套方案在定位上并不把自己称作传统意义上的 TTS。举例来说,句子「一日から三日まで休みです。」经过 LLM 处理后大致会变成这样一段 YomiScript:
ja /tsɯitatɕi<t:一日> kaɾa<t:から> mikka<t:三日> made<t:まで> jasɯmi<t:休み> desɯ<t:です。> ↘/
开头的 ja 标明语言,斜杠之间是音素序列,每个音素后面用 <t:…> 挂回原文,方便核对与调试。
环境要求
- 一台 Mac。Kokoro-82M 可以在 Mac 的 CPU 上运行,Apple Silicon 机器上表现更好。
- Node.js。MCP 方式与 CLI 方式都依赖它,用
npx可以免安装直接运行。 - 一个可用的 LLM 客户端。MCP 方式需要支持 MCP 的客户端(如 Claude Code、Claude Desktop);不支持 MCP 的 LLM 也能用,走「生成说明文本再手动喂给命令行」的路径。
- 首次运行需要联网下载模型权重,之后走本地缓存。
关于费用与许可
Kokoro-82M 以 Apache 2.0 许可公开,yomiscript 本身的代码同样是 Apache 2.0,日语音高预测模型采用 CC BY-SA 4.0。语音合成侧不含 LLM,因此不产生语音合成费用;需要付费的只有你用来写读音的那个 LLM。如果你用的是按量计费的 API,请注意 YomiScript 会让输出变长——据项目说明,YomiScript 的字符数约为原日文的 3 倍,加上 <t:…> 之后约为 6 倍,这部分 token 会计入账单。具体价格与许可以官网当前信息为准。
操作步骤
步骤一:把 MCP 服务器注册到 Claude Code
最省事的方式是把 yomiscript 作为 MCP 服务器挂到 Claude Code 上。只要机器上有 Node.js,一条命令即可:
claude mcp add yomiscript -- npx -y @yomiscript/mcp
注册完成后,Claude 会多出一个名为 speak 的工具。之后你只要说「把这段读出来」,Claude 就会自己写 YomiScript、调用工具,声音从 Mac 的扬声器输出。
这里有个设计细节值得知道:工具的描述文本本身就是 YomiScript 的写法说明。音素表、<t:…> 的挂法、示例句都写在描述里,所以 Claude 不需要额外教学就能写出合法的 YomiScript。如果写错了,服务器会把解析器的报错返回给 Claude,Claude 看到错误后可以自行修正并重新调用;这种情况下不会发出声音。
步骤二(可选):在 Claude Desktop 中配置
如果用的是 Claude Desktop,在 claude_desktop_config.json 中加入下面这段:
{
"mcpServers": {
"yomiscript": {
"command": "npx",
"args": ["-y", "@yomiscript/mcp"]
}
}
}
保存后重启客户端,speak 工具即可用。
步骤三:首次运行,等待模型下载
模型权重并不包含在 npm 包里。第一次发声时,相关文件会从 Hugging Face 下载到 ~/.cache/yomiscript/:
- Kokoro(fp32):约 325 MB
- 日语重音词典:约 28 MB,在第一次朗读日语时下载
- 日语音高预测模型:约 8 MB,同样在第一次朗读日语时下载
第二次起直接读缓存,不再下载。项目说明中给出的参考数据是:在 Mac 上第一句日语约 1.1 秒,第二句约 0.3 秒。实际耗时受机器负载影响,请以自己的环境为准。
步骤四:用命令行直接发声
不想走 MCP 也可以直接用 CLI。全局安装:
npm install -g yomiscript
不想安装的话,把下面每条命令开头的 yomiscript 换成 npx yomiscript 即可。
直接播放一段 YomiScript:
yomiscript speak "ja /tsɯitatɕi<t:一日> kaɾa<t:から> mikka<t:三日> made<t:まで> jasɯmi<t:休み> desɯ<t:です。> ↘/"
导出为 WAV 文件而不播放:
yomiscript speak --out hello.wav "ja /kʲoː<t:今日> wa<t:は> ‖<t:、> ame<t:雨> desɯ<t:です。> ↘/"
从文件读取,或从标准输入读取:
yomiscript speak --file utterance.ys
echo "ja /ame ↘/" | yomiscript speak
播放行为因平台而异:Mac 上通过 afplay 播放,Linux 上使用 paplay 或 aplay,其他环境则输出临时 WAV 文件的路径,由你自己处理。
步骤五:让不支持 MCP 的 LLM 也能写 YomiScript
你不需要手写 YomiScript。下面这条命令会输出一份给 LLM 看的写法说明:
yomiscript instructions
把输出粘进 ChatGPT、Claude 等任意对话模型的提示词里,再附上「把下面这句话转成 YomiScript」和原句,模型就会返回 YomiScript。如果返回内容带了说明文字或 ``` 代码围栏,去掉围栏后交给 yomiscript speak 即可。这是 MCP 不可用时的通用退路。
步骤六:按需调整环境变量
行为通过环境变量控制。用 claude mcp add 注册时,用 -e 传入。
| 变量 | 默认值 | 含义 |
|---|---|---|
YOMISCRIPT_PLAY | 1 | 设为 0 时不在本机播放,适合只想要文件或只做校验的场景 |
YOMISCRIPT_RETURN_AUDIO | 0 | 设为 1 时把音频(WAV)一并返回给客户端 |
YOMISCRIPT_MODEL | fp32 | 设为 w16 时使用更轻的 fp16 权重 |
YOMISCRIPT_KATARITE | kokoro | 设为 supertonic 可换用另一个语音引擎 |
关于 supertonic:Supertonic 3 的权重采用 OpenRAIL-M 许可,对用途有限制。如果只是免费、无顾虑地使用,保持默认的 Kokoro 更稳妥。许可条款请以官方当前说明为准。
一个完整示例
下面走一遍从安装到出声的最小闭环,全部在命令行完成,不依赖 MCP。
第一步,安装。
npm install -g yomiscript
第二步,准备一句容易读错的日文。就用「一日から三日まで休みです。」。这句话里的「一日」必须读作「ついたち」而不是「いちにち」,正是 yomiscript 要解决的典型场景。
第三步,拿到写法说明并让 LLM 转换。
yomiscript instructions
把输出连同原句一起交给你的 LLM,得到类似下面这样的 YomiScript:
ja /tsɯitatɕi<t:一日> kaɾa<t:から> mikka<t:三日> made<t:まで> jasɯmi<t:休み> desɯ<t:です。> ↘/
第四步,合成并导出 WAV。
yomiscript speak --out ichi.wav "ja /tsɯitatɕi<t:一日> kaɾa<t:から> mikka<t:三日> made<t:まで> jasɯmi<t:休み> desɯ<t:です。> ↘/"
成功时终端会打印类似 wrote ichi.wav 的信息,并在 stderr 输出把 <t:…> 拼回去的原文以及耗时,例如「一日から三日まで休みです。」以及音频时长与合成耗时。参考数据:约 2.9 秒的音频在约 2.0 秒内合成完成,且这是在机器负载较重的情况下测得的。你的数字会不同。
第五步,验证 MCP 通道(可选)。如果也想确认 MCP 服务器工作正常,可以在不发声的模式下直接通过标准输入输出调用 speak:
YOMISCRIPT_PLAY=0 npx -y @yomiscript/mcp
然后向它发送一次 speak 调用,正常时会返回类似 Synthesized "今日は雨です。" (1.82 s). 的文本结果。把 YOMISCRIPT_PLAY 设为 0 的好处是调试时不会反复从扬声器里冒出声音。
注意事项
长句会失败
Kokoro 单次最多处理 510 个音素。目前把一整段长文一次性交给它会导致失败。按句末的 ↘ / ↗ 切分后逐句朗读,是项目规划中的改进方向,尚未落地。现阶段请自己在调用前把长文拆成短句,逐条合成再拼接。
LLM 输出会显著变长
YomiScript 的字符数约为原文的 3 倍,加上 <t:…> 后约为 6 倍。用按量计费的 API 时,这部分输出会计费。批量处理长文本前,先估算一下成本。
项目仍处于早期
项目自述状态为 early,YomiScript 规范目前是 v0.2 草案,接口与写法都可能变化。用于生产前请确认当前版本的行为。
准确性数据的解读边界
公开的评测使用了一组 70 句容易读错的日文(涵盖同音异义词、数字、日期、专有名词等),结果大致是:由 LLM 写出的 YomiScript 正确率在 98.6% 到 100% 之间,基于词典的 pyopenjtalk 为 78.6%,Kokoro 自带的日语读音为 32.9%。用 Whisper 转写后统计假名错误率,LLM 的 YomiScript 配合 Kokoro 为 3.7% 到 3.9%,macOS 系统语音为 5.5%,原版 Kokoro 为 10.3%。
这些数字需要谨慎看待:每项只跑了一次;标准答案由项目的一位母语者确认,属于暂定版本;Whisper 本身也会出错,因此错误率只适合做系统之间的横向比较,不能当作绝对精度。另外,Claude 那次唯一的失败并不是读音错误,而是表记问题——「経済」被写成了不符合规范的拼法。
换引擎前先看许可
把 YOMISCRIPT_KATARITE 设为 supertonic 会切换到 Supertonic 3,其权重采用 OpenRAIL-M 许可,对使用场景有限制。默认的 Kokoro 采用 Apache 2.0,限制更少。
首次运行的等待
第一次朗读日语要下载约 325 MB 的模型、约 28 MB 的重音词典和约 8 MB 的音高预测模型。在网络受限的环境里,这一步可能失败或很慢,建议提前在目标机器上跑一次预热。