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

概要

Agent Observability SDK は、LLM アプリケーションの可観測性とインサイトを提供するために、自動インスツルメンテーションおよび手動インスツルメンテーション API を提供します。

セットアップ

要件

  • 最新の ddtrace パッケージがインストールされていること (Python 3.7 以降が必要です)。
    pip install ddtrace
    
  • 最新の dd-trace パッケージがインストールされていること (Node.js 16 以降が必要です)。
    npm install dd-trace
    
  • 最新の dd-trace-java JAR をダウンロード済みであること。Agent Observability SDK は dd-trace-java v1.51.0 以降でサポートされています (Java 8 以降が必要です)。

ddtrace-run コマンドを使用してアプリケーションを実行し、必要な環境変数を指定することで、Agent Observability を有効にします。

注: ddtrace-run は、すべての Agent Observability インテグレーションを自動的に有効にします。

DD_SITE=<YOUR_DATADOG_SITE> DD_API_KEY=<YOUR_API_KEY> DD_LLMOBS_ENABLED=1 \
DD_LLMOBS_ML_APP=<YOUR_ML_APP_NAME> ddtrace-run <YOUR_APP_STARTUP_COMMAND>

コマンドラインセットアップ用の環境変数

DD_SITE
必須 - 文字列
LLM データ送信先の Datadog サイト。使用するサイトは です。
DD_LLMOBS_ENABLED
必須 - 整数または文字列
Agent Observability へのデータ送信を有効にするための切り替えスイッチ。1 または true に設定する必要があります。
DD_LLMOBS_ML_APP
オプション - 文字列
すべてのトレースとスパンがグループ化される、LLM アプリケーション、サービス、またはプロジェクトの名前。これは、異なるアプリケーションや実験を区別するのに役立ちます。使用可能な文字やその他の制約については、アプリケーション命名ガイドラインを参照してください。特定のルートスパンに対してこの値を上書きするには、複数のアプリケーションのトレースを参照してください。指定しない場合、DD_SERVICE の値、またはアップストリームサービスから伝播された DD_LLMOBS_ML_APP の値がデフォルトで使用されます。
注: バージョン ddtrace==3.14.0 より前では、これは必須フィールドです。
DD_LLMOBS_AGENTLESS_ENABLED
オプション - 整数または文字列 - デフォルト: false
Datadog Agent を使用していない場合にのみ必要です。その場合は、1 または true に設定する必要があります。
DD_LLMOBS_SAMPLE_RATE
オプション - 浮動小数点数 - デフォルト: 1.0
Agent Observability によって保持されるトレースの割合。トレースサンプリングを参照してください。
DD_API_KEY
オプション - 文字列
Datadog API キー。Datadog Agent を使用していない場合にのみ必要です。
DD_MCP_CAPTURE_INTENT
オプション - 整数または文字列 - デフォルト: false
1 または true に設定すると、呼び出し元のモデルに対してツールを呼び出した理由を説明するよう要求する引数がすべての MCP サーバーツールに追加されます。インテントはツールのスパンに記録されます。

アプリケーションを NODE_OPTIONS="--import dd-trace/initialize.mjs" で実行し、必要な環境変数を指定することで、Agent Observability を有効にします。

注: dd-trace/initialize.mjs は、すべての APM インテグレーションを自動的に有効にします。

DD_SITE=<YOUR_DATADOG_SITE> DD_API_KEY=<YOUR_API_KEY> DD_LLMOBS_ENABLED=1 \
DD_LLMOBS_ML_APP=<YOUR_ML_APP_NAME> NODE_OPTIONS="--import dd-trace/initialize.mjs" node <YOUR_APP_ENTRYPOINT>

コマンドラインセットアップ用の環境変数

DD_SITE
必須 - 文字列
LLM データを送信する Datadog サイト。使用するサイトは です。
DD_LLMOBS_ENABLED
必須 - 整数または文字列
Agent Observability へのデータ送信を有効にするための切り替えスイッチ。1 または true に設定する必要があります。
DD_LLMOBS_ML_APP
オプション - 文字列
すべてのトレースとスパンがグループ化される、LLM アプリケーション、サービス、またはプロジェクトの名前。これは、異なるアプリケーションや実験を区別するのに役立ちます。使用可能な文字やその他の制約については、アプリケーション命名ガイドラインを参照してください。特定のルートスパンに対してこの値を上書きするには、複数のアプリケーションのトレースを参照してください。指定しない場合、DD_SERVICE の値、またはアップストリームサービスから伝播された DD_LLMOBS_ML_APP の値がデフォルトで使用されます。
注: バージョン dd-trace@5.66.0 より前では、これは必須フィールドです。
DD_LLMOBS_AGENTLESS_ENABLED
オプション - 整数または文字列 - デフォルト: false
Datadog Agent を使用していない場合にのみ必要です。その場合は、1 または true に設定する必要があります。
DD_LLMOBS_SAMPLE_RATE
オプション - 浮動小数点数 - デフォルト: 1.0
Agent Observability によって保持されるトレースの割合。トレースサンプリングを参照してください。
DD_API_KEY
オプション - 文字列
Datadog API キー。Datadog Agent を使用していない場合にのみ必要です。

Agent Observability を有効にするには、dd-trace-java を使用してアプリケーションを実行し、必要なパラメーターを環境変数またはシステムプロパティとして指定します。

DD_SITE=<YOUR_DATADOG_SITE> DD_API_KEY=<YOUR_API_KEY> \
java -javaagent:path/to/your/dd-trace-java-jar/dd-java-agent-SNAPSHOT.jar \
-Ddd.service=my-app -Ddd.llmobs.enabled=true -Ddd.llmobs.ml.app=my-ml-app -jar path/to/your/app.jar

環境変数とシステムプロパティ

次のパラメーターを環境変数 (たとえば、DD_LLMOBS_ENABLED) または Java システムプロパティ (たとえば、dd.llmobs_enabled) として指定できます。

DD_SITEまたは dd.site
必須 - 文字列
LLM データ送信先の Datadog サイト。使用するサイトは です。
DD_LLMOBS_ENABLED または dd.llmobs.enabled
必須 - 整数または文字列
Agent Observability へのデータ送信を有効にするための切り替えスイッチ。1 または true に設定する必要があります。
DD_LLMOBS_ML_APPまたは dd.llmobs.ml.app
オプション - 文字列
すべてのトレースとスパンがグループ化される、LLM アプリケーション、サービス、またはプロジェクトの名前。これは、異なるアプリケーションや実験を区別するのに役立ちます。使用可能な文字やその他の制約については、アプリケーション命名ガイドラインを参照してください。特定のルートスパンに対してこの値を上書きするには、複数のアプリケーションのトレースを参照してください。指定しない場合、DD_SERVICE の値、またはアップストリームサービスから伝播された DD_LLMOBS_ML_APP の値がデフォルトで使用されます。
注: dd-trace-java のバージョン 1.54.0 より前では、これは必須フィールドです。
DD_LLMOBS_AGENTLESS_ENABLEDまたは dd.llmobs.agentless.enabled
オプション - 整数または文字列 - デフォルト: false
Datadog Agent を使用していない場合にのみ必要です。その場合は、1 または true に設定する必要があります。
DD_LLMOBS_SAMPLE_RATEまたは dd.llmobs.sample.rate
オプション - 浮動小数点数 - デフォルト: 1.0
Agent Observability によって保持されるトレースの割合。dd-trace-java 1.66.0 以降が必要です。トレースサンプリングを参照してください。
DD_API_KEYまたは dd.api.key
オプション - 文字列
Datadog API キー。Datadog Agent を使用していない場合にのみ必要です。

コマンドラインのセットアップを使用する代わりに、プログラムにより Agent Observability を有効にすることもできます。

LLMObs.enable() 関数を使用して Agent Observability を有効にします。

このセットアップ方法を ddtrace-run コマンドと一緒に使用しないでください。
from ddtrace.llmobs import LLMObs
LLMObs.enable(
  ml_app="<YOUR_ML_APP_NAME>",
  api_key="<YOUR_DATADOG_API_KEY>",
  site="<YOUR_DATADOG_SITE>",
  agentless_enabled=True,
)
パラメーター
ml_app
オプション - 文字列
すべてのトレースとスパンがグループ化される、LLM アプリケーション、サービス、またはプロジェクトの名前。これは、異なるアプリケーションや実験を区別するのに役立ちます。使用可能な文字やその他の制約については、アプリケーション命名ガイドラインを参照してください。特定のトレースに対してこの値をオーバーライドするには、複数アプリケーションのトレースを参照してください。指定しない場合、DD_LLMOBS_ML_APP の値がデフォルト設定されます。
integrations_enabled- デフォルト: true
オプション - boolean
Datadog がサポートする LLM インテグレーション のために、LLM 呼び出しの自動追跡を有効化するフラグです。指定しない場合、サポートされているすべての LLM インテグレーションがデフォルトで有効になります。LLM インテグレーションを使用しないようにするには、この値を false に設定してください。
agentless_enabled
オプション - boolean - デフォルト: false
Datadog Agent を使用していない場合のみ必要で、その場合はこれを True に設定する必要があります。これは、ddtrace ライブラリにより、Datadog Agent を必要とするデータが送信されないように設定します。指定しない場合、DD_LLMOBS_AGENTLESS_ENABLED の値がデフォルト設定されます。
site
オプション - 文字列
LLM データを送信する Datadog サイト。使用するサイトは 指定しない場合、DD_SITE の値がデフォルト設定されます。
api_key
オプション - 文字列
Datadog API キー。Datadog Agent を使用していない場合にのみ必要です。指定しない場合、DD_API_KEY の値がデフォルト設定されます。
env
オプション - 文字列
アプリケーションの環境の名前 (例: prod、pre-prod、staging)。指定しない場合、DD_ENV の値がデフォルト設定されます。
service
オプション - 文字列
アプリケーションで使用されるサービスの名前。指定しない場合、DD_SERVICE の値がデフォルト設定されます。
sample_rate
オプション - 浮動小数点数
Agent Observability によって保持されるトレースの割合。ddtrace 4.12.0 以降が必要です。この設定は、DD_LLMOBS_SAMPLE_RATE よりも優先されます。トレースサンプリングを参照してください。
capture_intent
オプション - Boolean - デフォルト: false
True に設定すると、呼び出し元のモデルに対してツールを呼び出した理由を説明するよう要求する引数がすべての MCP サーバーツールに追加されます。インテントはツールのスパンに記録されます。指定しない場合、DD_MCP_CAPTURE_INTENT の値がデフォルト設定されます。
このセットアップ方法を dd-trace/initialize.mjs コマンドと一緒に使用しないでください。

init() 関数を使用して Agent Observability を有効にします。

const tracer = require('dd-trace').init({
  llmobs: {
    mlApp: "<YOUR_ML_APP_NAME>",
    agentlessEnabled: true,
  },
  site: "<YOUR_DATADOG_SITE>",
  env: "<YOUR_ENV>",
});

const llmobs = tracer.llmobs;

llmobs 構成のオプション

mlApp
オプション - 文字列
すべてのトレースとスパンがグループ化される、LLM アプリケーション、サービス、またはプロジェクトの名前。これは、異なるアプリケーションや実験を区別するのに役立ちます。使用可能な文字やその他の制約については、アプリケーション命名ガイドラインを参照してください。特定のトレースに対してこの値をオーバーライドするには、複数アプリケーションのトレースを参照してください。指定しない場合、DD_LLMOBS_ML_APP の値がデフォルト設定されます。
agentlessEnabled
オプション - boolean - デフォルト: false
Datadog Agent を使用していない場合のみ必要で、その場合はこれを true に設定する必要があります。これは、dd-trace ライブラリにより、Datadog Agent を必要とするデータが送信されないように設定します。指定しない場合、DD_LLMOBS_AGENTLESS_ENABLED の値がデフォルト設定されます。
sampleRate
オプション - 数値
Agent Observability によって保持されるトレースの割合。dd-trace 5.110.0 以降が必要です。この設定は、DD_LLMOBS_SAMPLE_RATE よりも優先されます。トレースサンプリングを参照してください。

一般的なトレーサー設定のオプション:

site
オプション - 文字列
LLM データを送信する Datadog サイト。使用するサイトは 指定しない場合、DD_SITE の値がデフォルト設定されます。
env
オプション - 文字列
アプリケーションの環境の名前 (例: prod、pre-prod、staging)。指定しない場合、DD_ENV の値がデフォルト設定されます。
service
オプション - 文字列
アプリケーションで使用されるサービスの名前。指定しない場合、DD_SERVICE の値がデフォルト設定されます。
環境変数

次の値を環境変数として設定してください。プログラムにより設定することはできません。

DD_API_KEY
オプション - 文字列
Datadog API キー。Datadog Agent を使用していない場合にのみ必要です。

AWS Lambda については、Trace an LLM Application in AWS Lambda を参照してください。

SDK をインストールしてアプリケーションを実行すると、自動インスツルメンテーションによって Agent Observability にデータが表示されるはずです。手動インスツルメンテーションを使用して、まだサポートされていないカスタムビルドのフレームワークやライブラリの操作をキャプチャできます。

トレースのサンプリング

トレースのサンプリングは、Python SDK (ddtrace 4.12.0 以降)、Node.js SDK(dd-trace 5.110.0 以降)、Java SDK(dd-trace-java 1.66.0 以降)。

トレースのサンプリングは、Agent Observability が保持するトレースの割合を設定します。Agent Observability の課金は送信するスパンの量に基づいているため、サンプルレートの設定は Agent Observability のコストを制御する 1 つの方法です。SDK はルートスパンでサンプリングの決定を行い、分散型トレーシングを通じてダウンストリームサービスで作成されたスパンを含む、そのルートスパンのすべての子スパンに適用します。

サンプリングは、Agent Observability メトリクスには、トークンおよびコストメトリクスやその他の運用メトリクスを含めて、影響しません。サンプリングされていないスパンは Datadog がトレースを取り込んだ後に破棄されるため、これらのメトリクスは指定されたサンプルレートに関係なく、アプリケーションのインスツルメンテーションされたトラフィックの 100% に基づいたままとなります。トレースのサンプリングは、取り込み後に適用される 自動化ルール や APM トレースのサンプリング などのアプリ内コントロールからも独立しています。

