otel-livekit-style について
LiveKit 音声エージェントに OpenTelemetry を導入するためのスタイルガイドです。セッションのライフサイクル、個別処理、LLM 呼び出しに関するスパンとメトリクスの規約を定めています。
主な機能
- 01セッション全体のスパンライフサイクル定義
- 02個別のセッション処理の計測
- 03セッション回数と所要時間の記録
- 04LLM 呼び出しとトークン数の追跡
活用シーン
- 01LiveKit 音声セッションの計測
- 02セッション開始と所要時間の記録
- 03音声エージェント内の LLM 処理の追跡
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ superloglabs/ skills --skill otel-livekit-styleインストール後、Claude Code で/otel-livekit-styleを入力して読み込まれたか確認します。
詳細
OTel LiveKit スタイル
LiveKit のセッションライフサイクルは entrypoint(ctx) で始まり、ctx.add_shutdown_callback(on_shutdown) でクリーンアップが終了します。
セッション全体のスパン
操作がフレームワークのコールバック境界をまたぐため、voice.session スパンを on_shutdown で終了しても問題ありません。子の処理を登録して開始する間、これをアクティブにしておきます。
async def entrypoint(ctx: agents.JobContext) -> None:
await ctx.connect()
started_at = asyncio.get_running_loop().time()
session_span = tracer.start_span(
"voice.session",
attributes={
"tenant.id": tenant_id,
"user.id": user_id,
"voice.room_name": room_name,
},
)
with trace.use_span(session_span, end_on_exit=False):
voice_sessions_started.add(1, {
"tenant.id": tenant_id,
"voice.room_name.present": room_name != "unknown",
})
async def on_shutdown() -> None:
duration_ms = int((asyncio.get_running_loop().time() - started_at) * 1000)
session_span.set_attribute("voice.duration_ms", duration_ms)
voice_session_duration.record(duration_ms, {
"tenant.id": tenant_id,
"voice.disconnect_reason": disconnect_reason,
"outcome": "success",
})
session_span.end()
ctx.add_shutdown_callback(on_shutdown)
await _deliver_initial_greeting(...)
これを、シャットダウン中の短い voice.session.end スパンに置き換えないでください。
有界なセッション処理
有界な操作には、それぞれ専用のデコレーターを付けます。
@tracer.start_as_current_span("voice.deliver_initial_greeting")
async def _deliver_initial_greeting(...):
...
セッションメトリクス
以下の両方を使用します。
- エントリーポイントの開始時に
voice.sessions.startedカウンター - シャットダウン時に
voice.session.duration_msヒストグラム
重要な音声イベントには、voice.greetings.delivered などのプロダクトメトリクスを追加します。
スモークテスト
最小限の LiveKit フィクスチャでは、エージェントをインポートして、小さな計装済み関数を1つ実行するか、ローカルの OTLP エンドポイントでスパンまたはログレコードを開始するのが、適切なスモークテストの手順です。トレーサー/メーターオブジェクトが None でないことを確認するだけでは不十分です。
LLM ターン
音声エージェント内のすべての LLM プロバイダー/呼び出し箇所に、以下が必要です。
- 呼び出しを囲むスパン
- トークンカウンター(
llm.tokens.input、llm.tokens.output) - テナント/プロバイダー/モデル/ユースケース/呼び出し箇所/結果の属性
llm.cost_usd メトリクスは追加しないでください。Superlog はプロバイダー/モデル/トークンのデータから、コストを一元的に推定します。
スパンにはプロバイダーのトランスポート呼び出しではなく、プロダクトの操作名を付けます。たとえば、llm.anthropic.messages.create よりも llm.voice_response や llm.generate_copy を使用してください。
attrs = {
"tenant.id": tenant_id,
"llm.provider": "anthropic",
"llm.model": model,
"llm.use_case": "voice.initial_greeting",
"llm.call_site": "_call_mug_copy_llm",
"outcome": "success",
}
llm_tokens_input.add(input_tokens, attrs)
llm_tokens_output.add(output_tokens, attrs)