以下の内容はhttps://techblog.zozo.com/entry/llmops-observability-with-langfuseより取得しました。


LangfuseによるLLMOps基盤の構築と活用事例

LangfuseによるLLMOps基盤の構築と活用事例

はじめに

こんにちは、データサイエンス部コーディネートサイエンスブロックの清水です。私たちのチームでは、WEARへ投稿されているコーディネート画像からVLM(Vision Language Model)で特徴を自動抽出するシステムを開発・運用しています。

プロンプト設計から推論パイプラインの構築、大規模推論まで、VLM・LLMを本番環境で活用する中、いくつかの運用課題に直面しました。本記事では、LLMOpsの全体像を整理した上で、観測基盤としてLangfuseを導入し、原因特定と改善の事例を紹介します。

目次

1. 直面した運用課題

私たちは、小規模なデータを用いた実験や検証を経て、VLM・LLMの本番運用フェーズに移行しました。その中で、以下の4つの課題が浮かび上がりました。

モニタリングの不足

API呼び出し時のエラーや構造化出力のJSONパースエラーなど、想定されるエラーの監視が実行時のロギングのみに留まっていました。ログの粒度を細かく設定することで対処していましたが、推論対象のデータ数が増加するにつれ運用上の限界が顕在化し、生成AIの処理を体系的に記録・監視する仕組みの整備が求められていました。

プロンプトとパラメーターの管理が分散

運用中の特徴抽出プロンプトは10個を超えており、今後も増加が見込まれます。当時はプロンプトをExcel、パラメーター・configをGitHubで管理しており、バージョン管理が分散していました。プロンプト更新時にはGitHub側のパラメーター設定との整合性を都度確認する必要があり、一元的に管理する仕組みが整っていませんでした。

コスト管理の不透明さ

APIの利用コストは請求画面上の合算値や日次の概算でしか把握できず、コスト急増時に原因となるリクエストや処理を特定することが困難でした。生成AIのモデルは世代ごとに料金体系が変動するため、日次推論の運用を見据えると、原因を追跡可能なコスト監視体制の構築が不可欠でした。

生成AIモデルのライフサイクルへの追従

生成AIモデルはライフサイクルが短く、迅速な更新サイクルへの追従が求められます。例えば私たちが利用しているGeminiでは、Stableモデルのリリースから概ね半年〜1年程度で提供終了を迎えるペースです1。モデル更新時には、データセットを用いた更新前後の精度比較やレイテンシーへの影響評価が不可欠です。

2. LLMOpsの全体像とLangfuseの導入

LLMOpsとは

LLMOpsとは、大規模言語モデルの開発・運用・改善を体系的に管理するための一連のプラクティスです。従来のMLOpsがモデルの学習・デプロイ・監視を対象としているのに対し、LLMOpsではLLM特有の運用課題をカバーします。具体的には、プロンプトエンジニアリングやモデルの選択と更新、入出力のトラッキング、コスト管理などが含まれます。

IBM2、NVIDIA3、Databricks4、Dify5など各社のLLMOpsに関するドキュメントを調査しました。LLMOpsの全体像はDesign(設計)・Development(開発)・Operation(運用)の3フェーズに分類しました。特にDevelopmentフェーズではプロンプト管理や入出力のトレーシングと評価が重要です。Operationフェーズではエラー監視やコストトラッキングが中心的なプラクティスとして位置づけられています。

セクション1で挙げた4つの課題は、いずれもこのDevelopmentとOperationの領域に該当します。そこで、トレーシング・プロンプト管理・コスト監視を備えたLLMOpsツールを導入する方針としました。

Langfuseの選定理由

今回は観測基盤としてLangfuse6を採用しました。選定にあたってはLangSmith7やDify8を含む複数のツールを候補とし、以下の3軸で比較評価した結果、最も適していると判断しました。

セルフホスティングの可否:社内のインフラ要件として、GCP上に自前でホスティングできることが重要でした。Langfuseはオープンソースで、この要件に最も合致しました。

既存の技術スタックとの統合のしやすさ:LangfuseはPython SDKを提供しています。私たちが利用しているVertex AI・LangChainなど主要フレームワークとの互換性もあり、既存のコードベースに自然に統合できました。

必要な機能の充足度:Langfuseはトレーシング、プロンプト管理、コスト監視をワンストップで提供しており、マルチモーダル(画像入力のトレース)にも対応していることが決め手になりました。

3. Langfuseの機能紹介

ここからは、実際にLangfuseを導入した上で活用している主要な機能を、セクション1の課題との対応とあわせて紹介します9

Tracing — モニタリングの不足を解決

トレーシング

Langfuseのトレーシングは、1回のリクエスト処理全体をTraceとして記録し、その中の個々の処理ステップをObservationとしてネストする階層構造をとります10

