mcpField
B
bolna-graph-agents

bolna-graph-agents

github.com/bolna-aiエージェントワークフロー368 回インストール3 日前に更新
リポジトリ

bolna-graph-agents について

bolna-graph-agents は、ノードとエッジで Bolna の多段階音声会話を構成し、決定的なルールと LLM によるルーティングを組み合わせるスキルです。段階、分岐、外部イベント、コンプライアンス確認を含む通話フローに適しています。

主な機能

  1. 01ノードとエッジによる会話フローの構成
  2. 02式、イベント、LLM によるルーティング
  3. 03静的ノードの音声を事前生成
  4. 04ノード単位の検索設定
  5. 05イベント注入による通話中の遷移

活用シーン

  1. 01予約受付など段階的な通話の構築
  2. 02営業時間や再試行回数による分岐
  3. 03決済完了などのバックエンドイベントへの応答
  4. 04コンプライアンス確認を通話フローに組み込む

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/bolna-ai/skills --skill bolna-graph-agents

インストール後、Claude Code で/bolna-graph-agentsを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

assets/
full-example.json
references/
debugging.md
edges-and-routing.md
event-injection.md
static-and-silence.md
scripts/
create_graph_agent.py
inject_event.py

詳細

Bolna Graph Agents

ノードとエッジからなる有向グラフとして、構造化された複数ステップの音声会話を構築します。各ノードには1つの役割と1組の遷移先があります。必要に応じて(式エッジやイベントで)ルーティングを決定論的に行い、柔軟性が求められる場面ではLLM主導で行います。

グラフエージェントを使う場面

グラフエージェントを使うsimple_llm_agent を使う
目的の異なる明確な段階がある場合(挨拶 → 適格性の確認 → 情報収集 → 確認 → 終了)FAQへの回答のような単一の目的
決定論的な分岐がある場合(営業時間、再試行回数、言語)あらゆる話題が出てくる可能性のある自由なチャット
外部イベントが会話を進行させる場合(支払い確認、リンクのクリック)音声のみで進行するフロー
省略できないコンプライアンス上のチェックポイントがある場合トーンや人格の違いのみ
静的ノードによってレイテンシーとLLMコストを削減できる大量処理のフロー低頻度のプロトタイプ

通話の流れをホワイトボード上のフローチャートで説明できるなら、グラフエージェントが適しています。「1つのペルソナで、さまざまな話題に対応する」場合は、プロンプトエージェントを使い続けてください。

1分でわかる基本概念

  • ノード — 1つの会話ステップです。独自のプロンプトを持ち、"llm" または "static" にできます。
  • エッジ — 遷移を表します。LLMによるルーティング、式ベース、無条件、またはイベント駆動にできます。
  • ルーティングLLM — ユーザーの各ターンで、どのLLMエッジを選ぶかを判断する2つ目のLLMです。デフォルトは gpt-4.1-mini です。
  • 決定論的な処理を優先 — ルーティングLLMの実行前に、式、無条件、イベントの各エッジを確認します。いずれかに一致すると、ルーティングLLMは実行されません(レイテンシーゼロ、コストゼロ)。
  • 静的ノード — エージェントの保存時にメッセージ音声が事前にレンダリングされ、キャッシュから配信されます(LLMの往復処理が約800ミリ秒であるのに対し約50ミリ秒、コストゼロ)。
  • 無音時の繰り返し — repeat_after_silence_seconds によりノードが自動再生され、_silence_repeats が増加します。そのため、式エッジで段階的に対応できます。
  • イベントの注入 — POST /v1/call/{run_id}/events により、実行中の通話に名前付きイベントを送信します。一致するイベントエッジがグラフを遷移させ、発話を開始します。
  • ノード単位のRAG — ノードの rag_config は、会話がそのノードにある場合にのみベクトルストアから情報を取得します。

設定の場所

agent_config
  └── tasks[]
        └── tools_config
              └── llm_agent          ← all graph fields go here
                    ├── agent_type: "graph_agent"
                    ├── agent_information
                    ├── routing_instructions
                    ├── current_node_id
                    └── nodes[]