サンプルレートは、以下のいずれかの方法で設定できます。

  • 環境変数 (DD_LLMOBS_SAMPLE_RATE): は、コマンドラインのセットアップ と コード内でのセットアップ の両方に適用されます。Java では、dd.llmobs.sample.rate システムプロパティで同じ値を設定します。
  • コード内パラメーター (sample_rate in Python, sampleRate in Node.js): は、Python では LLMObs.enable() に、Node.js では llmobs の下で渡され、コード内でのセットアップで SDK を有効化する際に使用されます。この設定は、DD_LLMOBS_SAMPLE_RATE よりも優先されます。Java SDK にはコード内の同等の機能はありません。

サンプルレートは、0.0 (トレースを一切保持しない) から 1.0 (すべてのトレースを保持する) までの浮動小数点数です。デフォルトは 1.0 です。範囲外の値は無視されます。

環境変数でサンプルレートを設定してください:

DD_LLMOBS_SAMPLE_RATE=0.5 ddtrace-run <YOUR_APP_STARTUP_COMMAND>

または、環境変数よりも優先される sample_rate を LLMObs.enable() に渡してください:

from ddtrace.llmobs import LLMObs

LLMObs.enable(
  ml_app="<YOUR_ML_APP_NAME>",
  sample_rate=0.5,
)

環境変数でサンプルレートを設定してください:

DD_LLMOBS_SAMPLE_RATE=0.5 NODE_OPTIONS="--import dd-trace/initialize.mjs" <YOUR_APP_STARTUP_COMMAND>

または、環境変数よりも優先される sampleRate を llmobs の下で init() に渡してください。

const tracer = require('dd-trace').init({
  llmobs: {
    mlApp: "<YOUR_ML_APP_NAME>",
    sampleRate: 0.5,
  },
});

const llmobs = tracer.llmobs;

環境変数でサンプルレートを設定してください:

DD_LLMOBS_SAMPLE_RATE=0.5 \
java -javaagent:path/to/your/dd-trace-java-jar/dd-java-agent-SNAPSHOT.jar \
-Ddd.service=my-app -Ddd.llmobs.enabled=true -Ddd.llmobs.ml.app=<YOUR_ML_APP_NAME> \
-jar path/to/your/app.jar

または、同等の dd.llmobs.sample.rate システムプロパティを設定してください:

java -javaagent:path/to/your/dd-trace-java-jar/dd-java-agent-SNAPSHOT.jar \
-Ddd.service=my-app -Ddd.llmobs.enabled=true -Ddd.llmobs.ml.app=<YOUR_ML_APP_NAME> \
-Ddd.llmobs.sample.rate=0.5 -jar path/to/your/app.jar

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

LLM 操作をキャプチャするために、関数デコレータを使用してワークフローを簡単にインスツルメントすることができます。

from ddtrace.llmobs.decorators import workflow

@workflow
def handle_user_request():
    ...

または、細かい操作をキャプチャするためのコンテキストマネージャーベースのアプローチ:

from ddtrace.llmobs import LLMObs

with LLMObs.llm(model="gpt-4o"):
    call_llm()
    LLMObs.annotate(
        metrics={
            "input_tokens": ...,
            "output_tokens": ...,
        },
    )

利用可能なスパンの種類のリストについては、スパンの種類のドキュメントを参照してください。関数内の操作をより詳細にトレースする方法については、インラインメソッドを使用したスパンのトレースを参照してください。

スパンをトレースするには、トレースしたい関数の関数ラッパーとして llmobs.wrap(options, function) を使用します。利用可能なスパンの種類のリストについては、スパンの種類のドキュメントを参照してください。関数内の操作をより詳細にトレースする方法については、インラインメソッドを使用したスパンのトレースを参照してください。

スパンの種類

スパンの種類は必須であり、llmobs トレース関数 (trace、wrap、および decorate) に渡される options オブジェクトに指定します。サポートされているスパンの種類のリストについては、スパンの種類のドキュメント を参照してください。

注: 無効なスパンの種類を持つスパンは、Agent Observability に送信されません。

自動関数引数/出力/名前キャプチャ

llmobs.wrap (TypeScript の場合は llmobs.decorate も) では、トレースされている関数の入力、出力、および名前を自動的にキャプチャしようとします。スパンに手動でアノテーションを付ける必要がある場合は、スパンの強化を参照してください。アノテーションを付けた入力と出力により、自動キャプチャがオーバーライドされます。さらに、関数名をオーバーライドするには、オプションオブジェクトの name プロパティを llmobs.wrap 関数に渡します。

function processMessage () {
  ... // user application logic
  return
}
processMessage = llmobs.wrap({ kind: 'workflow', name: 'differentFunctionName' }, processMessage)

ラップされた関数のスパンを終了する条件

llmobs.wrap は、tracer.wrap の基本的な動作を拡張します。関数が呼び出されたときに作成される基本的なスパンは、次の条件で終了します。

  • 関数が Promise を返す場合、スパンは Promise が解決または拒否されたときに終了します。
  • 関数が最後のパラメーターとしてコールバックを受け取る場合、スパンはそのコールバックが呼び出されたときに終了します。
  • 関数がコールバックを受け取らず、Promise を返さない場合、スパンは関数実行の終了時に終了します。

次の例は、最後の引数がコールバックである 2 番目の条件を示しています。

例

const express = require('express')
const app = express()

function myAgentMiddleware (req, res, next) {
  const err = ... // user application logic
  // the span for this function is finished when `next` is called
  next(err)
}
myAgentMiddleware = llmobs.wrap({ kind: 'agent' }, myAgentMiddleware)

app.use(myAgentMiddleware)

アプリケーションがコールバック関数を使用しない場合は、代わりにインラインでトレースされたブロックを使用することをお勧めします。詳細については、インラインメソッドを使用したトレースのスパンを参照してください。

const express = require('express')
const app = express()

function myAgentMiddleware (req, res) {
  // the `next` callback is not being used here
  return llmobs.trace({ kind: 'agent', name: 'myAgentMiddleware' }, () => {
    return res.status(200).send('Hello World!')
  })
}

app.use(myAgentMiddleware)

スパンの開始

開始するスパンの種類に基づいて、複数の方法でスパンを開始することができます。サポートされているスパンの種類のリストについては、スパンの種類のドキュメント を参照してください。

すべてのスパンは、LLMObsSpan のオブジェクトインスタンスとして開始されます。各スパンには、スパンとやり取りし、データを記録するためのメソッドがあります。

スパンの終了

トレースを送信し、Datadog アプリで表示するためには、スパンを終了する必要があります。

スパンを終了するには、スパンオブジェクトインスタンスで finish() を呼び出します。可能であれば、例外が発生した場合でもスパンが送信されるように、スパンを try/finally ブロックでラップしてください。

例

    try {
        LLMObsSpan workflowSpan = LLMObs.startWorkflowSpan("my-workflow-span-name", "ml-app-override", "session-141");
        // user logic
        // interact with started span
    } finally {
      workflowSpan.finish();
    }

LLM 呼び出し

LLM プロバイダーや、Datadog の LLM インテグレーションによってサポートされているフレームワークを使用している場合、これらの操作をトレースするために LLM スパンを手動で開始する必要はありません。
LLM スパンを手動でインスツルメントする場合は、スパンにアノテーションを付けて、トークン数 ( input_tokens,output_tokens、および total_tokens) を自分で記録する必要があります。詳細については、スパンの強化を参照してください。

LLM 呼び出しをトレースするには、関数デコレータ ddtrace.llmobs.decorators.llm() を使用します。

model_name
必須 - 文字列
呼び出された LLM の名前。
name
オプション - 文字列
操作の名前。指定されていない場合、name はデフォルトでトレースされた関数の名前に設定されます。
model_provider
オプション - 文字列 - デフォルト: "custom"
モデルプロバイダーの名前。
注: 米ドルでの推定コストを表示するには、model_provider を次のいずれかの値に設定してください: openai、azure_openai、または anthropic。
session_id
オプション - 文字列
基盤となるユーザーセッションの ID。詳細については、ユーザーセッションの追跡を参照してください。
ml_app
オプション - 文字列
操作が属する ML アプリケーションの名前。詳細については、複数のアプリケーションのトレースを参照してください。

例

from ddtrace.llmobs import LLMObs
from ddtrace.llmobs.decorators import llm

@llm(model_name="claude", name="invoke_llm", model_provider="anthropic")
def llm_call(prompt):
    completion = ... # user application logic to invoke LLM
    LLMObs.annotate(
        input_data=[{"role": "user", "content": prompt}],
        output_data=[{"role": "assistant", "content": completion}],
        metrics={"input_tokens": 4, "output_tokens": 6, "total_tokens": 10},
    )
    return completion

LLM 呼び出しをトレースするには、スパンの種類を llm と指定し、必要に応じてオプションオブジェクトに次の引数を指定します。

modelName
オプション - 文字列 - デフォルト: "custom"
呼び出された LLM の名前。
name
オプション - 文字列
操作の名前。指定されていない場合、name はデフォルトでトレースされた関数の名前に設定されます。
modelProvider
オプション - 文字列 - デフォルト: "custom"
モデルプロバイダーの名前。
注: 米ドルでの推定コストを表示するには、modelProvider を次のいずれかの値に設定してください: openai、azure_openai、または anthropic。
sessionId
オプション - 文字列
基盤となるユーザーセッションの ID。詳細については、ユーザーセッションの追跡を参照してください。
mlApp
オプション - 文字列
操作が属する ML アプリケーションの名前。詳細については、複数のアプリケーションのトレースを参照してください。

例

function llmCall (prompt) {
  const completion = ... // user application logic to invoke LLM
  llmobs.annotate({
    inputData: [{ role: "user", content: prompt }],
    outputData: [{ role: "assistant", content: completion }],
    metrics: { input_tokens: 4, output_tokens: 6, total_tokens: 10 }
  })
  return completion
}
llmCall = llmobs.wrap({ kind: 'llm', name: 'invokeLLM', modelName: 'claude', modelProvider: 'anthropic' }, llmCall)

LLM 呼び出しをトレースするには、次のメソッドをインポートして、次の引数を指定して呼び出します。

import datadog.trace.api.llmobs.LLMObs;
LLMObs.startLLMSpan(spanName, modelName, modelProvider, mlApp, sessionID);
spanName
オプション - 文字列
操作の名前。指定されていない場合、spanName はデフォルトでスパンの種類に設定されます。
modelName
オプション - 文字列 - デフォルト: "custom"
呼び出された LLM の名前。
modelProvider
オプション - 文字列 - デフォルト: "custom"
モデルプロバイダーの名前。
注: 米ドルでの推定コストを表示するには、modelProvider を次のいずれかの値に設定してください: openai、azure_openai、または anthropic。
mlApp
オプション - 文字列
操作が属する ML アプリケーションの名前。非 null の値を指定すると、アプリケーションの開始時に指定された ML アプリ名がオーバーライドされます。詳細については、複数のアプリケーションのトレースを参照してください。
sessionId
オプション - 文字列
基盤となるユーザーセッションの ID。詳細については、ユーザーセッションの追跡を参照してください。

例

import datadog.trace.api.llmobs.LLMObs;

public class MyJavaClass {
  public String invokeModel() {
    LLMObsSpan llmSpan = LLMObs.startLLMSpan("my-llm-span-name", "my-llm-model", "my-company", "maybe-ml-app-override", "session-141");
    String inference = ... // user application logic to invoke LLM
    llmSpan.annotateIO(...); // record the input and output
    llmSpan.setMetrics(Map.of(
      "input_tokens", 617,
      "output_tokens", 338,
      "total_tokens", 955
    ));
    llmSpan.finish();
    return inference;
  }
}

ワークフロー

ワークフローのスパンをトレースするには、関数デコレータ ddtrace.llmobs.decorators.workflow() を使用します。

name
オプション - 文字列
操作の名前。指定されていない場合、name はデフォルトでトレースされた関数の名前に設定されます。
session_id
オプション - 文字列
基盤となるユーザーセッションの ID。詳細については、ユーザーセッションの追跡を参照してください。
ml_app
オプション - 文字列
操作が属する ML アプリケーションの名前。詳細については、複数のアプリケーションのトレースを参照してください。

例

from ddtrace.llmobs.decorators import workflow

@workflow
def process_message():
    ... # user application logic
    return

ワークフローのスパンをトレースするには、スパンの種類を workflow と指定し、必要に応じてオプションオブジェクトに引数を指定します。

name
オプション - 文字列
操作の名前。指定されていない場合、name はデフォルトでトレースされた関数の名前に設定されます。
sessionId
オプション - 文字列
基盤となるユーザーセッションの ID。詳細については、ユーザーセッションの追跡を参照してください。
mlApp
オプション - 文字列
操作が属する ML アプリケーションの名前。詳細については、複数のアプリケーションのトレースを参照してください。

例

function processMessage () {
  ... // user application logic
  return
}
processMessage = llmobs.wrap({ kind: 'workflow' }, processMessage)

ワークフローのスパンをトレースするには、次のメソッドをインポートして、次の引数を指定して呼び出します。

import datadog.trace.api.llmobs.LLMObs;
LLMObs.startWorkflowSpan(spanName, mlApp, sessionID);
spanName
オプション - 文字列
操作の名前。指定されていない場合、spanName はデフォルトでスパンの種類に設定されます。
mlApp
オプション - 文字列
操作が属する ML アプリケーションの名前。非 null の値を指定すると、アプリケーションの開始時に指定された ML アプリ名がオーバーライドされます。詳細については、複数のアプリケーションのトレースを参照してください。
sessionId
オプション - 文字列
基盤となるユーザーセッションの ID。詳細については、ユーザーセッションの追跡を参照してください。

例

import datadog.trace.api.llmobs.LLMObs;

public class MyJavaClass {
  public String executeWorkflow() {
    LLMObsSpan workflowSpan = LLMObs.startWorkflowSpan("my-workflow-span-name", null, "session-141");
    String workflowResult = workflowFn(); // user application logic
    workflowSpan.annotateIO(...); // record the input and output
    workflowSpan.finish();
    return workflowResult;
  }
}

エージェント

エージェントの実行をトレースするには、関数デコレータ ddtrace.llmobs.decorators.agent() を使用します。

name
オプション - 文字列
操作の名前。指定されていない場合、name はデフォルトでトレースされた関数の名前に設定されます。
session_id
オプション - 文字列
基盤となるユーザーセッションの ID。詳細については、ユーザーセッションの追跡を参照してください。
ml_app
オプション - 文字列
操作が属する ML アプリケーションの名前。詳細については、複数のアプリケーションのトレースを参照してください。

例

from ddtrace.llmobs.decorators import agent

@agent
def react_agent():
    ... # user application logic
    return