上記の画像は、私たちの特徴抽出における実際のTrace画面です。左側のObservationツリーでは、1回の推論リクエスト全体がlangfuse_gemini_request_with_retryというTraceとして記録されています。その配下に以下のObservationがネストされています。

  1. fetch_langfuse_prompt(Span)— Langfuseからプロンプトを取得
  2. append_feedback(Span)— フィードバック情報を付与
  3. request_to_gemini(Generation, 8.36s, 4,986→302トークン、$0.000929)— Gemini APIの呼び出し
  4. validate_gemini_response(Span)— レスポンスの検証
  5. parse_gemini_result(Span)— 結果のパース

Observationには処理の期間を記録するSpanと、LLM呼び出し特有の情報を記録するGenerationの2種類があります。3番目のrequest_to_geminiがGenerationに該当し、実行時間・トークン数・コストといったLLM固有の情報が自動的に記録されます。右側のパネルでは入出力やメタデータも一覧表示され、1画面でリクエストの全容を把握できます。

従来のロギングでは個別のAPIコールしか追えず、エラー発生時にログを手動で突き合わせる必要がありました。Traceとして構造化することで、セクション1の「モニタリングの不足」を直接的に解決しました。導入も@observeデコレータを関数に付与するだけで済み、既存コードへの変更は最小限です。

Prompt Management — プロンプト管理の分散を解決

LangfuseのPrompt Management11は、プロンプトのバージョン管理・デプロイをLangfuse上で完結させる仕組みです。私たちが抱えていた「プロンプトはExcel、パラメーターはGitHub」という分散管理の課題に対して、以下の機能が直接的な解決策となりました。

バージョン管理とラベル12:プロンプトを更新するたびにバージョンが自動で作成され、変更履歴がイミュータブルに保持されます。各バージョンにはproductionstagingなどのラベルを付与でき、SDKからラベル指定で取得可能です。Diff表示機能もあり、バージョン間の差分をハイライトで確認できます。

Config13:プロンプトにモデル名・temperature・top_pなどのパラメーターを付与し、プロンプトと一緒にバージョン管理できます。コードの変更・再デプロイなしに、UI上でプロンプトとパラメーターをまとめて更新できるようになり、分散管理の解消に最も効いた機能です。

Traceとのリンク14:プロンプトをTraceに紐付けることで、どのバージョンがどの出力を生成したかを追跡できます。バージョンごとのレイテンシーやコストを比較でき、プロンプト改善の効果を定量的に測定可能です。

これにより、Excelとコードに分散していたプロンプトとパラメーターがLangfuse上に一元化されました。「どのバージョンが本番で動いているか」「何を変えたか」「変更の効果はどうか」を1つのツールで把握できます。

Cost Tracking — コスト管理の不透明さを解決

ダッシュボード

ダッシュボード15でモデルごとのコストやトークン数を時系列で可視化でき、運用時にコスト推移を一目で監視できます。セクション1で挙げた「コスト管理の不透明さ」について、従来は請求画面で合算値しか確認できませんでした。Langfuseの導入によりTrace単位・Generation単位で分解でき、異常なトークン消費の検知も容易になりました。

Tags・Session — モデルライフサイクルへの追従を支援

Langfuseでは、TraceにTags16やSession17といった属性を付与し、目的に応じてトレースデータを整理・フィルタリングできます。Tagsは任意の文字列をTraceやObservationに複数付与でき、アプリバージョン・LLM手法・実験IDなどの軸でUIやAPIからフィルタリング・グルーピングが可能です。Sessionは複数のTraceを1つのまとまりとしてグルーピングする仕組みで、session_idを指定するだけで関連するTraceがセッション単位で集約されます。

私たちの運用では、評価実験やモデル更新のたびにTagsでTraceをグルーピングし、バージョン間の精度・レイテンシー・コストを比較しています。これにより、モデルのライフサイクルが短い環境でも、更新前後の品質を定量的に検証した上で移行でき、精度を担保した運用が可能になりました。

4. トレースによるエラー調査と改善事例

Langfuseを導入したことで、本番運用時に感じていた課題を解決できました。その中でも最も効果を実感したのはエラー調査と改善のフェーズです。ダッシュボードから問題を発見し、原因特定から改善まで行った実例を紹介します。

ダッシュボードによる問題の発見

日次での推論実行において、「早く実行が終わる日もあれば、非常に時間がかかる日もある」という現象が発生していました。実行ログからは、それぞれの推論対象となる入力データ数が大きく異なっていないことが事前に分かっていました。まずは原因を調査するためにLangfuseのダッシュボードを確認しました。

ダッシュボードで実行が完了したTrace数の推移を確認すると、最初は短時間で多くのAPIコールが成功するものの、その後に推論完了数が大幅に減少するパターンが確認できました。下図はその時に観測されたものです。

不具合ありのトレーシング結果

