コンテンツにスキップ

全脳シミュレーション クエリレスポンス解析

[!NOTE] 最新の実装状況は 機能実装ステータス (Remaining Functionality) を参照してください。

実装ノート(アーティファクト): トレーニングスクリプトが出力する artifact_manifest.json と推奨CLIフラグについては docs/implementation/ARTIFACT_MANIFESTS.md を参照してください。

概要

全脳シミュレーションでクエリを実行した時のレスポンスの内容とデータフローを精査したドキュメント。

作成日: 2025年12月13日

このドキュメントの目的と使い方

  • 目的: クエリレスポンスのデータフローと生成物を把握し、ボトルネックや障害点を特定する。
  • 対象読者: API/Backend実装者、QA、運用担当。
  • まず読む順: 概要 → データフロー → ログ/出力フォーマット → 障害・遅延分析。
  • 関連リンク: 分散脳実行スクリプトは examples/run_zenoh_distributed_brain.py、PFC/Zenoh/Executive詳細は docs/implementation/PFC_ZENOH_EXECUTIVE.md。

1. レスポンスのデータフロー

1.1 クエリ送信フロー

ユーザー入力 (UI)
    ↓
フロントエンド (distributed_brain.py)
    ↓
APIエンドポイント (/api/distributed_brain/prompt)
    ↓
プロンプトファイル書き込み (/tmp/evospikenet_prompt_*.json)
    ↓
Zenoh Publish (evospikenet/api/prompt)
    ↓
各ノード (run_zenoh_distributed_brain.py)

1.2 レスポンス返却フロー

各ノード (推論処理)
    ↓
レスポンス生成
    ↓
Zenoh Publish (evospikenet/api/result)
    ↓
APIサーバー (Zenohサブスクライバー)
    ↓
結果ファイル書き込み (/tmp/evospikenet_query_result_*.json)
    ↓
フロントエンド (ポーリング)
    ↓
UI表示 (query-response-area)

2. レスポンスの構造

2.1 基本構造

{
    "response": "生成されたテキストレスポンス",
    "prompt_id": "UUID形式のプロンプトID",
    "timestamp": 1234567890.123
}

2.2 フィールド詳細

フィールド 必須 説明
response string 実際の生成テキストまたはシミュレーション結果
prompt_id string クエリを一意に識別するUUID
timestamp float レスポンス生成時刻(UNIXタイムスタンプ)

3. レスポンスの種類と内容

3.1 SpikingLM による生成 (lang-main ノード)

条件: - ノードタイプ: lang-main - モデル: SpikingEvoTextLM - トークナイザー: 利用可能

処理:

# トークナイズ
inputs = tokenizer(prompt, return_tensors="pt")
input_ids = inputs["input_ids"]

# 推論実行
generated_ids = model.generate(input_ids, max_new_tokens=20)

# デコード
response_text = tokenizer.decode(generated_ids[0], skip_special_tokens=True)

レスポンス形式:

[HH:MM:SS] SpikingLM Generated: '生成されたテキスト'

例:

