OpenTelemetry インスツルメンテーション

This product is not supported for your selected Datadog site. ().

概要

OpenTelemetry の生成 AI 向け標準化セマンティック規約を使用することで、任意の OpenTelemetry 互換ライブラリまたはフレームワークを用いて LLM アプリケーションをインスツルメンテーションし、LLM Observability でトレースを可視化できます。

LLM Observability は、生成 AI 向け OpenTelemetry 1.37+ セマンティック規約に従った OpenTelemetry トレースの取り込みをサポートしています。これにより、Datadog LLM Observability SDK や Datadog Agent を必要とせずに、OpenTelemetry でインスツルメンテーションされたアプリケーションから LLM トレースを Datadog に直接送信できます。

前提条件

OpenTelemetry スパンの外部評価を API に直接送信するには、評価に source:otel タグを含める必要があります。スパンを参照する場合は、 span_id および trace_id を 10 進数文字列として指定してください。OpenTelemetry はネイティブで16進数の ID を使用するため、評価を送信する前に10進数に変換してください。例えば、Python の int(hex_span_id, 16) を使用して、16 進数のスパン ID を10 進数の値に変換します。

OpenTelemetry スパンを使用した Prompt Tracking の詳細については、Prompt Tracking - OpenTelemetry インスツルメンテーションを参照してください。

また、LLM Observability Experiments 内で OpenTelemetry スパンを使用することもできます。 DD_TRACE_OTEL_ENABLED=1を設定することで、実験タスク内で作成された OTel スパンは自動的に実験スパンの子として表示されます。

セットアップ

OpenTelemetry トレースを LLM Observability に送信するには、次の設定で OpenTelemetry エクスポーターを構成してください。

構成

アプリケーションに以下の環境変数を設定します。

OTEL_EXPORTER_OTLP_TRACES_PROTOCOL=http/protobuf
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=
OTEL_EXPORTER_OTLP_TRACES_HEADERS=dd-api-key=<YOUR_API_KEY>,dd-otlp-source=llmobs

<YOUR_API_KEY> をユーザーの Datadog API キーに置き換えます。

フレームワークが以前に 1.37 未満の OpenTelemetry 仕様バージョンをサポートしていた場合は、次の設定も必要です。

OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental

この環境変数は、現在はバージョン 1.37+ のセマンティック規約をサポートしているものの、以前は旧バージョンをサポートしていたフレームワーク (例: strands-agents) 向けに、1.37+ 準拠の OpenTelemetry トレースを有効にします。

:

  • デフォルトの OpenTelemetry SDK 以外の OpenTelemetry ライブラリを使用している場合は、ライブラリの API に応じてエンドポイント、プロトコル、およびヘッダーを異なる方法で設定する必要がある場合があります。適切な設定方法については、ライブラリのドキュメントを参照してください。
  • OpenTelemetry インスツルメンテーションを使用する場合、LLM Observability に送信されるデータの一部は、対応する APM トレースにも書き込まれる場合があります。機密データを保護している場合は、LLM Observability のアクセス制御に一致するように APM で Restricted Dataset を構成することも検討してください。詳細については、データアクセス制御を参照してください。

strands-agents を使用する

strands-agents ライブラリを使用している場合、OpenTelemetry v1.37+ に準拠したトレースを有効にするために追加の環境変数を設定する必要があります。

OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental

この環境変数は、strands-agents が生成 AI 向けの OpenTelemetry v1.37+ セマンティック規約に従ったトレースを出力することを保証します。これは LLM Observability に必要です。

インスツルメンテーション

LLM Observability に互換性のあるトレースを生成するには、次のいずれかを実行してください。

  • OpenTelemetry ライブラリまたは生成 AI 向け OpenTelemetry 1.37+ セマンティック規約に従ってスパンを出力するインスツルメンテーションパッケージを使用してください。
  • セマンティック規約で定義された必要な gen_ai.* 属性を持つスパンを生成するカスタム OpenTelemetry インスツルメンテーションを作成してください。