エージェントの実行をトレースするには、スパンの種類を agent と指定し、必要に応じてオプションオブジェクトに引数を指定します。

name
オプション - 文字列
操作の名前。指定されていない場合、name はデフォルトでトレースされた関数の名前に設定されます。
sessionId
オプション - 文字列
基盤となるユーザーセッションの ID。詳細については、ユーザーセッションの追跡を参照してください。
mlApp
オプション - 文字列
操作が属する ML アプリケーションの名前。詳細については、複数のアプリケーションのトレースを参照してください。

例

function reactAgent () {
  ... // user application logic
  return
}
reactAgent = llmobs.wrap({ kind: 'agent' }, reactAgent)

エージェントの実行をトレースするには、次のメソッドをインポートして、次の引数を指定して呼び出します。

import datadog.trace.api.llmobs.LLMObs;
LLMObs.startAgentSpan(spanName, mlApp, sessionID);
spanName
オプション - 文字列
操作の名前。指定されていない場合、spanName はデフォルトでトレースされた関数の名前に設定されます。
mlApp
オプション - 文字列
操作が属する ML アプリケーションの名前。非 null の値を指定すると、アプリケーションの開始時に指定された ML アプリ名がオーバーライドされます。詳細については、複数のアプリケーションのトレースを参照してください。
sessionId
オプション - 文字列
基盤となるユーザーセッションの ID。詳細については、ユーザーセッションの追跡を参照してください。

ツール呼び出し

ツール呼び出しをトレースするには、関数デコレータ ddtrace.llmobs.decorators.tool() を使用します。

name
オプション - 文字列
操作の名前。指定されていない場合、name はデフォルトでトレースされた関数の名前に設定されます。
session_id
オプション - 文字列
基盤となるユーザーセッションの ID。詳細については、ユーザーセッションの追跡を参照してください。
ml_app
オプション - 文字列
操作が属する ML アプリケーションの名前。詳細については、複数のアプリケーションのトレースを参照してください。

例

from ddtrace.llmobs.decorators import tool

@tool
def call_weather_api():
    ... # user application logic
    return

ツール呼び出しをトレースするには、スパンの種類を tool と指定し、必要に応じてオプションオブジェクトに引数を指定します。

name
オプション - 文字列
操作の名前。指定されていない場合、name はデフォルトでトレースされた関数の名前に設定されます。
sessionId
オプション - 文字列
基盤となるユーザーセッションの ID。詳細については、ユーザーセッションの追跡を参照してください。
mlApp
オプション - 文字列
操作が属する ML アプリケーションの名前。詳細については、複数のアプリケーションのトレースを参照してください。

例

function callWeatherApi () {
  ... // user application logic
  return
}
callWeatherApi = llmobs.wrap({ kind: 'tool' }, callWeatherApi)

ツール呼び出しをトレースするには、次のメソッドをインポートし、次の引数を指定して呼び出します。

import datadog.trace.api.llmobs.LLMObs;
LLMObs.startToolSpan(spanName, mlApp, sessionID);
spanName
オプション - 文字列
操作の名前。指定されていない場合、spanName はデフォルトでトレースされた関数の名前に設定されます。
mlApp
オプション - 文字列
操作が属する ML アプリケーションの名前。非 null の値を指定すると、アプリケーションの開始時に指定された ML アプリ名がオーバーライドされます。詳細については、複数のアプリケーションのトレースを参照してください。
sessionId
オプション - 文字列
基盤となるユーザーセッションの ID。詳細については、ユーザーセッションの追跡を参照してください。

タスク

タスクのスパンをトレースするには、関数デコレータ LLMObs.task() を使用します。

name
オプション - 文字列
操作の名前。指定されていない場合、name はデフォルトでトレースされた関数の名前に設定されます。
session_id
オプション - 文字列
基盤となるユーザーセッションの ID。詳細については、ユーザーセッションの追跡を参照してください。
ml_app
オプション - 文字列
操作が属する ML アプリケーションの名前。詳細については、複数のアプリケーションのトレースを参照してください。

例

from ddtrace.llmobs.decorators import task

@task
def sanitize_input():
    ... # user application logic
    return

タスクスパンをトレースするには、スパンの種類を task と指定し、必要に応じてオプションオブジェクトに引数を指定します。

name
オプション - 文字列
操作の名前。指定されていない場合、name はデフォルトでトレースされた関数の名前に設定されます。
sessionId
オプション - 文字列
基盤となるユーザーセッションの ID。詳細については、ユーザーセッションの追跡を参照してください。
mlApp
オプション - 文字列
操作が属する ML アプリケーションの名前。詳細については、複数のアプリケーションのトレースを参照してください。

例

function sanitizeInput () {
  ... // user application logic
  return
}
sanitizeInput = llmobs.wrap({ kind: 'task' }, sanitizeInput)

タスクスパンをトレースするには、次のメソッドをインポートし、次の引数を指定して呼び出します。

import datadog.trace.api.llmobs.LLMObs;
LLMObs.startTaskSpan(spanName, mlApp, sessionID);
spanName
オプション - 文字列
操作の名前。指定されていない場合、spanName はデフォルトでトレースされた関数の名前に設定されます。
mlApp
オプション - 文字列
操作が属する ML アプリケーションの名前。非 null の値を指定すると、アプリケーションの開始時に指定された ML アプリ名がオーバーライドされます。詳細については、複数のアプリケーションのトレースを参照してください。
sessionId
オプション - 文字列
基盤となるユーザーセッションの ID。詳細については、ユーザーセッションの追跡を参照してください。

埋め込み

埋め込み操作をトレースするには、関数デコレータ LLMObs.embedding() を使用します。

注: 埋め込みスパンの入力のアノテーションを付けるには、ほかのスパンタイプとは異なるフォーマットが必要です。埋め込み入力を指定する方法の詳細については、スパンの強化を参照してください。

model_name
必須 - 文字列
呼び出された LLM の名前。
name
オプション - 文字列
操作の名前。指定されていない場合、name はトレースされた関数の名前に設定されます。
model_provider
オプション - 文字列 - デフォルト: "custom"
session_id
オプション - 文字列
基盤となるユーザーセッションの ID。詳細については、ユーザーセッションの追跡を参照してください。
ml_app
オプション - 文字列
操作が属する ML アプリケーションの名前。詳細については、複数のアプリケーションのトレースを参照してください。

例

from ddtrace.llmobs.decorators import embedding

@embedding(model_name="text-embedding-3", model_provider="openai")
def perform_embedding():
    ... # user application logic
    return

埋め込み操作をトレースするには、スパンの種類を embedding と指定し、必要に応じてオプションオブジェクトに引数を指定します。

注: 埋め込みスパンの入力のアノテーションを付けるには、ほかのスパンタイプとは異なるフォーマットが必要です。埋め込み入力を指定する方法の詳細については、スパンの強化を参照してください。

modelName
オプション - 文字列 - デフォルト: "custom"
呼び出された LLM の名前。
name
オプション - 文字列
操作の名前。指定されていない場合、name はトレースされた関数の名前に設定されます。
modelProvider
オプション - 文字列 - デフォルト: "custom"
モデルプロバイダーの名前。
sessionId
オプション - 文字列
基盤となるユーザーセッションの ID。詳細については、ユーザーセッションの追跡を参照してください。
mlApp
オプション - 文字列
操作が属する ML アプリケーションの名前。詳細については、複数のアプリケーションのトレースを参照してください。

例

function performEmbedding () {
  ... // user application logic
  return
}
performEmbedding = llmobs.wrap({ kind: 'embedding', modelName: 'text-embedding-3', modelProvider: 'openai' }, performEmbedding)

取得

取得スパンをトレースするには、関数デコレータ ddtrace.llmobs.decorators.retrieval() を使用します。

注: 取得スパンの出力のアノテーションを付けるには、ほかのスパンタイプとは異なるフォーマットが必要です。取得出力を指定する方法の詳細については、スパンの強化を参照してください。

name
オプション - 文字列
操作の名前。指定されていない場合、name はデフォルトでトレースされた関数の名前に設定されます。
session_id
オプション - 文字列
基盤となるユーザーセッションの ID。詳細については、ユーザーセッションの追跡を参照してください。
ml_app
オプション - 文字列
操作が属する ML アプリケーションの名前。詳細については、複数のアプリケーションのトレースを参照してください。

例

from ddtrace.llmobs.decorators import retrieval

@retrieval
def get_relevant_docs(question):
    context_documents = ... # user application logic
    LLMObs.annotate(
        input_data=question,
        output_data = [
            {"id": doc.id, "score": doc.score, "text": doc.text, "name": doc.name} for doc in context_documents
        ]
    )
    return

取得スパンをトレースするには、スパンの種類を retrieval と指定し、必要に応じてオプションオブジェクトに次の引数を指定します。

注: 取得スパンの出力のアノテーションを付けるには、ほかのスパンタイプとは異なるフォーマットが必要です。取得出力を指定する方法の詳細については、スパンの強化を参照してください。

name
オプション - 文字列
操作の名前。指定されていない場合、name はデフォルトでトレースされた関数の名前に設定されます。
sessionId
オプション - 文字列
基盤となるユーザーセッションの ID。詳細については、ユーザーセッションの追跡を参照してください。
mlApp
オプション - 文字列
操作が属する ML アプリケーションの名前。詳細については、複数のアプリケーションのトレースを参照してください。

例

ここには、スパンにアノテーションを付ける例も含まれています。詳細については、スパンの強化を参照してください。

function getRelevantDocs (question) {
  const contextDocuments = ... // user application logic
  llmobs.annotate({
    inputData: question,
    outputData: contextDocuments.map(doc => ({
      id: doc.id,
      score: doc.score,
      text: doc.text,
      name: doc.name
    }))
  })
  return
}
getRelevantDocs = llmobs.wrap({ kind: 'retrieval' }, getRelevantDocs)

スパンのネスト

現在のスパンが終了する前に新しいスパンを開始すると、2 つのスパンの間にある親子関係が自動的にトレースされます。親スパンは大きな操作を表し、子スパンはその中の小さなネストされたサブ操作を表します。

from ddtrace.llmobs.decorators import task, workflow

@workflow
def extract_data(document):
    preprocess_document(document)
    ... # performs data extraction on the document
    return

@task
def preprocess_document(document):
    ... # preprocesses a document for data extraction
    return
function preprocessDocument (document) {
  ... // preprocesses a document for data extraction
  return
}
preprocessDocument = llmobs.wrap({ kind: 'task' }, preprocessDocument)

function extractData (document) {
  preprocessDocument(document)
  ... // performs data extraction on the document
  return
}
extractData = llmobs.wrap({ kind: 'workflow' }, extractData)
import datadog.trace.api.llmobs.LLMObs;
import datadog.trace.api.llmobs.LLMObsSpan;

public class MyJavaClass {
  public void preprocessDocument(String document) {
  LLMObsSpan taskSpan = LLMObs.startTaskSpan("preprocessDocument", null, "session-141");
   ...   // preprocess document for data extraction
   taskSpan.annotateIO(...); // record the input and output
   taskSpan.finish();
  }

  public String extractData(String document) {
    LLMObsSpan workflowSpan = LLMObs.startWorkflowSpan("extractData", null, "session-141");
    preprocessDocument(document);
    ... // perform data extraction on the document
    workflowSpan.annotateIO(...); // record the input and output
    workflowSpan.finish();
  }
}

スパンの強化

このページの metrics パラメーターは、個々のスパンに属性として付加された数値を指します。Datadog プラットフォームメトリクスではありません。認識された特定のキー ( input_tokens,output_tokens、および total_tokensなど) に対し、Datadog はこれらのスパン属性を使用して、対応するプラットフォームメトリクス ( ml_obs.span.llm.input.tokensなど) をダッシュボードやモニターで使用するために生成します。

SDK には、入力、出力、およびメタデータでスパンを強化するための LLMObs.annotate() メソッドが用意されています。

LLMObs.annotate() メソッドは次の引数を受け付けます。

span
オプション - スパン - デフォルト: 現在のアクティブなスパン
アノテーションを付けるスパン。span が指定されていない場合 (関数デコレータを使用する場合など)、SDK は現在のアクティブなスパンにアノテーションを付けます。
input_data
オプション - JSON のシリアライズ可能な型、または辞書のリスト
JSON のシリアライズ可能な型 (非 LLM スパン用) または次の形式の辞書のリスト : {"content": "...", "role": "...", "tool_calls": ..., "tool_results": ..., "audio_parts": ..., "image_parts": ...}。ここで "tool_calls" は、必須キー "name"、"arguments" とオプションのキー "tool_id"、"type" を持つ呼び出し辞書のオプションのリストであり、"tool_results" は、必須キー "result" と、関数呼び出しシナリオ用のオプションのキー "name"、"tool_id"、"type" を持つツール結果辞書のオプションのリストです。"audio_parts" および "image_parts" は、マルチモーダルスパン用のメディア辞書のオプションのリストであり、それぞれに必須の "mime_type" と "content" (インラインで埋め込まれた base64 エンコードメディア) が必要です。注: 埋め込みスパンは特別なケースであり、{"text": "..."} という形式の文字列または辞書 (または辞書のリスト) が必要です。
output_data
オプション - JSON のシリアライズ可能な型、または辞書のリスト
JSON のシリアライズ可能な型 (非 LLM スパン用) または {"content": "...", "role": "...", "tool_calls": ..., "audio_parts": ..., "image_parts": ...} という形式の辞書のリスト。ここで "tool_calls" は、必須キー "name"、"arguments" と、関数呼び出しシナリオ用のオプションのキー "tool_id"、"type" を持つツール呼び出し辞書のオプションのリストです。"audio_parts" および "image_parts" は、マルチモーダルスパン用のメディア辞書のオプションのリストであり、それぞれに必須の "mime_type" と "content" (インラインで埋め込まれた base64 エンコードメディア) が必要です。注: 取得スパンは特別なケースであり、{"text": "...", "name": "...", "score": float, "id": "..."} という形式の文字列または辞書 (または辞書のリスト) が必要です。
tool_definitions
オプション - 辞書のリスト
関数呼び出しシナリオ用のツール定義辞書のリスト。各ツール定義には、必須の "name": "..." キーとオプションの "description": "..." および "schema": {...} キーが必要です。
metadata
オプション - 辞書
スパンで記述された入力または出力操作に関連するメタデータ情報としてユーザーが追加できる、JSON のシリアライズ可能なキーと値のペアの辞書です (model_temperature、max_tokens、top_k など)。
metrics
オプション - 辞書
スパンで記述された操作に関連するメトリクスとしてユーザーが追加できる、JSON のシリアライズ可能なキーと数値の辞書です (input_tokens、output_tokens、total_tokens、time_to_first_token など)。time_to_first_token の単位は秒であり、デフォルトで出力される duration メトリクスと同様です。
tags
オプション - 辞書
ユーザーがタグとしてスパンに追加できる、JSON のシリアライズ可能なキーと値のペアの辞書です。キーの例: session、env、system、および version。タグの詳細については、タグの概要を参照してください。
cost_tags
オプション - 文字列のリスト
生成された LLM コストおよびトークンメトリクスにカスタムタグとして伝播するタグキーのリスト (tags で設定済み、または同じスパンに以前にアノテーションされたもの)。既存のタグキーを参照していないエントリはスキップされます。詳細については、コストモニタリングを参照してください。

