1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

無料枠が月50リクエストしかなかったので、AIに"本当に重要なことだけ"喋らせることにした

1
Posted at

1次2次は、さくらのAI Engineのチャット(判断エンジン)の話でした。今回は音声です。ただし、チャットとは枠の桁がまるで違いました

TL;DR

  • さくらのAI Engineの音声読み上げ(TTS)は無償枠が月50リクエスト。チャットの3,000・埋め込みの10,000と比べて桁が2つ小さい
  • そのため「全部の通知を喋らせる」は最初から成立しません。何を喋らせるかを設計する必要がありました。
  • 自分のAI会社の通知イベントを実測したところ、承認待ちは月19〜28件なのに対し、「支払いなど不可逆な操作の承認待ち」は月1〜2件。= 緊急度で切ると、月数回に収まる
  • そこで「今すぐ人が動かないと業務が止まるもの」だけを音声にし、枠が尽きたらWindows標準TTSへ自動フォールバックする構成にしました。1次記事で作った「さくら→ローカル」の2段構えが、そのまま音声でも効きました。
  • 文字起こしも実測:TTSで作った音声(=正解が既知)で比べたら、さくらとローカルの一致率は88.8%で実質互角。ただしさくらの誤りは「表記の正規化」、ローカルの誤りは「意味の破壊」(助成金→女性菌)。スコアが同じでも中身は別物でした。
  • ついでに踏んだ罠:コントロールパネルが「利用可能」でも、APIが通りませんでした。コードは一切変えず、時間を置いたリトライで解決。同じ時刻に叩いても、あるモデルは通り別のモデルは通らない——反映はモデル単位で個別に進むようです(何分かかるかは、測り方の都合で測れていません)。

1. 音声だけ、枠の桁が2つ小さい

さくらのAI Engineの無償プランは、機能ごとに無料枠が決まっています。実際に使ってみて一番驚いたのは、音声だけ極端に少ないことでした。

機能 無償枠(月) 1次・2次での実感
チャット生成 3,000 9モデル×5ジャンルを一気に叩いても消化は数%。個人には実質無限
ベクトル埋め込み 10,000 同上、まず使い切らない
音声の文字起こし 50 音声入力を日常使いすると、あっという間
音声の読み上げ(TTS) 50 ←今回の主役

実際の消費を枠に対する割合で見ると、差がはっきりします。この記事を書くための検証で、チャットは3,000枠に対し2リクエスト(0.07%)読み上げは50枠に対し9リクエスト(18%)。同じ月の同じ作業なのに、消化スピードが約270倍違いました。しかもこれはまだ「試している」段階の数字です。

2次記事までは「使い倒しても減らない」という話を書いてきました。ところが音声は逆で、普通に使うと確実に足りません。1日1回喋らせるだけで月30リクエスト、2回なら60リクエスト。枠を超えます

つまり音声については、「どう使うか」より先に「何に使わないか」を決める必要がある。これが今回の出発点です。

2. 実測:うちのAI会社は、月に何回"人を呼ぶ"のか

私のAI会社(ミニPCで動く自作のエージェント群)には、人間に通知が飛ぶ場面がいくつかあります。どれを音声にすべきかを勘で決めても外すので、実際のチケットとログを数えました。

通知イベント 実測 性質
承認待ち(成果物ができて社長の確認へ) 月19〜28件 溜めても平気。後でまとめて見ればいい
L1(支払い・予約=対外で不可逆)の実行前承認 チケット6件(月1〜2件相当) 止まったまま誰も気づかないと困る
自己修正3回失敗で停止 記録上まだ0件 起きたら業務が止まる(保険)
スケジューラの失敗・無人更新レポート メールで運用中 緊急ではない。メールで十分

この数字を見て、判断がはっきりしました。

  • 承認待ち(月19〜28件)を全部喋らせたら、それだけで枠の半分以上を食う。しかも急がない(WebUIで後からまとめて確認すればいい)
  • L1承認待ちは月1〜2件。少ないが、止まったまま気づかないと業務が進まない
  • 自己修正3回失敗は、まだ一度も起きていません。 それでも音声に入れたのは、起きたときに気づけないと困るからです。「頻度が低い」と「重要でない」は別物——枠に余裕があるからこそ、こういう"保険"を入れられます

