9
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

エージェントを追え!OCI Enterprise AI Agents - Responses API を LangSmith でトレーシング

9
Posted at

はじめに

前回の記事では、OCI Enterprise AI Agents と Responses API を使って、MCP サーバー(DeepWiki)を呼び出すエージェント「GitHub DeepInsight」を作りました。たった数十行の Python コードで、サービス側がエージェントループを回してくれる体験を味わうことができました。今回は、「GitHub DeepInsight」にトレーシングの仕組みを追加してサービス側がエージェントループを回してくれている様子を見てみます。

エージェント・ループと Responses API

ところで、なぜループに注目しているかというとエージェントの本質は、推論とツール呼び出しのループだからです。

絵にかくとこんな感じです。

エージェント・ループ

  1. クライアントから初期コンテキスト(システムプロンプトとユーザーの要求)が、AIモデルに送信される
  2. AI モデルは、ユーザーの要求に応えるために適切なツールを選択する
  3. ツールは、外部環境とインタラクションする
  4. ツールと外部環境のインタラクションの結果が返る(外部環境からの情報取得である場合もあれば、外部環境を操作した結果ということもある)
  5. ツールの応答が AI モデルへ戻される
  6. モデルは、ユーザーの要求の応えるための情報が十分かどうか判断して不十分であれば、再度、ツールを選択する
  7. 以後、モデルがユーザーの要求の応えるための情報が十分揃ったと判断するまで繰り返す
  8. 情報が十分揃ったら回答を生成してクライアントへ最終応答を返す

これが、エージェントの本質、エージェント・ループですね。

エージェント・アプリケーションを開発していると、Planning、Execution、Clarification/Approval、Verification、Function Calling、Sub-Agentなどの様々なループを作ることになります。

これを毎回、開発者が作っていては大変です。そこで、API 側でループを回してくれる Responses API の登場です。

つまり、こんな感じです。

Responses API

コードも短くなりますが往復遅延が少なくなるのも大きなメリットです。

シーケンス図で見るとこの違いがより明確になります。

Chat Completions API の場合(従来)

エージェント・アプリケーションがループを管理し、ツール呼び出しのたびに API との往復が発生します。

Responses API の場合

エージェント・アプリケーションは 1 回 API を呼ぶだけで、ループはサービス側で完結します。

Chat Completions API では、ツール呼び出し 3 回のループなら API との往復が計 4 回(ツール呼び出し 3 回 + 最終推論 1 回)発生しますが、Responses API ではわずか 1 往復で済みます。

Responses API は、ループをAPI(サービス側)で回してくれるだけではなくて、会話履歴の管理もしてくれます。

上のコードの中で、messages にAPIやツールの呼び出しの都度、応答メッセージを append している部分を API 側で管理してくれます。

前回のコードでも、サービス側がエージェント・ループを回してくれているのは、OCI Enterprise AI Agents の Agentic API が OpenAI Responses API/Open Responses API 準拠だからでした。

しかし、実際にエージェントを作っていると、こんな疑問が出てきます。

  • 1 回の API 呼び出しの裏で、MCP ツールは何回呼ばれたのか?
  • 各ステップにどれくらい時間がかかっているのか?
  • トークン消費量はどのくらいか?
  • 期待どおりの順序でツールが呼ばれているか?

Responses API はエージェントループをサービス側で実行してくれるため、開発者のコードはシンプルになります。その反面、ループの内部で何が起きているかは API の戻り値だけでは把握しにくくなります。

そこで活躍するのが LangFuseLangSmith によるトレーシングです。この記事では、前回のサンプルコードに LangSmith のトレーシングを追加して、エージェントの動作を可視化する方法を試してみます。

OCI Enterprise AI Agents の可観測性

本題の LangSmith 連携に入る前に、OCI Enterprise AI Agents が提供する可観測性の仕組みを整理しておきます。

Responses API の構造化トレース

Responses API の output 配列には、エージェントループの各ステップが構造化された形で含まれています。

