こんにちは、エンジニアのkazukitashです。
今回は OpenTelemetryによるAI Agentの監視について紹介します。
AI Agentを運用すると、トークン使用量の急増、レスポンス低下、意図しないモデル呼び出しの連鎖など、従来のログやメトリクスでは捉えにくい課題に直面します。Legalscapeでも独自に監視していますが、標準化されていないためツール連携や運用コストに課題があります。
そこで注目しているのが、2024年から始まったOpenTelemetryの「Generative AI Observability」プロジェクトです。LLM呼び出しをSpan/Event/Metricsとして標準化し、AWS/Azure/OpenAIなどに対応した仕様を策定中で、将来の業界標準になり得ると期待されています。
この記事では、この仕様の解説と、Python(LangChain/LangGraph)での実装例、さらにJaeger/Prometheusによる可視化までを紹介します。
OpenTelemetry の GenAI 標準化の動向
OpenTelemetryとは何か
OpenTelemetryは、CNCF(Cloud Native Computing Foundation)が主導する、アプリケーションの観測性を実現するためのオープンソース標準です。トレース、メトリクス、ログという3つのシグナルを統一的に扱い、異なるベンダーのツール間でデータを相互運用できるようにします。
OpenTelemetryは従来の観測とは異なるモデル呼び出しのコストなどGenAI特有の観測量に対応するため、2024年から「Generative AI Observability」プロジェクトを立ち上げ、GenAI向けのSemantic Conventionsを策定しています。
GenAI Semantic Conventionsの構造
GenAI Semantic Conventionsは、4種類のシグナルで構成されています。
- Traces(トレース):LLM呼び出しのライフサイクルを追跡。リクエストからレスポンスまでの時間、エラーの発生箇所、複数モデル呼び出しの依存関係を可視化
- Metrics(メトリクス):トークン使用量、レイテンシ、スループットなどの集計データを記録。コスト管理やパフォーマンス分析に使用
- Events(イベント):プロンプトやレスポンスの詳細な内容を記録。デバッグや品質評価に活用
- Spans(スパン):モデル操作(Model spans)とエージェント操作(Agent spans)を区別し、それぞれに適した属性を定義
これらのシグナルはgen_ai.*プレフィックスで統一された属性体系になっています。それによりOpenAI、AWS Bedrock、Google Vertex AIなどのベンダー間の互換性を確保しデータ分析の継続性を保てます。
主要な属性
主要な属性は以下の通りです。
| 属性名 | 説明 | 例 |
|---|---|---|
gen_ai.provider.name |
モデル提供元 | openai, aws.bedrock, gcp.vertex_ai |
gen_ai.request.model |
リクエストしたモデル名 | gpt-4, claude-3-opus |
gen_ai.operation.name |
操作タイプ | chat, text_completion, embedding |
gen_ai.usage.input_tokens |
入力トークン数 | 150 |
gen_ai.usage.output_tokens |
出力トークン数 | 430 |
gen_ai.request.temperature |
温度パラメータ | 0.7 |
なお、まだDevelopment段階であるので、これらの属性の最新版を使う場合はOTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental環境変数でオプトインする必要があります。
策定のタイムライン
2023年の9月にissueとして提案されてから2年をかけて、実用可能な規約に成長してきています。
| 時期 | ver. | 主な変更 |
|---|---|---|
| 2023.9 | - | issue #327でLLM観測性向上の提案 |
| 2024.5 | v1.26.0 | 初登場(gen_ai.systemなど) |
| 2024.8 | v1.27.0 | トークン数属性を整理、メトリクス導入 |
| 2024.10 | v1.28.0 | プロンプト/応答をイベント方式に変更 |
| 2025.3 | v1.31.0 | AIエージェント用規約を導入 |
| 2025.8 | v1.37.0 | チャット履歴をgen_ai.input.messages/gen_ai.output.messagesに統一 |
この標準化の背景には、OpenLLMetryというコミュニティ主導の取り組みがあります。Traceloopが推進するOpenLLMetryは、OpenTelemetry上でLLM向けのセマンティック拡張を提案しており、多くの規約がOTel本体に統合されてきました。
OpenLLMetryからOTelへの統合状況
代表的な属性の統合状況をいくつか。
| OpenLLMetryの提案 | OTelでの採用 | ステータス |
|---|---|---|
llm.vendor |
gen_ai.provider.name |
統合済み |
llm.usage.prompt_tokens |
gen_ai.usage.input_tokens |
統合済み |
llm.usage.completion_tokens |
gen_ai.usage.output_tokens |
統合済み |
llm.temperature, llm.top_p |
gen_ai.request.temperature, gen_ai.request.top_p |
統合済み |
traceloop.span.kind (workflow/task/agent) |
- | 議論中(#2664, #2665) |
| ベクトルDB属性 | - | 未定 |
traceloop.span.kind は、エージェント/タスク/アクションの区別を行うための属性です。OTelへの統合が楽しみですね。
自動計装の対応状況
Development段階ということもあり自動計装の対応についてはばらつきがあります。ライブラリ実装はOpenTelemetry公式標準化だけでなくOpenLLMetry@traceloopなど別プロジェクト主導で行われているものも多いのが現状です。
| サービス | ライブラリ | コミュニティ |
|---|---|---|
| OpenAI | opentelemetry-instrumentation-openai-v2 | OpenTelemetry |
| Gemini | opentelemetry-instrumentation-google-generativeai | OpenLLMetry |
| Claude | opentelemetry-instrumentation-anthoropic | OpenLLMetry |
| LlamaIndex | openinference-instrumentation-llama-index | OpenInference |
| Langchain/Langgraph | opentelemetry-instrumentation-langchain | OpenLLMetry |
今後の展望
議論中の領域として、以下のような提案があります。
- エージェント/タスク/アクション属性:issue #2664でタスク・アクション・エージェント・チーム・アーティファクト・メモリの標準化を提案
- 外部ストレージ参照:issue #2753で長文プロンプトをS3/GCSに保存し参照する仕組みを議論
- Reasoning/Chain-of-Thought:PR #2797でモデルの思考過程を区別する提案
これらの議論は、OTel LLM Semantic Conventions WGで行われているようです。標準化の進展を追いたい場合は、このWGの動向をウォッチすると良いと思います。
実装例
実際にOpenTelemetryのGenAI規約を使ったシステムを構築してみます。Python+LangChain/LangGraphでチャットエージェントを実装し、Jaeger/Prometheusで可視化するまでの流れを紹介します。
環境構築
まず、必要なパッケージをインストールします。opentelemetry-instrumentation-langchainを使うことで、LangChain/LangGraphのコードを自動計装できます。
dependencies = [
"langchain>=0.1.0",
"langgraph>=0.2.0",
"opentelemetry-api>=1.37,<1.38",
"opentelemetry-sdk>=1.37,<1.38",
"opentelemetry-instrumentation-langchain>=0.18b0",
"opentelemetry-semantic-conventions>=0.58b0",
"opentelemetry-exporter-otlp>=1.37.0",
]
Jaeger、Prometheusはdocker-composeでまとめて起動します。
services: jaeger: image: jaegertracing/all-in-one:latest ports: - "16686:16686" # Jaeger UI - "4318:4318" # OTLP HTTP receiver environment: - COLLECTOR_OTLP_ENABLED=true prometheus: image: prom/prometheus:latest ports: - "9090:9090" volumes: - ./monitoring/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
OpenTelemetryの設定
次に、OpenTelemetry SDKを初期化します。LangchainInstrumentorを呼び出すだけで、LangChain/LangGraphの全ての操作が自動的に計装されるので、非常に簡単です。
from opentelemetry.instrumentation.langchain import LangchainInstrumentor # OpenTelemetry SDK初期化(TracerProvider、MeterProvider、Exporterの設定) # ... (省略) # LangChainの自動計装 LangchainInstrumentor().instrument( capture_message_content=os.getenv( "OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT", "false" ).lower() == "true", enrich_spans=True, capture_provider_info=os.getenv( "OTEL_INSTRUMENTATION_GENAI_CAPTURE_REQUEST_ATTRIBUTES", "false" ).lower() == "true", )
capture_message_contentをtrueにすると、プロンプトとレスポンスの内容をEventとして記録します。本番環境では個人情報保護のためfalse推奨ですが、開発環境ではデバッグに便利です。
計装の実装
エージェント側のコードは通常通りLangGraphで実装するだけで、自動的にgen_ai.*属性が付与されます。
from langgraph.graph import StateGraph, MessagesState from langchain_openai import ChatOpenAI # LLMインスタンス llm = ChatOpenAI(model="gpt-4") # エージェントの定義(通常通り実装) def chat_agent(state: MessagesState) -> dict: response = llm.invoke(state["messages"]) return {"messages": [response]} # LangGraphのグラフ構築 graph = StateGraph(MessagesState) graph.add_node("agent", chat_agent) # ... (省略)
このコードを実行すると、LangchainInstrumentorが裏で動作し、以下のような処理を自動実行します。
gen_ai.operation.name=chatを持つSpanを生成gen_ai.request.model、gen_ai.response.modelにモデル名を記録gen_ai.usage.input_tokens、gen_ai.usage.output_tokensにトークン数を記録gen_ai_client_operation_duration_seconds_countなどのメトリクスを自動生成
基本的なメトリクスについては手動で実装する必要はなく、自動的に収集してくれます。
可視化
トレースとメトリクスは、それぞれJaeger、Prometheusで確認できます。

Jaeger UIでは、gen_ai.request.temperature、gen_ai.request.model、gen_ai.usage.*などの属性がSpanに記録され、LLM呼び出しの詳細を追跡できます。複数のモデル呼び出しがある場合も、親子関係が可視化されるため、どこで時間がかかっているのか一目で分かります。

Prometheusでは、gen_ai_client_operation_duration_seconds_countなどのメトリクスが自動記録されます。この例では、過去5分間のLLM呼び出し頻度をrate()関数で集計しています。トークン使用量やレイテンシの時系列変化を可視化すれば、パフォーマンス分析やコスト予測が可能になります。
おわりに
OpenTelemetryのGenAI Semantic Conventionsは、まだDevelopment段階ではありますが、LLM運用の標準化に向けた大きな一歩です。ベンダーロックインを避け、複数のツールやプラットフォーム間でデータを共有できるようになれば、AI Agent開発の生産性を向上させると考えています。
Legalscapeでは、この記事で紹介したような最新の技術動向を継続的に追いかけ、実際のプロダクトに取り入れる試みを続けています。そういった試行錯誤を楽しめるエンジニアと一緒に働きたいと考えています。AI Agentの監視はまだ始まったばかりの領域です。もしこの記事を読んで、最先端の技術を追いかけながらプロダクトを作ることに興味を持っていただけたなら、ぜひLegalscapeで一緒に挑戦してみませんか。