1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

LLMオブザーバビリティ入門 — AIエージェントの「なぜ失敗したか」を可視化するLangfuseとOpenTelemetry

1
Posted at

LLMオブザーバビリティ入門 — AIエージェントの「なぜ失敗したか」を可視化するLangfuseとOpenTelemetry

LLMを使ったアプリを本番で動かしていると、こんな状況に直面することがあります。

「ユーザーから『AIの回答がおかしい』と報告が来た。でも何が起きていたのか分からない」

従来のWebアプリなら、エラーログを見れば何が起きたかが分かります。でもLLMアプリの場合、プロンプトに何を渡して、モデルが何を返して、どのツールが呼び出されたかという一連の流れが可視化できていないと、問題の原因が掴めません。

これがLLMオブザーバビリティの問題です。


LLMオブザーバビリティとは何か

オブザーバビリティ(可観測性)は、システムの内部状態を外部から観察できることを指します。LLMアプリにおいては具体的に:

  • どのプロンプトがモデルに渡されたか
  • モデルがどう応答したか
  • エージェントがどのツールを、どの順番で呼び出したか
  • 各ステップのレイテンシとコスト
  • ユーザーの評価(良かったか悪かったか)

これらを記録・可視化することです。

2026年現在、この分野で注目されているのがLangfuseと、その基盤となるOpenTelemetryです。


Langfuseとは

LangfuseはLLMアプリ向けのオブザーバビリティプラットフォームです。オープンソースで自己ホストも可能です。

主な機能は4つです。

  1. Tracing — LLM呼び出しとエージェントワークフローの完全なトレース
  2. Prompt Management — プロンプトのバージョン管理とPlayground
  3. Evaluation — LLM-as-Judge、人間によるアノテーション
  4. Metrics — コスト、レイテンシ、ユーザーフィードバックの集計

v3 SDKはOpenTelemetryをネイティブサポートしており、将来的に他のオブザーバビリティツールとの連携もスムーズになる設計です。


セットアップ

インストール

pip install langfuse openai

環境変数の設定

# .env
LANGFUSE_SECRET_KEY=sk-lf-xxxx
LANGFUSE_PUBLIC_KEY=pk-lf-xxxx
LANGFUSE_HOST=https://cloud.langfuse.com  # セルフホストの場合は変更

基本的な使い方

OpenAI APIのトレース

from langfuse.openai import openai  # Langfuseが提供するwrapper

client = openai.OpenAI()

# 通常のOpenAI呼び出しと同じ書き方でトレースが記録される
response = client.chat.completions.create(
    model="gpt-5.4",
    messages=[
        {"role": "system", "content": "あなたは親切なアシスタントです。"},
        {"role": "user", "content": "Pythonでフィボナッチ数列を書いてください。"}
    ],
    name="fibonacci-request",    # Langfuseでの表示名
    metadata={"user_id": "user_123"}  # メタデータを付加
)

print(response.choices[0].message.content)

これだけで、Langfuseのダッシュボードにトレースが記録されます。

手動トレース(より詳細な制御)

from langfuse import Langfuse

langfuse = Langfuse()

# トレースを開始
trace = langfuse.trace(
    name="document-qa",
    user_id="user_123",
    session_id="session_abc",
    metadata={"document_id": "doc_456"}
)

# スパンを追加(ネストした処理の記録)
with trace.span(name="document-retrieval") as span:
    # RAGのドキュメント検索
    docs = vector_db.search(query, top_k=5)
    span.update(
        output={"doc_count": len(docs)},
        metadata={"similarity_threshold": 0.7}
    )

# LLM呼び出しのスパン
with trace.generation(
    name="answer-generation",
    model="gpt-5.4",
    input={"query": query, "context": docs}
) as generation:
    response = openai_client.chat.completions.create(...)
    generation.update(
        output=response.choices[0].message.content,
        usage={
            "input": response.usage.prompt_tokens,
            "output": response.usage.completion_tokens
        }
    )

# トレースに評価スコアを付加
trace.score(
    name="relevance",
    value=0.9,
    comment="回答は質問に適切に対応していた"
)

エージェントのトレース

複数のツール呼び出しを含むエージェントのトレースも同様に書けます。

from langfuse import Langfuse
from langfuse.decorators import observe, langfuse_context

langfuse = Langfuse()

@observe()  # このデコレータでトレースが自動記録される
def search_web(query: str) -> str:
    """ウェブ検索ツール"""
    result = web_search_api.search(query)
    return result

@observe()
def summarize_text(text: str) -> str:
    """テキスト要約ツール"""
    response = openai_client.chat.completions.create(
        model="gpt-5.4",
        messages=[{"role": "user", "content": f"以下を要約してください: {text}"}]
    )
    return response.choices[0].message.content

@observe(name="research-agent")
def research_agent(topic: str) -> str:
    """リサーチエージェント(複数ツールを組み合わせる)"""
    
    # ウェブ検索
    search_results = search_web(f"{topic} 最新情報 2026")
    
    # 要約
    summary = summarize_text(search_results)
    
    return summary

# 実行
result = research_agent("AIエージェントのオブザーバビリティ")
langfuse.flush()  # バッファをフラッシュ

@observe() デコレータを付けるだけで、各関数の呼び出しがLangfuseのトレースとして記録されます。


評価の自動化(LLM-as-Judge)

人間がすべての回答を評価するのは非現実的です。LLMを使って評価を自動化できます。

from langfuse import Langfuse

langfuse = Langfuse()

def evaluate_response(question: str, answer: str, context: str) -> dict:
    """LLMで回答の品質を評価する"""
    
    eval_prompt = f"""以下の質問と回答を評価してください。

質問: {question}
回答: {answer}
参照文書: {context}

評価基準:
- 正確性(回答が参照文書に基づいているか): 0-1
- 関連性(回答が質問に答えているか): 0-1
- 網羅性(重要な情報を含んでいるか): 0-1

JSON形式で返してください:
{{
  "accuracy": 0.0-1.0,
  "relevance": 0.0-1.0,
  "completeness": 0.0-1.0,
  "reasoning": "評価の理由"
}}"""
    
    response = openai_client.chat.completions.create(
        model="gpt-5.4",
        messages=[{"role": "user", "content": eval_prompt}],
        response_format={"type": "json_object"}
    )
    
    return json.loads(response.choices[0].message.content)

# トレースに評価を追加
scores = evaluate_response(question, answer, context)
trace.score(name="accuracy", value=scores["accuracy"])
trace.score(name="relevance", value=scores["relevance"])

ダッシュボードで見えること

Langfuseのダッシュボードでは以下が確認できます。

トレース一覧
各リクエストのトレースがリスト表示され、プロンプト・レスポンス・ツール呼び出しの全履歴が確認できます。

コスト分析
モデルごと・ユーザーごとのトークン使用量とコストをグラフで確認できます。「なぜ今月の請求が高いのか」が分かります。

レイテンシ分析
どのステップで時間がかかっているかを特定できます。ボトルネックの発見に役立ちます。

品質メトリクス
LLM-as-Judgeスコアや人間評価の集計グラフで、時系列での品質変化を把握できます。


まとめ

LLMオブザーバビリティは、AIアプリを本番で安定して運用するための必須インフラになりつつあります。

「何が起きているか分からない」状態のまま本番運用を続けると、問題が起きたときの原因特定が困難になります。

Langfuseのような専用ツールを導入することで、プロンプトの変更がどう影響したか、どのユーザーでエラーが多いか、コストはどのように推移しているかが見えるようになります。

セルフホストも可能でオープンソースなので、まず試してみるハードルは低いと思います。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?