Skip to content

OpenTelemetryのサポート

このページでは、AIエージェントのトレースと監視のために、KoogエージェントフレームワークにおけるOpenTelemetryのサポートについて詳しく説明します。

概要

OpenTelemetryは、アプリケーションからテレメトリーデータ(トレース)を生成、収集、エクスポートするためのツールを提供する可観測性フレームワークです。KoogのOpenTelemetry機能を使用すると、AIエージェントを計装してテレメトリーデータを収集できます。これは、以下の点で役立ちます。

  • エージェントのパフォーマンスと挙動を監視する
  • 複雑なエージェントのワークフローにおける問題をデバッグする
  • エージェントの実行フローを可視化する
  • LLM呼び出しとツール使用状況を追跡する
  • エージェントの挙動パターンを分析する

OpenTelemetryの主要な概念

  • Spans: スパンは、分散トレース内の個々の作業単位または操作を表します。これらは、エージェントの実行、関数呼び出し、LLM呼び出し、ツール呼び出しなど、アプリケーション内の特定の活動の開始と終了を示します。
  • Attributes: 属性は、スパンなどのテレメトリー関連アイテムに関するメタデータを提供します。属性はキーと値のペアとして表現されます。
  • Events: イベントは、スパンのライフタイム中の特定の時点(スパン関連イベント)であり、発生した可能性のある注目すべき事柄を表します。
  • Exporters: エクスポーターは、収集されたテレメトリーデータをさまざまなバックエンドまたは宛先に送信する役割を担うコンポーネントです。
  • Collectors: コレクターは、テレメトリーデータを受信、処理、エクスポートします。これらはアプリケーションと可観測性バックエンドの間の仲介役として機能します。
  • Samplers: サンプラーは、サンプリング戦略に基づいてトレースを記録するかどうかを決定します。これらはテレメトリーデータのボリュームを管理するために使用されます。
  • Resources: リソースは、テレメトリーデータを生成するエンティティを表します。これらはリソース属性によって識別され、リソースに関する情報を提供するキーと値のペアです。

KoogのOpenTelemetry機能は、さまざまなエージェントイベントに対してスパンを自動的に作成します。これには以下が含まれます。

  • エージェントの実行開始と終了
  • ノードの実行
  • LLM呼び出し
  • ツール呼び出し

インストール

KoogでOpenTelemetryを使用するには、OpenTelemetry機能をエージェントに追加します。

kotlin
val agent = AIAgent(
    executor = simpleOpenAIExecutor(apiKey),
    llmModel = OpenAIModels.Chat.GPT4o,
    systemPrompt = "You are a helpful assistant.",
    installFeatures = {
        install(OpenTelemetry) {
            // Configuration options go here
        }
    }
)

設定

基本設定

エージェントでOpenTelemetry機能を設定する際に設定できる利用可能なプロパティの完全なリストを以下に示します。

NameData typeDefault valueDescription
serviceNameStringai.koog計装されるサービスの名前。
serviceVersionStringCurrent Koog library version計装されるサービスのバージョン。
isVerboseBooleanfalseOpenTelemetry設定のデバッグのための詳細ログを有効にするかどうか。
sdkOpenTelemetrySdkテレメトリー収集に使用するOpenTelemetry SDKインスタンス。
tracerTracerスパン作成に使用するOpenTelemetryトレーサーインスタンス。

NOTE

sdkおよびtracerプロパティは、アクセス可能なパブリックプロパティですが、以下にリストされているパブリックメソッドを使用してのみ設定できます。

OpenTelemetryConfigクラスには、異なる設定項目に関連するアクションを表すメソッドも含まれています。以下は、基本的な設定項目セットでOpenTelemetry機能をインストールする例です。

kotlin
install(OpenTelemetry) {
    // Set your service configuration
    setServiceInfo("my-agent-service", "1.0.0")
    
    // Add the Logging exporter
    addSpanExporter(LoggingSpanExporter.create())
}

利用可能なメソッドのリファレンスについては、以下のセクションを参照してください。

setServiceInfo

名前とバージョンを含むサービス情報を設定します。以下の引数を取ります。

