Stream Vision Agents と Amazon Nova 2 Sonic を用いたリアルタイム音声エージェントの実装
本文の状態
日本語全文を表示中
詳細モードで約18分の本文を読めます。
同じ出来事の情報源
この情報源を基点に整理
AWS Machine Learning Blog
ストリームとアマゾンは、自然で応答性の高い生産グレードの音声エージェントを構築する技術について解説し、音声モデルの調整や低遅延オーディオストリーミング管理の方法を示した。
Source Article
元記事を日本語で読む
本文に関係しない購読案内、埋め込み通知、サイト内プロモーションは除いています。
*この投稿は、*Stream の技術マーケティングリーダーである Neevash Ramdial 氏との共著です。
自然で応答性の高い本番環境向けの音声エージェントを構築するのは、複雑なエンジニアリングの課題です。音声入力から音声出力までのモデルをオーケストレーションし、低遅延のオーディオストリーミングを管理し、接続ライフサイクルを処理する必要があります。また、Web、モバイル、デスクトップアプリケーション全体で一貫した体験を提供することも求められます。
この投稿では、Stream の Vision Agents オープンソースフレームワークと Amazon Bedrock および Amazon Nova 2 Sonic を組み合わせることで、数分で本番環境に導入可能なリアルタイム音声エージェントを構築する方法を学びます。統合の内部仕組みについて解説し、コード例を通じて具体的な実装を確認するとともに、関数呼び出し(function calling)、自動再接続、多言語音声サポートといった高度な機能についても探求します。
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 のエッジネットワークは、エンドユーザー端末と Vision Agent ワーカープロセスの間でメディアブローカーとして機能します。ユーザーが発話すると、音声はキャプチャされ、暗号化された上で UDP 経由の RTP として最寄りの Stream SFU(Selective Forwarding Unit)へ送信されます。SFU は WebRTC 接続を終了し、NAT トリバーサルと帯域幅推定を処理した上で、音声トラックを Vision Agent ワーカーへ転送します。これは、エージェントがもう一人の通話参加者であるかのように扱われることを意味します。つまり、エージェントは通話モデルに自然に統合され、人間側の参加者が使用するのと同じインフラストラクチャを通じて音声をやり取りするピアとして機能します。
オーディオデータはシステム内で双方向に流れます。ユーザーからの音声入力はいちばん最初に Vision Agent ワーカーによって生 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 統合をブリッジする Vision Agent ランタイム(ワーカープロセス)。
エンドツーエンドのメディアフロー
- ユーザーは Web またはモバイルから参加します。
アプリは Stream のオーディオクライアント SDK を埋め込み、マイク(およびオプションでカメラ)へのアクセスを要求し、AI が参加するように構成された通話タイプに参加します。
- メディアは、予測可能な低遅延とヘッド・オブ・ラインの排除を実現するために、UDP 上の RTP (Real-time Transport Protocol) で送信されます。2. リージョン別 SFU 終端
- リージョン別 SFU 終端
最寄りのリージョンにある Stream の SFU (Selective Forwarding Unit) ノードが、ユーザーの WebRTC 接続を終端し、帯域幅推定、シミュルキャスト、NAT トリバーサル (Network Address Translation traversal) を処理します。
- SFU は、関連するオーディオトラックを、あたかも別の参加者であるかのように Vision Agent ワーカーに転送します。
- Vision Agent ワーカー
専用の Vision Agent ワーカープロセスが、そのセッションの PeerConnection (ピア接続) 状態を保持します。
- このワーカーはオーディオを生の PCM (Pulse Code Modulation) にデコードし、PCM フレームを Amazon Bedrock サービスにストリーミングして、顧客の AWS アカウント内でリアルタイムセッションとして Amazon Nova 2 Sonic に転送します。
- Amazon Bedrock を介した Vision エージェントとの Amazon Nova 2 Sonic の統合
Amazon Nova 2 Sonic は音声の境界を検出し、音声認識、推論、音声合成 (TTS: Text-to-Speech) を行う音声対音声モデルを実行します。必要に応じて顧客システム(RDS, APIs, ナレッジベース)へのツール呼び出しも可能です。
- バージ・イン (Barge-in: 会話中の割り込み) に柔軟に対応し、完全な会話コンテキストを維持することで、会話が自然で一貫性のあるものとなります。
- ユーザーへのストリーミング応答の返送
Amazon Nova Sonic が応答オーディオフレームを生成する際、Vision Agent ワーカーは以下の処理を行います:
フレームをスライスし、ギャップやドリフトを防ぐために単調に増加するタイムスタンプ付きで RTP にラップします。
- RTP パケットを同じ WebRTC セッション経由で SFU を通して送信します。ブラウザの WebRTC スack がデコードして再生し、500 ミリ秒未満の遅延を実現します。
- バージ・イン、トランスクリプト、およびサイドデータ
ブラウザ内のエコーキャンセレーションにより、エージェント自身の出力が VAD (Voice Activity Detection: 音声活動検出) を再トリガーするのを防ぎます。
- ユーザーが割り込むと、新しい発話が 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 ロールを持つテキストコンテンツブロックとして送信されます。
- 音声ストリーミング – マイクロフォンからの音声フレーム(各約32ミリ秒)が、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="Given a city, get the current weather"
)
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()
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デイリーブリーフで今日の重要ニュースをまとめ読み