アプリケーションがデータの送信を開始すると、トレースは自動的に LLM Observability Traces ページに表示されます。UI でトレースを検索するには、ml_app 属性を使用してください。これは自動的に OpenTelemetry ルートスパンの service 属性の値に設定されます。

  • OpenLLMetry バージョン 0.47+ がサポートされています。OpenLLMetry の例をご覧ください。
  • OpenInference はサポートされていません。
  • トレースを送信してから、LLM Observability Traces page に表示されるまでに 3〜5 分の遅延が発生する場合があります。APM が有効になっている場合、トレースは APM Traces page にすぐに表示されます。

テスト済みのフレームワークとライブラリ

これらのフレームワークとライブラリは、Datadog LLM Observability でテストされています。生成 AI 向け OpenTelemetry 1.37+ セマンティック規約に準拠したスパンを発行するフレームワークはすべてサポートされています。

フレームワークインスツルメンテーションサポートされているバージョン
OpenAI@opentelemetry/instrumentation-openai>= 4.19.0
フレームワークインスツルメンテーションサポートされているバージョン
Spring AIネイティブ (Micrometerを通じて)>= 1.0.0
LangChain4jネイティブ (OpenTelemetryモジュール)>= 0.31.0
AWS BedrockOpenTelemetry Java AgentAWS SDK >= 2.2

Strands Agents を使用する

以下の例は、OpenTelemetry インテグレーションを使用した Strands Agents による完全なアプリケーションを示しています。このアプローチは、生成 AI 向け OpenTelemetry バージョン 1.37+ のセマンティック規約をサポートする任意のフレームワークで機能します。

from strands import Agent
from strands_tools import calculator, current_time
from strands.telemetry.config import StrandsTelemetry
import os

# Configure AWS credentials for Bedrock access
os.environ["AWS_PROFILE"] = "<YOUR_AWS_PROFILE>"
os.environ["AWS_DEFAULT_REGION"] = "<YOUR_AWS_REGION>"

# Enable latest GenAI semantic conventions (1.37)
os.environ["OTEL_SEMCONV_STABILITY_OPT_IN"] = "gen_ai_latest_experimental"

# Configure OTLP endpoint to send traces to Datadog LLM Observability
os.environ["OTEL_EXPORTER_OTLP_TRACES_PROTOCOL"] = "http/protobuf"
os.environ["OTEL_EXPORTER_OTLP_TRACES_ENDPOINT"] = ""
os.environ["OTEL_EXPORTER_OTLP_TRACES_HEADERS"] = f"dd-api-key={os.getenv('DD_API_KEY')},dd-otlp-source=llmobs"

# Initialize telemetry with OTLP exporter
telemetry = StrandsTelemetry()
telemetry.setup_otlp_exporter()

# Create agent with tools
agent = Agent(tools=[calculator, current_time])

# Run the agent
if __name__ == "__main__":
    result = agent("I was born in 1993, what is my age?")
    print(f"Agent: {result}")

カスタム OpenTelemetry インスツルメンテーション

以下の例は、カスタム OpenTelemetry コードを使用して LLM アプリケーションをインスツルメンテーションする方法を示しています。このアプローチにより、アプリケーションが出力するトレースとスパンを完全に制御できます。

import os
import json
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.resources import Resource, SERVICE_NAME
from openai import OpenAI

# Configure OpenTelemetry to send traces to Datadog
os.environ["OTEL_EXPORTER_OTLP_TRACES_ENDPOINT"] = ""
os.environ["OTEL_EXPORTER_OTLP_TRACES_HEADERS"] = "dd-api-key=<YOUR_DATADOG_API_KEY>,dd-otlp-source=llmobs"
os.environ["OTEL_SEMCONV_STABILITY_OPT_IN"] = "gen_ai_latest_experimental"

# Initialize OpenTelemetry SDK
resource = Resource(attributes={SERVICE_NAME: "simple-llm-example"})
provider = TracerProvider(resource=resource)
provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter()))
trace.set_tracer_provider(provider)

tracer = trace.get_tracer(__name__)