例

from ddtrace.llmobs import LLMObs
from ddtrace.llmobs.decorators import embedding, llm, retrieval, workflow

@llm(model_name="model_name", model_provider="model_provider")
def llm_call(prompt):
    resp = ... # llm call here
    LLMObs.annotate(
        span=None,
        input_data=[{"role": "user", "content": "Hello world!"}],
        output_data=[{"role": "assistant", "content": "How can I help?"}],
        metadata={"temperature": 0, "max_tokens": 200},
        metrics={"input_tokens": 4, "output_tokens": 6, "total_tokens": 10},
        tags={"host": "host_name"},
    )
    return resp

@workflow
def extract_data(document):
    resp = llm_call(document)
    LLMObs.annotate(
        input_data=document,
        output_data=resp,
        tags={"host": "host_name"},
    )
    return resp

@embedding(model_name="text-embedding-3", model_provider="openai")
def perform_embedding():
    ... # user application logic
    LLMObs.annotate(
        span=None,
        input_data={"text": "Hello world!"},
        output_data=[0.0023064255, -0.009327292, ...],
        metrics={"input_tokens": 4},
        tags={"host": "host_name"},
    )
    return

@retrieval(name="get_relevant_docs")
def similarity_search():
    ... # user application logic
    LLMObs.annotate(
        span=None,
        input_data="Hello world!",
        output_data=[{"text": "Hello world is ...", "name": "Hello, World! program", "id": "document_id", "score": 0.9893}],
        tags={"host": "host_name"},
    )
    return

@llm(model_name="gpt-realtime", model_provider="openai")
def voice_turn(user_audio_bytes):
    import base64
    resp = ... # multimodal (audio) llm call here
    LLMObs.annotate(
        span=None,
        input_data=[
            {
                "role": "user",
                "content": "Hey, how are you?",  # transcript of the input audio
                "audio_parts": [
                    {"mime_type": "audio/wav", "content": base64.b64encode(user_audio_bytes).decode("utf-8")}
                ],
            }
        ],
        output_data=[
            {
                "role": "assistant",
                "content": "Hey! I'm doing great, thanks for asking. How about you?",
                "audio_parts": [
                    {"mime_type": "audio/wav", "content": base64.b64encode(resp.audio_bytes).decode("utf-8")}
                ],
            }
        ],
    )
    return resp

@llm(model_name="gpt-4o", model_provider="openai")
def describe_image(image_bytes):
    import base64
    resp = ... # multimodal (vision) llm call here
    LLMObs.annotate(
        span=None,
        input_data=[
            {
                "role": "user",
                "content": "What is in this image?",
                "image_parts": [
                    {"mime_type": "image/png", "content": base64.b64encode(image_bytes).decode("utf-8")}
                ],
            }
        ],
        output_data=[{"role": "assistant", "content": "The image shows a golden retriever puppy."}],
    )
    return resp

メッセージに audio_parts または image_parts の注釈が付いている場合、トレースを表示する画面では、インラインオーディオプレーヤーおよび画像がレンダリングされます。レンダリングされた例、サポートされている形式、サイズ制限、およびこれらのフィールドを自動的に設定するインテグレーションについては、マルチモーダルサポート を参照してください。

SDK には、入力、出力、メタデータを使用してスパンにアノテーションを付けるための llmobs.annotate() メソッドが用意されています。

LLMObs.annotate() メソッドは次の引数を受け付けます。

span
オプション - スパン - デフォルト: 現在のアクティブなスパン
アノテーションを付けるスパン。span が指定されていない場合 (関数ラッパーを使用している場合など)、SDK は現在のアクティブなスパンにアノテーションを付けます。
annotationOptions
必須 - オブジェクト
スパンにアノテーションを付けるための異なるタイプのデータのオブジェクトです。

annotationOptions オブジェクトには、次の項目を含めることができます。

inputData
オプション - JSON のシリアライズ可能な型、またはオブジェクトのリスト
(非 LLM スパン用の) JSON のシリアライズ可能な型、または : {role: "...", content: "...", audioParts: [...], imageParts: [...]} という形式の辞書のリスト (LLM スパン用)。audioParts および imageParts は、マルチモーダルスパン用のメディアオブジェクトのオプションのリストであり、それぞれに必須の mimeType と content (インラインで埋め込まれた base64 エンコードメディア) が必要です。注: 埋め込みスパンは特別なケースであり、{text: "..."} という形式の文字列またはオブジェクト (またはオブジェクトのリスト) が必要です。

outputData オプション - JSON のシリアライズ可能な型、またはオブジェクトのリスト
(非 LLM スパン用の) JSON のシリアライズ可能な型、または {role: "...", content: "...", audioParts: [...], imageParts: [...]} という形式の辞書のリスト (LLM スパン用)。audioParts および imageParts は、マルチモーダルスパン用のメディアオブジェクトのオプションのリストであり、それぞれに必須の mimeType と content (インラインで埋め込まれた base64 エンコードメディア) が必要です。注: 取得スパンは特別なケースであり、{text: "...", name: "...", score: number, id: "..."} という形式の文字列またはオブジェクト (またはオブジェクトのリスト) が必要です。

metadata
オプション - オブジェクト
スパンで記述された入力または出力操作に関連するメタデータ情報としてユーザーが追加できる、JSON のシリアライズ可能なキーと値のペアのオブジェクト (model_temperature、max_tokens、top_k など)。
metrics
オプション - オブジェクト
スパンで記述された操作に関連するメトリクスとしてユーザーが追加できる、JSON のシリアライズ可能なキーと数値のオブジェクト (input_tokens、output_tokens、total_tokens など)。
tags
オプション - オブジェクト
スパンのコンテキストに関するタグとしてユーザーが追加できる、JSON のシリアライズ可能なキーと値のペアのオブジェクト (session、environment、system、versioning など)。タグの詳細については、タグの概要を参照してください。
costTags
オプション - 文字列の配列
生成された LLM コストおよびトークンメトリクスにカスタムタグとして伝播するタグキーのリスト (tags で設定済み、または同じスパンに以前にアノテーションされたもの)。既存のタグキーを参照していないエントリはスキップされます。詳細については、コストモニタリングを参照してください。

例

function llmCall (prompt) {
  const completion = ... // user application logic to invoke LLM
  llmobs.annotate({
    inputData: [{ role: "user", content: "Hello world!" }],
    outputData: [{ role: "assistant", content: "How can I help?" }],
    metadata: { temperature: 0, max_tokens: 200 },
    metrics: { input_tokens: 4, output_tokens: 6, total_tokens: 10 },
    tags: { host: "host_name" }
  })
  return completion
}
llmCall = llmobs.wrap({ kind:'llm', modelName: 'modelName', modelProvider: 'modelProvider' }, llmCall)

function extractData (document) {
  const resp = llmCall(document)
  llmobs.annotate({
    inputData: document,
    outputData: resp,
    tags: { host: "host_name" }
  })
  return resp
}
extractData = llmobs.wrap({ kind: 'workflow' }, extractData)

function performEmbedding () {
  ... // user application logic
  llmobs.annotate(
    undefined, { // this can be set to undefined or left out entirely
      inputData: { text: "Hello world!" },
      outputData: [0.0023064255, -0.009327292, ...],
      metrics: { input_tokens: 4 },
      tags: { host: "host_name" }
    }
  )
}
performEmbedding = llmobs.wrap({ kind: 'embedding', modelName: 'text-embedding-3', modelProvider: 'openai' }, performEmbedding)

function similaritySearch () {
  ... // user application logic
  llmobs.annotate(undefined, {
    inputData: "Hello world!",
    outputData: [{ text: "Hello world is ...", name: "Hello, World! program", id: "document_id", score: 0.9893 }],
    tags: { host: "host_name" }
  })
  return
}
similaritySearch = llmobs.wrap({ kind: 'retrieval', name: 'getRelevantDocs' }, similaritySearch)

function voiceTurn (userAudioBytes) {
  const resp = ... // multimodal (audio) llm call here
  llmobs.annotate({
    inputData: [
      {
        role: "user",
        content: "Hey, how are you?", // transcript of the input audio
        audioParts: [{ mimeType: "audio/wav", content: userAudioBytes.toString("base64") }]
      }
    ],
    outputData: [
      {
        role: "assistant",
        content: "Hey! I'm doing great, thanks for asking. How about you?",
        audioParts: [{ mimeType: "audio/wav", content: resp.audioBuffer.toString("base64") }]
      }
    ]
  })
  return resp
}
voiceTurn = llmobs.wrap({ kind: 'llm', modelName: 'gpt-audio', modelProvider: 'openai' }, voiceTurn)

function describeImage (imageBytes) {
  const resp = ... // multimodal (vision) llm call here
  llmobs.annotate({
    inputData: [
      {
        role: "user",
        content: "What is in this image?",
        imageParts: [{ mimeType: "image/png", content: imageBytes.toString("base64") }]
      }
    ],
    outputData: [{ role: "assistant", content: "The image shows a golden retriever puppy." }]
  })
  return resp
}
describeImage = llmobs.wrap({ kind: 'llm', modelName: 'gpt-4o', modelProvider: 'openai' }, describeImage)

メッセージに audioParts または imageParts の注釈が付いている場合、トレースを表示する画面では、インラインオーディオプレーヤーおよび画像がレンダリングされます。レンダリングされた例、サポートされている形式、サイズ制限、およびこれらのフィールドを自動的に設定するインテグレーションについては、マルチモーダルサポート を参照してください。

OpenAI の音声チャット補完では、audioParts も Datadog の LLM インテグレーション によって自動的にキャプチャされるため、手動で注釈を付ける必要はありません。Node.js SDK は imageParts を自動的にキャプチャしません。上記のように注釈を付けてください。

SDK には、入力、出力、メトリクス、メタデータを使用してスパンにアノテーションを付けるためのいくつかのメソッドが用意されています。

入力と出力のアノテーション付け

LLMObsSpan インターフェイスの annotateIO() メンバーメソッドを使用して、LLMObsSpan に構造化された入力および出力データを追加します。ここにはオプションの引数と LLM メッセージオブジェクトが含まれます。

引数

引数が null または空の場合、処理は何も行われません。たとえば、inputData が空ではない文字列で、outputData が null の場合は、inputData のみが記録されます。

inputData
オプション - 文字列 または List<LLMObs.LLMMessage>
文字列 (非 LLM スパン用)、または LLM スパン用の LLMObs.LLMMessage のリスト。
outputData
オプション - 文字列 または List<LLMObs.LLMMessage>
文字列 (非 LLM スパン用)、または LLM スパン用の LLMObs.LLMMessage のリスト。

LLM メッセージ

LLM スパンは、LLMObs.LLMMessage オブジェクトを使用して LLM メッセージでアノテーションを付ける必要があります。

LLMObs.LLMMessage オブジェクトは、次の引数を指定して LLMObs.LLMMessage.from() を呼び出すことでインスタンス化できます。

role
必須 - 文字列
メッセージの作成者の役割を記述する文字列。
content
必須 - 文字列
メッセージの内容を含む文字列。

例

import datadog.trace.api.llmobs.LLMObs;

public class MyJavaClass {
  public String invokeChat(String userInput) {
    LLMObsSpan llmSpan = LLMObs.startLLMSpan("my-llm-span-name", "my-llm-model", "my-company", "maybe-ml-app-override", "session-141");
    String systemMessage = "You are a helpful assistant";
    Response chatResponse = ... // user application logic to invoke LLM
    llmSpan.annotateIO(
      Arrays.asList(
        LLMObs.LLMMessage.from("user", userInput),
        LLMObs.LLMMessage.from("system", systemMessage)
      ),
      Arrays.asList(
        LLMObs.LLMMessage.from(chatResponse.role, chatResponse.content)
      )
    );
    llmSpan.finish();
    return chatResponse;
  }
}

メトリクスの追加

メトリクスの一括追加

LLMObsSpan インターフェイスの setMetrics() メンバーメソッドは、複数のメトリクスを一括でアタッチするための次の引数を受け付けます。

引数
metrics
必須 - Map<String, Number>
スパンで記述された操作に関連するメトリクスを記録するためにユーザーが追加できる、JSON のシリアライズ可能なキーと数値のマップ (たとえば、input_tokens、output_tokens、またはtotal_tokens)。

単一のメトリクスを追加

LLMObsSpan インターフェイスの setMetric() メンバーメソッドは、単一のメトリクスをアタッチするための次の引数を受け付けます。

引数
key
必須 - CharSequence
メトリクスの名前。
value
必須 - int、long、または double
メトリクスの値。

例

import datadog.trace.api.llmobs.LLMObs;

public class MyJavaClass {
  public String invokeChat(String userInput) {
    LLMObsSpan llmSpan = LLMObs.startLLMSpan("my-llm-span-name", "my-llm-model", "my-company", "maybe-ml-app-override", "session-141");
    String chatResponse = ... // user application logic to invoke LLM
    llmSpan.setMetrics(Map.of(
      "input_tokens", 617,
      "output_tokens", 338,
      "time_per_output_token", 0.1773
    ));
    llmSpan.setMetric("total_tokens", 955);
    llmSpan.setMetric("time_to_first_token", 0.23);
    llmSpan.finish();
    return chatResponse;
  }
}

タグの追加

タグの詳細については、タグの概要 を参照してください。

タグの一括追加

LLMObsSpan インターフェイスの setTags() メンバーメソッドは、複数のタグを一括でアタッチするための次の引数を受け付けます。

引数
tags
必須 - Map<String, Object>
スパンのコンテキストを説明するためにユーザーがタグとして追加できる JSON のシリアライズ可能なキーと値のペアのマップ (たとえば、session、environment、system、またはversion)。

