bolna-graph-agents について
bolna-graph-agents は、ノードとエッジで Bolna の多段階音声会話を構成し、決定的なルールと LLM によるルーティングを組み合わせるスキルです。段階、分岐、外部イベント、コンプライアンス確認を含む通話フローに適しています。
主な機能
- 01ノードとエッジによる会話フローの構成
- 02式、イベント、LLM によるルーティング
- 03静的ノードの音声を事前生成
- 04ノード単位の検索設定
- 05イベント注入による通話中の遷移
活用シーン
- 01予約受付など段階的な通話の構築
- 02営業時間や再試行回数による分岐
- 03決済完了などのバックエンドイベントへの応答
- 04コンプライアンス確認を通話フローに組み込む
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ bolna-ai/ skills --skill bolna-graph-agentsインストール後、Claude Code で/bolna-graph-agentsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
assets/full-example.jsonreferences/debugging.mdedges-and-routing.mdevent-injection.mdstatic-and-silence.mdscripts/create_graph_agent.pyinject_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_effort | GPT-5のみ:minimal / low / medium / high。 |
ノードのフィールド
| フィールド | 型 | 備考 |
|---|---|---|
id | string | エッジと current_node_id から参照されます。 |
prompt | string | "llm" ノードで必須です。このノードで応答用LLMが行うことを指定します。 |
node_type | "llm"(デフォルト)または "static" | static = キャッシュ済み音声、約50ミリ秒、コストゼロ。 |
static_message | string | node_type == "static" の場合に必須です。 |
repeat_after_silence_seconds | number | ユーザーがN秒間無音の場合、自動的に再生します。どちらのノードタイプでも動作します。 |
edges | array | 遷移可能な接続先です。 |
examples | object | 言語ごとの表現例です。例:{ "en": [...], "hi": [...] }。 |
function_call | string | このノードに入る際、応答用LLMの tool_choice をこのツールに強制します。転送ノードで使用します。 |
rag_config | object | ノード単位のナレッジベースです。詳しくは以下を参照してください。 |
エッジフィールド
| フィールド | 説明 |
|---|---|
to_node_id | 必須です。 |
condition | 人が読める説明です。LLM エッジでは、ルーティング LLM のツール説明として使用されます。 |
condition_type | "llm"(デフォルト)、"expression"、"unconditional"、"event"。 |
expression | expression エッジで必須です。references/edges-and-routing.md を参照してください。 |
event_name | event エッジで必須です。references/event-injection.md を参照してください。 |
parameters | ユーザー入力から遷移時に抽出する {name: type} です。context_data にマージされます。 |
priority | 数値が小さいものから実行されます。デフォルトは、決定的エッジが 0、LLM エッジが 100 です。 |
function_name、function_description | 自動生成されるルーティングツールの名前と説明を上書きします。 |
ユーザーの各ターンでのルーティング順序
- 決定的エッジを先に処理します(expression、unconditional、event)。
priority順に評価され、最初に一致したものが選択されます。処理はサブミリ秒で完了します。 - LLM エッジ — ルーティング LLM が、ユーザーの返答に対して
condition文字列を評価します。最適なものを選ぶか、stay_on_current_nodeを返します。 - 一致なし — エージェントは現在のノードにとどまり、自然に再度質問します。
決定的なルールに一致した場合、ルーティング 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_hour | 0〜23。通話に timezone が指定されている場合にのみ設定されます。 |
recipient_data.current_weekday | 小文字です(例:"wednesday")。 |
recipient_data.current_day / _month / _year / _minute | 数値の各要素です。 |
recipient_data.timezone | tz データベース名です。 |
recipient_data.user_number | E.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.md | RESTエンドポイント、タイミング、同時実行、properties のマージ。 |
references/debugging.md | ルーティングログ、よくある誤動作、根本原因。 |
assets/full-example.json | すべての機能を組み合わせた注釈付き設定。 |
scripts/create_graph_agent.py | POST /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— ノードプロンプトのパターンと多言語対応。