実稼働環境でエージェント ワークフローの実行を開始するときに、遭遇することを最も恐れるものは何ですか?答えが間違っているのではなく、なぜ間違っているのかがわからないのです。監査ログがなければ、エージェントはブラック ボックスのようなものです。どのツールを調整するのか、どのパラメータを渡すのか、中間ステータスは何か、最終的な決定は何に基づくのか、すべて不透明です。
監査ログ (Audit Log) は、このブラック ボックスの問題を解決するように設計されています。ツールの呼び出し、LLM 入出力、状態遷移、異常なイベントなど、エージェント ワークフロー内のすべての主要なアクションが記録されます。これを使用して、事後レビューを実施し、例外をデバッグし、コンプライアンス監査要件を満たすことができます。
監査ログには何を記録する必要がありますか?
すべてのデータが覚えておく価値があるわけではありません。コアレコードアイテムは、次の 5 つのカテゴリに分類されます。
- リクエストとレスポンス: 温度、max_tokens、その他のパラメーターを含む、各 LLM 呼び出しの完全なプロンプトと完了。これを失うと、いかなる推論も再現できなくなります。
- ツール呼び出し追跡: エージェントによって呼び出された関数名、渡されたパラメーター、返された結果、および所要時間。多くのエラーは、ツールから返されたデータが予期した形式ではない場合に発生します。
- ステータス変更: ユーザーの意図、収集された情報、中間決定結果など、ワークフロー内の主要な変数の値の変更。
- 例外と再試行: ネットワーク タイムアウト、LLM 戻り形式エラー、例外をスローするツール - これらはデバッグのハイライトです。
- メタデータ: リクエスト ID、タイムスタンプ、バージョン番号、エージェント インスタンス ID。複数のインタラクションと水平的調査を相関させるために使用されます。
実際のプロジェクトでは、チームが LLM の会話のみを記録し、ツールの呼び出しを完全に無視しているのを見てきました。その結果、API スロットルによりワークフロー全体が中断されました。原因を突き止めるのに 2 日かかりました。原因は、ツールの呼び出しログが欠落していたためでした。

構築手順: ログ構造から取得まで
1. ログ構造を定義する
フラット JSON 形式を使用し、イベントごとに 1 つのレコードを使用します。キーフィールド: event_id、trace_id (同じワークフローを関連付けるために使用)、agent_id、event_type (llm_call、tool_call、state_change、error など)、timestamp、payload。
ネストが深すぎると、クエリのパフォーマンスが急激に低下します。カラム型ストレージ (ClickHouse など) または構造化ログ サービス (Seq、Loki など) を使用することをお勧めします。
2. 隠蔽戦略
すべての変数を記録しようとしないでください。これにより、ストレージ コストが削減され、分析が困難になります。優先レコード:
- 各 LLM 呼び出しの入出力 (大きなテキストを制限するために切り詰めをオンにすることができます)
- 各ツール呼び出しのパラメータと戻り結果
- ワークフローの開始と終了 (最終出力と消費時間を記録)
- 例外または再試行イベント
埋め込みコードは通常、デコレータ パターンまたは AOP を使用してエージェント フレームワークに挿入されます。 LangChain を例に挙げると、CallbackHandler、on_llm_start、on_tool_start およびその他のフックにログを書き込むことができます。
3. ストレージおよび保持ポリシー
監査ログはメモリにのみ保存することはできません。保存しないと、シャットダウンすると失われます。少なくともローカル ディスクに書き込み (圧縮は毎日ローテーションします)、オプションで S3 または ES に同期します。保存期間はコンプライアンス要件に基づいており (通常は 90 ~ 180 日)、古いデータはコールド ストレージにアーカイブされます。
4. 検索と可視化
ログは確認できる場合にのみ意味を持ちます。 Trace_id、時間範囲、イベント タイプ、agent_id によるフィルタリングをサポートする単純なクエリ インターフェイスを構築します。 「なぜワークフロー X は先週の水曜日に失敗しましたか?」のような自然言語クエリを使用できればさらに良いでしょう。

最も陥りやすい罠
私が最もよく目にする問題は、ログ ブロッキング ワークフローです。多くの人はリモート データベースに同期的に書き込みます。ネットワークが混雑すると、エージェントの応答が遅くなったり、タイムアウトになったりすることがあります。解決策は、非同期で書き込むことです。ローカル メモリ バッファ キューが最初に書き込まれ、バックグラウンド スレッドがバッチでフラッシュされます。キューがいっぱいの場合は、メイン プロセスに影響を与えるよりも、ログを失った方が良いでしょう。少なくとも、ログが失われた場合でも実行できますが、ワークフローがハングしても何も見つかりません。
2 番目の落とし穴は、ログが多すぎるとストレージの爆発を引き起こすことです。特に、LLM 通話ごとに会話全体が記録され、その量は 1 日で GB に達する場合があります。解決策: 過去 X 日間の元のログのみを保持し、集計と要約後に古いデータを破棄します。さらに、キー ペイロードのみが記録され、長いシステム プロンプトは削除されます。
3 番目の落とし穴は、ログに trace_id がないことです。関連するコンテキストがないと、何千ものログがファイル内に散在し、どれが同じワークフローに属しているのかわかりません。トレース ID は、ワークフローの開始時に生成され、すべてのサブ呼び出しを通じて実行される必要があります。
実際のシナリオ: 失敗したツール呼び出し
ユーザーの注文を照会する担当のエージェントがいるとします。 get_order(id) ツールを呼び出しますが、サーバーは 500 エラーを返します。監査ログには以下が記録されます。
- イベントタイプ:
tool_call_start、パラメータ:{order_id: "123"} - イベントタイプ:
tool_call_error、戻り値:{status: 500, error: "Internal Server Error"} - その後、エージェントは再試行 (または戦略の変更) し、
tool_call_retryとtool_call_endを記録します。
監査ログがなければ、この 500 エラーは LLM によってのみ無視されます。ユーザーには「クエリが失敗しました」というメッセージが表示されますが、開発者にはそれがエージェント コードの問題なのか、バックエンド インターフェイスの問題なのかわかりません。
代替プラン: 標準プランが失敗した場合
チームのリソースが限られており、独立したログ システムを構築できない場合は、LLM 自体をダウングレードして「監査」に使用できます。具体的な方法は次のとおりです。各アクション ステップの後に、エージェントに現在のステータスを自然言語で要約させ、それを一時変数に書き込みます。ワークフローの最後に、エージェントは完全なログを出力する必要があります。信頼性は低いものの(エージェントが省略したりでっち上げたりする可能性があります)、何もしないよりはマシです。
もう 1 つのより成熟したダウングレード ソリューションは、既存のビジネス ログとリクエスト ID を再利用することです。つまり、各エージェント インタラクションの Trace_id をビジネス データベースのリクエスト ログ テーブルに書き込み、バックエンド サービスに通話リンク自体を記録させます。欠点は、侵襲性が高いものの、追加のインフラストラクチャを必要としないことです。
##最後に
監査ログはオプションではありません。エージェント ワークフローが実際のユーザー リクエストの処理を開始するときは、それが唯一のトラブルシューティング ウィンドウです。最初にログを設定してからオンラインにします。そうしないと、遅かれ早かれ、再作業に数倍の時間がかかります。

コメントはまだありません