Stream Vision Agents と Amazon Nova 2 Sonic を用いたリアルタイム音声エージェントの実装
AWS と Stream は、Amazon Nova 2 Sonic と Vision Agents フレームワークを統合することで、複雑なインフラ管理なしに数分で本番環境対応のリアルタイム音声 AI エージェントを構築できる新ソリューションを発表しました。
キーポイント
音声パイプラインの簡素化と Nova 2 Sonic の役割
従来の個別な STT(音声認識)と TTS(音声合成)サービスを統合し、Amazon Nova 2 Sonic が双方向オーディオストリーミング、ネイティブターン検出、関数呼び出しを単一モデルで処理することで、遅延を最小化します。
インフラ複雑性の抽象化
Stream の Vision Agents オープンソースフレームワークが、WebRTC 接続管理、自動再接続ロジック、ブラウザ互換性など、本番環境特有のインフラ課題を抽象化し、開発者が AI ロジックに集中できる環境を提供します。
迅速な実装と多言語対応
この統合により、数分で生産レベルの音声エージェントを構築可能となり、関数呼び出しや自動再接続機能に加え、多言語音声サポートなどの高度な機能も即座に利用できます。
Amazon Nova 2 Sonic の統合
AWS Realtime モデルとして「amazon.nova-2-sonic-v1:0」を指定し、リアルタイム音声エージェントの基盤として利用しています。
Stream Edge と Agent ライフサイクル管理
getstream.Edge をエッジとして設定し、create_call と join コマンドを用いて通話への参加と終了を非同期処理で制御します。
双方向ストリーミングによるリアルタイム通信
Amazon Nova 2 Sonic はリクエストレスポンス型ではなく、イベント駆動型の双方向ストリーミング API を採用し、音声の流入と流出を同時に処理します。
構造化されたイベントシーケンス
セッション開始から終了まで、sessionStart、promptStart、audioInput、audioOutput などの明確なイベント順序で複雑な通信を管理し、文脈を維持します。
影響分析・編集コメントを表示
影響分析
この発表は、リアルタイム音声 AI アプリケーションの開発障壁を劇的に下げるものであり、特に低遅延と高信頼性が求められるコールセンターや対話型アシスタント分野での普及を加速させるでしょう。開発者がインフラ構築に費やす時間を削減し、AI ロジックの最適化にリソースを集中できるため、業界全体で音声 AI の実装スピードが向上すると予想されます。
編集コメント
音声 AI の実装における最大のボトルネックであったインフラ管理を、専用モデルとフレームワークの組み合わせで解決した点は非常に画期的です。今後は、この基盤の上にどのような具体的なユースケースが急速に生まれるかが注目されます。
*この投稿は、*Stream の技術マーケティングリーダーである Neevash Ramdial 氏との共著です。
自然で応答性の高い本番環境向けの音声エージェントを構築するのは、複雑なエンジニアリングの課題です。音声入力から音声出力までのモデルをオーケストレーションし、低遅延のオーディオストリーミングを管理し、接続ライフサイクルを処理する必要があります。また、Web、モバイル、デスクトップアプリケーション全体で一貫した体験を提供することも求められます。
本稿では、Stream の Vision Agents オープンソースフレームワークと Amazon Bedrock および Amazon Nova 2 Sonic を組み合わせることで、数分で本番環境に導入可能なリアルタイム音声エージェントを構築する方法について解説します。統合の内部仕組み、コード例の解説、および関数呼び出し、自動再接続、多言語音声サポートといった高度な機能について探ります。
⟦CODE_0⟧
The challenge
音声対応 AI アプリケーションを構築するには、信頼性を持って連携する複数の複雑なシステムを調整する必要があります。リアルタイムオーディオストリーミングインフラストラクチャの管理と並行して、音声認識、言語モデル、テキスト読み上げサービスの統合という課題に直面します。それぞれには独自のレイテンシ特性と障害モードが存在します。典型的な音声対話では、ユーザーのマイクから音声をキャプチャし、それを音声変換サービスへストリーミングし、その文字起こしを言語モデルで処理して応答を生成し、その応答を再度音声に変換してユーザーに配信するという一連のプロセスが行われます。これらすべてが自然に感じられるよう、数百ミリ秒の時間枠内で完了する必要があります。このパイプラインでの遅延は会話の流れを断ち切り、ユーザーをイライラさせる原因となります。
コアとなる AI パイプラインを超えて、本番環境の音声アプリケーションでは、現実世界の展開における複雑な事象に対処しなければなりません。具体的には、不安定なネットワーク接続、ブラウザの互換性問題、セッションタイムアウト、およびサービスが利用不能になった場合のグレースフルデグラデーションです。実際には、実際の AI 機能の開発よりも、再接続ロジックの構築や WebRTC コネクションの管理、エッジケースへの対応に多くの時間を費やすことがよくあります。このインフラストラクチャ上の負担により、チームはカスタムソリューションを構築するために数ヶ月を投資するか、特定のニーズを満たさない限定的な市販製品に妥協するかの二者択一を迫られます。Vision Agents は、インフラストラクチャの複雑さを抽象化しつつ、AI 体験のカスタマイズ性を提供します。
ソリューション概要
本ソリューションは、3 つの主要コンポーネントを統合したものです:
- Amazon Nova 2 Sonic は、Amazon Bedrock を通じて利用可能な音声対音声の基盤モデルであり、リアルタイム双方向オーディオストリーミング、ネイティブターン検出、および関数呼び出し機能を備えています。Nova 2 Sonic は完全な音声対音声パイプラインを処理し、オーディオ入力を受け付けてオーディオ出力を生成します。これにより、個別の STT(Speech-to-Text)および TTS(Text-to-Speech)サービスの必要性がなくなります。
- Stream の Vision Agents は、リアルタイム音声およびビデオ AI エージェントを構築するためのオープンソース Python フレームワークです。25 以上の統合、本番環境でのデプロイメントツール、React、iOS、Android、Flutter、React Native 向けのクライアント SDK を備えたプラグインベースのアーキテクチャを提供します。このシステムは柔軟性を中核に設計されており、Stream のグローバルエッジネットワークを使用して効率的なパフォーマンスを実現することも、お好みのリアルタイム通信(RTC)プロバイダーと統合することも可能です。Vision Agents は、クリーンなデコレータベースのインターフェースを通じてプロバイダー固有の仕様を処理し、最小限のボイラープレートコードでカスタマーサポートエージェント、ワークフロー自動化、API ドライブ型のアクションなどのユースケースを可能にします。Vision Agents を用いれば、オープンソースフレームワーク、サードパーティ製モデルプロバイダー、および電話サービスを使用して AI アプリケーションを構築できます。
- Stream のエッジネットワークは、グローバルに分散されたエッジネットワークであり、通常 500 ミリ秒未満の接続時間と 30 ミリ秒未満のオーディオレイテンシを提供し、クライアントとエージェントバックエンド間のリアルタイム転送層として機能します。
これら 3 つのコンポーネントを組み合わせることで、完全なスタックが構築されます。Stream がリアルタイムメディア転送とクライアント側のエクスペリエンスを担当し、Amazon Nova 2 Sonic が AI の知能を提供し、Vision Agents がそれらを結びつける接着剤としてのコード(グルーコード)を提供します。
アーキテクチャの概要
本システムは、関心の明確な分離を基盤に設計されています。Stream のインフラストラクチャがリアルタイムメディア転送とクライアント接続を担当し、Amazon Nova Sonic は顧客自身の AWS アカウント内で実行され、AI による知能機能を提供します。この分離により、機密データやビジネスロジックは顧客の管理下に保たれつつ、Stream のグローバルに分散されたエッジネットワークがユーザーが期待する低遅延のメディア体験を届けることができます。Stream のエッジネットワークは、エンドユーザー端末とビジョンエージェントワーカープロセスの間でメディアブローカーとして機能します。ユーザーが発話すると、音声はキャプチャされ、暗号化されて UDP 上の RTP プロトコルで最も近い Stream SFU(Selective Forwarding Unit:選択転送ユニット)へ送信されます。SFU は WebRTC 接続を終端し、NAT トリバーサルと帯域幅推定を処理した上で、音声トラックをビジョンエージェントワーカーへ転送します。これはあたかも別の通話参加者であるかのように扱われます。つまり、エージェントは通話モデルに自然に統合されることになります。エージェントはもう一つのピアであり、人間参加者が使用するのと同じインフラストラクチャを通じて音声をやり取りします。
オーディオデータはシステム内で双方向に流れます。ユーザーからの音声入力はいちばん最初にビジョンエージェントワーカーによって生 PCM にデコードされ、Bedrock リアルタイム API を経由して Amazon Nova Sonic へストリーミングされます。Nova Sonic からの応答オーディオフレームは再エンコードされ、RTP パケット化された上で SFU を通じてクライアントデバイスへと配信されます。エンドツーエンドのレイテンシは通常 500 ミリ秒未満です。音声活動検出 (VAD: Voice Activity Detection) はワーカー内で実行され、音声の境界とバージインイベントを検出します。一方、ブラウザ内のエコーキャンセレーション機能により、エージェント自身の出力が VAD ループを再トリガーするのを防ぎます。
##
アカウント境界
- カスタマー AWS アカウント
ビジネスロジックとオーケストレーション(エージェントポリシー、ツール、データアクセス)。
- Amazon Nova モデルへのアクセスのための Amazon Bedrock 統合。
- Stream AWS アカウント
グローバルな WebRTC/SFU メディアプレーン、TURN/STUN、およびシグナリング。
- WebRTC をロボットピアとして終端し、カスタマーの Amazon Bedrock 統合をブリッジするビジョンランタイム(ワーカープロセス)。
エンドツーエンドのメディアフロー
- ユーザーは Web またはモバイルから参加します。
アプリは Stream のオーディオクライアント SDK を埋め込み、マイク(およびオプションでカメラ)へのアクセスを要求し、AI が参加するように構成された通話タイプに参加します。
- メディアは、予測可能な低遅延とヘッド・オブ・ラインの排除を実現するために、UDP 上の RTP として送信されます。2. リージョン別 SFU 終端
- リージョン別 SFU 終端
最寄りのリージョンにある Stream の SFU ノードが、ユーザーの WebRTC 接続を終端し、帯域幅推定、シミュルキャスト、NAT トリバーサル(ネットワークアドレス変換の通過)を処理します。
- SFU は、関連するオーディオトラックを、あたかも別の参加者であるかのように Vision Agent ワーカーに転送します。
- Vision Agent ワーカー
専用の Vision Agent ワーカープロセスが、そのセッションの PeerConnection(ピア接続)状態を保持します。
- このワーカーはオーディオを生の PCM にデコードし、PCM フレームを Amazon Bedrock サービスにストリーミングして、顧客の AWS アカウント内でリアルタイムセッションとして Amazon Nova 2 Sonic へ転送します。
- Amazon Bedrock を介した Vision エージェントとの Amazon Nova 2 Sonic の統合
Amazon Nova 2 Sonic は音声の境界を検出し、音声認識(理解)、推論、およびテキスト読み上げ(TTS)を備えた音声対音声モデルを実行します。必要に応じて顧客システム(RDS、API、ナレッジベース)へのツール呼び出しも可能です。
- バージ・イン(会話中の割り込み)を適切に処理し、完全な会話コンテキストを維持することで、会話が自然で一貫性のあるものとなります。
- ユーザーへのストリーミング応答の返送
Amazon Nova Sonic が応答オーディオフレームを生成する際、Vision Agent ワーカーは次の処理を行います:
断片化して RTP にラップし、単調に増加するタイムスタンプを追加して、ギャップやドリフトを防ぎます。
- RTP パケットを同じ WebRTC セッションを通じて SFU を経由で送信します。ブラウザの WebRTC スタックがデコードして再生し、500 ミリ秒未満の遅延を実現します。
- バージ・イン、トランスクリプト、およびサイドデータ
ブラウザ内のエコーキャンセレーションにより、エージェント自身の出力が再度 VAD(音声活動検出)をトリガーするのを防ぎます。
- ユーザーが割り込むと、新しい発話が RTCDataChannel を介して割り込み信号として送信され、ワーカーは Amazon Nova Sonic の出力の転送を停止し、ローカルバッファをリセットします。
このアーキテクチャは一見複雑に思えるかもしれませんが、Vision Agents はその多くの複雑さを抽象化しています。実際のコードがどのようなものか見てみましょう:
前提条件
始める前に、以下の準備を必ず確認してください。
- AWS の認証情報は、環境変数、IAM ロール、または AWS コマンドラインインターフェース (AWS CLI) プロファイルを通じて設定されていること。本番環境では、長期の認証情報ではなく、計算リソースに紐付けられた IAM ロールを使用してください。ローカル開発では、AWS CLI プロファイル (aws configure) または AWS SSO を使用してください。認証情報が含まれる .env ファイルをバージョン管理システムにコミットしないでください。
- Stream アカウントを持っており、Audio API キーとシークレットが用意されていること(月額 333,000 パーティシント・マインツが無追加コストで利用可能です)。
- Python 3.12 以降がインストールされていること。
- uv パッケージマネージャーがインストールされていること (pip install uv)。
- Vision Agents がインストールされていること (uv add vision-agents)
はじめに
ステップ 1: 新しいプロジェクトディレクトリを作成し、AWS プラグイン付きで Vision Agents をインストールする
mkdir voice-agent
cd voice-agent
uv init
uv add "vision-agents[getstream,aws]"
python-dotenv
vision-agents[aws] エクストラをインストールすると、Amazon Bedrock プラグインとその依存関係(boto3、aws-sdk-bedrock-runtime、音声活動検出用の Silero VAD など)が一緒にインストールされます。
ステップ 2: 環境変数の設定
プロジェクトのルートディレクトリに「.env」ファイルを作成して設定を管理してください。AWS の認証情報については、このファイル内で AWS_PROFILE を参照させることを推奨します。これにより、アプリケーションが AWS リソースと対話する際に認証情報を取得できるようになります。ただし、AWS アクセスキーを直接このファイルに保存することは推奨しません。
Stream API の認証情報については、HashiCorp Vault や AWS Secrets Manager などのサードパーティ製ライブラリを使用できますが、セキュリティに関する考慮事項は本稿の範囲外です。
Stream API の認証情報
STREAM_API_KEY=test/geststream/api_key
STREAM_API_SECRET=test/getstream/api_secret
AWS の認証情報
AWS_PROFILE=your_aws_profile_name
AWS_REGION=us-east-1
ビジョンエージェント(Vision Agents)は起動時にこれらの環境変数を自動的に検出するため、各クライアントに明示的に渡す必要はありません。
ステップ 3: 最初の音声エージェントの構築
以下のコードを含む main.py ファイルを作成してください:
import asyncio
from dotenv import load_dotenv
from vision_agents.core import Agent, User, Runner
from vision_agents.core.agents import AgentLauncher
from vision_agents.plugins import aws, getstream
load_dotenv()
async def create_agent(**kwargs) -> Agent:
agent = Agent(
edge=getstream.Edge(),
agent_user=User(name="Helpful Assistant", id="agent"),
instructions="You are a helpful voice assistant. Be concise and friendly.",
llm=aws.Realtime(
model="amazon.nova-2-sonic-v1:0",
region_name="us-east-1",
voice_id="matthew",
),
)
return agent
async def join_call(agent: Agent, call_type: str, call_id: str, **kwargs) -> None:
call = await agent.create_call(call_type, call_id)
async with agent.join(call):
await asyncio.sleep(2)
await agent.llm.simple_response(
text="Greet the user warmly and ask how you can help."
)
await agent.finish() # Run until the call ends
if __name__ == "__main__":
Runner(AgentLauncher(create_agent=create_agent, join_call=join_call)).cli()
Step 4: Run the voice agent
Run the agent:
uv run main.py run
In fewer than 30 lines of code, you have a fully functional, real-time voice agent powered by Amazon Nova Sonic, accessible from a Stream client SDK.
Understanding the Amazon Bedrock integration
Let's take a closer look at how the aws.Realtime plugin works under the hood.
Bidirectional streaming with Amazon Nova 2 Sonic
Amazon Nova 2 Sonic uses an event-driven bidirectional streaming API. Instead of using a request-response pattern, this approach allows nearly continuous audio to flow in both directions simultaneously. The Vision Agents AWS plugin manages this complexity through a structured event sequence:
- セッション初期化 – セッション開始イベントが、推論設定(温度パラメータ、最大トークン数、top-p)と共に送信されます。
- プロンプト設定 – プロンプト開始イベントにより、音声出力形式(24kHz PCM)、音声の選択、およびツール定義が構成されます。
- システム指示 – システム指示は、SYSTEM ロールを持つテキストコンテンツブロックとして送信されます。
- 音声ストリーミング – マイクロフォンからの音声フレーム(各約32ms)が、audioInput イベントとしてストリーミングされます。
- レスポンスストリーミング – Nova Sonic は、生成された音声を含む audioOutput イベントをストリーミングして返します。
- セッション終了 – promptEnd および sessionEnd イベントにより、接続がきれいにクローズされます。
各コンテンツブロックは「contentStart → コンテンツペイロード → contentEnd」という 3 つの部分からなるパターンに従います。この階層構造により、モデルは対話全体を通じて適切な文脈を維持できます。
プラグインにおけるセッション開始イベントの例は以下の通りです:
def _create_session_start_event(self) -> Dict[str, Any]:
return {
"event": {
"sessionStart": {
"inferenceConfiguration": {
"maxTokens": 1024,
"topP": 0.9,
"temperature": 0.7,
}
},
"turnDetectionConfiguration": {
"endpointingSensitivity": "MEDIUM"
},
}
}
関数呼び出しの追加
Amazon Nova 2 Sonic の主要な機能の一つは、リアルタイム会話中のネイティブ関数呼び出しです。これにより、音声エージェントが自然な話し言葉による会話を維持しながら、データベースへの照会や API の呼び出し、ワークフローのトリガーなどのアクションを実行できるようになります。
モデルが呼び出せる関数を定義するには、@llm.register_function デコレータを使用します:
import asyncio
from dotenv import load_dotenv
from typing import Dict, Any
from vision_agents.core import Agent, User, Runner
from vision_agents.core.agents import AgentLauncher
from vision_agents.plugins import aws, getstream
load_dotenv()
async def create_agent(**kwargs) -> Agent:
agent = Agent(
edge=getstream.Edge(),
agent_user=User(name="Weather Assistant", id="agent"),
instructions="""あなたは親切な天気アシスタントです。ユーザーが天候について質問した場合は、get_weather 関数を使用して現在の状況を取得してください。
また、簡単な計算のサポートも可能です。""",
llm=aws.Realtime(
model="amazon.nova-2-sonic-v1:0",
region_name="us-east-1",
),
)
@agent.llm.register_function(
name="get_weather",
description="指定された都市の現在の天気を取得する"
)
async def get_weather(location: str) -> Dict[str, Any]:
# 本番環境では、実際の天気 API を呼び出してください
return {
"city": location,
"temperature": 72,
"condition": "Sunny",
"humidity": "45%"
}
@agent.llm.register_function(
name="calculate",
description="数学的な計算を実行する"
)
def calculate(operation: str, a: float, b: float) -> dict:
operations = {
"add": lambda x, y: x + y,
"subtract": lambda x, y: x - y,
"multiply": lambda x, y: x * y,
"divide": lambda x, y: x / y if y != 0 else None,
}
result = operations.get(operation, lambda x, y: None)(a, b)
return {"operation": operation, "a": a, "b": b, "result": result}
return agent
async def join_call(agent: Agent, call_type: str, call_id: str, **kwargs) -> None:
await agent.create_user()
call = await agent.create_call(call_type, call_id)
async with agent.join(call):
await asyncio.sleep(2)
await agent.llm.simple_response(
text="ユーザーに挨拶し、天気を確認できることを伝える"
)
await agent.finish()
if __name__ == "__main__":
Runner(AgentLauncher(create_agent=create_agent, join_call=join_call)).cli()
Amazon Nova 2 Sonic との関数呼び出しの実行方法
モデルが関数の呼び出しを決定すると、以下のシーケンスが発生します:
- Nova 2 Sonic が、関数名と引数を含む toolUse イベントを発行します。
- Vision Agents プラグインがこのイベントをインターセプトし、引数をシリアルの解除して、登録された Python 関数を実行します。
- 結果は、標準的な contentStart → toolResult → contentEnd パターンでラップされ、toolResult イベントとして Nova に返送されます。
- Nova 2 Sonic はこの関数の結果を応答に組み込み、自然な会話の流れを継続します。
このアプローチを用いることで、複雑な多段階ワークフローを構築できます。例えば、音声エージェントが顧客レコードを検索し、在庫を確認し、注文を行うといった一連の処理を、単一の自然な会話内で行うことが可能です。
Amazon Bedrock との標準 LLM の使用
リアルタイムの音声対音声(speech-to-speech)を超えて、AWS プラグインは aws.LLM を介して標準的な大規模言語モデル(LLM: Large Language Model)の統合も提供しています。これは、Amazon Bedrock モデルを個別の音声テキスト変換(STT: Speech-to-Text)およびテキスト音声変換(TTS: Text-to-Speech)プロバイダと組み合わせて使用したいカスタムパイプラインアーキテクチャにおいて有用です:
from vision_agents.core import Agent, User
from vision_agents.plugins import aws, getstream, cartesia, deepgram, smart_turnagent = Agent(
edge=getstream.Edge(),
agent_user=User(name="Custom Pipeline Agent"),
instructions="Be helpful and concise.",
llm=aws.LLM(
model="anthropic.claude-3-haiku-20240307-v1:0",
region_name="us-east-1"
),
tts=cartesia.TTS(),
stt=deepgram.STT(),
turn_detection=smart_turn.TurnDetection(
buffer_duration=2.0,
confidence_threshold=0.5
),
)
The standard LLM supports streaming responses via converse_stream(), full conversation history management, vision inputs for models like Claude, and multi-round tool calling with up to 3 rounds of function execution per request.
Text-to-speech with Amazon Polly
For custom pipeline architectures, the AWS plugin also includes an Amazon Polly TTS integration. This is useful when you're using a non-realtime LLM (like Claude on
原文を表示
*This post was co-authored with Neevash Ramdial, Technical Marketing leader at *Stream
Building production-grade voice agents that feel natural and responsive is a complex engineering challenge. You must orchestrate speech-to-speech models, manage low-latency audio streaming, and handle connection lifecycle. You also need to deliver consistent experiences across web, mobile, and desktop applications.
In this post, you learn how to combine Stream’s Vision Agents open-source framework with Amazon Bedrock and Amazon Nova 2 Sonic to build real-time voice agents that can be production-ready in minutes. You’ll learn how the integration works under the hood, walk through code examples, and explore advanced capabilities like function calling, automatic reconnection, and multilingual voice support.
The challenge
Building voice-enabled AI applications requires orchestrating multiple complex systems that must work together reliably. You face the challenge of managing real-time audio streaming infrastructure while simultaneously integrating speech recognition, language models, and text-to-speech services. Each of these has its own latency characteristics and failure modes. A typical voice interaction involves capturing audio from the user’s microphone, streaming it to a speech-to-text service, processing the transcript through a language model, generating a response, converting that response back to speech, and delivering it to the user. All of this must happen within a window of a few hundred milliseconds to feel natural. Delays in this pipeline can break the conversational flow and frustrate users.Beyond the core AI pipeline, production voice applications must handle the messy realities of real-world deployment: unreliable network connections, browser compatibility issues, session timeouts, and graceful degradation when services become unavailable. You often spend more time building reconnection logic, managing WebRTC connections, and handling edge cases than on the actual AI capabilities. This infrastructure burden means teams either invest months building custom solutions or settle for limited off-the-shelf products that don’t meet their specific needs. Vision Agents abstracts the infrastructure complexity while providing the flexibility to customize the AI experience.
Solution overview
The solution brings together three key components:
- Amazon Nova 2 Sonic a speech-to-speech foundation model available through Amazon Bedrock that provides real-time bidirectional audio streaming, native turn detection, and function calling capabilities. Nova 2 Sonic handles the full speech-to-speech pipeline, accepting audio input and producing audio output. This avoids the need for separate STT and TTS services.
- Stream’s Vision Agents an open-source Python framework for building real-time voice and video AI agents. It provides a plugin-based architecture with 25+ integrations, production deployment tooling, and client SDKs for React, iOS, Android, Flutter, and React Native. The system is designed with flexibility at its core. You can use Stream’s global edge network for efficient performance or integrate your preferred real-time communication (RTC) provider. Vision Agents handles provider-specific specifications through a clean decorator-based interface, enabling use cases like customer support agents, workflow automation, and API-driven actions with minimal boilerplate code. With Vision Agents, you can build AI applications using an open-source framework, third-party model providers, and telephony services.
- Stream’s Edge Network a globally distributed edge network that typically delivers sub-500ms join times and under 30ms audio latency, providing the real-time transport layer between clients and your agent backend.
Together, these components create a complete stack: Stream handles the real-time media transport and client-side experience, Amazon Nova 2 Sonic provides the AI intelligence, and Vision Agents provides the glue code that ties them together.
Architecture overview
The system is designed around a clean separation of concerns: Stream’s infrastructure handles the real-time media transport and client connectivity, while Amazon Nova Sonic runs in the customer’s own AWS account and provides the AI intelligence. This separation helps keep sensitive data and business logic remain within the customer’s control, while Stream’s globally distributed edge network delivers the low-latency media experience users expect.Stream’s edge network acts as the media broker between end-user devices and the Vision Agent worker processes. When a user speaks, audio is captured, encrypted, and transmitted as RTP over UDP to the nearest Stream SFU (Selective Forwarding Unit). The SFU terminates the WebRTC connection, handles NAT traversal and bandwidth estimation, and forwards audio tracks to the Vision Agent worker as if it were another call participant. This means the agent integrates naturally into the call model. The agent is another peer, receiving and sending audio through the same infrastructure used by human participants.
Audio data flows bidirectionally through the system: incoming speech from the user is decoded to raw PCM by the Vision Agent worker, streamed to Amazon Nova Sonic via the Bedrock real-time API, and response audio frames from Nova Sonic are re-encoded, packetized as RTP, and delivered back through the SFU to the client device. End-to-end latency is typically under 500 milliseconds. Voice activity detection (VAD) runs in the worker to detect speech boundaries and barge-in events, while echo cancellation in the browser helps prevent the agent’s own output from re-triggering the VAD loop.
##
Account boundaries
- Customer AWS account
Business logic and orchestration (agent policies, tools, data access).
- Amazon Bedrock integration to access Amazon Nova models.
- Stream AWS account
Global WebRTC/SFU media plane, TURN/STUN, and signaling.
- Vision Agent runtime (worker processes) that terminate WebRTC as robot peers and bridge the customer’s Amazon Bedrock integration.
End-to-end media flow
- User joins from web or mobile.
The app embeds Stream’s audio client SDK, requests mic (and optionally camera), and joins a call type configured for AI participation.
- Media is sent as RTP over UDP for predictable low latency and head‑of‑line–free delivery. 2. Regional SFU termination
- Regional SFU termination
A Stream SFU node in the closest region terminates the user’s WebRTC connection, handling bandwidth estimation, simulcast, and NAT traversal.
- The SFU forwards the relevant audio tracks to the Vision Agent worker as if it were another participant.
- Vision Agent worker
A dedicated Vision Agent worker process holds the PeerConnection state for that session.
- It decodes audio to raw PCM and the worker streams PCM frames to Amazon Bedrock service forwarding to Amazon Nova 2 Sonic as a real-time session in the customer’s AWS account.
- Amazon Nova 2 Sonic integration with Vision agents through Amazon Bedrock
Amazon Nova 2 Sonic detects speech boundaries and performs speech-to-speech modeling (understanding, reasoning, and TTS) with optional tool calls into customer systems (RDS, APIs, knowledge bases).
- It gracefully handles barge-in and maintains full conversational context so that the conversation remains natural and coherent.
- Streaming response back to the user
As Amazon Nova Sonic produces response audio frames, the Vision Agent worker:
Slices and wraps them in RTP with monotonically increasing timestamps to avoid gaps/drifts
- Sends RTP packets through the same WebRTC session via the SFU. The browser’s WebRTC stack decodes and plays audio with sub-500 ms latency.
- Barge-in, transcripts, and side data
Echo cancellation in the browser helps prevent the agent’s own output from retriggering VAD.
- When the user interrupts, new speech triggers an interrupt signal over an RTCDataChannel, causing the worker to stop forwarding Amazon Nova Sonic output and reset its local buffer.
This architecture might seem complex, but Vision Agents abstracts much of this complexity. Let’s see what the actual code looks like:
Prerequisites
Before getting started, make sure you have the following:
- AWS credentials configured via environment variables, IAM role, or AWS Command Line Interface (AWS CLI) profile. For production environments, use IAM roles attached to your compute resources instead of long-term credentials. For local development, use AWS CLI profiles (aws configure) or AWS SSO. Do not commit .env files containing credentials to version control.
- Stream account with an Audio API key and secret (you are expected to receive 333,000 participant minutes per month at no additional cost).
- Python 3.12 or later installed.
- uv package manager installed (pip install uv).
- Vision Agents installed (uv add vision-agents)
Getting started
Step 1: Create a new project directory and install Vision Agents with the AWS plugin
mkdir voice-agent
cd voice-agentuv inituv add "vision-agents[getstream,aws]"
python-dotenvThe vision-agents[aws] extra installs the Amazon Bedrock plugin along with its dependencies, including boto3, aws-sdk-bedrock-runtime, and Silero VAD for voice activity detection.
Step 2: Configure environment variables
Create a “.env” file in your project root to manage your configuration. For AWS credentials, we recommend pointing to your AWS_PROFILE in this file so the application can access your credentials when interacting with AWS resources. We do not recommend storing your AWS access keys directly in this file.
For Stream API credentials, you can use a third-party library like HashiCorp Vault or AWS Secrets Manager, but security considerations are not in the scope of this post.
# Stream API credentials
STREAM_API_KEY=test/geststream/api_key
STREAM_API_SECRET=test/getstream/api_secret
# AWS credentials
AWS_PROFILE=your_aws_profile_name
AWS_REGION=us-east-1Vision Agents automatically discovers these environment variables at startup, so you don’t need to pass them explicitly to each client.
Step 3: Build your first voice agent
Create a main.py file with the following code:
import asyncio
from dotenv import load_dotenv
from vision_agents.core import Agent, User, Runner
from vision_agents.core.agents import AgentLauncher
from vision_agents.plugins import aws, getstream
load_dotenv()
async def create_agent(**kwargs) -> Agent:
agent = Agent(
edge=getstream.Edge(),
agent_user=User(name="Helpful Assistant", id="agent"),
instructions="You are a helpful voice assistant. Be concise and friendly.",
llm=aws.Realtime(
model="amazon.nova-2-sonic-v1:0",
region_name="us-east-1",
voice_id="matthew",
),
)
return agent
async def join_call(agent: Agent, call_type: str, call_id: str, **kwargs) -> None:
call = await agent.create_call(call_type, call_id)
async with agent.join(call):
await asyncio.sleep(2)
await agent.llm.simple_response(
text="Greet the user warmly and ask how you can help."
)
await agent.finish() # Run until the call ends
if __name__ == "__main__":
Runner(AgentLauncher(create_agent=create_agent, join_call=join_call)).cli()
Step 4: Run the voice agent
Run the agent:
uv run main.py runIn fewer than 30 lines of code, you have a fully functional, real-time voice agent powered by Amazon Nova Sonic, accessible from a Stream client SDK.
Understanding the Amazon Bedrock integration
Let’s take a closer look at how the aws.Realtime plugin works under the hood.
Bidirectional streaming with Amazon Nova 2 Sonic
Amazon Nova 2 Sonic uses an event-driven bidirectional streaming API. Instead of using a request-response pattern, this approach allows nearly continuous audio to flow in both directions simultaneously. The Vision Agents AWS plugin manages this complexity through a structured event sequence:
- Session initialization – A sessionStart event is sent with inference configuration (temperature, max tokens, top-p).
- Prompt setup – A promptStart event configures the audio output format (24kHz PCM), voice selection, and tool definitions.
- System instructions – System instructions are sent as a text content block with the SYSTEM role.
- Audio streaming – Microphone audio frames (~32ms each) are streamed as audioInput events.
- Response streaming – Nova Sonic streams back audioOutput events with the generated speech.
- Session teardown – promptEnd and sessionEnd events cleanly close the connection.
Each content block follows a three-part pattern: contentStart → content payload → contentEnd. This hierarchical structure allows the model to maintain proper context throughout the interaction.
Here is what the session start event looks like in the plugin:
def _create_session_start_event(self) -> Dict[str, Any]:
return {
"event": {
"sessionStart": {
"inferenceConfiguration": {
"maxTokens": 1024,
"topP": 0.9,
"temperature": 0.7,
}
},
"turnDetectionConfiguration": {
"endpointingSensitivity": "MEDIUM"
},
}
}
Adding function calling
One of the key capabilities of Amazon Nova 2 Sonic is native function calling during real-time conversations. This allows your voice agent to perform actions like querying databases, calling APIs, and triggering workflows while maintaining a natural spoken conversation.Use the @llm.register_function decorator to define functions the model can call:
import asyncio
from dotenv import load_dotenv
from typing import Dict, Any
from vision_agents.core import Agent, User, Runner
from vision_agents.core.agents import AgentLauncher
from vision_agents.plugins import aws, getstream
load_dotenv()
async def create_agent(**kwargs) -> Agent:
agent = Agent(
edge=getstream.Edge(),
agent_user=User(name="Weather Assistant", id="agent"),
instructions="""You are a helpful weather assistant. When users ask
about weather, use the get_weather function to fetch current conditions.
You can also help with simple calculations.""",
llm=aws.Realtime(
model="amazon.nova-2-sonic-v1:0",
region_name="us-east-1",
),
)
@agent.llm.register_function(
name="get_weather",
description="Get the current weather for a given city"
)
async def get_weather(location: str) -> Dict[str, Any]:
# In production, call a real weather API
return {
"city": location,
"temperature": 72,
"condition": "Sunny",
"humidity": "45%"
}
@agent.llm.register_function(
name="calculate",
description="Perform a mathematical calculation"
)
def calculate(operation: str, a: float, b: float) -> dict:
operations = {
"add": lambda x, y: x + y,
"subtract": lambda x, y: x - y,
"multiply": lambda x, y: x * y,
"divide": lambda x, y: x / y if y != 0 else None,
}
result = operations.get(operation, lambda x, y: None)(a, b)
return {"operation": operation, "a": a, "b": b, "result": result}
return agent
async def join_call(agent: Agent, call_type: str, call_id: str, **kwargs) -> None:
await agent.create_user()
call = await agent.create_call(call_type, call_id)
async with agent.join(call):
await asyncio.sleep(2)
await agent.llm.simple_response(
text="Greet the user and let them know you can check the weather."
)
await agent.finish()
if __name__ == "__main__":
Runner(AgentLauncher(create_agent=create_agent, join_call=join_call)).cli()
How function calling works with Amazon Nova 2 Sonic
When the model decides to invoke a function, the following sequence occurs:
- Nova 2 Sonic emits a toolUse event containing the function name and arguments.
- The Vision Agents plugin intercepts this event, deserializes the arguments, and runs the registered Python function.
- The result is sent back to Nova via a toolResult event, wrapped in the standard contentStart → toolResult → contentEnd pattern.
- Nova 2 Sonic incorporates the function result into its response and continues the spoken conversation naturally.
You can build complex, multi-step workflows with this approach. For example, a voice agent could look up a customer record, check inventory, and place an order, all within a single natural conversation.
Using the standard LLM with Amazon Bedrock
Beyond real-time speech-to-speech, the AWS plugin also provides a standard LLM integration via aws.LLM. This is useful for custom pipeline architectures where you want to pair an Amazon Bedrock model with separate STT and TTS providers:
from vision_agents.core import Agent, User
from vision_agents.plugins import aws, getstream, cartesia, deepgram, smart_turn
agent = Agent(
edge=getstream.Edge(),
agent_user=User(name="Custom Pipeline Agent"),
instructions="Be helpful and concise.",
llm=aws.LLM(
model="anthropic.claude-3-haiku-20240307-v1:0",
region_name="us-east-1"
),
tts=cartesia.TTS(),
stt=deepgram.STT(),
turn_detection=smart_turn.TurnDetection(
buffer_duration=2.0,
confidence_threshold=0.5
),
)
The standard LLM supports streaming responses via converse_stream(), full conversation history management, vision inputs for models like Claude, and multi-round tool calling with up to 3 rounds of function execution per request.
Text-to-speech with Amazon Polly
For custom pipeline architectures, the AWS plugin also includes an Amazon Polly TTS integration. This is useful when you’re using a non-realtime LLM (like Claude on
関連記事
今日のまとめ
AI日報で今日の重要ニュースをまとめ読み