TraceやObservationを詳細に分析することで、以下の3つのケースを特定しました。

ケース1:503エラー(APIの接続失敗)

事象:Geminiへの初回のAPIコールが503エラーで失敗し、その後に複数回の503エラーが起こった後にようやく成功するパターンが多発していました。

対策:503エラーはAPI接続時のエラーであることから、API接続設定を調査しました。Vertex AIのPython SDKにはデフォルトで指数関数的バックオフ(Exponential Backoff)を利用したリトライ機構が備わっています18。私たちはこの仕組みを活かしつつも、システム全体が長時間ブロックされるのを防ぐため、リトライの上限回数(例:3回)やタイムアウト設定をクライアント側で適切にチューニングしました。結果として、一時的なエラーを許容しつつ、実行時のレイテンシー増加をコントロールできるようになりました。

ケース2:Langfuseプロンプト取得のレイテンシー増加

事象:一部のTraceで、数時間〜最大10時間も処理がブロックされているケースが発生していました。Traceの実行時間を確認したところ、API呼び出しそのものではなく、Langfuseからのプロンプト取得処理のSpanに異常な時間がかかっていることが特定できました。

対策:原因を調査した結果、プロンプト取得処理がリトライループの中に組み込まれていたことが判明しました。加えて、ネットワーク通信のタイムアウトが適切に設定されておらず、一時的な通信障害時に長時間プロセスがハングしていました。対策として、プロンプトの取得を最初の1回のみとし、オンメモリで保持するよう初期化処理を最適化しました。さらに、通信時のタイムアウト値を明示的に設定したことで、レイテンシーの異常な増加を根絶できました。

ケース3:無限文字列の繰り返し出力

Geminiの出力で特定の文字列が延々と繰り返され、構造化出力を想定していたJSONのパース処理で失敗してリトライが頻発しました。Trace Detail画面で出力内容がそのまま記録されていたため、無限に繰り返される文字列パターンを直接確認できました。あるTraceでは入力9,616トークンに対して出力64,999トークンという異常なトークン消費も記録されていました。

対策:temperatureが0の場合、出力は決定的であるため、同じ入力に対してリトライしても同一の異常出力が再現されるだけで意味がありません。根本的な原因は特定の画像データとプロンプトの組み合わせにあると考えられます。しかし、膨大なコーディネート画像すべてのエッジケースを網羅する完璧なプロンプトの追求は困難です。そこで、エラー発生ごとにtemperatureを+0.1ずつインクリメントする実装を導入しました。temperatureを上げることで出力にランダム性が加わり、リトライ時に異なる出力が生成されるため、無限繰り返しから抜け出せる可能性が高まります。またmax_tokensを明示的に指定し、万が一再発した場合でも異常な出力トークン数を制限できるようにしました。

改善の全体的な効果

それぞれ対策した結果、Traceのグラフも安定し、推論のスループットが一定で保たれるようになりました。Langfuse導入以前はVertex AIのログを手動で調査する必要があり、問題の全体像を把握するのに多大な時間を要していました。導入後は以下のような改善を実感しています。

  • エラー調査時間の短縮:Trace単位で調査が完結するようになり、Trace一覧からエラーが起きていたAPI呼び出しが一目瞭然になった
  • 入出力の精緻な監視:各プロンプトの入力・出力・トークン数・コストを精緻に調査でき、異常検知が容易になった
  • リトライ戦略の最適化:リトライ回数や各リトライの出力がObservationとして記録され、定量的なデータに基づく改善が可能になった
  • チーム内のコミュニケーション改善:TraceのURLを共有するだけで、エンジニア間のエラー議論が具体的なデータに基づいて行えるようになった

まとめ

本記事では、LLMの本番運用で直面した課題と、LangfuseによるLLMOps基盤の構築、トレースを活用したエラー調査と改善の事例を紹介しました。

Geminiのモデルライフサイクルに見られるように、Stableモデルのリリースから半年〜1年程度でRetirementを迎えるケースもあります。LLM特有の運用課題に対応するためには可観測性(Observability)の基盤を整えることが重要です。Langfuseは、トレーシング・プロンプト管理・コスト監視を統合的に提供するオープンソースのLLMOpsツールとして私たちの開発環境にフィットしました。特に、Traceの構造的な記録によってエラーの特定から対策実施までのサイクルを大幅に短縮できたことが最大の成果です。

今後は、Langfuseカスタムダッシュボードの活用、評価用データセットの構築とモデル更新時の自動評価パイプラインとの連携などに取り組んでいきます。さらなるLLMの安定した運用に活かしていきたいと考えております。

おわりに

ZOZOでは、一緒にサービスを作り上げてくれる方を募集中です。ご興味のある方は、以下のリンクからぜひご応募ください。

corp.zozo.com




以上の内容はhttps://techblog.zozo.com/entry/llmops-observability-with-langfuseより取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14