システムアーキテクチャ設計詳解
🏗️ アーキテクチャの概要
ASR-LLM-TTS 音声対話アシスタントのバックエンドは、イベント駆動型の非同期アーキテクチャを採用しています。WebSocket でリアルタイム双方向通信を実現し、ストリーミングデータ処理と並行タスク実行に対応しています。
📐 設計原則
1. 単一責任の原則
各モジュールは特定の機能領域に専念します:
server.py:WebSocket 接続の管理とメッセージのルーティングturn_manager.py:対話フローの調整llm/client.py:LLM API との通信tts/client.py:TTS サービスとの通信asr/asr_service.py:音声認識の処理
2. 非同期優先
- すべての I/O 処理で
async/awaitを使用 - ネットワークリクエスト、ファイル操作、音声処理はすべてノンブロッキング
asyncioのイベントループで並行タスクを管理
3. ストリーミング処理
- LLM の応答をストリーミングで返し、最初の文字が表示されるまでの遅延を短縮
- TTS の双方向ストリーミング合成で、生成しながら再生
- 音声のストリーミング再生で、リアルタイムのバッファ管理に対応
4. フォールトトレラント設計
- 多層的なエラー処理と回復の仕組み
- コンポーネントの障害が独立しており、サービス全体に影響しない
- 自動リトライと縮退運転の戦略
🔄 主要コンポーネントのアーキテクチャ
WebSocket サーバー(server.py)
# 架构特点
- FastAPI异步Web框架
- 单一WebSocket端点 /ws/chat
- 消息类型路由器
- 组件生命周期管理
- 全局状态维护
主な役割:
- 接続管理:アクティブな WebSocket 接続の一覧を維持
- メッセージのルーティング:メッセージタイプに応じて対応するハンドラに振り分け
- コンポーネントの初期化:起動時にすべてのサービスコンポーネントを初期化
- リソースのクリーンアップ:サービス終了時にリソースを安全にクリーンアップ
メッセージフロー:
Client WebSocket Message → server.py → Message Router → turn_manager.py
↑ ↓
Client ← WebSocket Response ← Callback Function ← Component Response
対話マネージャー(app/turn_manager.py)
# 架构特点
- 单轮对话状态机
- 多轮工具调用循环 (最多5轮)
- 并发任务协调器
- 流式数据管道
主な処理の流れ:
- ユーザー入力の受信 → メッセージ履歴の構築
- LLM の呼び出し → 応答のストリーミング処理
- ツール呼び出しの検出 → Function Calling の実行
- ツール結果の処理 → LLM に返して対話を継続
- TTS の起動 → 音声合成を並行して実行
- 状態の同期 → フロントエンドの状態をリアルタイムに更新
並行処理の制御:
# 三路并发处理
async def handle_turn():
# 任务1: LLM流式输出
llm_task = asyncio.create_task(stream_llm_response())
# 任务2: TTS合成与播放
tts_task = asyncio.create_task(stream_tts_and_play())
# 任务3: 工具调用处理
tool_task = asyncio.create_task(execute_function_calls())
# 协调任务执行
await asyncio.gather(llm_task, tts_task, tool_task)
LLM クライアント(llm/client.py)
# 架构特点
- HTTP/2连接池复用
- 流式响应处理器
- 错误重试策略
- Function Calling解析
ストリーミング処理の仕組み:
async def stream_chat(self, messages):
async with httpx.AsyncClient() as client:
async with client.stream("POST", self.api_url, json=payload) as response:
async for line in response.aiter_lines():
if line.startswith("data: "):
chunk = json.loads(line[6:])
yield self._process_chunk(chunk)
エラー処理の階層:
- HTTP 層のエラー:ステータスコード、接続タイムアウト
- API 層のエラー:ビジネスロジックのエラー、レート制限
- データ層のエラー:JSON の解析、形式の検証
- アプリケーション層のエラー:Function Calling の解析
TTS クライアント(tts/client.py)
# 架构特点
- WebSocket双向流式通信
- 会话状态管理
- 音频数据流处理
- 连接重试机制
双方向ストリーミングのアーキテクチャ:
Text Queue → TTS Client → WebSocket → Volcengine TTS
↑ ↓
TTS Player ← Audio Stream ← WebSocket Response
主要な技術の実装:
async def synthesize_stream_bidi(self, text_queue):
# 发送任务: 从队列读取文本发送
send_task = asyncio.create_task(self._send_text_stream(text_queue))
# 接收任务: 监听音频数据流
async for audio_chunk in self._receive_audio_stream():
yield audio_chunk # 实时返回音频数据
ASR サービス(asr/asr_service.py)
# 架构特点
- 多进程隔离架构
- VAD端点检测集成
- 实时音频流处理
- 进程间队列通信
マルチプロセスアーキテクチャの設計:
Main Process ASR Process
│ │
├─ WebSocket Server ├─ Audio Capture
├─ Turn Manager ├─ VAD Detection
├─ TTS Player ├─ ASR Recognition
│ │
└─ Queue Consumer ←──Queue──← └─ Result Publisher
VAD による発話区間検出の流れ:
- 音声の取り込み → マイクからのリアルタイムデータストリーム
- VAD 検出 → silero-vad モデルで音声区間を判定
- 音声の分割 → 無音区間に基づいて音声を区切る
- ASR 認識 → sherpa-onnx で音声区間を処理
- 結果の発行 → キューを介して認識結果を送信
🌐 通信プロトコルの設計
WebSocket メッセージプロトコル
メッセージ形式:
interface WebSocketMessage {
type: string; // 消息类型标识
payload: { // 消息载荷
[key: string]: any;
};
timestamp?: number; // 可选时间戳
}
メッセージタイプの分類:
| 分類 | メッセージタイプ | 方向 | 説明 |
|---|---|---|---|
| 制御 | USER_TEXT_INPUT | C→S | ユーザーのテキスト入力 |
| INTERRUPT_TURN | C→S | 現在の対話を中断 | |
| TOGGLE_ASR_LISTENING | C→S | ASR の聞き取りを切り替え | |
| 状態 | SYSTEM_STATUS | S→C | システム状態の更新 |
| TTS_STATUS | S→C | TTS の再生状態 | |
| データ | LLM_CHUNK | S→C | LLM のストリーミング応答チャンク |
| LLM_FINAL_RESPONSE | S→C | LLM の完全な応答 | |
| ASR_FINAL_RESULT | S→C | ASR の認識結果 | |
| ツール | TOOL_CALL_START | S→C | ツール呼び出しの開始 |
| TOOL_CALL_RESULT | S→C | ツール呼び出しの結果 | |
| セッション | TURN_ENDED | S→C | 対話ターンの終了 |
| TURN_INTERRUPTED | S→C | 対話の中断 |
ストリーミングデータパイプライン
User Input → WebSocket → Turn Manager
↓
LLM API ← HTTP Stream ← LLM Client
↓ ↓
LLM Chunks → WebSocket → Frontend
↓
Text Queue → TTS Client → Audio Stream
↓
Audio Player → sounddevice → Hardware
🔧 Function Calling のアーキテクチャ
ツール登録の仕組み
class FunctionRegistry:
_registry: Dict[str, Dict[str, Any]] = {}
@classmethod
def register_function(cls, name: str, description: str = ""):
def decorator(func: Callable):
cls._registry[name] = {
'func': func,
'description': description,
'is_async': inspect.iscoroutinefunction(func)
}
return func
return decorator
MCP 統合のアーキテクチャ
Local Function Registry ←─┐
│
├─ MCPClient (统一客户端)
│ │
│ ├─ MCPConnection 1 → vision-arm-control
│ ├─ MCPConnection 2 → face-tracker
│ └─ MCPConnection N → amap-maps
│
Enhanced Function Call ←─┘
ツール呼び出しの流れ:
- LLM がツール呼び出しを生成 → Function Calling 形式
- MCPClient がルーティングを判断 → ローカルツールか MCP ツールか
- ツール関数の実行 → 同期/非同期で実行
- 結果の整形 → 統一された戻り値形式
- LLM に返して継続 → 複数ターンのツール呼び出しに対応
📊 パフォーマンス最適化の戦略
1. コネクションプールの管理
- HTTP クライアントのコネクションプールを再利用
- WebSocket 接続をアクティブに維持
- データベースのコネクションプール(必要な場合)
2. メモリの最適化
- ストリーミング処理で大きなオブジェクトを回避
- 音声バッファを速やかに解放
- LRU キャッシュでよく使うデータを保持
3. 並行処理の制御
- 同時対話数の上限を設定
- ツール呼び出しのタイムアウト制御
- 非同期タスクの優先度スケジューリング
4. キャッシュ戦略
- TTS 音声断片のキャッシュ
- ASR モデルのホットロード
- 設定ファイルのメモリキャッシュ
🛡️ セキュリティ上の考慮事項
1. 入力の検証
- WebSocket メッセージ形式の検証
- Function Calling パラメータの検証
- ファイルパスの安全性チェック
2. リソースの制限
- 音声ファイルサイズの制限
- 対話ターン数の制限
- メモリ使用状況の監視
3. エラーの隔離
- コンポーネントの異常が他のモジュールに影響しない
- 悪意のある入力でシステムがクラッシュしない
- 機密情報をログに記録しない
🔮 拡張性を考慮した設計
1. プラグイン化アーキテクチャ
- Function Calling ツールのプラグイン化
- 音声コーデックのプラグイン化
- LLM プロバイダーの抽象化層
- MCP サーバーの動的な接続 - 設定ファイルで管理
2. 設定駆動
- 実行時パラメータを設定可能
- 複数環境の設定に対応
- 動的な設定のホットアップデート
3. マイクロサービス化への備え
- モジュール間の疎結合設計
- 標準化されたインターフェース定義
- 分散デプロイへの対応
このアーキテクチャ設計により、システムの高パフォーマンス、高可用性、拡張のしやすさが確保され、音声対話アシスタントの確かな技術基盤となっています。
ドキュメント