# Make LLM call with OpenTelemetry tracing
with tracer.start_as_current_span(
    "chat gpt-4o",
    kind=trace.SpanKind.CLIENT,
) as span:
    model = "gpt-4o"
    max_tokens = 1024
    temperature = 0.7
    messages = [{"role": "user", "content": "Explain OpenTelemetry in one sentence."}]

    # Set request attributes
    span.set_attribute("gen_ai.provider.name", "openai")
    span.set_attribute("gen_ai.request.model", model)
    span.set_attribute("gen_ai.operation.name", "chat")
    span.set_attribute("gen_ai.request.max_tokens", max_tokens)
    span.set_attribute("gen_ai.request.temperature", temperature)

    # Add input messages as event
    input_messages_parts = []
    for msg in messages:
        input_messages_parts.append({
            "role": msg["role"],
            "parts": [{"type": "text", "content": msg["content"]}]
        })

    span.add_event(
        "gen_ai.client.inference.operation.details",
        {
            "gen_ai.input.messages": json.dumps(input_messages_parts)
        }
    )

    # Make actual LLM call
    client = OpenAI(api_key="<YOUR_OPENAI_API_KEY>")
    response = client.chat.completions.create(
        model=model,
        max_tokens=max_tokens,
        temperature=temperature,
        messages=messages
    )

    # Set response attributes from actual data
    span.set_attribute("gen_ai.response.id", response.id)
    span.set_attribute("gen_ai.response.model", response.model)
    span.set_attribute("gen_ai.response.finish_reasons", [response.choices[0].finish_reason])
    span.set_attribute("gen_ai.usage.input_tokens", response.usage.prompt_tokens)
    span.set_attribute("gen_ai.usage.output_tokens", response.usage.completion_tokens)

    # Add output messages as event
    output_text = response.choices[0].message.content
    span.add_event(
        "gen_ai.client.inference.operation.details",
        {
            "gen_ai.output.messages": json.dumps([{
                "role": "assistant",
                "parts": [{"type": "text", "content": output_text}],
                "finish_reason": response.choices[0].finish_reason
            }])
        }
    )

    print(f"Response: {output_text}")

# Flush spans before exit
provider.force_flush()

この例を実行した後、生成されたトレースを見つけるために LLM Observability UI で ml_app:simple-llm-example を検索してください。

OpenLLMetry を使用する

以下の例は、OpenLLMetry を使用して OpenTelemetry により OpenAI 呼び出しを自動的にインスツルメンテーションする方法を示しています。

from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.instrumentation.openai import OpenAIInstrumentor
import openai
from opentelemetry.sdk.resources import Resource

resource = Resource.create({
    "service.name": "simple-openllmetry-test",
})

provider = TracerProvider(resource=resource)
trace.set_tracer_provider(provider)

exporter = OTLPSpanExporter(
    endpoint="",
    headers={
        "dd-api-key": "<YOUR_DATADOG_API_KEY>",
        "dd-ml-app": "simple-openllmetry-test",
        "dd-otlp-source": "llmobs",
    },
)

provider.add_span_processor(BatchSpanProcessor(exporter))

OpenAIInstrumentor().instrument()

# Make OpenAI call (automatically traced)
client = openai.OpenAI(api_key="<YOUR_OPENAI_API_KEY>")
client.chat.completions.create(
    model="gpt-3.5-turbo",
    messages=[{"role": "user", "content": "What is 15 multiplied by 7?"}]
)

provider.force_flush(timeout_millis=5000)

この例を実行した後、生成されたトレースを見つけるために LLM Observability UI で ml_app:simple-openllmetry-test を検索してください。

属性マッピングリファレンス

このセクションでは、OpenTelemetry GenAI セマンティック規約 (v1.37+) および OpenLLMetry から Datadog の LLM Observability スパンスキーマへのマッピングを提供します。

OpenLLMetry 特有のマッピングは、OpenLLMetry attribute mappings セクションに別途文書化されています。

OpenTelemetry 1.37+ 属性マッピング

ベーススパン属性

OTLP フィールドLLM Observability フィールドメモ
resource.attributes.service.nameml_apptags.service
namename存在する場合は gen_ai.tool.name によって上書きされます
parent_span_idparent_id
start_time_unix_nanostart_ns
end_time_unix_nanoduration計算: end - start
0 より大きい場合status.codestatus
status.messagemeta.error.message
attributes.error.typemeta.error.type

スパン種別の解決

gen_ai.operation.nameLLM Observability span.kind
generate_contentchattext_completioncompletionllm
embeddingsembeddingembedding
execute_tooltool
invoke_agentcreate_agentagent
rerankunknown(デフォルト)workflow

