
2026/03/03 6:23
**Show HN:** ゼロから構築したサブ500 msの低遅延音声エージェント - 2週間以内にスタック全体を開発 - リアルタイム音声取得と再生にはWebRTCを使用 - エッジデバイス上で軽量ニューラルネットワークを動作させ、遅延を500 ms未満に抑制 - カスタム音声→テキストパイプラインと連携し、コマンド解析を即時実行 - AndroidおよびiOSでネイティブAPIを利用してデプロイ 本プロジェクトは、高性能な音声アシスタントがクラウドサービスに頼らずとも社内開発だけで構築できることを示し、一般的なハードウェア上で0.5秒未満の応答時間を実現した例です。
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
著者は、エンドツーエンドのレイテンシを約半分に短縮するカスタム音声エージェントオーケストレーション層を構築しました。これにより、APIクレジットが約100ドルで約400 msを実現し、Vapiの約840 msと比較して大幅に高速化しています。この最適化は、標準的なターンテイキングロジックと既製サービスを置き換えることで達成されました。コアアーキテクチャは単一ループで構成され、2つの状態があります:ユーザーが話し始めたらすべてのエージェント音声を停止し、ユーザーが停止したら応答の生成/ストリーミングを開始します。リアルタイムターン検出はDeepgram Flux(ストリーミング文字起こし+ターン検出)を使用し、Groqの llama‑3.3‑70b が言語理解を担当し、ElevenLabs TTSソケットは事前にウォームアップしておくことで応答時間から約300 msを削減します。パイプラインはまた、飛行中のLLM生成を即座にキャンセルし、TTSを終了させ、ユーザーがバージン(バリッジ)した際にはアウトバウンド音声をフラッシュしてスムーズな会話体験を提供します。地理的配置も重要です:南トルコでのローカルデプロイでは約1.7 sの知覚遅延がありましたが、オーケストレーション層をEUエンドポイントと同居させることでこれを約790 msに削減し、Vapiの推定値を上回りました。OpenAI gpt‑4o‑mini(約3倍遅い)からGroqの llama‑3.3‑70b に切り替えることで、最初のトークンレイテンシが約80 msに短縮され、総合レイテンシは約400 msとなりました。著者は完全なソースコードをGitHub(github.com/NickTikhonov/shuo)で公開する予定であり、他チームが低レイテンシ音声エージェントを迅速にプロトタイピングできるようコンサルティングも提供します。これにより、カスタムパイプラインは既製プラットフォームよりもボトルネックへの深い洞察を与えることが示されています。
本文
2026年2月9日・12 分で読めます
私はここ数か月、世界最大級の消費財メーカー向けにエージェントプロトタイプを開発するスタートアップで働いていました。その作業の一環として、チームはオフザシェルフの音声エージェントプラットフォーム(VapiやElevenLabsなど)を活用し、企業の運営効率化に寄与していました。ビジネス詳細は触れませんが、技術的な結論は明確でした:音声エージェントは強力であり、VapiやElevenLabsといった優れたオフザシェルフ抽象化があれば、音声エージェントを素早く構築できます。しかし、これらの抽象化は驚くほど多くの複雑さを隠しています。
この記事を書き始める数日前にElevenLabsは業界最大級の資金調達ラウンドを実施し、GPT‑5.3やClaude 4.6といった新しいフロンティアモデルが登場しました。私は「自分で音声エージェントのオーケストレーション層を構築できるだろうか?」と思いました。ただのデモではなく、Vapiのようなワンボックスプラットフォームとほぼ同等のパフォーマンスを持つものです。
驚いたことに、それは可能でした。約1日、APIクレジットで10 ドルほどで構築でき、結果としてVapiの同等設定よりも遅延が2倍速く、エンドツーエンドで約400 ミリ秒という応答時間を実現しました。
この記事では、音声エージェントがいかに難しいか、ターンテイキングループの仕組み、STT・LLM・TTSをストリーミングパイプラインに結合した方法、および地理とモデル選択が最大の差異を生む理由について詳細に解説します。途中で音声デモを聴いたり、アーキテクチャ図をインタラクティブに操作したりできます。
音声エージェントは難しい理由
音声エージェントは、対話型チャットのエージェントと比べて複雑性が大きく飛躍します。
テキストベースのエージェントは比較的シンプルです。ユーザーのアクションがすべてを調整するため、モデルがテキストを生成し、ユーザーがそれを読んで返信を書き、「送信」ボタンを押します。この「送信」がターン境界を定義し、ユーザーが明示的にフローを進めるまで何も起こりません。
音声ではそういった仕組みは働きません。オーケストレーションは継続的でリアルタイムかつ複数モデルを同時に管理する必要があります。システムは「ユーザーが話しているのか、聞いているのか」を瞬間瞬間判断し、その二状態の遷移こそがすべての難点です。
誰かが話し終えたとき
- ユーザーが話し始めると、エージェントは直ちに発話を停止します ― 生成のキャンセル、音声合成の停止、バッファリングされた音声のフラッシュ。
- ユーザーが話し終えると、システムは確実にそれを判断して最小遅延で応答を開始します。誤った判断だと会話が壊れます。
これは単純に大きさを測るだけでは解決できません。人間の音声にはポーズやためらい、フィラー音、背景ノイズ、非言語的確認など、エージェントを中断すべきでない要素が含まれます。その下流には「遅延」「不自然な沈黙」「エージェントが途中で切る」「ユーザーの上に話す」など、誰もが気づく問題があります。
音声コミュニケーションの質は無意識に判断されます。テキストでは許容できる小さなタイミング誤差が、音声では即座に間違いとして認識されます。
実際に優れた音声エージェントを構築するには、単一のモデルではなく「オーケストレーション」問題です。複数コンポーネントをつなぎ合わせ、その時間的調整が体験品質を決定します。
すべて統合したSDKを使うと、多くのパラメータを微調整する必要がありますが、どれが重要か、何故重要なのかがわからないケースが多いです。問題点が分かりにくくなると、エラー箇所を特定できずに不具合が残ります。この経験から、私はもう一層深く掘り下げ、自身でコアループを構築しました。
ターンテイキングの出発点
コードを書く前に、ChatGPTと外部ツールを使ってアーキテクチャを何度も検討しました。未知領域ではまずメンタルモデルを作ることが重要です。
私の目標は常に同じでした:構築しているものの構造を十分理解し、ファイルを開くとすぐに「なぜ存在するのか」「システム全体でどう位置づけられるのか」が分かる状態にすることです。
数回のイテレーション後、問題全体を単一ループと小さな状態機械へ簡略化しました。音声エージェントは基本的に「ユーザーが話しているか聞いているか」を判断すれば十分です。
- ユーザーが話している
- ユーザーが聞いている
それぞれの遷移で起こることは次の2つ:
- ユーザーが話し始めたら、エージェント音声と生成を即座に停止。
- ユーザーが話し終えたら、最小遅延で応答生成・ストリーミング開始。
🗣️ユーザーが話す →← スタート 👂ユーザーが聞く ←→ エージェントが発話中
このターン検出ロジックは、音声システムの核心です。ここから始めました。
最初の試行:VAD とプレレコーディング
最初の実装では文字起こし・言語モデル・テキスト→音声を一切避け、音声エージェントに近いシンプルなチェックポイントを作りました。設定は極めてミニマム:FastAPIサーバーがTwilioから受信するWebSocket接続を処理し、8 kHzで約20 msフレームのbase64‑encoded μ‑law音声パケットをストリーミングします。各パケットはデコードされ、Silero VAD(約2 MBの小型オープンソースモデル)に渡して短時間音声が含まれるか判定します。
VADは「この音声をより高価な下流システムへ送るべきか」を決めるために有用です。上で、真っ簡単な状態機械を構築しました:ユーザーが話しているか聞いているかを表すブールフラグ。システムが音声終了を検知すると、事前録音したWAVファイルを呼び出しに再生します。再度話し始めるとTwilioのWebSocketでクリア信号を送ってバッファリングされた音声をフラッシュし、即座に停止します。
この方法は「ターン検出」という最も難しい部分を切り離して実装できました。その結果:
- VAD‑only テスト:話し終えるとプレ録音クリップが再生され、途中で中断すると即座にカット。
- 文字起こしや生成無しでも、ループは対話的に感じられます。
また、遅延ベンチマークとしても役立ちました:積極的なターン終了とプレ録音応答の組み合わせで、音声エージェントがどれだけ高速に動くかの下限を示すことができました。
VAD‑only アプローチの限界
単純に「話しているか」を検知することは、「ユーザーが考え終えた」時点と同じではありません。スローボイスの場合、文中で数秒間ポーズを取ることがあります。ピュアVADだと過度に早くターン終了と判断しすぎてしまいます。
実際のターンテイキングは低レベル音声信号と高レベル意味的手がかり(文字起こし)を組み合わせる必要があります。このため、VAD‑only アプローチはリアルシステムには拡張できませんでした。ただし、制御フローのモデル化と遅延ベンチマークとしては十分に役立ちました。次に全パイプラインを組み込みます。
2回目の試行:Flux と実際の音声エージェントパイプライン
次のステップでは、VAD を手作りから本番用に設計された Deepgram の Flux に置き換えました。Flux はストリーミング API で、文字起こしとターン検出を単一モデルで行います。連続音声を投入すると「ユーザーの発話開始」「終了」イベントが生成され、終了時に最終的な文字起こしが含まれます。
Flux はエージェントがいつ話すべきか、いつ即座に停止して聞くべきかの真実情報源となります。上で構築した専用のエージェントターンパイプラインを作成しました:Flux がユーザーのターン終了を検知すると、リアルタイムに次が走ります。
- 文字起こしと会話履歴をLLMへ送信して生成開始。
- 最初のトークンが到着したら、それをWebSocket経由で TTS サービスへストリーミング。
- TTS が生成する音声パケットをそのまま Twilio のアウトバウンドソケットへ転送。
このアイデアは「全てのストリームをパイプライン化」し、遅延を最大限に削減することです。
重要な点として、TTS 接続をウォーム状態に保ちました。ElevenLabs への新規 WebSocket は数百ミリ秒のレイテンシがかかるため、小さなプールで常に接続済み状態を維持しました。これだけで応答時間から約300 msを削減できます。
バーゲイン(ユーザーが再び話し始めた)も対称的に処理:Flux が開始を検知すると、エージェントパイプラインを即座にキャンセル。進行中の LLM 生成停止、TTS の破棄、Twilio へのクリアメッセージ送信で音声キューもフラッシュします。エージェントは瞬時に沈黙し、Flux は次のターン終了を待ちます。
全体構成:Twilio → Deepgram Flux(ターン検出)→ バーゲイン/エージェントターニング(LLM → TTS → Twilio)。
ローカル実行
最初はローカルでオーケストレーションを完結させ、地理的配置がレイテンシに与える影響を把握しました。プロジェクト全体のほとんどをトルコ南部の木造キャビンから構築しながら旅行・ハイキングしていました。
ローカル(トルコ南部)で走らせたレイテンシトレース:TTFT(Turn‑to‑First‑Token)は約1.3 秒、最初の音声はターン終了後約1.6 秒。
エンドツーエンド平均遅延は約1.6秒で、Twilio のメディアエッジがさらに100 msを追加すると総合的には約1.7秒に。
これは Vapi の同等構成(約840 ミリ秒)と比べて 2 倍以上遅く、会話が不自然に感じられます。ポーズが長くなるだけで、ユーザーは「待たされている」感を覚えます。
この経験は、正しいアーキテクチャを採用しても地理的要因が重要だと再認識させました。
本番デプロイ
私の構成では音声パケットが外部サービス(Twilio, Deepgram, ElevenLabs)間で往復します。レイテンシを最小化するには、オーケストレーション層をそれらに物理的に近い場所に置く必要があります。
Railway の EU リージョンにデプロイし、Twilio・Deepgram・ElevenLabs も EU デプロイメントを使用(ElevenLabs は自動で最寄りリージョンを選択)ように設定しました。
結果は即座に現れました:
- Railway EU 配置後のレイテンシトレース:TTFT が300‑500 ms、最初の音声が550‑750 ms。
- サーバー側で測定した平均遅延は約690 ms、Twilio エッジを加えると総合的に約790 ms。
同じ STT, LLM, TTS モデルを使った Vapi の推定値(840 ms)と比較すると、カスタムオーケストレーションが 50 ms ほど速くなります。
さらに主観的にも違いは顕著です。会話のレスポンス感が向上し、中断もスムーズに機能します。エージェントは「答える前に少し間を置く」ことなく、リアルな対話へ近づきます。
モデル選択
ここまで gpt‑4o‑mini を使っていましたが、Groq の llama‑3.3‑70b が推論レイテンシで 3 倍速いことを発見しました。プロダクションサーバー上に小さなテストハーネスを構築し、360 回のチャット完了を実行。最初のトークン受信後すぐにリクエストをキャンセルして測定した結果:
- Groq のモデルは OpenAI を凌駕。
- llama‑3.3‑70b の first‑token latency は約80 ms ― 人間の瞬き(≈100 ms)より速い。
gpt‑4o‑mini から llama‑3.3‑70b に切り替えると結果は驚くほど改善しました:
- Groq ベースの音声エージェント:応答がほぼ即時に到着。
- エンドツーエンド平均遅延は約400 ms、最初の音声は 500 ms 未満。
このレイテンシで中断処理も格段にスムーズです。ユーザーが話し始めると、エージェントはほぼ瞬時に音声を切り替え、実際に「リアルな会話」に近づきます。
技術的教訓
オフザシェルフプロバイダーを完全に上回ることができたのは驚きでした。Vapi と ElevenLabs のエージェント SDK を本番で実際に使った経験から、私のプロトタイプは 2 倍遅延改善を安定して達成しています。
スムーズな AI 音声会話に必要なのは
-
レイテンシ
「ユーザーが話し終えた時点」から「エージェントの最初の音節」を聞くまでの時間。ターン検出、文字起こし、LLM の to‑first‑token、TTS 合成、アウトバウンド音声バッファリング、およびネットワーク遅延を通過します。クリティカルパス上の不要なブロックを排除して最適化します。 -
モデル選択と TTFT
音声システムでは first‑token latency が全体レイテンシの半分以上を占めます。Groq のように推論最適化されたセットアップを選ぶことで最大差が生まれます。モデルサイズは大きいほど応答性が落ちるため、用途に合わせてバランスを取ります。 -
エージェントターンのパイプライン化
STT → LLM → TTS の順序で実行するだけでは遅延が増大します。LLM トークンは到着次第 TTS に渡し、音声フレームを即時に Twilio へ送ることでブロッキングを排除します。 -
中断処理の即時キャンセル
ユーザーが話し始めたら、LLM 生成・TTS を同時に停止し、Twilio に音声キューのフラッシュ指示を送ります。いずれか一つでも遅延するとバーゲインが壊れます。 -
地理的配置
テレフォニー、STT、TTS、LLM の各サービスを同じリージョンに置くことで、ネットワーク遅延を半減します。サービス間の距離が増えるとレイテンシは指数関数的に増加します。
これらを総合すると、音声が「難しい」ように見えて実際には「オーケストレーション問題」であることが分かります。ループが明確になれば、エンジニアリング課題として解決可能です。
オフザシェルフ vs. カスタム
Vapi や ElevenLabs のようなプラットフォームに対して反論する意図はありません。これらのシステムは API, 観測性, 信頼性, 豊富な設定オプションを提供し、再現には相当な労力が必要です。多くのチームにとって、それらすべてを自前で構築するのは間違いです。しかし、自分自身で音声エージェント(たとえ簡易版でも)を作ることは価値があります。
- 何がパラメータに影響しているか、なぜデフォルトがそうなのかを理解できます。
- ボトルネックがどこにあるかを把握でき、オフザシェルフプラットフォームの設定を最適化できます。
- 必要に応じてより特注のソリューションを構築する際の土台となります。
音声はオーケストレーション問題です。ループが見えると、実装可能なエンジニアリング課題になります。
完全なソースコードは GitHub で公開しています:https://github.com/NickTikhonov/shuo
音声エージェントや他の AI 製品をリリースしたい方はぜひご相談ください。アイデアからプロトタイプまで迅速に実装します。
X(旧 Twitter)でフォローして最新情報をチェックしてください。