トップレベルの llm_agent フィールド
フィールド説明
agent_type"graph_agent" にする必要があります。
agent_informationすべてのノードの先頭に追加されるグローバルシステムプロンプトです。ペルソナ、言語ルール、厳守すべきガードレールを指定します。すべてのLLM呼び出しで送信されるため、簡潔にしてください。
routing_instructionsルーティングLLM用のプロンプトです。context_data の {variable} 置換に対応しています(存在しないキーは NULL として展開されます)。
current_node_id開始ノードです。
nodesノードオブジェクトの配列です。
model応答用LLMです。デフォルトは gpt-4.1-mini です。
routing_modelルーティング用LLMです。デフォルトは gpt-4.1-mini です。
routing_max_tokensルーティングトークンの上限です。デフォルトは250(GPT-5以外)、150(GPT-5)です。
routing_reasoning_effortGPT-5のみ:minimal / low / medium / high。
ノードのフィールド
フィールド型備考
idstringエッジと current_node_id から参照されます。
promptstring"llm" ノードで必須です。このノードで応答用LLMが行うことを指定します。
node_type"llm"(デフォルト)または "static"static = キャッシュ済み音声、約50ミリ秒、コストゼロ。
static_messagestringnode_type == "static" の場合に必須です。
repeat_after_silence_secondsnumberユーザーがN秒間無音の場合、自動的に再生します。どちらのノードタイプでも動作します。
edgesarray遷移可能な接続先です。
examplesobject言語ごとの表現例です。例:{ "en": [...], "hi": [...] }。
function_callstringこのノードに入る際、応答用LLMの tool_choice をこのツールに強制します。転送ノードで使用します。
rag_configobjectノード単位のナレッジベースです。詳しくは以下を参照してください。
エッジフィールド
フィールド説明
to_node_id必須です。
condition人が読める説明です。LLM エッジでは、ルーティング LLM のツール説明として使用されます。
condition_type"llm"(デフォルト)、"expression"、"unconditional"、"event"。
expressionexpression エッジで必須です。references/edges-and-routing.md を参照してください。
event_nameevent エッジで必須です。references/event-injection.md を参照してください。
parametersユーザー入力から遷移時に抽出する {name: type} です。context_data にマージされます。
priority数値が小さいものから実行されます。デフォルトは、決定的エッジが 0、LLM エッジが 100 です。
function_name、function_description自動生成されるルーティングツールの名前と説明を上書きします。

ユーザーの各ターンでのルーティング順序

  1. 決定的エッジを先に処理します(expression、unconditional、event)。priority 順に評価され、最初に一致したものが選択されます。処理はサブミリ秒で完了します。
  2. LLM エッジ — ルーティング LLM が、ユーザーの返答に対して condition 文字列を評価します。最適なものを選ぶか、stay_on_current_node を返します。
  3. 一致なし — エージェントは現在のノードにとどまり、自然に再度質問します。

決定的なルールに一致した場合、ルーティング LLM は実行されません。営業時間、再試行回数、言語検出など、データに基づく処理には積極的に expression エッジを使用してください。無料で即座に実行されます。

例:予約受付(5 ノード)

{
  "agent_type": "graph_agent",
  "agent_information": "You are Tara, an appointment booking assistant for Acme Dental. Speak warmly and concisely. Never quote prices.",
  "routing_instructions": "Pick the edge whose condition best matches the customer's reply. If none match, stay on the current node.",
  "current_node_id": "welcome",
  "model": "gpt-4.1-mini",
  "routing_model": "gpt-4.1-mini",
  "nodes": [
    {
      "id": "welcome",
      "node_type": "static",
      "static_message": "Hi! This is Tara from Acme Dental. Are you calling to book a new appointment or reschedule an existing one?",
      "repeat_after_silence_seconds": 8,
      "edges": [
        { "to_node_id": "collect_slot", "condition": "Customer wants to book a new appointment" },
        { "to_node_id": "lookup_existing", "condition": "Customer wants to reschedule" },
        {
          "to_node_id": "goodbye",
          "condition": "User silent 3 times",
          "condition_type": "expression",
          "expression": { "conditions": [{ "variable": "_silence_repeats", "operator": "gte", "value": 3 }] }
        }
      ]
    },
    {
      "id": "collect_slot",
      "prompt": "Ask for the customer's preferred day and time. Confirm timezone is {recipient_data.timezone}. Once you have day + time, transition.",
      "repeat_after_silence_seconds": 10,
      "edges": [
        {
          "to_node_id": "confirm",
          "condition": "Customer provided day and time",
          "parameters": { "appointment_day": "string", "appointment_time": "string" }
        },
        {
          "to_node_id": "after_hours",
          "condition_type": "expression",
          "condition": "Outside booking window",
          "priority": 0,
          "expression": {
            "logic": "or",
            "conditions": [
              { "variable": "recipient_data.current_hour", "operator": "lt", "value": 9 },
              { "variable": "recipient_data.current_hour", "operator": "gte", "value": 19 }
            ]
          }
        }
      ]
    },
    {
      "id": "confirm",
      "prompt": "Confirm '{appointment_day} at {appointment_time}' with the customer. If they agree, transition to booked. If they want to change, transition back to collect_slot.",
      "edges": [
        { "to_node_id": "booked", "condition": "Customer confirms the slot" },
        { "to_node_id": "collect_slot", "condition": "Customer wants to change the slot" }
      ]
    },
    {
      "id": "booked",
      "node_type": "static",
      "static_message": "All set. You'll get a confirmation SMS shortly. Thanks for choosing Acme Dental!",
      "edges": [{ "to_node_id": "goodbye", "condition_type": "unconditional" }]
    },
    {
      "id": "after_hours",
      "node_type": "static",
      "static_message": "Our booking team is offline right now. I'll have them call you back during business hours. Have a great day!",
      "edges": []
    },
    {
      "id": "goodbye",
      "node_type": "static",
      "static_message": "Thanks for calling Acme Dental. Goodbye!",
      "edges": []
    }
  ]
}