NameData typeRequiredDefault valueDescription
serviceNameStringYes計装されるサービスの名前。
serviceVersionStringYes計装されるサービスのバージョン。

addSpanExporter

テレメトリーデータを外部システムに送信するためのスパンエクスポーターを追加します。以下の引数を取ります。

NameData typeRequiredDefault valueDescription
exporterSpanExporterYesカスタムスパンエクスポーターのリストに追加するSpanExporterインスタンス。

addSpanProcessor

スパンがエクスポートされる前に処理するためのスパンプロセッサーを追加します。以下の引数を取ります。

NameData typeRequiredDefault valueDescription
processorSpanProcessorYesエクスポート前にテレメトリーデータを処理するためのカスタムロジックを含むスパンプロセッサー。

addResourceAttributes

サービスに関する追加のコンテキストを提供するためのリソース属性を追加します。以下の引数を取ります。

NameData typeRequiredDefault valueDescription
attributesMap<AttributeKey<T>, T>Yesサービスに関する追加の詳細を提供するキーと値のペア。

setSampler

どのスパンを収集するかを制御するためにサンプリング戦略を設定します。以下の引数を取ります。

NameData typeRequiredDefault valueDescription
samplerSamplerYesOpenTelemetry設定のために設定するサンプラーインスタンス。

setVerbose

OpenTelemetry設定のデバッグ用の詳細ログを有効または無効にします。以下の引数を取ります。

NameData typeRequiredDefault valueDescription
verboseBooleanYesfalsetrueの場合、アプリケーションはより詳細なテレメトリーデータを収集します。

高度な設定

より高度な設定については、以下の設定オプションもカスタマイズできます。

  • Sampler: 収集されるデータの頻度と量を調整するためにサンプリング戦略を設定します。
  • Resource attributes: テレメトリーデータを生成しているプロセスに関する情報を追加します。
kotlin
install(OpenTelemetry) {
    // Set your service configuration
    setServiceInfo("my-agent-service", "1.0.0")
    
    // Add the Logging exporter
    addSpanExporter(LoggingSpanExporter.create())
    
    // Set the sampler 
    setSampler(Sampler.traceIdRatioBased(0.5)) 

    // Add resource attributes
    addResourceAttributes(mapOf(
        AttributeKey.stringKey("custom.attribute") to "custom-value")
    )
}

Sampler

サンプラーを定義するには、使用したいサンプリング戦略を表すopentelemetry-java SDKのSamplerクラス(io.opentelemetry.sdk.trace.samplers.Sampler)の対応するメソッドを使用します。

デフォルトのサンプリング戦略は以下の通りです。

  • Sampler.alwaysOn(): すべてのスパン(トレース)がサンプリングされるデフォルトのサンプリング戦略。

利用可能なサンプラーとサンプリング戦略の詳細については、OpenTelemetryのSamplerドキュメントを参照してください。

Resource attributes

リソース属性は、テレメトリーデータを生成するプロセスに関する追加情報を表します。Koogには、デフォルトで設定される一連のリソース属性が含まれています。

  • service.name
  • service.version
  • service.instance.time
  • os.type
  • os.version
  • os.arch

service.name属性のデフォルト値はai.koogであり、service.versionのデフォルト値は現在使用されているKoogライブラリのバージョンです。

デフォルトのリソース属性に加えて、カスタム属性を追加することもできます。KoogでOpenTelemetry設定にカスタム属性を追加するには、OpenTelemetry設定でaddResourceAttributes()メソッドを使用します。このメソッドはキーと値を引数として取ります。

kotlin
addResourceAttributes(mapOf(
    AttributeKey.stringKey("custom.attribute") to "custom-value")
)

スパンの種類と属性

OpenTelemetry機能は、エージェント内のさまざまな操作を追跡するために、異なるタイプのスパンを自動的に作成します。

  • CreateAgentSpan: エージェントを実行すると作成され、エージェントが閉じられるか、プロセスが終了すると閉じられます。
  • InvokeAgentSpan: エージェントの呼び出し。
  • NodeExecuteSpan: エージェントの戦略におけるノードの実行。これはカスタムのKoog固有スパンです。
  • InferenceSpan: LLM呼び出し。
  • ExecuteToolSpan: ツール呼び出し。