{
    "response": "[14:30:45] SpikingLM Generated: 'The capital of Japan is Tokyo.'",
    "prompt_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}

3.2 シミュレートされたレスポンス (その他のノード)

条件: - SpikingLM 利用不可の場合 - 他のノードタイプ (visual, audio, motor など)

レスポンス形式:

[HH:MM:SS] Zenoh Node Processed: 'プロンプト' (Simulated Response)

例:

{
    "response": "[14:30:47] Zenoh Node Processed: 'What is AI?' (Simulated Response)",
    "prompt_id": "b2c3d4e5-f6a7-8901-bcde-f23456789012"
}

3.3 Visual ノードのレスポンス

処理:

# 視覚処理シミュレーション
time.sleep(1)
response_text = f"Visual processing completed for: '{prompt}'"

例:

{
    "response": "Visual processing completed for: 'Analyze this image'",
    "prompt_id": "c3d4e5f6-a7b8-9012-cdef-345678901234"
}

3.4 Audio ノードのレスポンス

処理:

# 音声処理シミュレーション
time.sleep(1)
response_text = f"Audio processing completed for: '{prompt}'"

例:

{
    "response": "Audio processing completed for: 'Transcribe this audio'",
    "prompt_id": "d4e5f6a7-b8c9-0123-def0-456789012345"
}

3.5 エラーレスポンス

条件: - 推論中にエラーが発生

レスポンス形式:

Error during inference: エラーメッセージ

例:

{
    "response": "Error during inference: CUDA out of memory",
    "prompt_id": "e5f6a7b8-c9d0-1234-ef01-567890123456"
}


4. APIエンドポイント

4.1 プロンプト送信

エンドポイント: POST /api/distributed_brain/prompt

リクエストボディ:

{
    "prompt": "テキストプロンプト",
    "priority": 1,
    "session_id": "セッションID",
    "image": "Base64エンコードされた画像データ (オプション)",
    "audio": "Base64エンコードされた音声データ (オプション)"
}

レスポンス:

{
    "message": "Prompt received and written to file.",
    "file": "/tmp/evospikenet_prompt_1234567890_uuid.json",
    "prompt_id": "uuid"
}

4.2 結果取得

エンドポイント: GET /api/distributed_brain/result

クエリパラメータ: - prompt_id (オプション): 特定のプロンプトの結果を取得

レスポンス (結果あり):

{
    "response": "生成されたテキスト",
    "timestamp": 1234567890.123,
    "prompt_id": "uuid"
}

レスポンス (結果なし):

{
    "response": null,
    "timestamp": null,
    "prompt_id": "uuid"
}


5. ファイルシステム操作

5.1 プロンプトファイル

場所: /tmp/evospikenet_prompt_{timestamp}_{prompt_id}.json

内容:

{
    "prompt": "テキストプロンプト",
    "priority": 1,
    "session_id": "session_id",
    "timestamp": 1234567890.123,
    "prompt_id": "uuid",
    "image_path": "/tmp/{prompt_id}_image.png",
    "audio_path": "/tmp/{prompt_id}_audio.wav"
}

TTL (Time To Live): - デフォルト: 3600秒 (1時間) - 自動クリーンアップ: バックグラウンドスレッドで実行

5.2 結果ファイル

場所: /tmp/evospikenet_query_result_{prompt_id}.json

内容:

{
    "response": "生成されたテキスト",
    "prompt_id": "uuid",
    "timestamp": 1234567890.123
}

特徴: - 読み込み後に自動削除 - TTL: 3600秒

5.3 メディアファイル

画像: - 場所: /tmp/{prompt_id}_image.png - 形式: Base64デコード後のバイナリ

音声: - 場所: /tmp/{prompt_id}_audio.wav - 形式: Base64デコード後のバイナリ


6. Zenoh通信

6.1 プロンプト配信

トピック: evospikenet/api/prompt

ペイロード:

{
    "prompt": "テキストプロンプト",
    "priority": 1,
    "session_id": "session_id",
    "timestamp": 1234567890.123,
    "prompt_id": "uuid",
    "image_path": "/tmp/{prompt_id}_image.png",
    "audio_path": "/tmp/{prompt_id}_audio.wav"
}

6.2 結果配信

トピック: evospikenet/api/result

ペイロード:

{
    "response": "生成されたテキスト",
    "prompt_id": "uuid"
}

6.3 タスク完了通知

トピック: task/completion

ペイロード:

{
    "node_id": "pfc-0",
    "prompt_id": "uuid"
}


7. フロントエンドでのレスポンス処理

7.1 クエリ送信 (execute_query コールバック)

場所: distributed_brain.py

処理フロー:

# ペイロード作成
payload = {
    "prompt": query,
    "session_id": sim_state.get('session_id'),
    "priority": int(priority)
}

# メディアファイル追加
if image_contents:
    payload['image'] = content_string
if audio_contents:
    payload['audio'] = content_string

# API送信
response = requests.post(f"{api_base_url}/api/distributed_brain/prompt", json=payload)
response_data = response.json()
prompt_id = response_data.get("prompt_id")

# プロンプトIDを保存
return "", prompt_id  # 入力をクリアし、IDを保存

7.2 レスポンス表示 (update_visualizations コールバック)

場所: distributed_brain.py

ポーリングロジック:

# 現在のプロンプトIDがある場合
if current_prompt_id:
    # 結果取得を試行
    result_response = requests.get(
        f"{api_base_url}/api/distributed_brain/result",
        params={"prompt_id": current_prompt_id}
    )

    if result_response.status_code == 200:
        result_data = result_response.json()
        response_text = result_data.get('response')

        if response_text:  # 有効なレスポンスがある場合
            query_response_out = response_text
            new_prompt_id = None  # プロンプトIDをクリア

表示コンポーネント:

dcc.Textarea(
    id='query-response-area',
    style={'width': '100%', 'height': 150},
    readOnly=True,
    placeholder="The simulation's response will appear here..."
)


8. SDK での使用例

8.1 基本的な使用

場所: run_simulation_query.py

```python
from evospikenet.sdk import EvoSpikeNetAPIClient
# Example: use EvoSpikeNetAPIClient as implemented in evospikenet.sdk

クライアント初期化

client = EvoSpikeNetAPIClient()

プロンプト送信

prompt_text = "What is the capital of Japan?" submission_response = client.submit_prompt(prompt=prompt_text)

結果をポーリング

result = client.poll_for_result(timeout=120, interval=5)

結果表示

if result and result.get("response"): print(f"Response: {result['response']}") print(f"Timestamp: {result['timestamp']}")

### 8.2 マルチモーダル使用

**場所:** `run_multimodal_simulation_query.py`

```python
# マルチモーダルプロンプト送信
submission_response = client.submit_prompt(
    prompt="Describe this image and audio",
    image_path=DUMMY_IMAGE_PATH,
    audio_path=DUMMY_AUDIO_PATH,
    priority=1
)

# 結果をポーリング
result = client.poll_for_result(timeout=120, interval=5)


9. レスポンスのタイムライン

典型的な実行シーケンス

T+0秒:   ユーザーがクエリを入力し "Execute Query" をクリック
T+0.1秒: フロントエンドがAPIにPOSTリクエスト送信
T+0.2秒: APIがプロンプトファイルを作成し、Zenohにパブリッシュ
T+0.3秒: 各ノードがZenohからプロンプトを受信
T+0.4秒: Lang-mainノードが推論スレッドを起動
T+2秒:   推論処理完了
T+2.1秒: Lang-mainノードが結果をZenohにパブリッシュ
T+2.2秒: APIサーバーが結果を受信し、ファイルに書き込み
T+2-7秒: フロントエンドがポーリング (5秒間隔)
T+7秒:   フロントエンドが結果を取得し、UIに表示

パフォーマンス要因

要因 影響時間 備考
ネットワーク遅延 0.1-0.5秒 APIリクエスト往復
Zenoh通信 0.01-0.1秒 非常に高速
モデル推論 1-10秒 モデルサイズとGPU性能に依存
ポーリング間隔 0-5秒 デフォルト5秒間隔

10. デバッグとトラブルシューティング

10.1 レスポンスが返ってこない

確認ポイント:

  1. シミュレーションが実行中か確認

    status = client.get_simulation_status()
    print(json.dumps(status, indent=2))
    

  2. プロンプトファイルの存在確認

    ls -la /tmp/evospikenet_prompt_*.json
    

  3. 結果ファイルの確認

    ls -la /tmp/evospikenet_query_result_*.json
    

  4. Zenoh接続の確認

  5. APIログで "✅ Zenoh session established in API" を確認
  6. ノードログで Zenoh購読メッセージを確認

  7. ノードログの確認

    # Docker環境の場合
    docker-compose exec frontend cat /tmp/sim_rank_4.log  # Lang-main
    

10.2 レスポンス内容の検証

期待される内容: - ✅ タイムスタンプを含む - ✅ プロンプトIDが一致 - ✅ レスポンステキストが null でない

問題のある例:

{
    "response": null,
    "timestamp": null,
    "prompt_id": "uuid"
}

原因: - ノードが推論を完了していない - Zenoh通信エラー - モデルロードエラー

10.3 一般的なエラーパターン

エラー 1: "CUDA out of memory"

レスポンス:

{
    "response": "Error during inference: CUDA out of memory"
}

対処法: - バッチサイズを減らす - モデルのパラメータサイズを縮小 - GPUメモリを増やす

エラー 2: "Could not write result file"

ログ:

WARNING: Could not write result file (expected in remote mode): [Errno 2] No such file or directory

原因: - リモートノードで /tmp ディレクトリへのアクセス権限がない

対処法: - Zenoh通信のみに依存(ファイルは不要) - 警告は無視可能(リモートモードでは正常)

エラー 3: タイムアウト

症状:

Polling timed out. No result received.

対処法: - timeout値を増やす: poll_for_result(timeout=300) - モデルの推論時間を確認 - ノードが正常に動作しているか確認


11. レスポンスの拡張性

11.1 現在サポートされている情報

  • ✅ テキストレスポンス
  • ✅ プロンプトID
  • ✅ タイムスタンプ
  • ✅ ノードID(タスク完了通知内)

11.2 将来の拡張候補

詳細なメタデータ

{
    "response": "生成されたテキスト",
    "prompt_id": "uuid",
    "timestamp": 1234567890.123,
    "metadata": {
        "node_id": "lang-main-0",
        "model_type": "SpikingEvoTextLM",
        "inference_time_ms": 1234,
        "tokens_generated": 20,
        "energy_consumed": 0.5,
        "spike_count": 15000
    }
}

スパイクデータの添付

{
    "response": "生成されたテキスト",
    "prompt_id": "uuid",
    "spike_data": {
        "total_spikes": 15000,
        "spike_rate": 75.5,
        "layer_stats": {
            "layer_0": 5000,
            "layer_1": 6000,
            "layer_2": 4000
        }
    }
}

マルチノード協調結果

{
    "response": "統合された最終レスポンス",
    "prompt_id": "uuid",
    "node_responses": [
        {
            "node_id": "visual-0",
            "response": "Visual: 画像に猫が写っています"
        },
        {
            "node_id": "lang-main-0",
            "response": "Lang: これは猫の画像です"
        },
        {
            "node_id": "pfc-0",
            "response": "PFC: 統合された最終レスポンス"
        }
    ]
}

12. ベストプラクティス

12.1 効率的なポーリング

# ✅ 推奨: 適切なタイムアウトと間隔
result = client.poll_for_result(timeout=120, interval=5)

# ❌ 非推奨: 短すぎる間隔
result = client.poll_for_result(timeout=120, interval=1)  # APIに負荷

12.2 エラーハンドリング

try:
    result = client.poll_for_result(timeout=120, interval=5)

    if result and result.get("response"):
        # 成功
        print(f"Response: {result['response']}")
    else:
        # タイムアウトまたは結果なし
        print("No result received within timeout")

        # デバッグ情報取得
        status = client.get_simulation_status()
        print("Simulation status:", status)

except RequestException as e:
    # ネットワークエラー
    print(f"Network error: {e}")

12.3 プロンプトIDの管理

# ✅ 推奨: プロンプトIDを保存して追跡
submission = client.submit_prompt(prompt="...")
prompt_id = submission.get("prompt_id")

# 後で特定の結果を取得
result = client.get_simulation_result()  # 最新結果

12.4 マルチモーダル入力

# ✅ 推奨: すべての入力を検証
if os.path.exists(image_path) and os.path.exists(audio_path):
    response = client.submit_prompt(
        prompt="Describe this",
        image_path=image_path,
        audio_path=audio_path
    )
else:
    print("Error: Media files not found")

13. 関連ファイル

ファイル 役割
api.py APIエンドポイント定義、Zenohサブスクライバー
sdk.py Python SDK、ポーリングロジック
distributed_brain.py UI、クエリ送信、レスポンス表示
run_zenoh_distributed_brain.py ノード実装、推論処理、結果パブリッシュ
run_simulation_query.py SDK使用例
run_multimodal_simulation_query.py マルチモーダル使用例

14. まとめ

レスポンスの特徴

  1. 非同期処理: クエリ送信と結果取得は分離
  2. ポーリングベース: フロントエンドが定期的に結果を確認
  3. Zenoh通信: 高速で信頼性の高いメッセージング
  4. ファイルベース: ローカル実行とリモート実行の両方をサポート
  5. UUID追跡: 各クエリを一意に識別

設計上の利点

  • ✅ スケーラビリティ: 複数ノードでの並列処理
  • ✅ 柔軟性: ローカル/リモート両対応
  • ✅ デバッグ性: ファイルベースで中間状態を確認可能
  • ✅ 耐障害性: Zenoh通信の冗長性

改善の余地

  • ⚠️ ポーリング効率: WebSocketやServer-Sent Eventsの検討
  • ⚠️ メタデータ不足: 推論時間、エネルギー消費などの情報
  • ⚠️ エラー詳細: より詳細なエラー情報の提供

参考リンク