GitHub Copilot usage metrics APIでAgent App別の利用状況を集計する場合は、新しく追加されたtotals_by_3rd_party_agent配列を利用します。
ただし、安全に集計するために必ず守るべきポイントが2つあります。期間をまたぐ集計やデータ結合にはagent_nameではなくagent_idを使うこと、そして配列内のuser_initiated_interaction_countをトップレベルの同名フィールドへ加算しないことです。
GitHubは2026年8月7日、Enterprise、Organization、ユーザー単位の1日・28日レポートで、認識されたAgent Appごとの利用状況を取得できるようにしました。これにより、複数のエージェントを導入している組織でも、エージェントごとの利用実態を分けて分析できます。(The GitHub Blog)
Copilot Metrics APIに追加されたtotals_by_3rd_party_agentとは
totals_by_3rd_party_agentは、レポート期間中に利用された、認識済みのAgent Appごとのメトリックを格納するオプションの配列です。
従来は外部エージェントの利用が実質的に一つのまとまりとして扱われていましたが、この配列によってエージェント別のジョブ開始数やセッション数を取得できます。公式仕様上のレポート別の違いは次のとおりです。(The GitHub Blog)
| レポート種別 | 配列が入る位置 | session_count | 主な用途 |
|---|---|---|---|
| Enterprise・Organizationの1日集約レポート | 集約レコード内 | あり | その日のエージェント別利用比較 |
| Enterprise・Organizationの28日集約レポート | day_totals[]内の日別レコード | あり | 28日間の日次推移 |
| Enterprise・Organizationのユーザー別1日レポート | ユーザーレコード内 | なし | エージェント別の利用者把握 |
| Enterprise・Organizationのユーザー別28日レポート | 期間単位のユーザーレコード内 | なし | 28日間のユーザー別利用分析 |
集約レポートとユーザー別レポートではスキーマが異なります。特に、ユーザー別レポートにsession_countが含まれない点は、データベース設計やBIツールへの取り込み時に注意が必要です。(GitHub Docs)
エージェント別スキーマのフィールド構成
totals_by_3rd_party_agentの各要素には、次のフィールドが含まれます。(GitHub Docs)
| JSONフィールド | 型 | 意味 | 取り込み先で推奨する名前 |
|---|---|---|---|
agent_id | string | Agent Appの安定した識別子 | agent_id |
agent_name | string | 画面表示用のエージェント名 | agent_name_snapshot |
user_initiated_interaction_count | integer | ユーザーが開始したAgent Appジョブの開始数 | agent_job_start_count |
session_count | integer | Agent Appのセッション数 | agent_session_count |
agent_idは、値が数字だけに見える場合でも文字列として定義されています。数値型へ変換せず、文字列のまま保存するのが安全です。(GitHub Docs)
簡略化したJSONの例
{
"day": "2026-08-07",
"user_initiated_interaction_count": 120,
"totals_by_3rd_party_agent": [
{
"agent_id": "1234567",
"agent_name": "Example Agent",
"session_count": 18,
"user_initiated_interaction_count": 31
},
{
"agent_id": "7654321",
"agent_name": "Another Agent",
"session_count": 12,
"user_initiated_interaction_count": 19
}
]
}
この例では、トップレベルと配列内に同じuser_initiated_interaction_countという名前のフィールドがあります。しかし、両者は意味も計測単位も異なります。
集計と結合にはagent_nameではなくagent_idを使う
agent_nameは表示名であり、将来変更される可能性があります。一方、agent_idはレポート期間をまたいでデータを結合するための安定した識別子です。GitHubも、グループ化や期間比較にはagent_idを使用するよう案内しています。(The GitHub Blog)
例えば、同じエージェントの表示名が途中で変更されたとします。
| 月 | agent_id | agent_name | ジョブ開始数 |
|---|---|---|---|
| 8月 | 1234567 | Example Agent | 100 |
| 9月 | 1234567 | Example Agent for GitHub | 140 |
agent_nameで集計すると、8月と9月が別のエージェントとして分割されます。agent_idで集計すれば、同じエージェントの継続データとして合計240件を取得できます。
実務では、次のように扱うと安全です。
- 主キーや結合キーには
agent_idを使用する agent_nameは表示用のスナップショットとして保存する- ダッシュボードでは最新の
agent_nameを表示する - 過去レポートの
agent_nameを書き換えず、名称変更履歴を残す agent_idを整数へ変換しない
また、同じエージェントに対応する複数のインテグレーションがある場合、それらの活動は同じagent_idの一つのエントリへまとめられます。逆に、エージェントを特定できない活動は配列に含まれません。そのため、この配列だけで個別のGitHub Appインストール単位や、未識別エージェントを分析できるわけではありません。(The GitHub Blog)
同名のuser_initiated_interaction_countを加算してはいけない
最も間違えやすいのが、トップレベルと配列内にある同名フィールドの扱いです。
| JSONパス | 計測しているもの |
|---|---|
user_initiated_interaction_count | Copilotへ明示的に送信されたプロンプト数 |
totals_by_3rd_party_agent[].user_initiated_interaction_count | ユーザー操作によって開始されたAgent Appジョブ数 |
配列内の値はサーバー側のAgent Appジョブ活動から取得されます。トップレベルの値は、別の対応済みテレメトリから取得された明示的なプロンプト数です。GitHubは、両者を加算したり、同じ指標として扱ったりしないよう明記しています。(The GitHub Blog)
先ほどのJSON例では、次の計算は誤りです。
120 + 31 + 19 = 170件のユーザー操作
正しくは、別々のKPIとして表示します。
Copilotへの明示的なプロンプト数:120件
認識済みAgent Appのジョブ開始数:50件
配列内の31件と19件を合計し、認識済みAgent Appのジョブ開始数を50件とすることはできます。ただし、それをトップレベルの120件へ加えて「総インタラクション数」とすることはできません。
取り込み先では、同じフィールド名をそのまま使わず、次のように意味が分かる名前へ変更すると事故を防げます。
トップレベル:
copilot_explicit_prompt_count
Agent App配列内:
agent_job_start_count
配列を展開するとトップレベル値が重複する点にも注意する
二重計上は、フィールド同士を直接加算した場合だけでなく、配列をテーブルへ展開した場合にも発生します。
元データが次の内容だったとします。
トップレベルのプロンプト数:120
Agent App数:2
BIツールやETLで配列を2行へ展開し、各行へトップレベルの120をコピーすると、次のようなテーブルになります。
agent_id | Agent Appジョブ開始数 | トップレベルのプロンプト数 |
|---|---|---|
1234567 | 31 | 120 |
7654321 | 19 | 120 |
このテーブルでプロンプト数を単純に合計すると、実際は120件なのに240件になります。
安全な設計は、トップレベル指標とエージェント別指標を別テーブルに分ける方法です。
| テーブル | データ粒度 | 保存する主な値 |
|---|---|---|
copilot_usage_fact | 日・組織・ユーザーなどのレポート粒度 | copilot_explicit_prompt_count |
copilot_agent_usage_fact | 日・組織・ユーザー・agent_id | agent_job_start_count、agent_session_count |
一つのテーブルへまとめる場合は、トップレベル値を合計不可の属性として扱う必要があります。ただし、Power BIや集計SQLで誤ってSUMされる可能性を考えると、別テーブルに分ける方が安全です。
session_countがない場合は0ではなくNULLとして扱う
session_countは、EnterpriseまたはOrganizationの集約レポートにだけ含まれます。ユーザー別レポートでは省略されます。(The GitHub Blog)
ユーザー別レポートにsession_countがないからといって、「そのユーザーのセッション数は0」と解釈してはいけません。正しい意味は「このレポート粒度では提供されていない」です。
したがって、データベースには次のように保存します。
集約レポートでsession_countが10:
10として保存
ユーザー別レポートでsession_countが存在しない:
NULLとして保存
0とNULLを区別しないと、「セッションを一度も使っていないユーザー」と「APIがセッション数を返していないユーザー」を判別できなくなります。
配列が存在しない場合に備える
totals_by_3rd_party_agentは必須フィールドではありません。対象期間に認識済みAgent Appの活動がなければ、空配列ではなくフィールド自体が省略されることがあります。今回の変更は既存フィールドの形を変えない後方互換の追加です。(The GitHub Blog)
そのため、次のような直接参照は避けます。
record.totals_by_3rd_party_agent.map(...)
フィールドがない場合でも処理を継続できるよう、配列かどうかを確認します。
const agents = Array.isArray(record.totals_by_3rd_party_agent)
? record.totals_by_3rd_party_agent
: [];
フィールドが省略されている場合は、エラー行や架空の「Unknown Agent」行を作らず、エージェント別テーブルへ0行を出力するのが基本です。
ただし、特定できないエージェントの活動も配列から除外されます。そのため、配列がないことを根拠に「すべての外部エージェント利用が完全に0だった」とまで断定しない方が安全です。(The GitHub Blog)
28日レポートはday_totalsの位置を確認する
EnterpriseとOrganizationの28日集約レポートでは、日別データがday_totals配列に格納されます。totals_by_3rd_party_agentも、それぞれの日別レコードの中に入ります。(GitHub Docs)
{
"report_start_day": "2026-07-11",
"report_end_day": "2026-08-07",
"day_totals": [
{
"day": "2026-08-07",
"totals_by_3rd_party_agent": [
{
"agent_id": "1234567",
"agent_name": "Example Agent",
"session_count": 18,
"user_initiated_interaction_count": 31
}
]
}
]
}
一方、ユーザー別28日レポートは、ユーザーごとの期間レコードとして扱われます。集約28日レポートとユーザー別28日レポートを、同じJSON階層だと決めつけないことが重要です。
また、1日レポートと、その日を含む28日レポートを同じ集計へ加えると期間が重複します。日次推移には1日レポートまたはday_totalsのどちらか一方を使用してください。
APIから取得したレポートを安全に正規化するコード
Copilot usage metrics APIのエンドポイントは、メトリック本体を直接返すのではなく、レポートファイルのdownload_linksを返します。レポートは有効期限付きの署名URLからダウンロードするため、レスポンスを取得した後は全リンクを保存し、NDJSONを行単位で処理します。(GitHub Docs)
Organizationの1日集約レポートを要求する例は次のとおりです。APIバージョンは、利用時点でGitHub公式ドキュメントに掲載されているサポート対象バージョンを確認してください。公式例では2026-03-10が使用されています。(GitHub Docs)
curl -L \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $GITHUB_TOKEN" \
-H "X-GitHub-Api-Version: 2026-03-10" \
"https://api.github.com/orgs/ORG/copilot/metrics/reports/organization-1-day?day=2026-08-07"
ダウンロードしたNDJSONの各オブジェクトは、次のJavaScriptでトップレベル指標とエージェント別指標に分けて正規化できます。
/**
* 1件のCopilot usage metricsレコードを、
* トップレベル指標とAgent App指標に分離する。
*/
function normalizeCopilotUsageRecord(record) {
const metricRecords = Array.isArray(record.day_totals)
? record.day_totals
: [record];
const createContext = (metric) => ({
day: metric.day ?? null,
reportStartDay: record.report_start_day ?? metric.day ?? null,
reportEndDay: record.report_end_day ?? metric.day ?? null,
enterpriseId:
metric.enterprise_id ?? record.enterprise_id ?? null,
organizationId:
metric.organization_id ?? record.organization_id ?? null,
userId:
metric.user_id ?? record.user_id ?? null
});
// トップレベルのプロンプト数を保存するテーブル用
const usageRows = metricRecords.map((metric) => ({
...createContext(metric),
copilotExplicitPromptCount:
typeof metric.user_initiated_interaction_count === "number"
? metric.user_initiated_interaction_count
: null
}));
// Agent App別のジョブ開始数を保存するテーブル用
const agentRows = metricRecords.flatMap((metric) => {
const agents = Array.isArray(metric.totals_by_3rd_party_agent)
? metric.totals_by_3rd_party_agent
: [];
return agents
.filter(
(agent) =>
agent &&
typeof agent === "object" &&
typeof agent.agent_id === "string"
)
.map((agent) => ({
...createContext(metric),
// 数字だけに見えても文字列のまま保持する
agentId: agent.agent_id,
// 結合キーではなく表示用のスナップショット
agentNameSnapshot:
typeof agent.agent_name === "string"
? agent.agent_name
: null,
// トップレベルとは別の指標
agentJobStartCount:
typeof agent.user_initiated_interaction_count === "number"
? agent.user_initiated_interaction_count
: null,
// ユーザー別レポートでは存在しないためNULLにする
agentSessionCount:
typeof agent.session_count === "number"
? agent.session_count
: null
}));
});
return {
usageRows,
agentRows
};
}
このコードでは、トップレベルのプロンプト数をagentRowsへコピーしていません。そのため、Agent App配列を展開した後に、トップレベル値がエージェント数だけ重複する問題を防げます。
エージェント別ダッシュボードで使える集計指標
正規化したデータからは、次の指標を作成できます。
| 指標 | 計算方法 | 注意点 |
|---|---|---|
| エージェント別ジョブ開始数 | agent_idごとにagent_job_start_countを合計 | agent_nameでは集計しない |
| Agent App利用者数 | ユーザー別レポートでuser_idを重複除外 | session_countは利用しない |
| 1利用者あたりジョブ開始数 | ジョブ開始数÷Agent App利用者数 | 同じ期間とスコープを使う |
| エージェント構成比 | 各エージェントのジョブ開始数÷全エージェントのジョブ開始数 | 「認識済みAgent App内の構成比」と表示する |
| エージェント別セッション数 | 集約レポートのsession_countを使用 | ユーザー別セッション数には分解できない |
例えば、エージェント構成比を表示する場合は、「Copilot全利用の30%」ではなく、「認識済みAgent Appのジョブ開始数のうち30%」と表記します。トップレベルのプロンプト数とは母集団が異なるためです。
チーム別の利用状況を作る場合は、ユーザー別の日次レポートとuser-teamsレポートを、user_id、day、organization_idまたはenterprise_idで結合します。チーム単位のメトリックはAPI側で事前集計されていません。(GitHub Docs)
よくある集計ミスと修正方法
| 症状 | 原因 | 修正方法 |
|---|---|---|
| 表示名変更後に別エージェントとして分かれる | agent_nameでグループ化している | agent_idでグループ化する |
| 新配列対応後に全体件数が急増した | トップレベル値と配列内値を加算した | 別々のKPIとして保存する |
| Agent App数に比例してプロンプト数が増える | 配列展開時にトップレベル値を複製した | トップレベルとAgent Appを別テーブルにする |
| ユーザー別セッション数がすべて0になる | 欠落したsession_countを0へ変換した | 未提供を示すNULLで保存する |
| 利用がない日に処理が停止する | 配列が常に存在すると仮定した | 存在しない場合は空配列として処理する |
| 組織全体の件数がほぼ2倍になる | 集約レポートとユーザー別レポートを合算した | KPIごとに使用するレポートを一つに決める |
| 1日分の数値が重複する | 1日レポートと28日レポートを合算した | 重複しない期間・粒度に統一する |
| API変更後にJSON検証で失敗する | 未知フィールドを禁止する厳格なスキーマ | クライアントモデルを更新し、オプション項目として追加する |
GitHub側では後方互換の変更でも、受け側のJSON SchemaがadditionalProperties: falseになっている場合や、固定クラスへ厳格にデシリアライズしている場合は、追加フィールドによって処理が失敗することがあります。
導入前に確認するテストケース
本番の集計処理へ反映する前に、最低限次のパターンをテストします。
totals_by_3rd_party_agentが存在しないレコード- Agent Appが1件だけのレコード
- Agent Appが複数あるレコード
- 同じ
agent_idでagent_nameだけが変わったレコード session_countを含む集約レポートsession_countを含まないユーザー別レポートday_totalsを持つ28日集約レポート- 同じ期間の集約レポートとユーザー別レポート
- 複数の
download_linksに分割されたレポート
APIを利用するには、Copilot usage metricsポリシーを有効にし、EnterpriseまたはOrganizationのCopilot Metricsを閲覧できる権限が必要です。対象期間に認識済みAgent Appの活動がなければ、新しい配列はレポートから省略されます。(The GitHub Blog)
まとめ:安全な集計のために最初に直すべき点
Copilot Metrics APIのエージェント別スキーマへ対応する際は、単にtotals_by_3rd_party_agentを展開するだけでは不十分です。
まず、agent_idを文字列の結合キーとして保存し、agent_nameは表示用データとして扱います。次に、配列内のuser_initiated_interaction_countをagent_job_start_countなどへ改名し、トップレベルのプロンプト数とは別テーブル・別KPIに分離します。
さらに、session_countがないユーザー別レポートではNULLを保持し、オプション配列が省略されても停止しない処理にします。
この設計にしておけば、表示名の変更、新しいAgent Appの追加、28日レポートへの対応があっても、過去データとの継続性を保ちながら安全に利用状況を比較できます。

コメント