Article by: Alex Sohn
今年の初めにエージェントモニタリングをリリースし、ユーザーがアプリケーション内での LLM の利用状況やツール呼び出しを計測できるようにしました。ただし当時、エージェントモニタリングに対応していたのは Python と JavaScript のみでした。そこで私たちは、.NET 向けのエージェントモニタリング SDK、具体的には Microsoft.Extensions.AI.Abstractions 向けの開発に取り組んできました。
Sentry.Extensions.AIのご紹介
Sentry.Extensions.AI は、Microsoft.Extensions.AI.Abstractions に基づく .NET の LLM パッケージ用のインストゥルメンテーションレイヤーです。このレイヤーを使用することで、以下の LLM 使用状況を計測できます。
- LLM呼び出し
- 入力・出力
- トークン数
- モデル名
- ツール呼び出しの入出力
- LLM 呼び出しに関連する Issue
- 総コスト
これらすべてを Sentry でスパンやイベントとして確認できるため、AI の挙動を他のアプリケーション部分、例えば HTTP リクエスト、バックグラウンドジョブ、データベースクエリなどと関連付けることが可能です。
Microsoft.Extensions.AI.Abstractions とは
AI.Abstractions パッケージは、多くの他のライブラリにとっての低レベルな契約レイヤーです。これは .NET における生成 AI 用のインターフェースやデータモデルを含んでおり、他のライブラリによって実装されることを目的としています。依存関係が最小限に抑えられているため、ライブラリエコシステムの基盤として使用できます。
Microsoft.Extensions.AIとは混同しないでください。Microsoft.Extensions.AIには ChatClientBuilder などのユーティリティ、ロギングやツール呼び出しのような組み込み機能が含まれています。抽象化パッケージと Microsoft.Extensions.AI の関係は、Microsoft.Extensions.Logging とその抽象化パッケージとの関係に非常に似ています。
Microsoft.Extensions.AI.Abstractions を中心にエージェントモニタリングを構築することにより、抽象化パッケージから IChatClientを実装している限り、ユーザーは任意の LLM ライブラリを使用することができます。例えば、私たちの ASP.NET Core サンプルプロジェクトでは Microsoft.Extensions.AI.OpenAI を使用しています。これは OpenAI API を利用する IChatClient 実装を提供します。同様に、IChatClient 実装を提供する別のライブラリを使うことで、利用する LLM も簡単に差し替えることができます。
仕組み
Sentry.Extensions.AI は既存のIChatClientやツールをラップすることで動作します。これによりアプリケーションのロジックを変更することなく、LLM 呼び出しやツールの呼び出しが自動的に計測されます。
コードはこのような形になります。

AddSentry は OpenAI IChatClient をラップし、AddSentryToolInstrumentation はツール呼び出しを計測します。リクエストとレスポンスをインターセプトし、処理にかかる時間を測定し、トークンの使用状況やエラーをキャプチャした上で、すべてを基盤となるクライアントに渡します。これによりアプリケーションの挙動は変わりません。
このライブラリの作業の大半は、ストリーミングレスポンスやマルチステップのツール呼び出しループといった複雑なケースにも対応しつつ、可能な限り透過的かつ低コストで実現することでした。
エラーハンドリングを壊さずにストリーミングレスポンスを処理する方法
IChatClient.GetStreamingResponseAsync の処理を行うことは、特に厄介な部分の一つでした。このメソッドは IAsyncEnumerable<ChatResponseUpdate> を返すため、以下のことを実現したいと考えていました。
- ストリーミングループを Sentry のスパンでラップする
- オーバーヘッドを最低限に抑える
- 次のトークンを取得する際に発生する例外をキャッチし、記録した上で呼び出し元に再スローする
しかし、C# では MoveNextAsync を含む try/catch 内から yield return することができず、foreach を使用すると MoveNextAsync と yield return が暗黙的に一緒にラップされてしまいます。
そこで解決策として、非同期イテレーターを直接扱い、ストリームを進める処理と値を yield する処理を分離しました。