この方法が有効な理由:

  • welcome は静的なため、最初の言葉が 50ms で再生されます。
  • collect_slot は parameters を使用し、1 回の LLM 呼び出しで両方のフィールドを抽出します。
  • after_hours は expression エッジです。ユーザーが実際には有効な時刻を伝えていても、ルーティング LLM より先に実行されます。
  • _silence_repeats は、無音のラウンドが 3 回続くと goodbye にエスカレーションします。LLM コストはかかりません。
  • booked と goodbye は静的なため、終了経路では LLM を使用しません。

支払いイベントと通話転送を含む、より高度な例については assets/full-example.json を参照してください。

イベント駆動フローを 30 秒で設定する

{
  "id": "awaiting_payment",
  "prompt": "Reassure the user while payment processes. Amount: {currency} {amount}.",
  "edges": [
    { "to_node_id": "confirmation", "condition_type": "event", "event_name": "payment_completed" },
    { "to_node_id": "payment_failed", "condition_type": "event", "event_name": "payment_failed" }
  ]
}

支払いゲートウェイから応答があったときに、バックエンドからイベントを発火します。

curl -X POST https://api.bolna.ai/v1/call/$RUN_ID/events \
  -H "Authorization: Bearer $BOLNA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "event": "payment_completed", "properties": { "ref": "TXN-98765" } }'

イベントの properties は context_data にマージされます。下流の任意のノードのプロンプトで {ref} 置換として、また expression エッジでは変数として使用できるようになります。run_id は POST /call の応答または受信ウェブフックから取得します。

イベントのタイミングに関する詳細(発話中、再生中、イベントの重複)については、references/event-injection.md を参照してください。

組み込み変数

以下の変数は自動的に設定されます。expression エッジを含む、{variable} 置換に対応する場所であればどこでも参照できます。

変数説明
recipient_data.current_hour0〜23。通話に timezone が指定されている場合にのみ設定されます。
recipient_data.current_weekday小文字です(例:"wednesday")。
recipient_data.current_day / _month / _year / _minute数値の各要素です。
recipient_data.timezonetz データベース名です。
recipient_data.user_numberE.164 形式の電話番号です。
detected_languageトップレベルです。"hindi"、"en" など。
_node_turns現在のノードでのユーザーメッセージ数です。遷移時にリセットされます。
_total_turns通話全体でのユーザーメッセージ数です。
_silence_repeats現在のノードでの無音リプレイ数です。遷移時にリセットされます。

時間ベースの expression が実行されない場合、通話に timezone を指定し忘れています。 これはグラフエージェントで最もよくある落とし穴です。

デバッグ

ルーティングの判断ごとに、1 行のログが記録されます。

Routing decision (LLM): transition_to_offer_pitch | confidence: 0.95 |
  reasoning: Customer confirmed identity by saying 'yeah'. (latency: 210ms)

Routing decision (deterministic): -> after_hours |
  deterministic:expression:Outside working hours (latency: 0.6ms)

reasoning フィールドは、デバッグに最も役立つ情報です。エージェントが誤った遷移を行った場合、ほとんどの場合、その選択をした理由が説明されています。症状から修正方法を確認できる表については、references/debugging.md を参照してください。

本番公開前の品質チェックリスト

  • すべてのノードに少なくとも1つの出口エッジがあるか、明示的な終端ノードになっています。
  • すべてのツール/APIエラーに、音声で案内する代替経路があります。
  • 静的ノードに、安全にテンプレート化されていない動的な情報が含まれていません。
  • コンプライアンスに関する文言(開示事項、録音通知)がルーティングによってスキップされないようになっています。
  • 時刻ベースの式エッジは、通話に timezone が設定されている場合にのみ有効です。
  • イベントエッジには、イベントがない場合のフォールバック(_node_turns または _silence_repeats によるタイムアウト)があります。
  • 分析用に、結果がディスポジションまたは context_data フィールドに対応付けられています。

詳細情報

ファイル内容
references/edges-and-routing.md式演算子、インライン抽出、優先順位のセマンティクス。
references/static-and-silence.md事前レンダリングされた音声、無音時のエスカレーションパターン。
references/event-injection.mdRESTエンドポイント、タイミング、同時実行、properties のマージ。
references/debugging.mdルーティングログ、よくある誤動作、根本原因。
assets/full-example.jsonすべての機能を組み合わせた注釈付き設定。
scripts/create_graph_agent.pyPOST /v2/agent を使用して、上記の予約エージェントを作成します。
scripts/inject_event.py実行中の通話にイベントを送信します。

関連項目

  • create-agent — エージェントの基本構造、tools_config、テレフォニー/STT/TTS。
  • setup-tools — transfer_call およびカスタムHTTPツールの定義。
  • create-knowledgebase — rag_config で使用する vector_id の生成。
  • create-disposition — グラフエージェントの通話から構造化された結果を取得します。
  • https://raw.githubusercontent.com/bolna-ai/skills/main/references/prompting-tips.md — ノードプロンプトのパターンと多言語対応。

コメント