つまり——

「重要だから喋らせる」ではなく、「今すぐ人が動かないと止まるから喋らせる」。

この基準で残した2つは、合わせて月2〜3リクエスト。枠50に対して十分な余裕があります。

音声の枠が月50しかないという制約が、通知の優先順位を強制的に考えさせてくれた格好です。全部を音声化できる潤沢な枠だったら、おそらく何も考えずに全部喋らせて、うるさくて切っていたと思います。

3. 実装:さくらTTS → 枠切れたらWindows標準TTS

方針が決まったので実装します。全体の流れはこうなりました。

音声通知の2段構え。voiceを渡す通知だけがspeak()に進み、今月の使用が45リクエスト未満ならさくらTTS、超えていればWindows標準TTSへ落ちる
voice-fallback-flow.png

※ この図は @enomoso_pm さんの drawio-diagram-skills(MIT License) を利用して作成しました。

1次記事の判断エンジンの図と、まったく同じ形です。違うのは分岐の条件だけ——あちらは「さくらが応答するか(障害・レート制限)」、こちらは「無償枠が残っているか」。

ポイントは、この枠を守るガードです。

FREE_QUOTA = 50       # さくらTTSの無償枠(月)
SAFETY_MARGIN = 5     # 使い切らないための余裕

def speak(text: str) -> str:
    """重要通知を読み上げる。使ったバックエンド名を返す。"""
    if not text or not text.strip():
        return "none"
    # 枠に余裕があるときだけ、さくらのずんだもんに喋ってもらう
    if used_this_month() < (FREE_QUOTA - SAFETY_MARGIN):
        if _speak_sakura(text):
            return "sakura"
    # 枠切れ・障害・オフライン → Windows標準TTSへ落ちる(無音にしない)
    if _speak_windows(text):
        return "windows"
    return "none"

used_this_month() は、自前の使用量ログ(.sakura-tts-usage.jsonl)から今月の消費を数えるだけの関数です。判断エンジンのフォールバックが、そのまま流用できました。

さくら側の呼び出しはOpenAI互換で、拍子抜けするほど簡単です。

POST https://api.ai.sakura.ad.jp/v1/audio/speech
{"model": "zundamon", "input": "...", "voice": "normal", "response_format": "wav"}
 WAVバイナリがそのまま返る

これを一時ファイルに書いて winsound で鳴らすだけ。VOICEVOXの「ずんだもん」がAPI経由で使えます(他に四国めたん・東北きりたん等も選べます)。

追記:実装確認後、東北イタコ・冥鳴ひまりも試し聴きして、最終的に本番の声は東北イタコに決めました(支払いの承認のような通知には、落ち着いた声の方が合っていたため)。この2モデルの選定過程で、次章の"反映ラグ"についてもう一つデータが取れたので、そちらでまとめて紹介します。SAKURA_TTS_MODEL環境変数で、コード変更なしにモデルを切り替えられるようにしてあります。

そして呼び出し側(エージェント監視プロセス)は、音声を出すかどうかを引数で明示する形にしました。

notify_human(
    f"[AI秘書] {agent} の確認待ち",
    "...(デスクトップ通知の本文)...",
    voice=f"{agent} の確認待ちです。対外の操作なので、社長の承認をお願いします。",
)

voice を渡したときだけ喋る。渡さない通知は今まで通り静かにデスクトップ通知だけ。これで「音声を足す」判断が、コードを読めば一目で分かるようになりました。

動作確認

$ python scripts/voice-notify/speak.py "支払いの承認をお願いします"
今月のさくらTTS使用: 0/50 回(安全上限 45)
読み上げ完了: backend=sakura

枠を使い切った状況を模擬すると、ちゃんと落ちます。

模擬: 今月46回使用済み → 安全上限45超え
backend = windows

使用量ログにも両方が残ります。

{"datetime": "2026-08-05 18:29:16", "backend": "sakura",  "model": "zundamon",     "requests": 1}
{"datetime": "2026-08-05 18:30:14", "backend": "windows", "model": "windows-sapi", "requests": 0}