単一のタグを追加

LLMObsSpan インターフェイスの setTag() メンバーメソッドは、単一のタグをアタッチするための次の引数を受け付けます。

引数
key
必須 - 文字列
タグのキー。
value
必須 - int、long、double、boolean、または 文字列
タグの値。

例

import datadog.trace.api.llmobs.LLMObs;

public class MyJavaClass {
  public String invokeChat(String userInput) {
    LLMObsSpan llmSpan = LLMObs.startLLMSpan("my-llm-span-name", "my-llm-model", "my-company", "maybe-ml-app-override", "session-141");
    String chatResponse = ... // user application logic to invoke LLM
    llmSpan.setTags(Map.of(
      "chat_source", "web",
      "users_in_chat", 3
    ));
    llmSpan.setTag("is_premium_user", true);
    llmSpan.finish();
    return chatResponse;
  }
}

エラーのアノテーション付け

LLMObsSpan インターフェイスの addThrowable() メンバーメソッドは、スタックトレースを持つ Throwable をアタッチするための次の引数を受け付けます。

引数
throwable
必須 - Throwable
発生した Throwable/Exception。

エラーメッセージの追加

LLMObsSpan インターフェイスの setErrorMessage() メンバーメソッドは、エラー文字列をアタッチするための次の引数を受け付けます。

引数
errorMessage
必須 - 文字列
エラーメッセージ。

エラーフラグの設定

LLMObsSpan インターフェイスの setError() メンバーメソッドは、操作にエラーがあることを示すための次の引数を受け付けます。

引数
error
必須 - boolean
true の場合、スパンでエラーが発生しています。

例

import datadog.trace.api.llmobs.LLMObs;

public class MyJavaClass {
  public String invokeChat(String userInput) {
    LLMObsSpan llmSpan = LLMObs.startLLMSpan("my-llm-span-name", "my-llm-model", "my-company", "maybe-ml-app-override", "session-141");
    String chatResponse = "N/A";
    try {
      chatResponse = ... // user application logic to invoke LLM
    } catch (Exception e) {
      llmSpan.addThrowable(e);
      throw new RuntimeException(e);
    } finally {
      llmSpan.finish();
    }
    return chatResponse;
  }
}

メタデータのアノテーション付け

LLMObsSpan インターフェイスの setMetadata() メンバーメソッドは、次の引数を受け付けます。

metadata
必須 - Map<String, Object>
スパンによって記述された入力または出力操作に関連するメタデータを含む、JSON のシリアライズ可能なキーと値のペアのマップです。

例

import datadog.trace.api.llmobs.LLMObs;

public class MyJavaClass {
  public String invokeChat(String userInput) {
    LLMObsSpan llmSpan = LLMObs.startLLMSpan("my-llm-span-name", "my-llm-model", "my-company", "maybe-ml-app-override", "session-141");
    llmSpan.setMetadata(
      Map.of(
        "temperature", 0.5,
        "is_premium_member", true,
        "class", "e1"
      )
    );
    String chatResponse = ... // user application logic to invoke LLM
    return chatResponse;
  }
}

自動インスツルメンテーションスパンのアノテーション付け

SDK の LLMObs.annotation_context() メソッドは、アノテーションコンテキストがアクティブな間に開始されたすべての自動インスツルメンテーションスパンを変更するために使用できるコンテキストマネージャーを返します。

LLMObs.annotation_context() メソッドは次の引数を受け付けます。

name
オプション - str
アノテーションコンテキスト内で開始される自動インスツルメンテーションされたスパンのスパン名をオーバーライドする名前です。
prompt
オプション - 辞書
LLM 呼び出しに使用されるプロンプトを表す辞書です。完全なスキーマとサポートされているキーについては、プロンプトオブジェクトのドキュメントを参照してください。Promptオブジェクトを ddtrace.llmobs.utils からインポートして、prompt 引数として渡すこともできます。注: この引数は LLM スパンにのみ適用されます。
tags
オプション - 辞書
ユーザーがタグとしてスパンに追加できる、JSON のシリアライズ可能なキーと値のペアの辞書です。キーの例: session、env、system、および version。タグの詳細については、タグの概要を参照してください。
cost_tags
オプション - 文字列のリスト
生成された LLM コストおよびトークンメトリクスにカスタムタグとして伝播するタグキーのリスト。各エントリでは、スパン開始時に tags に存在するキー (同じコンテキストまたは親コンテキストに提供されたもの) を指定する必要があります。LLMObs.annotate() で後から追加されたタグキーは保持されません。詳細については、コストモニタリングを参照してください。

例

from ddtrace.llmobs import LLMObs
from ddtrace.llmobs.decorators import workflow

@workflow
def rag_workflow(user_question):
    context_str = retrieve_documents(user_question).join(" ")

    with LLMObs.annotation_context(
        prompt = Prompt(
            id="chatbot_prompt",
            version="1.0.0",
            template="Please answer the question using the provided context: {{question}}\n\nContext:\n{{context}}",
            variables={
                "question": user_question,
                "context": context_str,
            }
        ),
        tags = {
            "retrieval_strategy": "semantic_similarity"
        },
        name = "augmented_generation"
    ):
        completion = openai_client.chat.completions.create(...)
    return completion.choices[0].message.content

SDK の llmobs.annotationContext() は、コールバック関数のスコープ内で開始されたすべての自動インスツルメンテーションスパンを変更するために使用できるコールバック関数を受け付けます。

llmobs.annotationContext() メソッドは、最初の引数で次のオプションを受け付けます。

name
オプション - str
アノテーションコンテキスト内で開始される自動インスツルメンテーションされたスパンのスパン名をオーバーライドする名前です。
tags
オプション - オブジェクト
ユーザーがスパンにタグとして追加できる JSON のシリアライズ可能なキーと値のペアのオブジェクトです。キーの例: : session、env、system、および version。タグの詳細については、タグの概要を参照してください。
costTags
オプション - 文字列の配列
生成された LLM コストおよびトークンメトリクスにカスタムタグとして伝播するタグキーのリスト。各エントリでは、スパン開始時に tags に存在するキー (同じコンテキストまたは親コンテキストに提供されたもの) を指定する必要があります。llmobs.annotate() で後から追加されたタグキーは保持されません。詳細については、コストモニタリングを参照してください。

例

const { llmobs } = require('dd-trace');

function ragWorkflow(userQuestion) {
    const contextStr = retrieveDocuments(userQuestion).join(" ");

    const completion = await llmobs.annotationContext({
      tags: {
        retrieval_strategy: "semantic_similarity"
      },
      name: "augmented_generation"
    }, async () => {
      const completion = await openai_client.chat.completions.create(...);
      return completion.choices[0].message.content;
    });
}

プロンプト追跡

構造化されたプロンプトメタデータを LLM スパンにアタッチすることにより、結果を再現し、変更を監査し、バージョン間でプロンプトのパフォーマンスを比較できるようにします。テンプレートを使用する際、Agent Observability は、テンプレートの内容の変更に基づいてバージョン追跡も提供します。

LLM 呼び出しの前にプロンプトメタデータをアタッチするには、LLMObs.annotation_context(prompt=...) を使用します。スパンアノテーションの詳細については、スパンの強化を参照してください。

引数

prompt
必須 - 辞書
次のプロンプトスキーマに従った型付き辞書。

