はじめに
OpenClaw で複数のチャットプラットフォームを設定した後、重要な問題が浮上します。異なるプラットフォーム、異なるユーザー、異なる会話間のメッセージはどのようにルーティングし分離すべきなのか。すべてのメッセージが混ざり合えば、AIの返信は必然的に混乱します。
OpenClaw はマルチ Agent ルーティングとセッション分離メカニズムで、この問題をエレガントに解決しています。各 Agent は独立したセッション空間を持ち、セッションは JSONL 形式で永続化ストレージされ、ツリー構造による分岐と圧縮をサポートしています。本記事ではこのメカニズムの動作原理と設定方法を深く解析します。
マルチ Agent ルーティングアーキテクチャ
OpenClaw のコア設計理念は「会話ごとのルーティング」です。複数のプラットフォーム(Telegram、Discord、Slack など)を設定した場合、システムはすべてのメッセージを同じ処理パイプラインに投げ込むのではなく、各独立した会話に対して分離されたセッションコンテキストを維持します。
ユーザーA (Telegram DM) ──→ Agent-1 ──→ Session A-001
ユーザーA (Discord #general) ──→ Agent-2 ──→ Session A-002
ユーザーB (Telegram DM) ──→ Agent-1 ──→ Session B-001
ユーザーB (Slack グループ) ──→ Agent-3 ──→ Session B-002
同じユーザーでも、異なるプラットフォーム上の会話は異なる Agent にルーティングされ、完全に分離されたセッションを持ちます。この設計によりコンテキストの相互汚染を防止します。
セッションストレージ:JSONLとツリー構造
OpenClaw のセッションデータはJSONL(JSON Lines)形式で保存され、各セッションファイルは一連のメッセージ記録を含みます。ストレージパスは統一的なディレクトリ構造に従います。
~/.openclaw/agents/<agentId>/sessions/
├── session-a001.jsonl
├── session-a002.jsonl
├── session-b001.jsonl
└── session-b002.jsonl
各メッセージ記録には id と parentId フィールドが含まれ、ツリー構造を形成します。
{"id":"msg_001","parentId":null,"role":"user","content":"こんにちは","timestamp":1710000000}
{"id":"msg_002","parentId":"msg_001","role":"assistant","content":"こんにちは!何かお手伝いできることはありますか?","timestamp":1710000001}
{"id":"msg_003","parentId":"msg_002","role":"user","content":"Pythonのコードを書いてほしい","timestamp":1710000010}
{"id":"msg_004","parentId":"msg_002","role":"user","content":"今日の天気はどうですか","timestamp":1710000015}
上記の msg_003 と msg_004 は同じ parentId を持っており、これは msg_002 の後に会話が分岐したことを意味します。ツリー構造により、OpenClaw は会話のすべての分岐パスを完全に記録でき、単なる線形のチャット記録にとどまりません。これはユーザーが以前のメッセージを再編集したり、システムが自動圧縮を行う場合に特に重要です。
チャンネルタイプ別の履歴制限
異なるタイプのチャットチャンネルには異なるユースケースがあり、OpenClaw はこれに基づいて履歴記録の長さに差異化された処理を行います。
プライベートチャット(DM)チャンネル
プライベートチャットは通常、1対1の深い対話であり、ユーザーはAIがより長いコンテキストを記憶することを期待します。そのためDMチャンネルはデフォルトでより多くの履歴メッセージを保持します。
{
agents: {
"personal-assistant": {
history: {
dm: {
maxMessages: 100, // 最新100件のメッセージを保持
maxTokens: 32000, // 最大Token数
},
},
},
},
}
グループ(Group)チャンネル
グループシーンではメッセージ量が多くトピックの切り替えが頻繁で、過度な履歴保持はむしろノイズになります。OpenClaw はグループチャンネルにデフォルトでより厳格な制限を適用します。
{
agents: {
"group-bot": {
history: {
group: {
maxMessages: 30, // 最新30件のメッセージのみ保持
maxTokens: 8000, // より小さいTokenウィンドウ
},
},
},
},
}
このチャンネルタイプ別の差異化設計により、Tokenコストを節約しつつ、異なるシーンでの最適な体験を保証します。
コンテキストオーバーフロー時の自動圧縮
会話履歴がモデルのコンテキストウィンドウ制限を超えた場合、OpenClaw は古いメッセージを単純に切り詰めるのではなく、自動圧縮(Auto-compaction)メカニズムをトリガーします。
自動圧縮のワークフローは以下のとおりです。
- 現在のセッションのToken数がモデルのコンテキスト制限に近づいていることを検出
- 古い会話内容をモデルに送信して圧縮要約を生成
- 要約で元の履歴メッセージを置換し、Token消費を大幅に削減
- JSONLファイルに新しい圧縮ノードを作成。元のメッセージはツリーの旧分岐に保持
{"id":"compact_001","parentId":null,"role":"system","type":"compaction","content":"[セッション要約] ユーザーはPythonクローラー開発について議論。requestsライブラリの使用、アンチクローリング戦略、データパース方法を含む...","timestamp":1710001000}
{"id":"msg_050","parentId":"compact_001","role":"user","content":"Scrapyフレームワークについて続けて教えて","timestamp":1710001001}
圧縮操作はユーザーにとって完全に透明です。AIは要約に基づいてそれまでの会話背景を理解でき、同時にリクエストごとのToken消費を大幅に削減します。
圧縮動作は設定で調整できます。
{
agents: {
"my-agent": {
compaction: {
enabled: true,
// Token使用率がどの程度で圧縮をトリガーするか(0-1)
threshold: 0.85,
// 圧縮要約の最大Token数
summaryMaxTokens: 1024,
// 直近何件のメッセージを圧縮から除外するか
preserveRecent: 10,
},
},
},
}
セッションの永続化と分岐管理
JSONL形式とツリー構造の組み合わせにより、OpenClaw は強力なセッション永続化能力を備えています。サービスが再起動しても、すべてのセッション状態を完全に復元できます。
分岐シーン
ツリー構造は以下のシーンで力を発揮します。
- ユーザーがメッセージを編集:ユーザーが以前のメッセージを修正して再送信した場合、OpenClaw は元の会話パスを上書きせず、編集されたノードから新しい分岐を作成
- 自動圧縮の分岐:圧縮操作は新しい要約ノードを作成し、元の会話は旧分岐として保持。データの損失なし
- 会話の遡及:管理者はDashboardで任意の分岐の完全な会話履歴を確認可能
セッションデータの確認
元のセッションファイルを直接確認できます。
# あるAgentのすべてのセッションを一覧表示
ls ~/.openclaw/agents/my-agent/sessions/
# 特定セッションの内容を確認
cat ~/.openclaw/agents/my-agent/sessions/session-xxx.jsonl | jq .
プロバイダー非依存のモデル切り替え
OpenClaw のマルチ Agent アーキテクチャはもう一つの重要な利点をもたらします。各 Agent は独立してモデルプロバイダーとモデル名を指定でき、互いに影響しません。
{
agents: {
// Agent 1:Claudeを使用、Telegram DMを処理
"telegram-dm": {
model: {
provider: "claude",
name: "claude-sonnet-4-20250514",
},
channels: ["telegram"],
scope: "dm",
},
// Agent 2:Ollamaローカルモデルを使用、Discordグループチャットを処理
"discord-group": {
model: {
provider: "ollama",
name: "llama3.1:70b",
},
channels: ["discord"],
scope: "group",
},
// Agent 3:GPT-4oを使用、Slackワークチャンネルを処理
"slack-work": {
model: {
provider: "openai",
name: "gpt-4o",
},
channels: ["slack"],
scope: "all",
},
},
}
このプロバイダー非依存の設計により、ある Agent のモデルをいつでも切り替えても、他の Agent の稼働に影響しません。例えば、コスト重視のグループチャット Agent を Claude からOllamaローカルモデルに切り替えつつ、プライベートチャット Agent は高品質の商用モデルを継続使用できます。
ルーティングルールのまとめ
OpenClaw のマルチ Agent ルーティングは以下の優先順位チェーンに従います。
- プラットフォームマッチング:メッセージがどのチャットプラットフォームからのものか(Telegram / Discord / Slack など)
- チャンネルタイプマッチング:メッセージがプライベートチャットからか、グループからか
- Agent 割り当て:マッチング結果に基づいてメッセージを対応する Agent にルーティング
- セッションの検索または作成:Agent のセッションディレクトリで既存のセッションを検索するか、新しいセッションを作成
- 履歴の読み込み:チャンネルタイプの履歴制限に基づいて適切な長さのコンテキストを読み込み
- モデル呼び出し:その Agent に設定されたモデルでメッセージを処理
全プロセスは完全に自動で行われ、ユーザーの介入は不要です。
まとめ
OpenClaw のマルチ Agent ルーティングとセッション分離メカニズムは、そのアーキテクチャの最もコアとなる設計の一つです。会話ごとのルーティングによる完全なコンテキスト分離、JSONLツリー構造による永続化と分岐管理、チャンネルタイプ別に差異化された履歴制限によるコストと体験のバランス、さらに自動圧縮によるコンテキストオーバーフローへの対応——このメカニズムにより、複数のプラットフォームに複数の Agent を安心してデプロイでき、各 Agent が自身のセッション空間で安定・効率的に稼働します。