自前のログだけでなく、さくらの管理画面でも消費が確認できます。ここまでの検証を全部やって、利用料金は0円のままです。

さくらのAI Engine 利用量パネル。利用料金0円、読み上げ9リクエスト・文字起こし4リクエスト
sakura-usage-panel-voice.png

4. ついでに文字起こしも測る:TTSで作った音声なら"正解"が既知

さくらのAI Engineには**音声の文字起こし(Whisper)**もあり、こちらも無償枠は月50リクエストです。せっかくTTSが動くようになったので、さくらTTSで作った音声を、そのまま文字起こしに投げ返すという往復テストをしてみました。

この測り方には利点があります。TTSに読ませた文がそのまま"正解テキスト"になるので、精度を主観ではなく数値で測れるのです。同じ音声をローカルのfaster-whisper(small・CPU)にも通して比較しました。

結果:平均はほぼ互角

さくら(whisper-large-v3-turbo) ローカル(faster-whisper small / CPU)
平均一致率(文字単位) 88.80% 88.83%
平均所要時間 1.4秒 1.9秒

差は0.03ポイント。サンプル4件での0.03差に意味はないので、実質互角と見るべきです(小数第1位で丸めるとどちらも88.8%になります)。少なくとも**「クラウドの大きいモデルが圧勝」ではなかった**のは確かです。

ただし、間違え方がまるで違った

面白いのはここからです。同じ88.8%でも、誤りの中身が正反対でした。

正解テキスト さくらの誤り ローカルの誤り
三件処理しました 3件処理しました 3連処理しました
エクセルに出力 Excelに出力 エクセルに出力(正解)
助成金の調査 助成金の調査(正解) 女性菌の調査
領収書 領収書(正解) 領収証
  • **さくらの誤りは「表記の正規化」**です。「三件→3件」「エクセル→Excel」は、文字列一致率こそ下げますが、意味としてはむしろ正しい
  • ローカルの誤りは「意味の破壊」です。「助成金→女性菌」は、読み返しても何のことか分かりません。

つまり——一致率という1つの指標で並べると同点でも、"意味が壊れないか"で見るとさくらが明確に上でした。2次記事で「正解数という1軸だけで並べるとモデル選定を誤る」と書きましたが、まったく同じ罠が文字起こしの評価でも待っていたわけです。スコアだけ見て「互角だからローカルでいい」と判断していたら、危ないところでした。

両方に出た誤りは、音声側を疑う

なお「払いの承認をお願いします」は、**さくら・ローカルとも揃って「払いの承認」**と冒頭が欠けました。両方に同じ誤りが出たときは、文字起こし側ではなく音声側(TTSの出だし)を疑うのが筋です。比較実験をすると、こういう切り分けもついでにできます。

使い分けの結論

用途 選択 理由
日常の音声入力(1日に何十回も喋る) ローカル さくらは月50リクエストでは到底足りない。ローカルは無制限
機密が混ざりうる口述 ローカル 音声は"何を喋るか"が事前に分からない。クラウドに出さない
精度が要る一発・非機密の検証 さくら 意味が壊れにくい。速度も速い

5. 罠:「利用可能」と表示されていても、APIはまだ使えない

さくらのTTSは、チャットや埋め込みと違ってモデルごとに個別の利用規約同意が必要です。コントロールパネルの「音声の読み上げ (audio speeches)」で、ライセンス表示を開かないと同意のチェックボックスすら押せません

そして同意を済ませ、ステータスが「✅ 利用可能」になった後でも、APIはこう返してきます。

400 Bad Request
{"error":{"message":"This model is not available."}}

コードは正しいのに通りません。 私はリクエストの形を疑いましたが、結局一切変えないまま、時間を置いたリトライで通りました(試した3モデルとも同じ)。原因は特定できていません——同意の反映ラグかもしれませんし、一時的な不調かもしれません(NETASSISTさんのブログには、同じエラーについて「一時的なもので、リトライすれば正常に応答する」とあります)。

なお**「何分待てば直るか」は書けません**。再試行の間隔を自分で決めている以上、手元にある「◯分」はサービスの復旧時間ではなく、自分が見に行った間隔でしかないからです。

