ホーム チュートリアル カテゴリ Skills サイトについて
ZH EN JA KO
上級テクニック

OpenClaw会話記録のエクスポートとデータ分析

· 21 分で読了

はじめに

会話データは AI Agent 運用において最も貴重な資産の一つです。会話記録を分析することで、ユーザーの本当のニーズを理解し、Agent の改善点を発見し、プロンプト効果を最適化し、コスト消費を計算できます。OpenClaw はすべてのセッションデータを JSONL 形式で保存し、柔軟なエクスポートツールと豊富な分析ディメンションを提供しています。

本記事では、JSONL セッションファイルの構造、エクスポート方法、実際のデータ分析シナリオを詳しく紹介します。

JSONL セッションファイル構造

ファイルの場所

OpenClaw のセッションデータはデフォルトで以下のパスに保存されます。

~/.openclaw/agents/<agentId>/sessions/
├── session-abc123.jsonl
├── session-def456.jsonl
└── session-ghi789.jsonl

メッセージ形式

各行は独立した JSON オブジェクトで、1件のメッセージを表します。

{"id":"msg_001","parentId":null,"role":"user","content":"こんにちは","timestamp":1710400000,"metadata":{"userId":"user_123","platform":"telegram","channelType":"dm"}}
{"id":"msg_002","parentId":"msg_001","role":"assistant","content":"こんにちは!何かお手伝いできますか?","timestamp":1710400002,"metadata":{"model":"claude-sonnet-4-20250514","inputTokens":45,"outputTokens":12}}
{"id":"msg_003","parentId":"msg_002","role":"user","content":"Pythonのコードを書いて","timestamp":1710400010,"metadata":{"userId":"user_123"}}
{"id":"msg_004","parentId":"msg_003","role":"assistant","content":"はい、こちらがサンプルコードです...","timestamp":1710400015,"metadata":{"model":"claude-sonnet-4-20250514","inputTokens":120,"outputTokens":280,"toolsUsed":["run_code"]}}

メッセージフィールドの説明

フィールド 説明
id string メッセージ一意ID
parentId string/null 親メッセージID、ツリー構造を形成
role string ロール:user / assistant / system / tool
content string メッセージ内容
timestamp number Unix タイムスタンプ(秒)
type string 特殊タイプ:compaction / edit / branch
metadata object メタデータ

メタデータフィールド

{
  "metadata": {
    "userId": "user_123",
    "platform": "telegram",
    "channelType": "dm",
    "channelId": "chat_456",
    "model": "claude-sonnet-4-20250514",
    "inputTokens": 150,
    "outputTokens": 320,
    "totalTokens": 470,
    "latencyMs": 2340,
    "toolsUsed": ["search", "run_code"],
    "costUsd": 0.0023
  }
}

会話記録のエクスポート

コマンドラインエクスポート

# 特定Agentの全セッションをエクスポート
openclaw export --agent my-agent --output ./export/

# 指定期間でエクスポート
openclaw export --agent my-agent \
  --from "2026-03-01" --to "2026-03-14" \
  --output ./export/march.jsonl

# CSV形式でエクスポート
openclaw export --agent my-agent \
  --format csv --output ./export/conversations.csv

# JSON形式でエクスポート(完全なツリー構造付き)
openclaw export --agent my-agent \
  --format json --output ./export/conversations.json

# 特定ユーザーの会話のみエクスポート
openclaw export --agent my-agent \
  --user-id "user_123" --output ./export/user123.jsonl

# 特定プラットフォームの会話のみエクスポート
openclaw export --agent my-agent \
  --platform telegram --output ./export/telegram.jsonl

API エクスポート

# API経由でエクスポート
curl -X GET "http://localhost:3000/api/v1/export/conversations" \
  -H "Authorization: Bearer sk-openclaw-xxx" \
  -G -d "agentId=my-agent" \
  -d "from=2026-03-01" \
  -d "to=2026-03-14" \
  -d "format=jsonl" \
  -o conversations.jsonl

Dashboard エクスポート

OpenClaw Web Dashboard はビジュアルなエクスポートインターフェースを提供しています。

  1. Dashboard → セッション管理に移動
  2. フィルタ条件を設定(期間、Agent、プラットフォームなど) 3.「エクスポート」ボタンをクリック
  3. 形式を選択(JSONL / CSV / JSON)
  4. ファイルをダウンロード

データ分析の実践

Python 分析スクリプト

基本データの読み込み

import json
from datetime import datetime
from collections import Counter, defaultdict

def load_sessions(filepath):
    messages = []
    with open(filepath, "r", encoding="utf-8") as f:
        for line in f:
            if line.strip():
                messages.append(json.loads(line))
    return messages

messages = load_sessions("./export/conversations.jsonl")
print(f"総メッセージ数: {len(messages)}")

分析1:Token 消費統計