スパンはネストされた階層構造で整理されます。以下はスパン構造の例です。

text
CreateAgentSpan
    InvokeAgentSpan
        NodeExecuteSpan
            InferenceSpan
        NodeExecuteSpan
            ExecuteToolSpan
        NodeExecuteSpan
            InferenceSpan

スパン属性

スパン属性は、スパンに関連するメタデータを提供します。各スパンは独自の属性セットを持ち、一部のスパンは属性を繰り返すこともできます。

Koogは、OpenTelemetryの生成AIイベントのセマンティック規約に従う事前定義された属性のリストをサポートしています。たとえば、規約ではgen_ai.conversation.idという名前の属性が定義されており、これは通常、スパンに必須の属性です。Koogでは、この属性の値はエージェント実行の一意の識別子であり、agent.run()メソッドを呼び出すと自動的に設定されます。

さらに、KoogはカスタムのKoog固有属性も含まれています。これらの属性のほとんどはkoog.プレフィックスで識別できます。利用可能なカスタム属性は以下の通りです。

  • koog.agent.strategy.name: エージェント戦略の名前。戦略は、エージェントの目的を説明するKoog関連エンティティです。InvokeAgentSpanスパンで使用されます。
  • koog.node.name: 実行中のノードの名前。NodeExecuteSpanスパンで使用されます。

イベント

スパンには_イベント_もアタッチできます。イベントは、何か関連する出来事が起こった特定の時点を表します。たとえば、LLM呼び出しが開始または終了したときなどです。イベントには属性もあり、さらにイベントの_本体フィールド_も含まれます。

OpenTelemetryの生成AIイベントのセマンティック規約に沿って、以下のイベントタイプがサポートされています。

  • SystemMessageEvent: モデルに渡されるシステム指示。
  • UserMessageEvent: モデルに渡されるユーザーメッセージ。
  • AssistantMessageEvent: モデルに渡されるアシスタントメッセージ。
  • ToolMessageEvent: モデルに渡されるツールまたは関数呼び出しからの応答。
  • ChoiceEvent: モデルからの応答メッセージ。

NOTE

optentelemetry-java SDKは、イベントを追加する際にイベント本体フィールドパラメータをサポートしていません。したがって、KoogのOpenTelemetryサポートでは、イベント本体フィールドはキーがbodyで値の型が文字列である個別の属性です。この文字列には、イベント本体フィールドのコンテンツまたはペイロードが含まれており、通常はJSONのようなオブジェクトです。イベント本体フィールドの例については、OpenTelemetryドキュメントを参照してください。opentelemetry-javaにおけるイベント本体フィールドのサポート状況については、関連するGitHubイシューを参照してください。

エクスポーター

エクスポーターは、収集されたテレメトリーデータをOpenTelemetry Collectorまたは他の種類の宛先やバックエンド実装に送信します。エクスポーターを追加するには、OpenTelemetry機能をインストールする際にaddSpanExporter()メソッドを使用します。このメソッドは以下の引数を取ります。

NameData typeRequiredDefaultDescription
exporterSpanExporterYesカスタムスパンエクスポーターのリストに追加するSpanExporterインスタンス。

以下のセクションでは、opentelemetry-java SDKの最も一般的に使用されるエクスポーターのいくつかについて説明します。

ロギングエクスポーター

トレース情報をコンソールに出力するロギングエクスポーターです。LoggingSpanExporterio.opentelemetry.exporter.logging.LoggingSpanExporter)は、opentelemetry-java SDKの一部です。

このタイプのエクスポートは、開発およびデバッグ目的で役立ちます。

kotlin
install(OpenTelemetry) {
    // Add the logging exporter
    addSpanExporter(LoggingSpanExporter.create())
    // Add more exporters as needed
}

OpenTelemetry HTTPエクスポーター

OpenTelemetry HTTPエクスポーター(OtlpHttpSpanExporter)は、opentelemetry-java SDK(io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter)の一部であり、HTTP経由でスパンデータをバックエンドに送信します。