モデル情報

OTel 属性LLM Observability フィールドメモ
gen_ai.operation.namemeta.span.kind上記の解決表を参照してください
gen_ai.provider.namemeta.model_providergen_ai.system にフォールバックし、その後 custom
gen_ai.response.modelmeta.model_name
gen_ai.request.modelmeta.model_nameresponse.model が存在しない場合のフォールバック

トークン使用量メトリクス

OTel 属性LLM Observability フィールド
gen_ai.usage.input_tokensmetrics.input_tokens
gen_ai.usage.output_tokensmetrics.output_tokens
gen_ai.usage.prompt_tokensmetrics.prompt_tokens
gen_ai.usage.completion_tokensmetrics.completion_tokens
gen_ai.usage.total_tokensmetrics.total_tokens

リクエストパラメーター

すべての gen_ai.request.* パラメーターは、プレフィックスが削除された meta.metadata.* にマッピングされます。

OTel 属性LLM Observability フィールド
gen_ai.request.seedmetadata.seed
gen_ai.request.frequency_penaltymetadata.frequency_penalty
gen_ai.request.max_tokensmetadata.max_tokens
gen_ai.request.stop_sequencesmetadata.stop_sequences
gen_ai.request.temperaturemetadata.temperature
gen_ai.request.top_kmetadata.top_k
gen_ai.request.top_pmetadata.top_p
gen_ai.request.choice.countmetadata.choice.count

ツール属性

OTel 属性LLM Observability フィールドメモ
gen_ai.tool.namenameスパン名を上書きします
gen_ai.tool.call.idmetadata.tool_id
gen_ai.tool.descriptionmetadata.tool_description
gen_ai.tool.typemetadata.tool_type
gen_ai.tool.definitionsmeta.tool_definitions解析された JSON 配列
gen_ai.tool.call.argumentsinput.value
gen_ai.tool.call.resultoutput.value

セッションと会話

OTel 属性LLM Observability フィールドメモ
gen_ai.conversation.idsession_idまた、metadata.conversation_id とタグにも追加されます

レスポンス属性

OTel 属性LLM Observability フィールド
gen_ai.response.modelmeta.model_name
gen_ai.response.finish_reasonsmetadata.finish_reasons

入力および出力メッセージ

入力および出力メッセージは、以下のソースから優先順位順に抽出されます。

  1. 直接属性: gen_ai.input.messagesgen_ai.output.messagesgen_ai.system_instructions
  2. 名前が gen_ai.client.inference.operation.details のスパンイベント (meta["events"])
OTel ソースLLM Observability フィールドメモ
gen_ai.input.messagesmeta.input.messages (llm) / meta.input.value (その他)
gen_ai.output.messagesmeta.output.messages (llm) / meta.output.value (その他)
gen_ai.system_instructions入力の先頭に追加されますシステムロールメッセージとして追加されます
埋め込みスパン
OTel ソースLLM Observability フィールド
gen_ai.input.messagesmeta.input.documents
N/Ameta.output.value = [N embedding(s) returned]

タグ

タグはスパンに直接配置されます。

  • gen_ai.* 属性は key:value タグに変換されます
  • 不明な gen_ai.* キーは、プレフィックスを削除して追加されます
  • フィルタリング対象外: _dd.*llm.*ddtagsevents、およびすでに特定的にマッピングされた gen_ai.* キー
LLM Observability のスパンフィールドに明示的にマッピングされていないすべての gen_ai.* 属性は、LLM スパンのタグに格納され、各値は 256 文字の制限があります。この制限を超える値は切り詰められます。すべてのその他の非gen_ai 属性は破棄されます。

OpenLLMetry 属性マッピング

このセクションでは、標準の OpenTelemetry GenAI セマンティック規約と異なる、またはそれを拡張する OpenLLMetry 特有の属性マッピングについて説明します。

スパン種別の解決

llm.request.typegen_ai.operation.name が存在しない場合のフォールバックとして使用されます。

llm.request.typeLLM Observability span.kind
chatllm
completionllm
embeddingembedding
rerankworkflow
unknown(デフォルト)workflow