output タイプ 内容
message アシスタントの応答テキスト
mcp_call Remote MCP ツールの呼び出しと結果
mcp_list_tools MCP サーバの利用可能ツール一覧
file_search_call File Search (Vector Store) の呼び出しとヒット
reasoning 思考プロセスサマリ(Reasoning 有効時)
function_call_output Function Tool 実行結果(クライアント返却)

つまり、レスポンスの output を見れば、ループ内で何が起きたかをプログラム的に取得できます。しかし、これだけでは時系列の可視化やプロジェクト横断での分析は難しいため、外部の可観測性ツールとの連携が重要になります。

サードパーティの可観測性ツールとの連携

OCI Enterprise AI Agents は OpenAI Responses API 互換であるため、OpenAI SDK のエコシステムで利用できる可観測性ツールがそのまま使えます。代表的なものとして以下があります。

  • LangSmith ー LangChain 社が提供するトレーシング・評価プラットフォーム
  • LangFuse ー オープンソースの LLM 可観測性プラットフォーム
  • OpenTelemetry ベースのツール

この記事では LangSmith を使った連携方法を紹介します。

LangSmith とは

LangSmith は、LLM アプリケーションの開発・テスト・監視を支援するプラットフォームです。主な機能として、トレーシング(LLM 呼び出しやツール実行の記録・可視化)、評価(出力品質の自動評価)、モニタリング(本番環境でのパフォーマンス監視)があります。

この記事ではトレーシング機能に焦点を当てます。LangSmith のトレーシングでは、エージェントの 1 回の実行(ラン)の中で発生した LLM 呼び出し、ツール呼び出し、それぞれの入出力、所要時間、トークン消費量などが、ネストされたスパン(span)として階層的に記録されます。

LangSmith トレーシングの設定方法

LangSmith のトレーシングを有効にするのはとても簡単です。たった 3 ステップで完了します。

ステップ 1. 環境変数を設定する

.env ファイルまたは環境変数に、以下を追加します。

.env
# LangSmith トレーシング
LANGSMITH_TRACING=true
LANGSMITH_API_KEY=lsv2_pt_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
LANGSMITH_PROJECT=my-deepwiki-agent
環境変数 説明
LANGSMITH_TRACING true にするとトレースの送信が有効になります
LANGSMITH_API_KEY LangSmith の API キー。LangSmith のコンソールから取得できます
LANGSMITH_PROJECT トレースの送信先プロジェクト名。未設定の場合は default プロジェクトに送信されます

LANGCHAIN_TRACING_V2LANGCHAIN_API_KEYLANGCHAIN_PROJECT という旧名の環境変数も互換として認識されます。

ステップ 2. OpenAI クライアントを wrap_openai でラップする

langsmith パッケージの wrap_openai で OpenAI クライアントをラップします。これにより、client を経由するすべての API 呼び出しが自動的にトレースされるようになります。

from openai import OpenAI
from langsmith.wrappers import wrap_openai

# 通常の OpenAI クライアントを作成
_base_client = OpenAI(
    base_url=os.environ["ENTERPRISE_AI_BASE_URL"],
    api_key=os.environ["ENTERPRISE_AI_API_KEY"],
    project=os.environ["ENTERPRISE_AI_PROJECT_ID"],
)

# LangSmith でラップしてトレースを有効化
client = wrap_openai(_base_client)

ポイントは、OCI Enterprise AI Agents は OpenAI API 互換なので、OpenAI クライアントの base_url を OCI のエンドポイントに向けるだけで接続できるという点です。LangSmith の wrap_openai もそのままこのクライアントに適用できます。

ステップ 3. 関数に @traceable デコレータを付与する

トレースの粒度を制御したい関数に @traceable デコレータを付けます。

from langsmith import traceable

@traceable(name="DeepWiki MCP ターン", run_type="chain")
def run_agent(user_input: str, conversation_id: str) -> None:
    with console.status("[bold blue]お調べしています..."):
        response = client.responses.create(
            **agent,
            conversation=conversation_id,
            input=user_input,
        )
    console.print(Panel(Markdown(response.output_text)))

@traceable を付けた関数が親スパンとなり、その中で呼ばれる client.responses.create() などの API 呼び出しが子スパンとしてネストされます。これにより、LangSmith のトレース画面でエージェントの動作を階層的に確認できるようになります。

