ふくふくHukuhuku Inc.
EP.04Eng Dash 11分公開: 2026-05-10

OpenAI / Gemini / 自社 LLM:複数プロバイダの usage を統合する

OpenAI、Google Gemini、Azure OpenAI、AWS Bedrock、self-hosted LLM ── プロバイダごとの usage API はバラバラ。統一スキーマで取り込み、横断比較ダッシュにまとめる実装。

#OpenAI#Gemini#Bedrock#コスト統合
CO📔 Google Colab で開く(上から順にセルを実行)
シェア

現実の現場では だけでなく OpenAI / Gemini / OpenAI / Bedrock / 自社 が混在します。各プロバイダの usage はバラバラなので、統一スキーマで取り込んで横断比較 できるようにします。

プロバイダ別 usage 取得

プロバイダAPI粒度
OpenAI`/v1/usage`日次・モデル別
Anthropic`/v1/organizations/usage_report/messages`日次・key 別・モデル別
Google Gemini ( Studio)Cloud Billing API + Vertex AIプロジェクト別・モデル別
Azure OpenAICost Management APIリソース別
AWS BedrockCost Explorer + CloudWatchリソース別
self-hosted (vLLM 等)OpenTelemetry / 自前メトリクス個別実装

統一スキーマ

BigQuery / Snowflake の統合テーブル設計
YAML
# llm_usage 統合テーブルcolumns:  - timestamp        # UTC  - provider         # "anthropic" | "openai" | "gemini" | "azure_oai" | "bedrock" | "self_hosted"  - model            # "claude-opus-4-7" | "gpt-5" | "gemini-2-flash" 等  - api_key_id       # 個人/用途識別子(プロバイダ非依存)  - person           # マッピング後の個人 ID  - team             # チーム  - input_tokens  - output_tokens  - cache_read_tokens   # 0 if not supported  - cache_creation_tokens  - cost_usd         # プロバイダの単価で計算  - request_count  - latency_p50_ms   # 任意  - latency_p99_ms   # 任意

OpenAI usage 取得

OpenAI の Usage API
Python
import os, requests
OPENAI_KEY = os.environ["OPENAI_API_KEY"]
def fetch_openai_usage(date_str: str) -> dict:    """日次の usage(admin key required)"""    r = requests.get(        "https://api.openai.com/v1/organization/usage/completions",        headers={"Authorization": f"Bearer {OPENAI_KEY}"},        params={"start_time": int(date_str_to_epoch(date_str)),                "bucket_width": "1d", "group_by": ["api_key_id", "model"]},    )    return r.json()

: 各プロバイダ → 統合テーブル

プロバイダごとの adapter で統合形式に
Python
from dataclasses import dataclassfrom datetime import datetime
@dataclassclass UsageRow:    timestamp: datetime    provider: str    model: str    api_key_id: str    input_tokens: int    output_tokens: int    cache_read_tokens: int = 0    cache_creation_tokens: int = 0    request_count: int = 0
def normalize_anthropic(raw: dict) -> list[UsageRow]:    """Anthropic レスポンス → UsageRow"""    rows = []    for bucket in raw["data"]:        ts = datetime.fromisoformat(bucket["starting_at"].replace("Z", "+00:00"))        for r in bucket["results"]:            rows.append(UsageRow(                timestamp=ts, provider="anthropic", model=r["model"],                api_key_id=r["api_key_id"],                input_tokens=r["uncached_input_tokens"],                output_tokens=r["output_tokens"],                cache_read_tokens=r.get("cache_read_input_tokens", 0),                cache_creation_tokens=r.get("cache_creation_input_tokens", 0),            ))    return rows
def normalize_openai(raw: dict) -> list[UsageRow]:    # ... OpenAI 用の adapter    pass
# 全プロバイダから取り込みall_rows = []all_rows.extend(normalize_anthropic(get_anthropic_usage(...)))all_rows.extend(normalize_openai(fetch_openai_usage(...)))# ... 他
# BigQuery / Snowflake へ insertload_to_dwh(all_rows)

ダッシュ設計の核

  • プロバイダ別の費用比率: 「Claude が 60%、OpenAI が 30%、Gemini が 10%」のような円グラフ
  • モデル別の費用効率: 同じユースケースで OpenAI と Anthropic を比較
  • 個人別の利用パターン: 「Aさんは Claude Opus 中心、Bさんは Gemini Flash 中心」が見える
  • 自社 LLM の比率: コスト削減のためのオンプレ比率
  • 異常検知: 1 人が 1 日に通常の 10 倍消費したらアラート

次の話

EP.05 では CI/CD のコスト ── Actions / Vercel / CircleCI の使用量を扱います。

シェア

この記事の感想を教えてください

あなたの 1 クリックで、本当にこの記事は更新されます。「もっと詳しく」「続編希望」が一定数集まった記事は、 ふくふくが 実際に内容を拡充したり続編記事を公開 します。 送信したリアクションはお使いのブラウザに記録され、再カウントされません。

シリーズの外も探す:

まずは、現状を聞かせてください。

要件が固まっていなくて大丈夫です。現状診断と方針提案までを無料でお手伝いします。

無料相談フォームへ hello [at] hukuhuku [dot] co [dot] jp