コンテンツにスキップ

実践的な例

実践的な例

このページでは、ドラマ作成時によくあるパターンと具体的な実装例を紹介します。


例: ドラマ開始時点からの経過時間でゲートを制御

ドラマの開始時点でstates.start_timestampを設定し、Gateのトリガ条件で経過時間を計算します。

必要なコンポーネント

graph LR
    A[Entry] --> B[StateSet<br/>開始時刻記録]
    B --> C{Gate<br/>時間判定}
    C -->|30秒経過| D[次の処理...]
    C -.->|30秒未満| E[スキップ]

    style B fill:#e1f5ff
    style C fill:#fff4e1
    style D fill:#e8f5e9
    style E fill:#ffebee

設定方法

1. StateSet - 開始時刻を記録
  • モード : once
  • キー : start_timestamp
  • : lambda: time.time() if not states.get('start_timestamp') else Skip()
2. Gate - 経過時間でゲート開閉
  • トリガ : lambda: (time.time() - (states.start_timestamp or 0)) >= 30

応用例

複数の時間ゲート
graph LR
    A[Entry] --> B[StateSet<br/>開始時刻記録]
    B --> C1{Gate<br/>10秒}
    B --> C2{Gate<br/>30秒}
    B --> C3{Gate<br/>60秒}
    C1 -->|10秒経過| D1[メッセージ1]
    C2 -->|30秒経過| D2[メッセージ2]
    C3 -->|60秒経過| D3[メッセージ3]

    style B fill:#e1f5ff
    style C1 fill:#fff4e1
    style C2 fill:#fff4e1
    style C3 fill:#fff4e1

各Gateに排他的な時間条件を設定:

  • Gate1(10〜30秒) : lambda: 10 <= (time.time() - (states.start_timestamp or 0)) < 30
  • Gate2(30〜60秒) : lambda: 30 <= (time.time() - (states.start_timestamp or 0)) < 60
  • Gate3(60秒以上) : lambda: (time.time() - (states.start_timestamp or 0)) >= 60

例: 状態が切り替わったタイミングで特定のsystemプロンプトを追加

DialogAddのconditionパラメータでprev_statesを使用して、stateの変化を検出します。

必要なコンポーネント

graph LR
    A[処理] --> B[StateSet<br/>状態更新]
    B --> C{DialogAdd<br/>条件判定}
    C -->|状態変化あり| D[Systemメッセージ<br/>追加]
    C -.->|変化なし| E[スキップ]

    style B fill:#e1f5ff
    style C fill:#fff4e1
    style D fill:#e8f5e9
    style E fill:#ffebee

設定方法

1. StateSet - 状態を更新
  • モード : once
  • キー : conversation.phase
  • : values.new_phase
2. DialogAdd - 状態変化を検出してメッセージ追加
  • ロール : system
  • テキスト : {{ "フェーズが" + states.conversation.phase|string + "に変わりました" }}
  • トリガ条件 : lambda: prev_states and prev_states.get('conversation', {}).get('phase') != states.conversation.phase

さまざまな条件例

特定の値に変化したときのみメッセージ追加
# phaseが2になったときのみメッセージを追加
lambda: prev_states and prev_states.get('conversation', {}).get('phase') != 2 and states.conversation.phase == 2

テキスト:

会話フェーズが終了フェーズに移行しました

複数の状態変化を検出
# phaseまたはlevelが変化したときにメッセージを追加
lambda: prev_states and (
    prev_states.get('conversation', {}).get('phase') != states.conversation.phase or
    prev_states.get('user', {}).get('level') != states.user.level
)

例: Structured Outputで盛り上がり判定

Structured Outputを使って、会話の盛り上がり度を判定し、Stateに保存します。

graph LR
    A[DialogHistory] --> B[PublicLLM<br/>盛り上がり判定<br/>Structured Output]
    B --> C[StateSet<br/>結果を保存]

    style A fill:#e8f5e9
    style B fill:#fff4e1
    style C fill:#e1f5ff

設定方法

1. DialogHistory - 会話履歴を取得
  • role_filter : ["system", "user*", "assistant"]
  • max_history_items : 10