run_type="chain" は、この関数が複数のステップをオーケストレーションする「チェーン」であることを示しています。

完全なサンプルコード

前回の記事のコードに LangSmith トレーシングを追加した完全版です。変更箇所にはコメントで # [LangSmith] と記しています。

300_demo_mcp_deepwiki_langsmith.py
import os
import pyfiglet
from dotenv import load_dotenv
from rich.console import Console
from rich.markdown import Markdown
from rich.panel import Panel
from openai import OpenAI
from langsmith import traceable              # [LangSmith] traceable をインポート
from langsmith.wrappers import wrap_openai   # [LangSmith] wrap_openai をインポート

"""
このPython スクリプトは、OpenAI SDKを使用してインタラクティブなチャットを実行するデモです。
 - Conversations APIによるマルチターンの対話
 - ターミナルでのインタラクティブなチャット体験
 - MarkdownとPanelによるリッチフォーマットの応答表示
 - LangSmith へ OpenAI 呼び出し(Responses / Conversations 含む)をトレース

LangSmith を有効にするには .env などに次を設定してください。
 - LANGSMITH_TRACING=true  (トレースを送るとき必須)
 - LANGSMITH_API_KEY=<LangSmith の API キー>
 - LANGSMITH_PROJECT=<任意。未設定時は default プロジェクト>

LANGCHAIN_TRACING_V2 / LANGCHAIN_API_KEY / LANGCHAIN_PROJECT も互換として解釈されます。
"""
load_dotenv()
console = Console()

# OpenAIクライアントオブジェクトを作成(LangSmith でラップしてトレース)
_base_client = OpenAI(
    base_url=os.environ["ENTERPRISE_AI_BASE_URL"],
    api_key=os.environ["ENTERPRISE_AI_API_KEY"],
    project=os.environ["ENTERPRISE_AI_PROJECT_ID"],
)
client = wrap_openai(_base_client)           # [LangSmith] ラップ

# Agent を定義
agent = {
    "model": "xai.grok-4-1-fast-reasoning",
    "instructions": (
        "あなたはDeepWiki MCPを使用して GitHub のリポジトリを分析するエージェントです。"
        "DeepWiki MCPを使用してリポジトリを理解してユーザーのリクエストに応えます。"
        "DeepWiki から得られた情報だけに基づいて回答します。"
        "DeepWiki で情報が見つからない場合は、その旨を報告します。"
    ),
    "tools": [
        {
            "type": "mcp",
            "server_label": "DeepWiki",
            "server_url": "https://mcp.deepwiki.com/mcp",
            "require_approval": "never"
        }
    ],
}

# ユーザーのメッセージに対してエージェントを実行
@traceable(name="DeepWiki MCP ターン", run_type="chain")  # [LangSmith] デコレータ
def run_agent(user_input: str, conversation_id: str) -> None:

    # Responses API でエージェントループを実行
    with console.status("[bold blue]お調べしています..."):
        response = client.responses.create(
            **agent,
            conversation=conversation_id,
            input=user_input,
        )
    # レスポンスをMarkdown形式でパネル表示する
    console.print(Panel(Markdown(response.output_text)))

# メインエントリーポイント
if __name__ == "__main__":

    # 新しい会話を作成して、複数のターンをサポート
    conv = client.conversations.create()

    # ウェルカムメッセージを表示
    console.print(pyfiglet.figlet_format("GitHub DeepInsight"))
    console.print(
        "GitHub DeepInsightは、GitHubのリポジトリを分析し、"
        "その内容を深掘りすることができます。"
        "調査対象リポジトリは、オーナー名/リポジトリ名形式で指定してください。"
        "最大10個まで指定できます。"
    )
    console.print(
        "LangSmith: LANGSMITH_TRACING=true と LANGSMITH_API_KEY を設定すると"
        "トレースが送られます。"
    )
    console.print("'quit''bye' で終了します")

    # インタラクティブなチャットループ
    while True:
        # ユーザーの入力を取得
        user_input = console.input("\n[bold green]メッセージ:[/] ").strip()
        # 終了コマンドを処理
        if user_input.lower() in (
            "quit", "exit", "q",
            "bye", "byebye",
            "さようなら", "さよなら", "バイバイ",
            "終わります", "終了", "終了します",
        ):
            break
        # 空の入力を処理
        if not user_input:
            continue
        # エージェントを実行してレスポンスを表示
        run_agent(user_input, conv.id)

