Nullstead

AIエージェント

2026年版 AIエージェント観測性入門:MCPとOpenTelemetryでデバッグ地獄を抜ける実践設計

AIエージェントが本番に入ると、失敗原因の追跡が一気に難しくなります。本記事ではMCP、OpenTelemetry、Cloudflare Workersの最新情報を踏まえ、個人開発でも運用できる観測性設計を具体的なコード付きで解説します。

約11分

はじめに:エージェントは賢い、でも障害報告書は書いてくれない

AIエージェントを開発していると、最初はかなり気持ちよく進みます。デモではスイスイ動きますし、スクリーンショットも映えます。ところが本番運用を始めると、急に現実が顔を出します。

「なぜこのツール呼び出しは遅かったのか」 「なぜ同じ質問で結果が変わったのか」 「そもそもどのMCPサーバーがボトルネックなのか」

このあたりが追えないと、開発者の心拍数だけが観測可能になります。しかも高頻度です。

この記事では、2026年時点の公開情報をもとに、AIエージェント運用で効く観測性設計をまとめます。特に次の3点をつなげて扱います。

  • MCP ※Model Context Protocol。LLMと外部ツールを標準化してつなぐ仕組み
  • OpenTelemetry ※分散トレーシングの標準仕様
  • Cloudflare Workers などの実行基盤でのトレース収集

私は「すごい理想論」より「夜中2時に障害対応できる具体策」を重視したいので、実装寄りで進めます。

2026年の前提整理:なぜ今、観測性が急に重要になったのか

2026年は、エージェントが単なる補助機能から、実際に作業を進める実行主体に寄ってきた年です。

例えばGitHubは2026年3月のChangelogで、Copilot code reviewがエージェント的なツール呼び出しアーキテクチャに移行したことを案内しています。要するに「AIが周辺コンテキストを取りに行ってレビューする」方向が本格化しています。さらにGitHub CLIからCopilotレビューを直接要求できる更新も出ていて、開発フローへの組み込みが一段深くなりました。

一方で、モデルとツールをつなぐMCPも急速に普及しました。MCP公式リポジトリは仕様とスキーマを公開しており、実装間の相互運用が進みやすい状態です。便利になったぶん、通信経路も増えます。

そして観測性側では、OpenTelemetryがGenerative AI向けのセマンティック規約を整備中で、モデル呼び出しだけでなくエージェント操作やMCPにも視野を広げています。標準化の流れがあるので、最初からログ項目を合わせておく価値が高いです。

まとめると、2026年の現場はこうです。

  • エージェントは複数ツールをまたいで仕事をする
  • レビューや運用の自動化が実務に入ってきた
  • 標準化は進んでいるが、設計を間違えると調査が難しい

つまり、観測性は「後で足すもの」ではなく「最初に設計するもの」です。

設計原則:とりあえず全部ログ、はコストと混乱を呼ぶ

まず大事なのは、記録する粒度を決めることです。全部を無差別に保存すると、

  • コストが上がる
  • ノイズで重要イベントが埋もれる
  • 個人情報や機密情報の漏えいリスクが増える

という三重苦になります。

私のおすすめは、次の4階層を分けて設計する方法です。

  1. セッション単位
  • 1つのユーザー依頼や1つのジョブ実行に対応
  • session_id、user_type、entrypointを持つ
  1. トレース単位
  • 1回のエージェント実行全体
  • trace_idを必ず採番し、再実行時は関連IDで束ねる
  1. スパン単位
  • モデル推論、ツール呼び出し、MCPサーバー往復などの区間
  • 開始時刻、終了時刻、成否、エラー分類を記録
  1. イベント単位
  • リトライ、タイムアウト、フォールバック発動など
  • 重要な意思決定ポイントを明示

OpenAI Agents SDKのtracing機能は、LLM生成、ツール呼び出し、handoff、guardrailなどを標準で記録できるとドキュメントにあります。まずはSDKの標準トレースを基準にし、足りないイベントだけ自前で追加するのが現実的です。

MCPを使うときの観測ポイント:成功率より原因分離を重視する

MCPは便利ですが、障害時は責任境界があいまいになりがちです。MCP公式のSecurity Best Practicesでも、認可フローやプロキシ構成に関する注意点が細かく書かれています。観測設計でも、境界を明確にしておくと事故対応が速くなります。

最低限、次の属性はログに残したいです。

  • mcp.server_name
  • mcp.tool_name
  • mcp.request_size_bytes
  • mcp.response_size_bytes
  • mcp.latency_ms
  • auth.mode ※OAuth、token、internalなど
  • auth.subject_type ※human、service、agent
  • result.status ※ok、timeout、rate_limited、auth_error、validation_error

ここで重要なのは、エラーを一種類の「失敗」にしないことです。例えばrate_limitedとauth_errorは対応手順が全く違います。前者は待機や分散制御で改善できますが、後者は権限設定ミスなので即時修正が必要です。

また、MCPサーバーを複数使う場合は「どのサーバーが遅いか」だけでなく、「どのサーバーで再試行が増えているか」を見ます。遅延より先に、リトライ雪だるまがコストを燃やすことが多いからです。

OpenTelemetryでそろえる:将来の移行コストを今つぶす

OpenTelemetryのGenAI向けセマンティック規約は開発ステータスですが、モデル、イベント、メトリクス、エージェントスパンの切り分けが整理されています。ここに寄せると、将来ツールを乗り換えるときに痛みが減ります。