2. PublicLLM - 盛り上がり判定(Structured Output)
  • プロンプト :

会話の盛り上がり度を1〜5で判定してください。1が最も低い。

会話履歴:
{% for msg in values.messages %}
{{ msg.role }}: {{ msg.content }}
{% endfor %}

- 構造化出力スキーマ :

{
  "type": "object",
  "properties": {
    "excitement": {
      "type": "integer"
    }
  },
  "required": ["excitement"]
}
3. StateSet - 結果を保存
  • キー : conversation.excitement
  • : values.response.excitement

例: 対話数に応じて会話履歴の詳細度を変える

直近10対話はsystem・metadataを含めて詳細に、それ以前はシンプルにPublicLLMに渡します。Jinjaテンプレートで実現します。

graph LR
    A[Entry] --> B[DialogHistory<br/>limit=100]
    B --> C[PublicLLM]

    style B fill:#e8f5e9
    style C fill:#fff4e1

設定方法

1. DialogHistory - 会話履歴を取得
  • role_filter: ["system", "user*", "assistant"]
  • max_history_items: 100
2. PublicLLM - Jinjaで詳細度を制御
  • プロンプト :
あなたは親切なアシスタントです。

会話履歴:
{% set recent_count = 10 %}
{% set total = values.history|length %}
{% for msg in values.history %}
{% if loop.index > total - recent_count %}
{{ msg.role }}: {{ msg.text }}{% if msg.meta %} (meta: {{ msg.meta }}){% endif %}
{% else %}
{% if msg.role != "system" %}{{ msg.role }}: {{ msg.text }}
{% endif %}
{% endif %}
{% endfor %}

出力例

15件の履歴がある場合(直近10件は詳細、それ以前5件はシンプル):

あなたは親切なアシスタントです。

会話履歴:
user: こんにちは
assistant: はじめまして!
user: 今日の天気は?
assistant: 晴れです。
user: ありがとう
system: あなたは親切なアシスタントです。
user: 最近どう? (meta: {'timestamp': 1234567890})
assistant: 元気ですよ!
user: 何か面白い話ある?
assistant: 昨日公園で猫を見ました。 (meta: {'emotion': 'happy'})
...

補足

  • loop.indexで現在のループ位置を取得
  • 直近10件(total - recent_count以降)は詳細表示(meta付き、systemも含む)
  • それ以前はシンプル表示(systemを除外、metaなし)

例: クライアントから渡された会話履歴を使用

クライアント側で前回セッションの会話履歴をstates.historyにセットしてもらい、それを使って応答を生成します。

graph LR
    A[Entry] --> B[PublicLLM<br/>履歴をStateから取得]

    style B fill:#e8f5e9

クライアント側の設定

クライアントからstate.setで前回セッションの履歴をセットします:

{
  "data": {
    "history": [
      {"role": "user", "text": "こんにちは"},
      {"role": "assistant", "text": "こんにちは!何かお手伝いできますか?"}
    ]
  }
}

設定方法

1. PublicLLM - Stateから履歴を取得
  • プロンプト :
前回の会話履歴を要約してください。

{% if states.history %}
前回の会話履歴:
{% for msg in states.history %}
{{ msg.role }}: {{ msg.text }}
{% endfor %}
{% endif %}

例: 複数処理の完了を待ってからEventResponseを送信

DialogAdd、TTS3、PublicLLM(Structured Output)+StateSetの3つの処理が全て終了してからEventResponseを送信します。

graph TB
    A[Entry] --> B[DialogAdd]
    A --> C[TTS3]
    A --> D[PublicLLM<br/>Structured Output]
    D --> E[StateSet]
    B --> F[EventResponse]
    C --> F
    E --> F

    style B fill:#e1f5ff
    style C fill:#e8f5e9
    style D fill:#fff4e1
    style E fill:#e1f5ff
    style F fill:#ffe8e8

設定方法

1. EventResponse - 全処理完了後に送信

EventResponseに複数の入力を接続すると、すべての入力がis_last=Trueになるまで待機してから送信します。

  • mode : once
  • データ : lambda values: {"status": "completed"}