def analyze_token_usage(messages):
    total_input = 0
    total_output = 0
    daily_usage = defaultdict(lambda: {"input": 0, "output": 0})

    for msg in messages:
        if msg["role"] == "assistant" and "metadata" in msg:
            meta = msg["metadata"]
            input_t = meta.get("inputTokens", 0)
            output_t = meta.get("outputTokens", 0)
            total_input += input_t
            total_output += output_t

            date = datetime.fromtimestamp(msg["timestamp"]).strftime("%Y-%m-%d")
            daily_usage[date]["input"] += input_t
            daily_usage[date]["output"] += output_t

    print(f"総入力Token: {total_input:,}")
    print(f"総出力Token: {total_output:,}")
    print(f"日平均入力Token: {total_input // max(len(daily_usage), 1):,}")

    return daily_usage

usage = analyze_token_usage(messages)

分析2:ユーザーアクティビティ

def analyze_user_activity(messages):
    user_messages = Counter()
    user_sessions = defaultdict(set)

    for msg in messages:
        if msg["role"] == "user" and "metadata" in msg:
            uid = msg["metadata"].get("userId", "unknown")
            user_messages[uid] += 1

    print("Top 10 アクティブユーザー:")
    for uid, count in user_messages.most_common(10):
        print(f"  {uid}: {count} 件のメッセージ")

    return user_messages

activity = analyze_user_activity(messages)

分析3:よくある質問のカテゴリ分類

def categorize_topics(messages):
    """シンプルなキーワード分類"""
    categories = {
        "技術的な質問": ["コード", "バグ", "エラー", "デプロイ", "設定"],
        "製品に関する問い合わせ": ["価格", "機能", "比較", "トライアル"],
        "使い方のヘルプ": ["どうやって", "方法", "チュートリアル", "手順"],
        "フィードバック・提案": ["提案", "希望", "改善", "使いにくい"]
    }

    results = Counter()
    for msg in messages:
        if msg["role"] == "user":
            content = msg["content"]
            for category, keywords in categories.items():
                if any(kw in content for kw in keywords):
                    results[category] += 1
                    break

    return results

topics = categorize_topics(messages)
for topic, count in topics.most_common():
    print(f"  {topic}: {count}")

分析4:レスポンスレイテンシ分布

def analyze_latency(messages):
    latencies = []
    for msg in messages:
        if msg["role"] == "assistant" and "metadata" in msg:
            latency = msg["metadata"].get("latencyMs")
            if latency:
                latencies.append(latency)

    if latencies:
        latencies.sort()
        print(f"平均レイテンシ: {sum(latencies)/len(latencies):.0f}ms")
        print(f"P50レイテンシ: {latencies[len(latencies)//2]:.0f}ms")
        print(f"P95レイテンシ: {latencies[int(len(latencies)*0.95)]:.0f}ms")
        print(f"P99レイテンシ: {latencies[int(len(latencies)*0.99)]:.0f}ms")

analyze_latency(messages)

分析5:ツール使用統計

def analyze_tool_usage(messages):
    tool_counts = Counter()
    for msg in messages:
        if msg["role"] == "assistant" and "metadata" in msg:
            tools = msg["metadata"].get("toolsUsed", [])
            for tool in tools:
                tool_counts[tool] += 1

    print("ツール使用頻度:")
    for tool, count in tool_counts.most_common():
        print(f"  {tool}: {count} 回")

analyze_tool_usage(messages)

データの可視化

matplotlib でグラフを描画

import matplotlib.pyplot as plt

def plot_daily_usage(daily_usage):
    dates = sorted(daily_usage.keys())
    input_tokens = [daily_usage[d]["input"] for d in dates]
    output_tokens = [daily_usage[d]["output"] for d in dates]

    fig, ax = plt.subplots(figsize=(12, 6))
    ax.bar(dates, input_tokens, label="入力Token", alpha=0.7)
    ax.bar(dates, output_tokens, bottom=input_tokens,
           label="出力Token", alpha=0.7)
    ax.set_xlabel("日付")
    ax.set_ylabel("Token数")
    ax.set_title("日次Token消費トレンド")
    ax.legend()
    plt.xticks(rotation=45)
    plt.tight_layout()
    plt.savefig("daily_token_usage.png", dpi=150)

plot_daily_usage(usage)

プライバシーとコンプライアンス

データ匿名化エクスポート

# エクスポート時に自動匿名化
openclaw export --agent my-agent \
  --anonymize \
  --redact-patterns "phone,email,id_card" \
  --output ./export/anonymized.jsonl

データ保持ポリシー

{
  storage: {
    retention: {
      // セッションデータの保持日数
      sessionTTL: 90,  // 90日後に自動クリーンアップ
      // エクスポートデータの保持日数
      exportTTL: 30,
      // 削除前に自動アーカイブするかどうか
      archiveBeforeDelete: true,
      archiveDir: "./archive/"
    }
  }
}

まとめ

OpenClaw の JSONL セッション保存形式はシンプルかつ強力です。1行1メッセージ、JSON 形式で解析が容易、ツリー構造で会話の分岐を完全に記録します。コマンドライン、API、Dashboard からデータをエクスポートした後、Python などのツールで Token 消費、ユーザーアクティビティ、トピック分布からレスポンスレイテンシまで、AI Agent の運用状況を多角的に把握する深い分析が可能です。これらのデータインサイトにより、Agent のパフォーマンスとコスト効率を継続的に最適化できます。

OpenClawは無料のオープンソースAIアシスタント。WhatsApp、Telegram、Discordなど多数のプラットフォームに対応