try/catch 内で MoveNextAsync() を呼び出し、その後に yield return を行うことで、次のことが可能になります。
- 元のストリーミング挙動を維持する
- プロバイダー側の列挙子によって発生した例外を捕捉する
- ストリームが終了または失敗したタイミングにスパンに情報を付加し完了させる
ストリーミングレスポンスを完全に可視化しつつ、呼び出し元にほぼ追加の負荷をかけない結果となります。
単一のスパンでツール呼び出しループ全体をキャプチャする
もう一つの課題は、個々のモデル呼び出しやツールの起動だけでなく、全体の「LLM + ツール」ループを表す1つのスパンをキャプチャすることでした。以下のスクリーンショットでは、1つのスパンが他のすべてのスパンの親であることがわかります。これをエージェントスパンと呼んでいます。

エージェントスパンはツール呼び出しやテキスト生成を含む全体のLLMとの一連のやり取り全体の所要時間を示します。また元の入力と最終的な出力も含まれています。
Microsoft.Extensions.AI の FunctionInvokingChatClient または UseFunctionInvocation を使用する場合、LLMの呼び出しフローはおおよそ次のようになります。

私たちはこのループ全体をカバーする1つのスパンを作成したいと考えていました。最初のLLM 呼び出しから、すべてのツール呼び出し、最終的なレスポンスに至るまでを一続きで捉えるスパンです。しかし問題は FunctionInvokingChatClient が Microsoft.Extensions.AI に存在しており、Microsoft.Extensions.AI.Abstractionsには存在していないことです。私の計測は抽象化レイヤーに基づいて構築されており、「全ループ」レベルで使えそうな分かりやすいフックがありませんでした。
そこで回避策として、FunctionInvokingChatClient の既存のテレメトリを利用しました。
- FunctionInvokingChatClientはツール呼び出しループが始まると Activity を開始し、ループが終了すると停止します。
- 私たちは Activity に接続する ActivityListener を作成し、ActivityStarted と ActivityStopped のコールバック関数を使用してSentryスパンを作成するようにしました。
- そのスパンの中では個々の LLM 呼び出しやツール呼び出しを子スパンとして記録し続けます。
これにより、まさに私たちが求めていたものを実現することができました。抽象化レイヤーから FunctionInvokingChatClient に直接アクセスできなくても、エージェントやツールのオーケストレーション全体を表す 単一の最上位スパンを作成できます。
.NET におけるエージェントモニタリングの未来
Microsoft.Extensions.AI.Abstractions は多くのAIライブラリの基盤に位置しているため、この統合はまだ始まりに過ぎません。
Microsoft の新しいエージェントフレームワークである Microsoft.Agents.AI もこれらの抽象化の上に構築されており、Semantic Kernelのような他の高レベルフレームワークも同様です。つまり私たちが現在、IChatClient の直接呼び出しを計測するために使用しているコンセプトを次のように拡張できます。
- マルチステップエージェントワークフローの追跡
- ツールやプラグインのオーケストレーションを可視化
- Semantic Kernel のパイプライン、プランナー、スキルにオブザーバビリティを追加
私たちは Sentry.Extensions.AI が .NET AI ワークロードをモニタリングする標準的な方法となることを目指しています。単一のモデルを直接呼び出す場合でも、Microsoft.Extensions.AI.Abstractions の上に複雑なエージェントシステムを構築する場合でも、同様に対応できるようにしていきます。
Original Page: A better way to monitor your AI agents in .NET apps
IchizokuはSentryと提携し、日本でSentry製品の導入支援、テクニカルサポート、ベストプラクティスの共有を行なっています。Ichizokuが提供するSentryの日本語サイトについてはこちらをご覧ください。またご導入についての相談はこちらのフォームからお気軽にお問い合わせください。