実装のコツは「理想の完全準拠を待たない」ことです。以下のように段階導入します。

  • 第1段階:trace_idとspan_idを全処理に付ける
  • 第2段階:モデル呼び出しとMCP呼び出しに共通属性キーを付ける
  • 第3段階:サンプリング率を調整し、重要ワークフローは高めにする

Cloudflare Workersのtraces機能は、設定で有効化するとfetchや各種binding呼び出しを追跡できます。さらにOpenTelemetry準拠で外部連携しやすい設計になっているので、軽量構成でも始めやすいです。

wrangler設定例は次の通りです。

# wrangler.toml
[observability]
enabled = true

[observability.traces]
enabled = true
head_sampling_rate = 0.1

※head_sampling_rateは0.1なら10パーセント収集です。高トラフィック環境では最初から100パーセントにしない方が安全です。

実装サンプル:エージェント実行にトレース文脈を通す

ここではPythonの擬似実装を示します。動作未検証ですが、設計意図はそのまま使えます。

import time
import uuid
from contextlib import contextmanager


def now_ms() -> int:
    return int(time.time() * 1000)


@contextmanager
def span(name: str, attrs: dict):
    start = now_ms()
    span_id = str(uuid.uuid4())
    try:
        print({"event": "span_start", "name": name, "span_id": span_id, "attrs": attrs, "ts": start})
        yield span_id
        end = now_ms()
        print({"event": "span_end", "name": name, "span_id": span_id, "status": "ok", "duration_ms": end - start, "ts": end})
    except Exception as e:
        end = now_ms()
        print({"event": "span_end", "name": name, "span_id": span_id, "status": "error", "error_type": type(e).__name__, "duration_ms": end - start, "ts": end})
        raise


def run_agent(task: str, mcp_server: str):
    trace_id = f"trace_{uuid.uuid4()}"
    with span("agent.run", {"trace_id": trace_id, "task_type": "automation"}):
        with span("llm.generation", {"trace_id": trace_id, "model": "gpt-family"}):
            time.sleep(0.2)

        with span("mcp.call", {
            "trace_id": trace_id,
            "mcp.server_name": mcp_server,
            "mcp.tool_name": "search_docs"
        }):
            time.sleep(0.1)

        with span("tool.execute", {"trace_id": trace_id, "tool": "shell"}):
            time.sleep(0.05)

    return {"trace_id": trace_id, "status": "ok"}

ポイントは、どの層でもtrace_idを必ず持つことです。これが無いと、ダッシュボードで「多分これが同じ処理かな」という推理ゲームが始まります。推理小説は読む分には最高ですが、障害対応でやると胃にきます。

運用の現実解:アラートは少なく、復旧手順は多めに

観測できるようになったら、次は運用です。ここでありがちな失敗は「アラートを増やして安心する」ことです。実際は通知だけ増えて、誰も見なくなります。

個人開発や少人数チームなら、次の3種類だけ先に作ると回りやすいです。

  1. 重大失敗アラート
  • 例:mcp.callのauth_errorが5分で3回以上
  1. 速度劣化アラート
  • 例:p95のmcp.latency_msが通常比2倍以上
  1. コスト異常アラート
  • 例:トークン使用量やツール呼び出し回数が急増

さらに、アラートごとに復旧プレイブックを1ページで作ります。

  • 何を見るか
  • どこで切り分けるか
  • まず止血する手順
  • 恒久対策の候補

Datadog MCP Serverのドキュメントでは、MCP関連の利用状況を監査証跡やメトリクスで追える旨が示されています。こういう監査情報は、あとで効いてきます。障害調査だけでなく、権限事故や不審アクセスの追跡にも使えるからです。

セキュリティとプライバシー:観測は強力、だからこそ最小化

観測性を入れると、つい「プロンプト全文も全部保存しよう」となりがちです。気持ちは分かります。未来の自分を助けたいのです。でも情報を持つほど、漏えい時の破壊力も上がります。

MCPのセキュリティガイドでも、認可と同意の扱いに関するリスクが強調されています。観測データにも同じ原則を適用しましょう。

  • 機密情報は収集前にマスキング
  • 個人情報はハッシュ化または削除
  • 保存期間を明示し、目的外利用を防ぐ
  • デバッグ権限を最小に分ける

運用では「見えること」と「見せてよいこと」を分離します。デバッグで便利だからという理由で、全員が全ログを見られる構成にしないことです。

まとめ:エージェント時代の差は、モデル性能より調査速度でつく

2026年の開発は、モデル選定だけで勝てる時代ではありません。むしろ、問題が起きたときにどれだけ速く原因へ到達できるかで、開発速度が決まります。

本記事の要点を短くまとめます。

  • MCP時代は責任境界をログ属性で明確化する
  • OpenTelemetryに寄せて将来の移行コストを下げる
  • Cloudflare Workersなど基盤のトレース機能を先に使う
  • アラート数より復旧プレイブックの品質を上げる
  • 観測データは最小化して安全に扱う

私自身、以前は「まず作ってから見る」で走って、後で大量のログに埋もれました。あの時の私に一言だけ言えるなら、「最初にtrace_idを通しておけ」です。これだけで未来の自分がかなり救われます。

エージェントは便利です。だからこそ、便利さを本番で維持するために観測性を先に作っておく。地味ですが、ここが長く勝つための土台になります。

参考リンク

Tags #AIエージェント #MCP #OpenTelemetry #Cloudflare Workers #Observability