kotlin
install(OpenTelemetry) {
   // Add OpenTelemetry HTTP exporter 
   addSpanExporter(
      OtlpHttpSpanExporter.builder()
         // Set the maximum time to wait for the collector to process an exported batch of spans 
         .setTimeout(30, TimeUnit.SECONDS)
         // Set the OpenTelemetry endpoint to connect to
         .setEndpoint("http://localhost:3000/api/public/otel/v1/traces")
         // Add the authorization header
         .addHeader("Authorization", "Basic $AUTH_STRING")
         .build()
   )
}

OpenTelemetry gRPCエクスポーター

OpenTelemetry gRPCエクスポーター(OtlpGrpcSpanExporter)は、opentelemetry-java SDK(io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter)の一部です。gRPC経由でテレメトリーデータをバックエンドにエクスポートし、データを受信するバックエンド、コレクター、またはエンドポイントのホストとポートを定義できます。デフォルトのポートは4317です。

kotlin
install(OpenTelemetry) {
   // Add OpenTelemetry gRPC exporter 
   addSpanExporter(
      OtlpGrpcSpanExporter.builder()
          // Set the host and the port
         .setEndpoint("http://localhost:4317")
         .build()
   )
}

Jaegerとの統合

Jaegerは、OpenTelemetryと連携する人気の分散トレースシステムです。Koogリポジトリのexamples内のopentelemetryディレクトリには、JaegerとKoogエージェントでOpenTelemetryを使用する例が含まれています。

前提条件

KoogとJaegerでOpenTelemetryをテストするには、提供されているdocker-compose.yamlファイルを使用してJaeger OpenTelemetryオールインワンプロセスを開始します。以下のコマンドを実行してください。

bash
docker compose up -d

提供されているDocker Compose YAMLファイルには、以下の内容が含まれています。

yaml
# docker-compose.yaml
services:
  jaeger-all-in-one:
    image: jaegertracing/all-in-one:1.39
    container_name: jaeger-all-in-one
    environment:
      - COLLECTOR_OTLP_ENABLED=true
    ports:
      - "4317:4317"
      - "16686:16686"

Jaeger UIにアクセスしてトレースを表示するには、http://localhost:16686を開いてください。

Jaegerで使用するためのテレメトリーデータをエクスポートするために、この例ではopentelemetry-java SDKのLoggingSpanExporterio.opentelemetry.exporter.logging.LoggingSpanExporter)とOtlpGrpcSpanExporterio.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter)を使用しています。

以下に完全なコードサンプルを示します。

kotlin
fun main() {
    runBlocking {
        val agent = AIAgent(
            executor = simpleOpenAIExecutor(openAIApiKey),
            llmModel = OpenAIModels.Reasoning.O4Mini,
            systemPrompt = "You are a code assistant. Provide concise code examples."
        ) {
            install(OpenTelemetry) {
                // Add a console logger for local debugging
                addSpanExporter(LoggingSpanExporter.create())

                // Send traces to OpenTelemetry collector
                addSpanExporter(
                    OtlpGrpcSpanExporter.builder()
                        .setEndpoint("http://localhost:4317")
                        .build()
                )
            }
        }

        agent.use { agent ->
            println("Running the agent with OpenTelemetry tracing...")

            val result = agent.run("Tell me a joke about programming")

            println("Agent run completed with result: '$result'." +
                    "
Check Jaeger UI at http://localhost:16686 to view traces")
        }
    }
}

トラブルシューティング

よくある問題

  1. JaegerまたはLangfuseにトレースが表示されない

    • サービスが実行されており、OpenTelemetryポート(4317)にアクセス可能であることを確認してください。
    • OpenTelemetryエクスポーターが正しいエンドポイントで設定されていることを確認してください。
    • トレースがエクスポートされるまで、エージェントの実行後に数秒待つようにしてください。
  2. スパンが見つからない、またはトレースが不完全

    • エージェントの実行が正常に完了したことを確認してください。
    • エージェントの実行後にアプリケーションを早すぎる段階で終了させていないことを確認してください。
    • スパンがエクスポートされる時間を確保するために、エージェント実行後に遅延を追加してください。
  3. 過剰な数のスパン

    • samplerプロパティを設定して、別のサンプリング戦略の使用を検討してください。
    • たとえば、Sampler.traceIdRatioBased(0.1)を使用して、トレースの10%のみをサンプリングします。