モデル情報

OpenLLMetry 属性LLM Observability フィールドメモ
gen_ai.systemmeta.model_providergen_ai.provider.name が存在しない場合のフォールバック

トークン使用量メトリクス

OpenLLMetry 属性LLM Observability フィールドメモ
llm.usage.total_tokensmetrics.total_tokensgen_ai.usage.total_tokens が存在しない場合のフォールバック

入力および出力メッセージ

OpenLLMetry は、JSON 配列の代わりにインデックス付き属性を使用します。これらは最も優先度の低いソースであり、OTel の標準ソースが存在しない場合にのみ使用されます。

プロンプト属性 (入力)
OpenLLMetry 属性説明
gen_ai.prompt.<index>.roleメッセージロール (user、system、assistant、tool)
gen_ai.prompt.<index>.contentメッセージ内容
gen_ai.prompt.<index>.tool_call_idツール応答メッセージのツール呼び出し ID
完了属性 (出力)
OpenLLMetry 属性説明
gen_ai.completion.<index>.roleメッセージロール
gen_ai.completion.<index>.contentメッセージ内容
gen_ai.completion.<index>.finish_reason完了終了理由
マッピング

メッセージは OTel 互換フォーマットに変換され、通常通り処理されます。

OpenLLMetry ソースLLMObs フィールド
gen_ai.prompt.*meta.input.messages (llm) / meta.input.value (その他)
gen_ai.completion.*meta.output.messages (llm) / meta.output.value (その他)

ツール呼び出し

ツール呼び出しは完了属性内にネストされます。

OpenLLMetry 属性マッピング先
gen_ai.completion.<index>.tool_calls.<idx>.nametool_calls[].name
gen_ai.completion.<index>.tool_calls.<idx>.idtool_calls[].tool_id
gen_ai.completion.<index>.tool_calls.<idx>.argumentstool_calls[].arguments
ツール応答メッセージ

role = "tool"tool_call_id が存在する場合、メッセージはツールの結果に変換されます。

OpenLLMetry 属性マッピング先
gen_ai.prompt.<index>.tool_call_idtool_results[].tool_id
gen_ai.prompt.<index>.contenttool_results[].result

埋め込みスパン

埋め込みスパンの場合、ドキュメントはプロンプトコンテンツ属性から抽出されます。

OpenLLMetry ソースLLM Observability フィールド
gen_ai.prompt.<index>.contentmeta.input.documents[].text

タグのフィルタリング

以下の OpenLLMetry 特有の属性は、タグからフィルタリングされます。

  • gen_ai.prompt.*
  • gen_ai.completion.*
  • llm.*

サポートされているセマンティック規約

LLM Observability は、生成 AI 向け OpenTelemetry 1.37+ セマンティック規約に従うスパンをサポートしています。具体的には以下のとおりです。

  • LLM 操作は gen_ai.provider.name"gen_ai.operation.name"gen_ai.request.model、およびその他の gen_ai 属性を含みます。
  • 直接スパン属性またはスパンイベントを介した操作の入力および出力
  • トークン使用量メトリクス (gen_ai.usage.input_tokensgen_ai.usage.output_tokens)
  • モデルパラメーターおよびメタデータ

サポートされている属性とその仕様の完全な一覧については、生成 AI 向け OpenTelemetry セマンティック規約ドキュメントを参照してください。

LLM Observability 変換の無効化

生成 AI スパンを APM に残し、LLM Observability に表示させたくない場合は、dd_llmobs_enabled 属性を false に設定することで自動変換を無効にできます。トレース内の任意のスパンにこの属性を設定すると、トレース全体が LLM Observability に変換されるのを防ぎます。

環境変数の使用

dd_llmobs_enabled=false 属性を OTEL_RESOURCE_ATTRIBUTES 環境変数に追加してください。

OTEL_RESOURCE_ATTRIBUTES=dd_llmobs_enabled=false

コードの使用

トレース内の任意のスパンに属性をプログラムで設定することもできます。

from opentelemetry import trace

tracer = trace.get_tracer(__name__)

with tracer.start_as_current_span("my-span") as span:
    # Disable LLM Observability conversion for this entire trace
    span.set_attribute("dd_llmobs_enabled", False)