ビヘイビアツリーボット
公式リポジトリのexamples/bt-botは、ビヘイビアツリーとLLMを組み合わせた自律行動ボットのテンプレートです。
ツリーが行動の順序と割り込みを管理し、LLMは発話と選択肢の判断を担当します。
セットアップ
git clone https://github.com/urth-inc/metatell-ai-bot.git
cd metatell-ai-bot
pnpm install
cd examples/bt-bot
cp .env.example .env
.envにはルームURL、必要に応じた認証トークン、LLM API、音声サービスの設定を記入します。
詳しくは設定リファレンスを参照してください。
pnpm dev -- https://metatell.app/YOUR_ROOM_ID
主に編集するファイル
| ファイル | 用途 |
|---|---|
my-bot/bot.config.json | ボット名、挨拶、巡回地点、実行間隔、アニメーション割り当てを設定します。 |
my-bot/tree.json | 行動の分岐と順序を定義します。 |
my-bot/persona.md | LLMが使 うキャラクター設定を記述します。 |
my-bot/custom-nodes.ts | 独自の条件と行動を追加します。 |
srcはテンプレートの実行エンジンです。
通常のカスタマイズはmy-bot配下で行ってください。
ツリーの基本
{
"root": {
"type": "priority_selector",
"children": [
{
"type": "sequence",
"children": [
{ "type": "condition", "name": "mentioned" },
{ "type": "action", "name": "llm_reply" }
]
},
{ "type": "action", "name": "patrol_next" }
]
}
}
| ノード | 動作 |
|---|---|
selector | 子を上から試し、実行中の子を完了まで継続します。 |
priority_selector | 実行中も上位の子を再評価し、メンションなどを割り込ませます。 |
sequence | 子を順番に実行し、失敗した時点で停止します。 |
inverter | 子の成功と失敗を反転します。 |
cooldown | 前回の成功から指定時間が経つまで子を実行しません。 |
repeat | 子を指定条件で繰り返します。 |
condition | 状態を判定します。 |
action | 発話、移動、アニメーションなどを実行します。 |
変更後はJSON Schemaとノード定義に対して検証します。
pnpm check
ボットの起動中にtree.jsonを保存した場合、検証に成功したツリーだけが再読み込みされます。
組み込みの条件
| 名前 | 主なパラメーター | 用途 |
|---|---|---|
mentioned | なし | ボット宛てのメンションまたは認識音声があるかを判定します。 |
user_nearby | range | 指定距離以内にユーザーがいるかを判定します。 |
is_alone | なし | 自分以外に誰もいないかを判定します。 |
anyone_in_room | なし | 自分以外のユーザーがいるかを判定します。 |
user_count | min | ユーザー数が指定値以上かを判定します。 |
chat_contains | word | 直近のチャットに語句が含まれるかを判定します。 |
cooldown | sec、key | 同じキーの前回成功からの経過時間を判定します。 |
random_chance | p | 0から1の確率で成功します。 |
blackboard_equals | key、value | blackboardの値を比較します。 |
time_elapsed | sec | 起動から指定秒数が経過したかを判定します。 |
既定では、他のボットは在室人数、近くのユーザー、在室ユーザー一覧の判定対象から除外されます。
監督下のマルチボット検証で他のボットも対象にする場合のみ、.envへALLOW_BOT_PERCEPTION=1を設定してください。
組み込みの行動
| 名前 | 主なパラメーター | 用途 |
|---|---|---|
say | text | チャットで発言します。音声設定が有効な場合は音声でも発言します。 |
move_to | x、y、z | 指定座標へ移動します。 |
patrol_next | なし | 設定した巡回地点を一つ進みます。 |
move_to_user | なし | 最も近いユーザーのそばへ移動します。 |
look_at_user | なし | 最も近いユーザーの方向を向きます。 |
emote | animation | 固定のアニメーションを再生します。 |
emote_from_blackboard | key | blackboardで選ばれたアニメーションを再生します。 |
wait | sec | 指定秒数待機します。 |
set_blackboard | key、value | blackboardへ値を書き込みます。 |
report_users | なし | 在室ユーザーを発言します。 |
サンプルのbt-botでは、my-bot/custom-nodes.tsでgreet_userを追加登録しています。
組み込みの行動ではありません。
LLM行動
| 名前 | 用途 |
|---|---|
llm_reply | メンションまたは認識音声へペルソナに沿って返信します。 |
llm_say | 現在の状況に応じた自発的な発言を生成します。 |
llm_choose | 選択肢から一つを選び、blackboardへ保存します。 |
llm_sayとllm_chooseを自発的に実行する分岐は、連続呼び出しを避けるためcooldownで囲んでください。
独自ノードを追加する
import {
registerAction,
registerCondition,
} from "../src/engine/registry.js";
registerCondition("has_ticket", (ctx) => {
return ctx.bb.get("hasTicket") === true;
});
registerAction("announce", async (ctx) => {
if (ctx.signal?.aborted) return "FAILURE";
await ctx.api.emote("greet");
if (ctx.signal?.aborted) return "FAILURE";
return (await ctx.api.say("まもなく開始します")) ? "SUCCESS" : "FAILURE";
});
行動はSUCCESS、FAILURE、RUNNINGのいずれかを返します。
非同期処理が上位の分岐に割り込まれた場合は、awaitの直後にctx.signal.abortedを確認し、発話など次の副作用を止めてください。
運用上の安全策
テンプレートには発話間隔、移動速度、ルーム境界、他ボット発言の無視などの安全策があります。
OPERATOR_SESSION_IDSを設定すると、指定した運営の/killallで停止できます。
セッションIDは接続によって変わる可能性があるため、運用前に値を確認してください。
実験用のUNSAFE_MODEは通常運用で有効にしないでください。