前回のコードからの変更点は以下の 3 箇所だけです。

  1. langsmith パッケージから traceablewrap_openai をインポート
  2. OpenAI クライアントを wrap_openai() でラップ
  3. run_agent 関数に @traceable デコレータを付与

追加の依存パッケージとして langsmith が必要です。

requirements.txt(追加分)
langsmith

LangSmith のトレース画面で見えること

コードを実行して LangSmith のコンソール( https://smith.langchain.com )を開くと、トレースが記録されているのを確認できます。

以下は、「kutsushitaneko/multimodal_retrieval について説明してください。また、どのような API プロバイダーに対応しているのかの一覧もください。」というタスクを実行したときのトレース画面の例です。

image.png

このトレースから、以下のことが読み取れます。

  • 1 回の Responses API 呼び出し(run_agent)の中で、サービス側で MCP ツールが 3 回呼び出されている
  • 各 MCP 呼び出しの入出力と所要時間
  • トークン消費量(入力トークン・出力トークン)

Responses API はサービス側でエージェントループを回すため、開発者のコードからは「1 回の API 呼び出し」に見えますが、LangSmith のトレースを見ると、その裏で何が起きていたかが一目瞭然です。

なぜ可観測性が重要なのか

AI エージェントの開発において、可観測性は「あると便利」ではなく「なくてはならない」ものです。

開発フェーズ

エージェントが期待どおりに動作しないとき、トレースを見れば、どのステップで何が起きたかを特定できます。

運用フェーズ

本番環境では、レイテンシの変動、トークン消費量の増加、エラー率の上昇などを継続的にモニタリングすることが重要です。LangSmith や LangFuse のダッシュボードでこれらの指標をプロジェクト単位で追跡できます。

コスト最適化

トークン消費量を可視化することで、モデルの選択やプロンプトの最適化によるコスト削減の余地が見えてきます。

Responses API の構造化トレースとの使い分け

Responses API 自体が返す output 配列と、LangSmith のトレースは相補的な関係にあります。

観点 Responses API の output LangSmith/LangFuse トレース
取得方法 API レスポンスに含まれる バックグラウンドで自動送信
用途 プログラム的な後処理 可視化・分析・モニタリング
時間情報 なし 各スパンの所要時間を記録
トークン情報 レスポンスに含まれる ダッシュボードで集計・可視化
永続化 開発者が実装 LangSmith/LangFuse が自動保存
複数ランの比較 開発者が実装 ダッシュボードで横断分析

開発中のデバッグには LangSmith/LangFuse のトレース画面が直感的で便利です。一方、本番環境でレスポンスの内容に基づいて条件分岐するような場合は、Responses API の output 配列をプログラム的に処理するのが適しています。

まとめ

この記事では、OCI Enterprise AI Agents のエージェントに LangSmith トレーシングを追加してみた体験をご紹介しました。

ポイントを振り返ります。

  • OCI Enterprise AI Agents は OpenAI API 互換のため、LangSmith の wrap_openai がそのまま使える
  • コード変更はインポート 2 行、ラップ 1 行、デコレータ 1 行の合計 4 行だけ
  • Responses API はサービス側でエージェントループを回すため、トレーシングなしではループ内部の動作が見えにくい
  • LangSmith のトレースにより、MCP ツール呼び出しの回数・順序・所要時間・トークン消費量が可視化される

OCI Enterprise AI Agents が OpenAI Responses API 互換であることの恩恵は、単にコードの書き方がシンプルになるだけではありません。LangSmith、LangFuse、OpenTelemetry といった OpenAI エコシステムの可観測性ツールをそのまま活用できることも、大きなメリットだということがわかりました。

エージェントの動作を「見える化」して、安心して開発・運用を進めていきたいですね。

参考リンク

9
6
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
9
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?