サポートされているキー:

  • id (str): このプロンプトの論理識別子。ml_app ごとに一意である必要があります。デフォルトは {ml_app}-unnamed_prompt です。
  • version (str): プロンプトのバージョンタグ (例: “1.0.0”)。詳細については、バージョン追跡を参照してください。
  • variables(Dict[str, str]): テンプレートのプレースホルダーに入力するために使用される変数。
  • template(str): プレースホルダーを含むテンプレート文字列 (例: `“Translate {{text}} to {{lang}}")。
  • chat_template(List[Message]): マルチメッセージテンプレート形式。{ "role": "<role>", "content": "<template string with placeholders>" } オブジェクトのリストを指定します。
  • tags(Dict[str, str]): プロンプト実行にアタッチするタグ。
  • rag_context_variables(List[str]): グラウンドトゥルース/コンテキストコンテンツを含む変数キー。ハルシネーションの検出に使用されます。
  • rag_query_variables(List[str]): ユーザーのクエリを含む変数キー。ハルシネーションの検出に使用されます。

例: シングルテンプレートプロンプト

from ddtrace.llmobs import LLMObs

def answer_question(text):
    # Attach prompt metadata to the upcoming LLM span using LLMObs.annotation_context()
    with LLMObs.annotation_context(prompt={
        "id": "translation-template",
        "version": "1.0.0",
        "chat_template": [{"role": "user", "content": "Translate to {{lang}}: {{text}}"}],
        "variables": {"lang": "fr", "text": text},
        "tags": {"team": "nlp"}
    }):
        # Example provider call (replace with your client)
        completion = openai_client.chat.completions.create(
            model="gpt-4o",
            messages=[{"role": "user", "content": f"Translate to fr: {text}"}]
        )
    return completion

例: LangChain プロンプトテンプレート

LangChain のプロンプトテンプレートを自動インスツルメンテーションと一緒に使用する際は、意味のある名前の変数にテンプレートを割り当ててください。自動インスツルメンテーションは、これらの名前を使用してプロンプトを特定します。

# "translation_template" will be used to identify the template in Datadog
translation_template = PromptTemplate.from_template("Translate {text} to {language}")
chain = translation_template | llm

LLM 呼び出しの前にプロンプトメタデータをアタッチするには、llmobs.annotationContext({ prompt: ... }, () => { ... }) を使用します。スパンアノテーションの詳細については、スパンの強化を参照してください。

引数

prompt
必須 - オブジェクト
次のプロンプトスキーマに従うオブジェクト。

サポートされているプロパティ:

  • id (文字列): このプロンプトの論理識別子。ml_app ごとに一意である必要があります。デフォルトは {ml_app}-unnamed_prompt です。
  • version (文字列): プロンプトのバージョンタグ (例: “1.0.0”)。詳細については、バージョン追跡を参照してください。
  • variables(Record<string, string>): テンプレートのプレースホルダーに入力するために使用される変数。
  • template(文字列 | List[Message]): プレースホルダーを含むテンプレート文字列 (例: "Translate {{text}} to {{lang}}"). Alternatively, a list of { "role": "<role>", "content": "<template string with placeholders>" } オブジェクトのリスト。
  • tags(Record<string, string>): プロンプト実行にアタッチするタグ。
  • contextVariables(string[]): グラウンドトゥルース/コンテキストコンテンツを含む変数キー。ハルシネーションの検出に使用されます。
  • queryVariables(string[]): ユーザーのクエリを含む変数キー。ハルシネーションの検出に使用されます。

例: シングルテンプレートプロンプト

const { llmobs } = require('dd-trace');

function answerQuestion(text) {
    // Attach prompt metadata to the upcoming LLM span using LLMObs.annotation_context()
    return llmobs.annotationContext({
      prompt: {
        id: "translation-template",
        version: "1.0.0",
        chat_template: [{"role": "user", "content": "Translate to {{lang}}: {{text}}"}],
        variables: {"lang": "fr", "text": text},
        tags: {"team": "nlp"}
      }
    }, () => {
      // Example provider call (replace with your client)
      return openaiClient.chat.completions.create({
          model: "gpt-4o",
          messages: [{"role": "user", "content": f"Translate to fr: {text}"}]
        });
    });
}

注

  • プロンプトのアノテーション付けは LLM スパンでのみ利用可能です。
  • アノテーションは、正しい LLM スパンに適用されるようにするため、プロバイダー呼び出しの直前に配置します。
  • アプリケーション内の異なるプロンプトを区別するために、固有のプロンプト id を使用してください。
  • 次のようなプレースホルダー構文を使用してテンプレートを静的に保ち (例: {{variable_name}}) and define dynamic content in the variables セクションで動的コンテンツを定義します。
  • ブロック内で複数の自動インスツルメンテーション LLM 呼び出しを行う場合、アノテーションコンテキストを使用して同じプロンプトメタデータを呼び出し全体に適用します。自動インスツルメンテーションスパンのアノテーション付けを参照してください。

バージョン追跡

Agent Observability は、バージョンが明示的に指定されていない場合に、プロンプトの自動バージョニングを提供します。プロンプトメタデータに version タグなしで template または chat_template を指定すると、システムではテンプレートの内容のハッシュを計算して自動的にバージョンが生成されます。version タグを指定した場合、Agent Observability では自動生成したバージョンラベルの代わりに指定したバージョンラベルが使用されます。

バージョニングシステムは次のように機能します。

  • 自動バージョニング: version タグを指定していない場合、Agent Observability では template または chat_template の内容のハッシュを計算して自動的に数値のバージョン識別子が生成されます。
  • 手動バージョニング: version タグを指定した場合、Agent Observability では指定したとおりにバージョンラベルが使用されます。
  • バージョン履歴: プロンプトの進展を時系列で追跡するために、自動生成されたバージョンと手動バージョンの両方がバージョン履歴に保持されます。

これにより、テンプレート内容の変更に基づく自動バージョン管理に依存するか、独自のバージョンラベルでバージョニングを完全に制御するかを柔軟に選択できます。

MCP インテントキャプチャ

MCP ツールが呼び出された理由を把握するには、MCP サーバーでインテントキャプチャを有効にします。有効にすると、SDK はすべての MCP サーバーツールに、呼び出し元のモデルがそのツールを呼び出した理由を説明するよう要求する引数を追加します。インテントはツールスパンに記録されるため、ツール定義や説明の改善に役立ちます。

DD_MCP_CAPTURE_INTENT 環境変数を使用して MCP インテントキャプチャを有効にします。

DD_MCP_CAPTURE_INTENT=1 DD_SITE=<YOUR_DATADOG_SITE> DD_API_KEY=<YOUR_API_KEY> DD_LLMOBS_ENABLED=1 \
DD_LLMOBS_ML_APP=<YOUR_ML_APP_NAME> ddtrace-run <YOUR_APP_STARTUP_COMMAND>

または、LLMObs.enable() の capture_intent パラメーターを使用してプログラムで有効にします。

from ddtrace.llmobs import LLMObs
LLMObs.enable(
  ml_app="<YOUR_ML_APP_NAME>",
  capture_intent=True,
)

コストモニタリング

トークンメトリクス (自動コスト追跡用) またはコストメトリクス (手動コスト追跡用) を LLM/埋め込みスパンにアタッチします。トークンメトリクスを使用すると、Datadog でプロバイダーの価格を使用してコストを計算でき、コストメトリクスを使用すると、カスタムモデルまたはサポートされていないモデルを使用する際に、独自の価格を提供できます。詳細については、コスト を参照してください。

自動インスツルメンテーションを使用している場合、トークンとコストメトリクスは自動的にスパンに表示されます。手動でインスツルメントする場合は、次のガイダンスに従ってください。

このコンテキストでは、「トークンメトリクス」と「コストメトリクス」は、 metrics パラメーター ( LLMObs.annotate() メソッドの) を介してスパンにアタッチする数値のキーと値のペアを指します。これらは、Datadog プラットフォームの Agent Observability メトリクスとは異なります。認識されたキー ( input_tokens,output_tokens,input_cost、および output_costなど) に対し、Datadog はこれらのスパン属性を使用して、対応するプラットフォームメトリクス ( ml_obs.span.llm.input.costなど) をダッシュボードやモニターで使用するために生成します。

ユースケース: 一般的なモデルプロバイダーの使用

Datadog では、OpenAI、Azure OpenAI、Anthropic、Google Gemini などの一般的なモデルプロバイダーがサポートされています。これらのプロバイダーを使用する場合、LLM リクエストにモデル名、モデルプロバイダー、およびトークン使用量によりアノテーション付けするだけで済みます。Datadog では、プロバイダーの価格に基づいて推定コストが自動的に計算されます。

各トークンが何を表し、Datadog がどのように計算するかについて詳しくは、トークン数の計算方法を参照してください。

from ddtrace.llmobs import LLMObs
from ddtrace.llmobs.decorators import llm

@llm(model_name="gpt-5.1", model_provider="openai")
def llm_call(prompt):
    resp = ... # llm call here
    # Annotate token metrics
    LLMObs.annotate(
        metrics={
          "input_tokens": 50,
          "output_tokens": 120,
          "total_tokens": 170,
          "non_cached_input_tokens": 13,  # optional
          "cache_read_input_tokens": 22,  # optional
          "cache_write_input_tokens": 15, # optional
        },
    )
    return resp
function llmCall (prompt) {
  const resp = ... // llm call here
  llmobs.annotate({
    metrics: {
      input_tokens: 50,
      output_tokens: 120,
      total_tokens: 170,
      non_cached_input_tokens: 13,  // optional
      cache_read_input_tokens: 22,  // optional
      cache_write_input_tokens: 15  // optional
    }
  })
  return resp
}
llmCall = llmobs.wrap({ kind: 'llm', modelName: 'gpt-5.1', modelProvider: 'openai' }, llmCall)
import datadog.trace.api.llmobs.LLMObs;
import datadog.trace.api.llmobs.LLMObsSpan;
import java.util.Map;

public class MyJavaClass {
  public String llmCall(String prompt) {
    LLMObsSpan llmSpan = LLMObs.startLLMSpan("llm-call", "gpt-5.1", "openai", null, null);
    String resp = ... // llm call here
    llmSpan.setMetrics(Map.of(
      "input_tokens", 50,
      "output_tokens", 120,
      "total_tokens", 170,
      "non_cached_input_tokens", 13,  // optional
      "cache_read_input_tokens", 22,  // optional
      "cache_write_input_tokens", 15  // optional
    ));
    llmSpan.finish();
    return resp;
  }
}

ユースケース: カスタムモデルの使用

カスタムモデルまたはサポートされていないモデルの場合、ドル単位のコストデータにより手動でスパンにアノテーション付けする必要があります。

from ddtrace.llmobs import LLMObs
from ddtrace.llmobs.decorators import llm

@llm(model_name="custom_model", model_provider="model_provider")
def llm_call(prompt):
    resp = ... # llm call here
    # Annotate cost metrics
    LLMObs.annotate(
        metrics={
          "input_cost": 3,
          "output_cost": 7,
          "total_cost": 10,
          "non_cached_input_cost": 1,    # optional
          "cache_read_input_cost": 0.6,  # optional
          "cache_write_input_cost": 1.4, # optional
        },
    )
    return resp
function llmCall (prompt) {
  const resp = ... // llm call here
  llmobs.annotate({
    metrics: {
      input_cost: 3,
      output_cost: 7,
      total_cost: 10,
      non_cached_input_cost: 1,    // optional
      cache_read_input_cost: 0.6,  // optional
      cache_write_input_cost: 1.4  // optional
    }
  })
  return resp
}
llmCall = llmobs.wrap({ kind: 'llm', modelName: 'custom_model', modelProvider: 'model_provider' }, llmCall)
import datadog.trace.api.llmobs.LLMObs;
import datadog.trace.api.llmobs.LLMObsSpan;
import java.util.Map;

public class MyJavaClass {
  public String llmCall(String prompt) {
    LLMObsSpan llmSpan = LLMObs.startLLMSpan("llm-call", "custom_model", "model_provider", null, null);
    String resp = ... // llm call here
    llmSpan.setMetrics(Map.of(
      "input_cost", 3,
      "output_cost", 7,
      "total_cost", 10,
      "non_cached_input_cost", 1,    // optional
      "cache_read_input_cost", 0.6,  // optional
      "cache_write_input_cost", 1.4  // optional
    ));
    llmSpan.finish();
    return resp;
  }
}

コストおよびトークンメトリクスへのカスタムタグの追加

デフォルトでは、LLM コストおよびトークンメトリクスには、model_name、model_provider、ml_app などの固定された OOTB タグが含まれています。チーム、顧客、機能など、アプリケーション固有の属性で LLM の支出を分析するには、スパンの既存のタグキーの一部を、それらのメトリクスにカスタムタグとして伝播するよう指定します。カスタムダッシュボードやモニターなどの使用例については、コストおよびトークンメトリクスへのカスタムタグを参照してください。

各エントリは文字列であり、アノテーションを適用する時点で、スパンの tags パラメーターを通じてすでに提供されているキーを指定する必要があります。単一のスパンにアノテーションを付ける場合、キーは同じアノテーション呼び出し内の tags を通じて提供するか、同じスパンに対する以前のアノテーションで提供できます。アノテーションコンテキストを使用する場合、スパン開始時に tags に存在するキーのみが対象となります。後から個別のスパンアノテーションを通じて追加されたキーは保持されません。既存のタグキーを参照していないエントリはスキップされます。

from ddtrace.llmobs import LLMObs
from ddtrace.llmobs.decorators import llm

@llm(model_name="gpt-5.1", model_provider="openai")
def llm_call(prompt):
    resp = ... # llm call here
    LLMObs.annotate(
        metrics={"input_tokens": 50, "output_tokens": 120, "total_tokens": 170},
        tags={"team": "nlp", "customer_tier": "enterprise", "host": "host_name"},
        cost_tags=["team", "customer_tier"],
    )
    return resp
function llmCall (prompt) {
  const resp = ... // llm call here
  llmobs.annotate({
    metrics: { input_tokens: 50, output_tokens: 120, total_tokens: 170 },
    tags: { team: 'nlp', customer_tier: 'enterprise', host: 'host_name' },
    costTags: ['team', 'customer_tier']
  })
  return resp
}
llmCall = llmobs.wrap({ kind: 'llm', modelName: 'gpt-5.1', modelProvider: 'openai' }, llmCall)

この方法でアノテーションコンテキストを通じてタグを伝播し、コンテキスト内で開始されたすべての自動インスツルメンテーションスパンに適用することもできます。

with LLMObs.annotation_context(
    tags={"team": "nlp", "customer_tier": "enterprise"},
    cost_tags=["team", "customer_tier"],
):
    resp = ... # llm call here
llmobs.annotationContext({
  tags: { team: 'nlp', customer_tier: 'enterprise' },
  costTags: ['team', 'customer_tier']
}, () => {
  const resp = ... // llm call here
})

評価

Agent Observability SDK には、評価を Datadog にエクスポートおよび送信するためのメソッドが用意されています。

豊富な結果メタデータを使用して、再利用可能なクラスベースの評価機能 (BaseEvaluator,BaseSummaryEvaluator) を構築する方法については、評価開発者ガイドを参照してください。

評価は単一のスパンに結合する必要があります。ターゲットスパンは、次の 2 つの方法のいずれかを使用して特定できます。

  • タグベースの結合 - 単一のスパンに設定された一意のキーと値のタグペアを使用して、評価を結合します。タグのキーと値ペアが複数のスパンに一致する場合、またはどのスパンにも一致しない場合、評価の結合は失敗します。
  • 直接スパン参照 - スパンの一意のトレース ID とスパン ID の組み合わせを使用して、評価を結合します。

スパンのエクスポート

LLMObs.export_span()は、スパンからスパンのコンテキストを抽出するために使用できます。このメソッドは、評価をそれに対応するスパンに関連付けるのに役立ちます。

引数

LLMObs.export_span() メソッドは次の引数を受け付けます。

span
オプション - スパン
スパンのコンテキスト (スパンおよびトレース ID) を抽出するスパン。指定しない場合 (関数デコレータを使用する場合など)、SDK により現在のアクティブスパンがエクスポートされます。

例

from ddtrace.llmobs import LLMObs
from ddtrace.llmobs.decorators import llm

@llm(model_name="claude", name="invoke_llm", model_provider="anthropic")
def llm_call():
    completion = ... # user application logic to invoke LLM
    span_context = LLMObs.export_span(span=None)
    return completion

llmobs.exportSpan() は、スパンからスパンのコンテキストを抽出するために使用できます。このメソッドを使用して、評価をそれに対応するスパンに関連付ける必要があります。

引数

llmobs.exportSpan() メソッドは次の引数を受け付けます。

span
オプション - スパン
スパンのコンテキスト (スパンおよびトレース ID) を抽出するスパン。指定しない場合 (関数ラッパーを使用する場合など)、SDK により現在アクティブなスパンがエクスポートされます。

例

function llmCall () {
  const completion = ... // user application logic to invoke LLM
  const spanContext = llmobs.exportSpan()
  return completion
}
llmCall = llmobs.wrap({ kind: 'llm', name: 'invokeLLM', modelName: 'claude', modelProvider: 'anthropic' }, llmCall)

評価の送信

LLMObs.submit_evaluation() は、指定されたスパンに関連付けられたカスタム評価を送信するために使用できます。

LLMObs.submit_evaluation_for は非推奨であり、次のメジャーバージョンの ddtrace (4.0) で削除されます。移行するには、 LLMObs.submit_evaluation_for 呼び出しの名前を LLMObs.submit_evaluation.

注: カスタム評価は、自分で実装し、ホストする評価機能です。これらは、組み込みの評価機能を使用して Datadog により自動的に計算される、既成の評価機能とは異なります。ご使用のアプリケーション用にすぐに使用できる評価を構成するには、Datadog の Agent Observability > Settings > Evaluations ページを使用してください。

LLMObs.submit_evaluation() メソッドは次の引数を受け付けます。

label
必須 - 文字列
評価の名前。
metric_type
必須 - 文字列
評価のタイプ。categorical、score、boolean、または json である必要があります。
value
必須 - 文字列、数値型、または辞書
評価の値。文字列 (metric_type==categorical)、整数/浮動小数点数 (metric_type==score)、Boolean (metric_type==boolean)、または辞書 (metric_type==json) である必要があります。
span
オプション - 辞書
この評価に関連付けられたスパンを一意に識別する辞書。span_id (文字列) と trace_id (文字列) を含む必要があります。この辞書を生成するには、LLMObs.export_span() を使用します。
span_with_tag_value
オプション - 辞書
この評価に関連付けられたスパンを一意に識別する辞書。tag_key (文字列) と tag_value (文字列) を含む必要があります。

注: span または span_with_tag_value のいずれか一方のみを指定する必要があります。両方を指定するか、どちらも指定しないと、ValueError が発生します。

ml_app
必須 - 文字列
ML アプリケーションの名前。
timestamp_ms
オプション - 整数
評価メトリクス結果が生成されたときのミリ秒単位の Unix タイムスタンプです。指定しない場合は、現在の時間がデフォルト設定されます。
tags
オプション - 辞書
評価に関してユーザーがタグとして追加できる文字列のキーと値のペアの辞書です。タグの詳細については、タグの概要を参照してください。
assessment
オプション - 文字列
この評価に対するアセスメントです。指定可能な値は、pass と fail です。
reasoning
オプション - 文字列
評価結果のテキスト説明。
metadata
オプション - 辞書
評価結果に関連付けられた任意の構造化メタデータを含む辞書。

例

from ddtrace.llmobs import LLMObs
from ddtrace.llmobs.decorators import llm

@llm(model_name="claude", name="invoke_llm", model_provider="anthropic")
def llm_call():
    completion = ... # user application logic to invoke LLM

    # joining an evaluation to a span via a tag key-value pair
    msg_id = get_msg_id()
    LLMObs.annotate(
        tags = {'msg_id': msg_id}
    )

    LLMObs.submit_evaluation(
        span_with_tag_value = {
            "tag_key": "msg_id",
            "tag_value": msg_id
        },
        ml_app = "chatbot",
        label="harmfulness",
        metric_type="score",
        value=10,
        tags={"evaluation_provider": "ragas"},
        assessment="fail",
        reasoning="Malicious intent was detected in the user instructions.",
        metadata={"details": ["jailbreak", "SQL injection"]}
    )

    # joining an evaluation to a span via span ID and trace ID
    span_context = LLMObs.export_span(span=None)
    LLMObs.submit_evaluation(
        span_context = span_context,
        ml_app = "chatbot",
        label="harmfulness",
        metric_type="score",
        value=10,
        tags={"evaluation_provider": "ragas"},
        assessment="fail",
        reasoning="Malicious intent was detected in the user instructions.",
        metadata={"details": ["jailbreak", "SQL injection"]}
    )
    return completion

llmobs.submitEvaluation() は、指定されたスパンに関連付けられたカスタム評価を送信するために使用できます。

llmobs.submitEvaluation() メソッドは次の引数を受け付けます。

span_context
必須 - 辞書
評価に関連付けるスパンコンテキスト。これは LLMObs.export_span() の出力である必要があります。
evaluationOptions
必須 - オブジェクト
評価データのオブジェクト。

evaluationOptions オブジェクトには、次の項目を含めることができます。

label
必須 - 文字列
評価の名前。
metricType
必須 - 文字列
評価のタイプ。“categorical”、“score”、“boolean” または “json” のいずれかである必要があります。
value
必須 - 文字列または数値型
評価の値。文字列 (カテゴリカル metric_type の場合)、数値 (スコア metric_type の場合)、boolean (boolean metric_type の場合)、または JSON オブジェクト (json metric_type の場合) である必要があります。
tags
オプション - 辞書
評価に関してユーザーがタグとして追加できる文字列のキーと値のペアの辞書です。タグの詳細については、タグの概要を参照してください。
assessment
オプション - 文字列
この評価に対するアセスメントです。指定可能な値は、pass と fail です。
reasoning
オプション - 文字列
評価結果のテキスト説明。
metadata
オプション - 辞書
評価結果に関連付けられた任意の構造化メタデータを含む JSON オブジェクト。

例

function llmCall () {
  const completion = ... // user application logic to invoke LLM
  const spanContext = llmobs.exportSpan()
  llmobs.submitEvaluation(spanContext, {
    label: "harmfulness",
    metricType: "score",
    value: 10,
    tags: { evaluationProvider: "ragas" }
  })
  return completion
}
llmCall = llmobs.wrap({ kind: 'llm', name: 'invokeLLM', modelName: 'claude', modelProvider: 'anthropic' }, llmCall)

LLMObs.SubmitEvaluation() を使用して、指定されたスパンに関連付けられたカスタム評価を送信します。

LLMObs.SubmitEvaluation() メソッドは次の引数を受け付けます。

llmObsSpan
必須 - LLMObsSpan
評価に関連付けるスパンコンテキスト。
label
必須 - 文字列
評価の名前。
categoricalValueまたは scoreValue
必須 - 文字列 または double
評価の値。文字列 (カテゴリ評価用) または double (スコア評価用) である必要があります。
tags
オプション - Map<String, Object>
評価をタグ付けするために使用される文字列のキーと値のペアの辞書。タグの詳細については、タグの概要を参照してください。

例

import datadog.trace.api.llmobs.LLMObs;

public class MyJavaClass {
  public String invokeChat(String userInput) {
    LLMObsSpan llmSpan = LLMObs.startLLMSpan("my-llm-span-name", "my-llm-model", "my-company", "maybe-ml-app-override", "session-141");
    String chatResponse = "N/A";
    try {
      chatResponse = ... // user application logic to invoke LLM
    } catch (Exception e) {
      llmSpan.addThrowable(e);
      throw new RuntimeException(e);
    } finally {
      llmSpan.finish();

      // submit evaluations
      LLMObs.SubmitEvaluation(llmSpan, "toxicity", "toxic", Map.of("language", "english"));
      LLMObs.SubmitEvaluation(llmSpan, "f1-similarity", 0.02, Map.of("provider", "f1-calculator"));
    }
    return chatResponse;
  }
}

エンドユーザーフィードバックの送信

エンドユーザーフィードバックは、LLM アプリケーションのユーザーからの入力 (高評価や低評価、ユーザーがエージェントによる変更を受け入れたかどうか、自由記述のコメントなど) を収集します。評価とは異なり、フィードバックには送信者の ID が含まれ、スパン、トレース、セッション、または顧客定義のエンティティを対象にできます。詳細については、エンドユーザーフィードバックを参照してください。

スパン、トレース、セッション、または顧客定義のエンティティに関連付けられたエンドユーザーフィードバックを送信するには、LLMObs.submit_feedback() を使用します。

LLMObs.submit_feedback() メソッドは次の引数を受け付けます。

label
必須 - 文字列
フィードバックメトリクスの名前。. を含めないでください。
metric_type
必須 - 文字列
フィードバックのタイプ。categorical、score、boolean、json、または text である必要があります。
value
必須 - 文字列、数値型、Boolean、または辞書
フィードバックの値。文字列 (metric_type==categorical または metric_type==text)、整数または浮動小数点数 (metric_type==score)、Boolean (metric_type==boolean)、または辞書 (metric_type==json) である必要があります。
submitter
必須 - 辞書
フィードバックの送信者を識別する辞書。空でない id (文字列) を含める必要があり、user などの任意の type (文字列) を含めることができます。
span
オプション - 辞書
このフィードバックに関連付けられたスパンを識別する辞書。この辞書を生成するには、LLMObs.export_span() を使用します。
span_id
オプション - 文字列
このフィードバックに関連付けられたスパンの ID。
trace_id
オプション - 文字列
このフィードバックに関連付けられたトレースの ID。
session_id
オプション - 文字列
このフィードバックに関連付けられたセッションの ID。
feedback_join_key
オプション - 文字列
インシデント ID やチケット ID など、このフィードバックに関連付けられた顧客定義のキー。フィードバックをスパンに関連付けるには、まず同じ値を持つ feedback_join_key タグを付けてスパンにアノテーションを付けてください。スパンの拡張を参照してください。

注: span、span_id、trace_id、session_id、または feedback_join_key のいずれか 1 つのみを指定する必要があります。複数指定した場合、または何も指定しなかった場合は、ValueError が発生します。

ml_app
オプション - 文字列
ML アプリケーションの名前。指定されていない場合、SDK 用に構成された ML アプリケーションがデフォルトで使用されます。
timestamp_ms
オプション - 整数
フィードバックが生成された Unix タイムスタンプ (ミリ秒単位)。指定しない場合は、現在の時間がデフォルト設定されます。
tags
オプション - 辞書
フィードバックに関してユーザーがタグとして追加できる文字列のキーと値のペアの辞書。タグの詳細については、タグの概要を参照してください。
assessment
オプション - 文字列
このフィードバックの評価。指定可能な値は、pass と fail です。
reasoning
オプション - 文字列
フィードバックのテキストによる説明。

例

from ddtrace.llmobs import LLMObs
from ddtrace.llmobs.decorators import llm

@llm(model_name="claude", name="invoke_llm", model_provider="anthropic")
def llm_call():
    completion = ... # user application logic to invoke LLM
    span_context = LLMObs.export_span(span=None)

    # submitting feedback for a trace
    LLMObs.submit_feedback(
        label="thumbs",
        metric_type="categorical",
        value="down",
        submitter={"id": "user-123", "type": "user"},
        trace_id=span_context["trace_id"],
        assessment="fail",
    )

    # connecting the span to a customer-defined entity
    LLMObs.annotate(tags={"feedback_join_key": "incident-123"})

    # submitting feedback for that entity
    LLMObs.submit_feedback(
        label="user_comment",
        metric_type="text",
        value="The investigation missed the customer impact.",
        submitter={"id": "user-123", "type": "user"},
        feedback_join_key="incident-123",
    )
    return completion

スパン、トレース、セッション、または顧客定義のエンティティに関連付けられたエンドユーザーフィードバックを送信するには、llmobs.submitFeedback() を使用します。

llmobs.submitFeedback() メソッドは、以下のプロパティを持つオプションオブジェクトを受け入れます。

label
必須 - 文字列
フィードバックメトリクスの名前。. を含めないでください。
metricType
必須 - 文字列
フィードバックのタイプ。categorical、score、boolean、json、または text のいずれかである必要があります。
value
必須 - 文字列、数値、Boolean、またはオブジェクト
フィードバックの値。文字列 (categorical および text メトリクスタイプの場合)、数値 (score の場合)、Boolean (boolean の場合)、または JSON オブジェクト (json の場合) である必要があります。
submitter
必須 - オブジェクト
フィードバックを送信したユーザーを識別するオブジェクト。空でない id (文字列) を含める必要があり、user などの任意の type (文字列) を含めることができます。
span
オプション - オブジェクト
フィードバックを関連付けるスパンのコンテキスト。これは llmobs.exportSpan() の出力である必要があります。
spanId
オプション - 文字列
フィードバックを関連付けるスパンの ID。
traceId
オプション - 文字列
フィードバックを関連付けるトレースの ID。
sessionId
オプション - 文字列
フィードバックを関連付けるセッションの ID。
feedbackJoinKey
オプション - 文字列
インシデント ID やチケット ID など、フィードバックを関連付けるために顧客が定義したキー。フィードバックをスパンに関連付けるには、スパンにも同じキーを設定してください。

注: span、spanId、traceId、sessionId、または feedbackJoinKey のいずれか 1 つのみを指定する必要があります。1 つより多く指定した場合、または何も指定しなかった場合は、エラーが発生します。

mlApp
オプション - 文字列
ML アプリケーションの名前。指定されていない場合、SDK 用に構成された ML アプリケーションがデフォルトで使用されます。
timestampMs
オプション - 数値
フィードバックが生成された Unix タイムスタンプ (ミリ秒単位)。指定しない場合は、現在の時間がデフォルト設定されます。
tags
オプション - オブジェクト
フィードバックに関してユーザーがタグとして追加できる文字列のキーと値のペアのオブジェクト。タグの詳細については、タグの概要を参照してください。
assessment
オプション - 文字列
このフィードバックの評価。指定可能な値は、pass と fail です。
reasoning
オプション - 文字列
フィードバックのテキストによる説明。

例

function llmCall () {
  const completion = ... // user application logic to invoke LLM
  const spanContext = llmobs.exportSpan()

  // submitting feedback for a trace
  llmobs.submitFeedback({
    label: 'thumbs',
    metricType: 'boolean',
    value: true,
    submitter: { id: 'user-123', type: 'user' },
    traceId: spanContext.traceId,
    assessment: 'pass'
  })

  // connecting the span to a customer-defined entity
  llmobs.annotate({
    tags: { feedback_join_key: 'incident-123' }
  })

  // submitting feedback for that entity
  llmobs.submitFeedback({
    label: 'user_comment',
    metricType: 'text',
    value: 'This answer was helpful.',
    submitter: { id: 'user-123', type: 'user' },
    feedbackJoinKey: 'incident-123'
  })
  return completion
}
llmCall = llmobs.wrap({ kind: 'llm', name: 'invokeLLM', modelName: 'claude', modelProvider: 'anthropic' }, llmCall)

スパン、トレース、セッション、または顧客定義のエンティティに関連付けられたエンドユーザーフィードバックを送信するには、LLMObs.submitFeedback() を使用します。LLMObs.Feedback.builder()を使用してフィードバックを構築します。

ビルダーでは以下のメソッドを使用できます。

label(String label)
必須
フィードバックメトリクスの名前。. を含めないでください。
categoricalValue(String)、scoreValue(double)、booleanValue(boolean)、jsonValue(Map<String, Object>)、または textValue(String)
必須
フィードバックの値。これらのメソッドのうち、いずれか 1 つのみを設定してください。これにより、メトリクスタイプも決定されます。
submitter(String id, String type)または submitter(Submitter submitter)
必須
フィードバックを送信したユーザーを識別します。idは空ではない文字列である必要があります。typeは、userのような任意の修飾子です。
span(LLMObsSpan span)、spanId(String)、traceId(String)、sessionId(String)、または feedbackJoinKey(String)
必須
フィードバックを関連付けるエンティティ。これらのメソッドのうち、いずれか 1 つのみを設定してください。インシデント ID やチケット ID などの顧客定義エンティティには feedbackJoinKey を使用し、スパンにも同じキーを設定してフィードバックを関連付けてください。
mlApp(String mlApp)
オプション
ML アプリケーションの名前。指定されていない場合、トレーサー用に構成された ML アプリケーションがデフォルトで使用されます。
timestampMs(long timestampMs)
オプション
フィードバックが生成された Unix タイムスタンプ (ミリ秒単位)。指定しない場合は、現在の時間がデフォルト設定されます。
tags(Map<String, Object> tags)または tag(String key, Object value)
オプション
フィードバックのタグ付けに使用するキーと値のペア。タグの詳細については、タグの概要を参照してください。
assessment(Assessment assessment)
オプション
このフィードバックの評価。指定可能な値は、LLMObs.Feedback.Assessment.PASS と LLMObs.Feedback.Assessment.FAIL です。
reasoning(String reasoning)
オプション
フィードバックのテキストによる説明。

注: LLMObs.submitFeedback() はフィードバックを検証し、Agent Observability が有効でフィードバックが無効な場合 (ターゲット、値、または送信者が指定されていない場合など) に IllegalArgumentException をスローします。Agent Observability が無効な場合、または Agent がアタッチされていない場合、この呼び出しは何も行いません。

例

import datadog.trace.api.llmobs.LLMObs;

public class MyJavaClass {
  public String invokeChat(String userInput) {
    LLMObsSpan llmSpan = LLMObs.startLLMSpan("my-llm-span-name", "my-llm-model", "my-company", "maybe-ml-app-override", "session-141");
    String chatResponse = "N/A";
    try {
      chatResponse = ... // user application logic to invoke LLM
    } catch (Exception e) {
      llmSpan.addThrowable(e);
      throw new RuntimeException(e);
    } finally {
      // connecting the span to a customer-defined entity
      llmSpan.setTag("feedback_join_key", "incident-123");
      llmSpan.finish();

      // submitting feedback for a trace
      LLMObs.submitFeedback(
          LLMObs.Feedback.builder()
              .traceId(llmSpan.getTraceId().toString())
              .label("thumbs")
              .booleanValue(true)
              .submitter("user-123", "end_user")
              .assessment(LLMObs.Feedback.Assessment.PASS)
              .reasoning("answered the question")
              .build());

      // submitting feedback for that entity
      LLMObs.submitFeedback(
          LLMObs.Feedback.builder()
              .feedbackJoinKey("incident-123")
              .label("user_comment")
              .textValue("The answer missed the customer impact.")
              .submitter("user-123", "end_user")
              .assessment(LLMObs.Feedback.Assessment.FAIL)
              .build());
    }
    return chatResponse;
  }
}

スパン処理

スパン上の入力および出力データを変更するには、プロセッサー関数を設定します。プロセッサー関数は、条件付きの入力/出力変更を可能にするために、スパンタグにアクセスできます。プロセッサー関数は、変更されたスパンを返してそれを出力するか、None/nullを返してスパンが完全に出力されるのを防ぐことができます。これは、機密データを含むスパンや特定の基準を満たすスパンをフィルタリングするのに便利です。

例

from ddtrace.llmobs import LLMObs
from ddtrace.llmobs import LLMObsSpan

def redact_processor(span: LLMObsSpan) -> LLMObsSpan:
    if span.get_tag("no_output") == "true":
        for message in span.output:
            message["content"] = ""
    return span


# If using LLMObs.enable()
LLMObs.enable(
  ...
  span_processor=redact_processor,
)
# else when using `ddtrace-run`
LLMObs.register_processor(redact_processor)

with LLMObs.llm("invoke_llm_with_no_output"):
    LLMObs.annotate(tags={"no_output": "true"})

例: 自動インスツルメンテーションによる条件付き変更

自動インスツルメンテーションを使用する場合、スパンは必ずしもコンテキスト的にアクセスできるわけではありません。自動インスツルメンテーションスパンの入力と出力を条件付きで変更するには、スパンプロセッサーに加えて annotation_context() を使用します。

from ddtrace.llmobs import LLMObs
from ddtrace.llmobs import LLMObsSpan

def redact_processor(span: LLMObsSpan) -> LLMObsSpan:
    if span.get_tag("no_input") == "true":
        for message in span.input:
            message["content"] = ""
    return span

LLMObs.register_processor(redact_processor)


def call_openai():
    with LLMObs.annotation_context(tags={"no_input": "true"}):
        # make call to openai
        ...

例: スパンの出力を防ぐ

from ddtrace.llmobs import LLMObs
from ddtrace.llmobs import LLMObsSpan
from typing import Optional

def filter_processor(span: LLMObsSpan) -> Optional[LLMObsSpan]:
    # Skip spans that are marked as internal or contain sensitive data
    if span.get_tag("internal") == "true" or span.get_tag("sensitive") == "true":
        return None  # This span will not be emitted

    # Process and return the span normally
    return span

LLMObs.register_processor(filter_processor)

# This span will be filtered out and not sent to Datadog
with LLMObs.workflow("internal_workflow"):
    LLMObs.annotate(tags={"internal": "true"})
    # ... workflow logic

例

const tracer = require('dd-trace').init({
  llmobs: {
    mlApp: "<YOUR_ML_APP_NAME>"
  }
})

const llmobs = tracer.llmobs

function redactProcessor(span) {
  if (span.getTag("no_output") === "true") {
    for (const message of span.output) {
      message.content = ""
    }
  }
  return span
}

llmobs.registerProcessor(redactProcessor)

例: 自動インスツルメンテーションによる条件付き変更

自動インスツルメンテーションを使用する場合、スパンは必ずしもコンテキスト的にアクセスできるわけではありません。自動インスツルメンテーションスパンの入力と出力を条件付きで変更するには、スパンプロセッサーに加えて llmobs.annotationContext() を使用します。

const { llmobs } = require('dd-trace');

function redactProcessor(span) {
  if (span.getTag("no_input") == "true") {
    for (const message of span.input) {
      message.content = "";
    }
  }

  return span;
}

llmobs.registerProcessor(redactProcessor);

async function callOpenai() {
  await llmobs.annotationContext({ tags: { no_input: "true" } }, async () => {
    // make call to openai
  });
}

例: スパンの出力を防ぐ

const tracer = require('dd-trace').init({
  llmobs: {
    mlApp: "<YOUR_ML_APP_NAME>"
  }
})

const llmobs = tracer.llmobs

function filterProcessor(span) {
  // Skip spans that are marked as internal or contain sensitive data
  if (span.getTag("internal") === "true" || span.getTag("sensitive") === "true") {
    return null  // This span will not be emitted
  }

  // Process and return the span normally
  return span
}

llmobs.registerProcessor(filterProcessor)

// This span will be filtered out and not sent to Datadog
function internalWorkflow() {
  return llmobs.trace({ kind: 'workflow', name: 'internalWorkflow' }, (span) => {
    llmobs.annotate({ tags: { internal: "true" } })
    // ... workflow logic
  })
}

ユーザーセッションの追跡

セッション追跡により、特定のユーザーに複数のインタラクションを関連付けることができます。

新しいトレースまたは新しいプロセス内のスパンの root スパンを開始する際には、基盤となるユーザーセッションの文字列 ID を持つ session_id 引数を指定し、スパンのタグとして送信します。オプションで、user_handle、user_name、および user_id タグを指定することもできます。

from ddtrace.llmobs.decorators import workflow

@workflow(session_id="<SESSION_ID>")
def process_user_message():
    LLMObs.annotate(
        ...
        tags = {"user_handle": "poodle@dog.com", "user_id": "1234", "user_name": "poodle"}
    )
    return

セッショントラッキングタグ

タグ説明
session_id単一のユーザーセッション、たとえばチャットセッションを表す ID。
user_handleチャットセッションのユーザーのハンドル。
user_nameチャットセッションのユーザーの名前。
user_idチャットセッションのユーザーの ID。

新しいトレースまたは新しいプロセス内のスパンの root スパンを開始する際には、基盤となるユーザーセッションの文字列 ID を持つ sessionId 引数を指定します。

function processMessage() {
    ... # user application logic
    return
}
processMessage = llmobs.wrap({ kind: 'workflow', sessionId: "<SESSION_ID>" }, processMessage)

新しいトレースまたは新しいプロセス内のスパンの root スパンを開始する際には、基盤となるユーザーセッションの文字列 ID を持つ sessionId 引数を指定します。

import datadog.trace.api.llmobs.LLMObs;

public class MyJavaClass {
  public String processChat(int userID) {
    LLMObsSpan workflowSpan = LLMObs.startWorkflowSpan("incoming-chat", null, "session-" + System.currentTimeMillis() + "-" + userID);
    String chatResponse = answerChat(); // user application logic
    workflowSpan.annotateIO(...); // record the input and output
    workflowSpan.finish();
    return chatResponse;
  }
}

分散トレーシング

SDK では、分散サービスまたはホスト間のトレーシングがサポートされています。分散トレーシングは、Web リクエスト間でスパン情報を伝播させることによって機能します。

ddtrace ライブラリには、よく使用される Web フレームワーク および HTTP ライブラリ向けの分散トレーシングに役立つ、すぐに使用できるインテグレーションが用意されています。サポートされているこれらのライブラリを使用してアプリケーションでリクエストが行われる場合、次のコマンドを実行することで分散トレーシングを有効にできます。

from ddtrace import patch
patch(<INTEGRATION_NAME>=True)

アプリケーションにより、サポートされているこれらのライブラリのいずれも使用されていない場合、HTTP ヘッダーとの間でスパン情報を手動で伝播させることで、分散トレーシングを有効にできます。SDK には、リクエストヘッダーにトレースコンテキストを挿入および有効化するためのヘルパーメソッド LLMObs.inject_distributed_headers() と LLMObs.activate_distributed_headers() が用意されています。

分散ヘッダーへの挿入

LLMObs.inject_distributed_headers() メソッドはスパンを受け取り、リクエストに含まれる HTTP ヘッダーにそのコンテキストを挿入します。このメソッドは次の引数を受け付けます。

request_headers
必須 - 辞書
トレースコンテキスト属性で拡張するための HTTP ヘッダー。
span
オプション - スパン - デフォルト: The current active span.
指定されたリクエストヘッダーにそのコンテキストを挿入するスパン。関数デコレータを含む任意のスパン、デフォルトでは現在のアクティブスパンになります。

分散ヘッダーの有効化

LLMObs.activate_distributed_headers() メソッドは HTTP ヘッダーを受け取り、新しいサービスで有効にするトレースコンテキスト属性を抽出します。

注: 下流サービスでスパンを開始する前に LLMObs.activate_distributed_headers() を呼び出す必要があります。以前に開始されたスパン (関数デコレータのスパンを含む) は、分散トレースに取り込まれません。

このメソッドは次の引数を受け付けます。

request_headers
必須 - 辞書
トレースコンテキスト属性を抽出するための HTTP ヘッダー。

例

client.py

from ddtrace.llmobs import LLMObs
from ddtrace.llmobs.decorators import workflow

@workflow
def client_send_request():
    request_headers = {}
    request_headers = LLMObs.inject_distributed_headers(request_headers)
    send_request("<method>", request_headers)  # arbitrary HTTP call

server.py

from ddtrace.llmobs import LLMObs

def server_process_request(request):
    LLMObs.activate_distributed_headers(request.headers)
    with LLMObs.task(name="process_request") as span:
        pass  # arbitrary server work

dd-trace ライブラリには、よく使用される Web フレームワーク 向けの分散トレーシングに役立つ、すぐに使用できるインテグレーションが用意されています。トレーサーを要求すると、これらのインテグレーションが自動的に有効になりますが、次のようにオプションで無効にすることもできます。

const tracer = require('dd-trace').init({
  llmobs: { ... },
})
tracer.use('http', false) // disable the http integration

高度なトレース

インラインメソッドを使用したスパンのトレース

各スパンの種類について、ddtrace.llmobs.LLMObs クラスには、特定のコードブロックが含む操作を自動的にトレースするための対応するインラインメソッドが用意されています。これらのメソッドは、対応する関数デコレータと同じ引数シグネチャを持ち、指定されていない場合は name がスパンの種類 (llm、workflow など) にデフォルト設定されます。これらのメソッドは、囲まれたコードブロックが完了した後にスパンを自動的に終了させるためのコンテキストマネージャーとして使用できます。

例

from ddtrace.llmobs import LLMObs

def process_message():
    with LLMObs.workflow(name="process_message", session_id="<SESSION_ID>", ml_app="<ML_APP>") as workflow_span:
        ... # user application logic
    return

コンテキストをまたがるスパンの永続化

異なるコンテキストやスコープにまたいでスパンを手動で開始および停止するには、次のようにします。

  1. 同じメソッド (たとえば、ワークフロースパンの LLMObs.workflow メソッド) を使用して手動でスパンを開始しますが、コンテキストマネージャーとしてではなく、単なる関数呼び出しとして行います。
  2. ほかの関数の引数としてスパンオブジェクトを渡します。
  3. span.finish() メソッドを使用してスパンを手動で停止します。注: スパンは手動で終了する必要があります。そうしないと、送信されません。

例

from ddtrace.llmobs import LLMObs

def process_message():
    workflow_span = LLMObs.workflow(name="process_message")
    ... # user application logic
    separate_task(workflow_span)
    return

def separate_task(workflow_span):
    ... # user application logic
    workflow_span.finish()
    return

サーバーレス環境における強制フラッシュ

LLMObs.flush() は、バッファされたすべての Agent Observability データを Datadog バックエンドに送信するブロッキング関数です。これは、サーバーレス環境で、すべての Agent Observability トレースが送信されるまでアプリケーションが終了しないようにするのに役立ちます。

複数のアプリケーションのトレース

SDK では、同じサービスからの複数の LLM アプリケーションのトレースがサポートされています。

環境変数 DD_LLMOBS_ML_APP を、生成されるすべてのスパンがデフォルトでグループ化される LLM アプリケーションの名前に設定できます。

この構成をオーバーライドして、指定された root スパンに異なる LLM アプリケーション名を使用するには、新しいトレースまたは新しいプロセス内のスパンの root スパンを開始するときに、ml_app 引数に基礎となる LLM アプリケーションの文字列名を渡します。

from ddtrace.llmobs.decorators import workflow

@workflow(name="process_message", ml_app="<NON_DEFAULT_ML_APP_NAME>")
def process_message():
    ... # user application logic
    return

インラインメソッドを使用したスパンのトレース

llmobs SDK には、指定のコードブロックが含む操作を自動的にトレースするための対応するインラインメソッドが用意されています。これらのメソッドは、対応する関数ラッパーと同じ引数シグネチャを持っていますが、名前を匿名コールバックから推測することができないため、name が必要です。このメソッドは、次の条件下でスパンを終了します。

  • 関数が Promise を返す場合、スパンは Promise が解決または拒否されたときに終了します。
  • 関数が最後のパラメーターとしてコールバックを受け取る場合、スパンはそのコールバックが呼び出されたときに終了します。
  • 関数がコールバックを受け取らず、Promise を返さない場合、スパンは関数実行の終了時に終了します。

コールバックなしの例

function processMessage () {
  return llmobs.trace({ kind: 'workflow', name: 'processMessage', sessionId: '<SESSION_ID>', mlApp: '<ML_APP>' }, workflowSpan => {
    ... // user application logic
    return
  })
}

コールバックありの例

function processMessage () {
  return llmobs.trace({ kind: 'workflow', name: 'processMessage', sessionId: '<SESSION_ID>', mlApp: '<ML_APP>' }, (workflowSpan, cb) => {
    ... // user application logic
    let maybeError = ...
    cb(maybeError) // the span will finish here, and tag the error if it is not null or undefined
    return
  })
}

この関数の戻り値の型は、トレースされた関数の戻り値の型と一致します。

function processMessage () {
  const result = llmobs.trace({ kind: 'workflow', name: 'processMessage', sessionId: '<SESSION_ID>', mlApp: '<ML_APP>' }, workflowSpan => {
    ... // user application logic
    return 'hello world'
  })

  console.log(result) // 'hello world'
  return result
}

TypeScript における関数デコレータ

Node.js Agent Observability SDK には、TypeScript アプリケーション用の関数デコレータとして機能する llmobs.decorate 関数が用意されています。この関数のトレース動作は llmobs.wrap と同じです。

例

// index.ts
import tracer from 'dd-trace';
tracer.init({
  llmobs: {
    mlApp: "<YOUR_ML_APP_NAME>",
  },
});

const { llmobs } = tracer;

class MyAgent {
  @llmobs.decorate({ kind: 'agent' })
  async runChain () {
    ... // user application logic
    return
  }
}

サーバーレス環境における強制フラッシュ

llmobs.flush() は、バッファされたすべての Agent Observability データを Datadog バックエンドに送信するブロッキング関数です。これは、サーバーレス環境で、すべての Agent Observability トレースが送信されるまでアプリケーションが終了しないようにするのに役立ちます。

複数のアプリケーションのトレース

SDK では、同じサービスからの複数の LLM アプリケーションのトレースがサポートされています。

環境変数 DD_LLMOBS_ML_APP を、生成されるすべてのスパンがデフォルトでグループ化される LLM アプリケーションの名前に設定できます。

この構成をオーバーライドして、指定された root スパンに異なる LLM アプリケーション名を使用するには、新しいトレースまたは新しいプロセス内のスパンの root スパンを開始するときに、mlApp 引数に基礎となる LLM アプリケーションの文字列名を渡します。

function processMessage () {
  ... // user application logic
  return
}
processMessage = llmobs.wrap({ kind: 'workflow', name: 'processMessage', mlApp: '<NON_DEFAULT_ML_APP_NAME>' }, processMessage)

アプリケーション命名ガイドライン

アプリケーション名 (DD_LLMOBS_ML_APP の値) は、次のガイドラインに従う必要があります。

  • 小文字の Unicode 文字列でなければならない
  • 最大 193 文字まで使用できる
  • 連続したアンダースコアや末尾のアンダースコアを含むことはできない
  • 次の文字を含めることができる:
    • 英数字
    • アンダースコア
    • マイナス
    • コロン
    • ピリオド
    • スラッシュ

参考資料