反映はモデル単位で進む

条件をそろえて言えることが1つだけあります。東北イタコと冥鳴ひまりを同じタイミングで同意し、同じスクリプトの同じ実行で両方を叩いたところ——

東北イタコ 冥鳴ひまり
1回目 400 400
2回目(同一実行) 400 200 成功
3回目 200 成功

同じ瞬間に、片方は通り、片方は通らない。 つまり反映はモデルごとに個別に進みます。「1つ通ったから他も大丈夫」とは考えない方がよく、しかも先に同意した方が先に使えるわけでもありません(先に同意したのはイタコです)。

/v1/models にTTSは載らない(誤診の元)

もう1つ共有します。私は当初「/v1/models の一覧に出てこない=まだ反映されていない」と考えましたが、これは誤りでした。TTSが正常に動く今も載りません。 この一覧はチャット・埋め込み・文字起こし用で、音声合成モデルは最初から対象外です。ここを反映確認の材料に使うと、判断を誤ります。

対処法

  • コードを書き換える前に、時間を置いてリトライする。 闇雲に直していると、直ったときに「どの修正が効いたのか」が分からなくなります。
  • コントロールパネルの「利用可能」は、"今すぐAPIが通る"保証ではない。

まとめ

  • さくらのAI Engineの音声(文字起こし・読み上げ)は月50リクエスト。チャット3,000・埋め込み10,000とは桁が2つ違う。「使い倒しても減らない」感覚のまま手を出すと確実に足りません。
  • だから音声は、使う前に「何に使わないか」を決める必要があります。私は実測(承認待ち月19〜28件 vs 不可逆操作の承認 月1〜2件)から、「今すぐ人が動かないと止まるもの」だけに絞りました。
  • 枠が尽きたらWindows標準TTSへフォールバック。判断エンジンで作った「さくら優先→ローカル」の2段構えが、切り替え理由を「障害」から「枠の残り」に変えるだけでそのまま流用できました。
  • 文字起こしは、一致率88.8%でさくらとローカルが実質互角。ただし**さくらは「表記を正規化する誤り」、ローカルは「意味が壊れる誤り」**で中身は別物。スコア1軸で並べると判断を誤る——2次記事と同じ教訓が、ここでも出ました。
  • 同意直後、コントロールパネルが「利用可能」でもAPIが通らないことがありました。コード無変更のリトライで解決。同じ時刻に叩いてもモデルによって通ったり通らなかったりするので、反映はモデル単位で個別に進むようです。なお「何分待てば直るか」は、再試行の間隔を自分で決めている以上、測れていません(自分のポーリング間隔を、サービスの仕様として書かないよう気をつけました)。対処は同じ——コードを疑って書き換える前に、時間を置いて再試行すること。

制約が厳しいと、かえって設計がはっきりします。月3,000のチャットでは「とりあえず全部投げる」で済んでいたものが、月50の音声では「本当に必要なのはどれか」を数えることになりました。枠の狭さは、優先順位を教えてくれる——それが今回いちばんの収穫です。

質問・ツッコミ歓迎です。「音声、うちはこう使っている」などあれば、ぜひ教えてください。

余興:講評を、講評させた本人の"声"で読ませてみた

1次2次に続き、この記事もgpt-oss-120b自身に読ませました。以下は実際の出力そのままです(temperature=0・max_tokens=800・無加工)。

さくらAIの音声APIは無料枠が極端に小さく、実装で「枠管理+フォールバック」を組んだ点が実用的でした。TTSとWhisperの精度比較で、誤りの性質まで掘り下げた分析も好印象です。実測データに基づく優先順位付けは参考になります。今後はリトライロジックやモデル別反映遅延の情報をもう少し体系化すると、さらに使いやすくなるでしょう。

今回は音声編なので、ひと工夫。この講評文を、記事の主役である東北イタコにそのまま読み上げさせました。「文章を書くAI」の感想を「声のAI」が代読する——さくらのAI Engineの2つの顔を、両方使った締めくくりです(Qiitaは音声を直接埋め込めないので、実際の音声は手元で確認したものになりますが、記事末に生成の様子だけ記録しておきます)。

関連記事

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?