はじめに
Pendoはプロダクトアナリティクスとユーザーエンゲージメントのプラットフォームで、アプリの操作ログを収集・分析したり、ガイドやアンケートをノーコードで配信できるツールです。最近ではAI機能を持つプロダクト向けに「Agent Analytics」という機能も提供しており、AIエージェントとユーザーの会話を記録・分析できるようになっています。
Pendo Agent Analyticsとは
Agent Analyticsは、AIエージェントとユーザーの会話を収集・可視化するPendoの機能です。従来のプロダクトアナリティクスが「どの画面を操作したか」を追跡するのに対し、Agent Analyticsは「AIに何を聞いたか・AIがどう答えたか・会話に共通の課題はあるか?」という会話レベルのインタラクションを記録します。
具体的には以下のようなことができます:
- 会話ごとのプロンプト・レスポンス・フィードバックをタイムライン形式で確認
- エージェントごとの利用状況(会話数、アクティブユーザー数など)を集計
- ユーザーのリアクション(thumbs up / down)からAIの回答品質を把握
- 全体を通じて会話に課題はあるか?や共通するユースケースの傾向をリストアップ
データはクライアントから送る方式とサーバーサイドからAPIで送り込む方式があります。AIエージェントの実装に関係なく会話ログを流し込めます。今回のように外部サービス(Microsoft 365 Copilot)の会話ログをインポートするケースにも対応しています。
きっかけ
お客様と話していると、「Microsoft 365 Copilotを導入したけど、実際にどう使われているか把握したい」という声をよく耳にします。MicrosoftのCopilot Dashboardでも利用状況は確認できますが、Pendoのプロダクトデータと組み合わせて分析したいというニーズがありました。
そこでPoTとして、Microsoft Graph APIからCopilotの会話ログを取得してAgent Analyticsに流し込む、というのを試してみました。
Agent Anlyticsに流した結果を先にお見せします。
Pendo上での見え方
実際にスクリプトを実行してデータを送り込むと、Pendo上でこんな風に確認できます。
エージェントの利用状況
BizChatやExcelなど、アプリ(エージェント)ごとに会話数やアクティブユーザー数が集計されます。
エージェントのユースケース
エージェントを何に使用しているか傾向が見られます。
エージェントの問題
問題とは、エージェントの回答にいら立っているユーザーがいないか?や適切な回答ができていないセッションを洗い出すことができます。
会話タイムライン
全体の仕組み
Microsoft 365 Copilot
↓ (会話履歴)
Microsoft Graph API
/copilot/users/{user}/interactionHistory/getAllEnterpriseInteractions
↓ (Python スクリプトで変換)
Pendo Agent Analytics
POST https://data.pendo.io/data/agentic
- Azureにアプリ登録して、Graph APIのアクセストークンを取得
- Graph APIの
getAllEnterpriseInteractionsエンドポイントからCopilotのやり取りを全件取得 - MicrosoftのイベントタイプをPendoのイベントタイプに変換
- PendoのAgenticsエンドポイントに1件ずつPOST
準備するもの
1. Azure ADアプリの登録
Azure Portalで「アプリの登録」→ 新規作成して、以下のアプリケーション権限を付与し、管理者の同意を与えます。
| 権限 | 用途 |
|---|---|
AiEnterpriseInteraction.Read.All |
テナント全体のCopilot会話履歴を読む |
テナントID・クライアントID・クライアントシークレットを控えておきましょう。
2. Pendo Agent Analyticsの設定
Pendo上で対象エージェント(Copilot BizChat、Excel等)を作成し、各エージェントのURLからagentIdを取得します。
また、Settings → Subscription settings → Applications からTrack Event shared secretを取得します。
3. 設定ファイルを用意する
.envにPendoのシークレットを書くだけです。python-dotenvすら不要なシンプルな実装にしています:
pendotrackkey=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
appclass_agent_map.jsonにMicrosoftのappClassとPendoのagentIdのマッピングを書きます。Copilotは利用しているアプリによってappClassが違うので、どれをPendoで見たいか決めてIDを埋めていきます:
{
"mappings": {
"IPM.SkypeTeams.Message.Copilot.BizChat": "pendoから発行されるID",
"IPM.SkypeTeams.Message.Copilot.Excel": "pendoから発行されるID",
"IPM.SkypeTeams.Message.Copilot.Teams": "pendoから発行されるID",
"IPM.SkypeTeams.Message.Copilot.Word": "FILL_IN_PENDO_AGENT_ID"
},
"fallback": "unknown"
}
FILL_IN_PENDO_AGENT_IDのままのエージェントは自動的にスキップされます。Pendo側にまだ登録していないアプリは後から追加すればOKです。
コードの解説
Graph APIからデータを取得する
ページネーションを@odata.nextLinkで追いかけながら全件取得します:
def fetch_interactions(token, user, start, end, limit=None):
base = (
f"https://graph.microsoft.com/v1.0"
f"/copilot/users/{user}/interactionHistory/getAllEnterpriseInteractions"
f"?$top=100"
)
url = base
fetched = 0
while url:
resp = requests.get(url, headers={"Authorization": f"Bearer {token}"})
data = resp.json()
for record in data.get("value", []):
# クライアント側で日付フィルタリング(APIが$filterを非サポート)
ts = _iso_to_epoch_ms(record.get("createdDateTime") or "")
if start_ms and ts < start_ms:
continue
if end_ms and ts >= end_ms:
continue
yield record
fetched += 1
if limit and fetched >= limit:
return
url = data.get("@odata.nextLink") # 次ページへ
注意: このエンドポイントは$filterをサポートしていません。日付フィルタリングは全件取得後にクライアント側で行うため、履歴が多いユーザーはそれなりに時間がかかります。
イベントタイプの変換
MicrosoftとPendoでイベントの呼び方が違うので変換します:
Microsoft interactionType
|
Pendo type
|
|---|---|
userPrompt |
prompt |
aiResponse |
agent_response |
userFeedback |
user_reaction |
AIレスポンスのテキスト抽出
実装で一番ハマったポイントです。CopilotのaiResponseはbodyが空のことが多く、テキストがAdaptiveCardというJSON添付ファイルの中に格納されています。
def _text_from_adaptive_card(content_str):
card = json.loads(content_str)
blocks = []
def _walk(node):
if isinstance(node, dict):
if node.get("type") == "TextBlock" and node.get("text"):
blocks.append(node)
for v in node.values():
_walk(v)
elif isinstance(node, list):
for item in node:
_walk(item)
_walk(card)
if not blocks:
return ""
# id="MessageTextField" のブロックを優先(アクセシビリティ用プレーンテキスト版)
preferred = next((b for b in blocks if b.get("id") == "MessageTextField"), None)
return str((preferred or blocks[0])["text"])
カードのJSONをツリー探索してTextBlockを全部集め、id="MessageTextField"(アクセシビリティ用のプレーンテキスト版)を優先して取り出します。これを知らないとレスポンスの内容が全部空文字になるので注意が必要です。
Pendoへ送るペイロード
最終的にこんな形のJSONをPendoに投げます:
{
"type": "prompt",
"visitor_id": "user@example.com",
"timestamp": 1716854400000,
"props": {
"agentId": "Eo5zg9bJmPigK4QTSskr917nozI",
"conversationId": "19:meeting_...",
"messageId": "1716854400000",
"content": "Excelのデータを集計する方法を教えて",
"modelUsed": "",
"suggestedPrompt": false,
"toolsUsed": [],
"fileUploaded": false
},
"context": {}
}
visitor_idはユーザーのメールアドレス(UPN)を使います。aiResponseは送信者がAIなのでfrom.userがnullになりますが、CLIの--usersで渡したメールアドレスをフォールバックとして使います。
使い方
# 依存パッケージのインストール
pip install requests
# まずは--dry-runで確認!ペイロードをstdoutに出力するだけ
python3 pendo_sync.py --users daichi@example.com --dry-run
# 日付範囲を指定して送信
python3 pendo_sync.py --users daichi@example.com \
--start 2024-11-01T00:00:00Z \
--end 2024-11-30T23:59:59Z
# 生データをJSONファイルに書き出し(Pendoには送らない)
python3 pendo_sync.py --users daichi@example.com --export prompts.json
# テスト用:先頭500件だけ取得
python3 pendo_sync.py --users daichi@example.com --limit 500 --dry-run
初回は--dry-runか--exportで中身を確認してから送信することをおすすめします。
ハマりポイントと対処法
1. インポートできるのは過去24時間以内のデータのみ
Pendo Agent Analyticsの重要な制約として、agenticsエンドポイントは過去24時間より古いタイムスタンプを持つイベントを受け付けません。 エラーも返さず黙って無視するため、Pendoに何も表示されない原因として気づくまでに時間がかかりました。
実運用で回す場合は、毎日バッチで「前日分の会話を翌日中にPendoへ送る」という運用であれば24時間以内に収まりますが、週次や月次でまとめて送ろうとすると古いデータはすべて破棄されます。定期実行の間隔は必ず24時間以内にする必要があります。
初回のバックフィル(過去データの一括投入)は原理的に不可能なので、運用開始日以降のデータだけをPendoで扱うことになります。
実運用に向けた設計
今回はPoTとして手動実行を前提に作りましたが、実運用では毎日定期バッチで前日分を送る構成が現実的です。前述の通り24時間制約があるため、バッチ間隔は24時間以内が必須です。
[毎日AM6時などに定期実行]
1. 前回実行時刻をウォーターマークファイルから読む
2. Graph APIから前回〜現在の差分を取得
3. Pendoに送信
まとめ
今回のPoTで、Microsoft 365 CopilotのログをPendo Agent Analyticsに流し込むことができました。
実際に入れてみると、「誰がどのアプリのCopilotをどのくらい使っているか」「どんなユースケースが多いか」「回答に不満を持っているユーザーはいるか」といった観点が、Pendoの画面上でひとまとめに確認できます。Copilot Dashboardでは見えなかった会話の中身や品質の傾向まで把握できるのは、かなり実用的だと感じました。
Pendoをすでに使っているなら、Copilotの会話ログを追加するだけで既存のプロダクトデータと組み合わせた分析が広がります。Microsoft 365 CopilotのAI活用状況をもっと深く把握したい方は、ぜひ試してみてください。



