第3章 アプリケーション開発 / 想定学習時間:30〜40分 / 最終確認:2026年8月

3-8. MLflowでのチェーン/エージェント管理(pyfunc・ResponsesAgent)

🎯 この節の学習目標

1. なぜチェーンをMLflowモデルにするのか

3-1〜3-7 で構築してきたチェーン(RAGパイプラインやガードレール付きの処理列)は、このままではノートブック上のPythonコードにすぎません。これを本番にデプロイし、バージョン管理し、チームに配布するためには、標準化されたパッケージ形式に変換する必要があります。それが MLflowモデルとしてのログ(logging)です。

MLflowモデルとしてログすると、次が手に入ります。

つまりこの節は、「開発したチェーン」を「デプロイ可能な資産」に変える、第3章と第4章をつなぐ結節点です。なお、現行の MLflow 3 は GenAI 向けに Tracing・評価(mlflow.genai.evaluate)・プロンプトレジストリを統合した世代で、チェーン/エージェントのログから評価・運用までを一貫して支える基盤になっています。

2. 実装インターフェースの選択:PythonModel と ResponsesAgent

チェーン/エージェントをMLflowモデルにするときの実装インターフェースは、主に2つから選びます。

観点mlflow.pyfunc.PythonModel(汎用)mlflow.pyfunc.ResponsesAgent(エージェント推奨)
位置付け任意のPythonロジックをラップできる万能の入れ物エージェント/チェーン向けにMLflowが用意した推奨インターフェース
入出力形式自由(DataFrame・dict など自分で設計)OpenAI Responses API 互換のリクエスト/レスポンス形式に統一
ストリーミング自前で設計・実装するpredict_stream として標準サポート
ツール呼び出し・マルチエージェント自前で形式を設計する形式として標準対応
向いている場合非対話型の変換処理や、独自の入出力形式が必要な場合チャット/エージェント系の新規開発の第一候補

従来の PythonModel ラップや ChatAgent インターフェースで作られたモデルも引き続き動作しますが、新規のエージェント/チェーン開発では ResponsesAgent が第一候補です。入出力が業界標準の形式に揃うため、クライアント・評価ツール・トレーシングとの相互運用性が高くなります。

📘 試験対策(出題時はこの名称もありうる)

試験では「mlflow.pyfunc.PythonModel を継承して predict() を実装し、log_model でログする」という従来型のラップ方法が問われる可能性があります。「pyfunc は任意のPythonロジックをモデル化できる汎用フレーバー」という理解は現在も有効で、そのまま得点につながります。

🚀 現行Databricks(2026年8月)

現行の MLflow 3 では、エージェント/チェーンの実装インターフェースとして ResponsesAgent(mlflow.pyfunc.ResponsesAgent)が推奨です。OpenAI Responses API 互換の入出力で、ストリーミング・ツール呼び出し・マルチエージェントに標準対応します。ロギングは models from code(コードベースロギング)が推奨方式です。

2-1. mlflow.pyfunc.PythonModel によるラップ(汎用)

最も汎用的な方法が、mlflow.pyfunc.PythonModel を継承したクラスを作り、predict() メソッドにチェーンの呼び出しを実装する方法です。pyfunc(Python function)フレーバーは「Pythonで書けるものなら何でもモデルにできる」万能の入れ物で、独自のガードレールや複数ステージを含む複雑なチェーンもラップできます。

💡 コード例:RAGチェーンのpyfuncラップ

import mlflow
import mlflow.pyfunc

class RAGChainModel(mlflow.pyfunc.PythonModel):
    def load_context(self, context):
        # エンドポイント名などの初期化(サービング起動時に1回実行される)
        from databricks_langchain import ChatDatabricks
        self.llm = ChatDatabricks(
            endpoint="databricks-meta-llama-3-3-70b-instruct"
        )

    def predict(self, context, model_input):
        # model_input から質問を取り出してチェーンを実行
        question = model_input["question"][0]
        docs = self.retrieve(question)      # 検索ステージ
        answer = self.generate(question, docs)  # 生成ステージ
        return [answer]

with mlflow.start_run():
    mlflow.pyfunc.log_model(
        name="rag_chain",
        python_model=RAGChainModel(),
        pip_requirements=["mlflow", "databricks-langchain"],
        input_example={"question": ["RAGとは何ですか?"]},
    )

load_context() には重い初期化(クライアント生成など)を、predict() にはリクエストごとの処理を書く、という役割分担が基本です。

2-2. ResponsesAgent による実装(エージェントの推奨)

対話型のエージェント/チェーンを作るなら、ResponsesAgent を継承します。predict() が受け取るリクエストと返すレスポンスが OpenAI Responses API 互換の形式に統一されている点が特徴です。

💡 コード例:ResponsesAgent の最小実装

from mlflow.pyfunc import ResponsesAgent
from mlflow.types.responses import (
    ResponsesAgentRequest,
    ResponsesAgentResponse,
)

class SimpleRAGAgent(ResponsesAgent):
    def predict(self, request: ResponsesAgentRequest) -> ResponsesAgentResponse:
        # Responses API 互換のリクエストから最新のユーザー入力を取り出す
        question = request.input[-1].content
        docs = self.retrieve(question)          # 検索ステージ
        answer = self.generate(question, docs)  # 生成ステージ
        return ResponsesAgentResponse(
            output=[self.create_text_output_item(text=answer, id="msg-1")]
        )

入出力が標準形式に揃っているため、クライアント側は一般的な LLM API と同じ感覚で呼び出せます。ストリーミング応答が必要な場合は predict_stream() を実装します。ツール呼び出し(3-9)やマルチエージェント構成の途中経過も、この形式の中で表現できます。

3. LangChainフレーバーと models from code

インターフェースの選択とは別に、「どうやってログするか」にも選択肢があります。

方法内容向いている場合
pyfunc(mlflow.pyfunc.log_model)PythonModel / ResponsesAgent を実装してログする独自ロジック・複数フレームワーク混在・ガードレール込みの複雑なチェーンやエージェント
LangChainフレーバー(mlflow.langchain.log_model)LangChain のチェーンオブジェクトを直接ログする専用フレーバーチェーンが LangChain(LCEL)で完結している場合
models from code(コードベースロギング)チェーンを定義したPythonファイルそのものをモデルとしてログする方式MLflow 3 の推奨ロギング方式。直列化(pickle)が難しいチェーンでも壊れず、コードがそのまま保存されるためレビューしやすい

models from code(コードベースロギング)は、チェーンオブジェクトをシリアライズする代わりに「チェーンを定義するコードファイル」を保存し、ロード時にそのコードを実行してチェーンを再構築します。複雑なGenAIチェーンはオブジェクトの直列化が壊れやすいため、MLflow 3 ではこれが推奨ロギング方式です。ResponsesAgent もこの方式でログするのが基本で、エージェントを定義したファイル内で mlflow.models.set_model(SimpleRAGAgent()) のようにモデルを指定し、log_model にはオブジェクトではなくそのファイルのパスを渡します。

4. モデルシグネチャと input_example

モデルシグネチャ(model signature)は、モデルの入力・出力のスキーマ(名前と型)を定義するメタデータです。GenAIのチェーンでは特に重要で、次の役割を持ちます。

シグネチャは input_example(入力例)を渡すと自動推論されます。input_example はドキュメントとしても機能し、ロードしたモデルの動作確認にも使えるため、GenAIモデルでは必ず指定する習慣をつけましょう。なお、ResponsesAgent は入出力形式が標準化されているため、シグネチャが自動的に設定されるのも実務上の利点です。

📝 試験のポイント

「Model Serving にデプロイしたモデルが入力の形式エラーを返す。何を確認・定義すべきか?」という問題ではモデルシグネチャが答えの軸になります。「シグネチャは入出力スキーマを定義し、サービング時のリクエスト検証に使われる」という一文を覚えてください。

5. 依存関係の記録とデプロイへの流れ

モデルをログする際には、実行に必要なライブラリを pip_requirements(または conda 環境)として記録します。サービング環境はノートブックの環境をそのまま引き継がないため、依存関係の記録漏れはデプロイ後のロードエラーの代表的な原因です。databricks-langchain のようなチェーンが使うライブラリは漏れなく列挙します。

ログしたチェーンのその後の流れは次のとおりです(第4章の予告)。

  1. ログ(この節) — チェーン/エージェントをMLflowモデルとして記録する
  2. Unity Catalog に登録(4-1)catalog.schema.model_name の3レベル名で登録し、バージョン・権限・リネージを管理
  3. Model Serving にデプロイ(4-2) — 登録したモデルをRESTエンドポイントとして公開

また、MLflow 3 には MLflow Tracing が統合されており、チェーン実行の各ステップ(検索・LLM呼び出し・パース)の入出力とレイテンシをトレースとして自動記録できます。mlflow.genai.evaluate による評価やプロンプトレジストリと合わせて、デバッグ・品質分析の基盤になるもので、詳しくは 5-6 で扱います。

✅ この節のまとめ

練習問題

問1. LangChain と独自のガードレール処理を組み合わせた複雑なRAGチェーンを、任意のPythonロジックを含む形でMLflowモデルとしてログしたい。最も適切な方法はどれか。

  1. mlflow.pyfunc.PythonModel を継承したクラスの predict() にチェーン呼び出しを実装し、mlflow.pyfunc.log_model でログする
  2. チェーンのコードをテキストファイルとして保存し、mlflow.log_artifact でアップロードする
  3. mlflow.sklearn.log_model を使う
  4. ノートブックをエクスポートしてGitにコミットする
解答と解説を見る

正解:A

pyfunc は任意のPythonロジックを predict() インターフェースでラップできる汎用フレーバーで、独自処理を含むチェーンに最適です。Bの log_artifact は単なるファイル保存であり、ロード・サービング可能な「モデル」にはなりません。Cのsklearnフレーバーはscikit-learnモデル専用です。DのGit管理はコードのバージョン管理としては有効ですが、デプロイ可能なモデルアーティファクトの作成にはなりません。なお、対話型エージェントとして開発する場合は、pyfunc の一種である ResponsesAgent を使うのが現行の推奨です。

問2. モデルシグネチャの説明として最も適切なのはどれか。

  1. モデルの作成者を証明する電子署名である
  2. モデルの入力・出力のスキーマを定義し、Model Serving でのリクエスト検証に使われる
  3. モデルの重みファイルのチェックサムである
  4. モデルのライセンス条項を記述したものである
解答と解説を見る

正解:B

モデルシグネチャは入出力の名前と型を定義するメタデータで、input_example から自動推論できます。サービングエンドポイントはこのスキーマに基づいてリクエストを検証します。A・C・Dはいずれも「署名」という語感からの引っかけで、セキュリティやライセンスとは無関係です。

問3. ノートブックでは正常に動作するチェーンを Model Serving にデプロイしたところ、エンドポイント起動時にライブラリの ImportError が発生した。最も可能性の高い原因はどれか。

  1. temperature の設定が高すぎる
  2. モデルログ時に pip_requirements へ必要な依存ライブラリを記録し忘れた
  3. プロンプトテンプレートの変数名が間違っている
  4. Databricks AI Search(旧 Vector Search)インデックスの同期が止まっている
解答と解説を見る

正解:B

サービング環境はノートブックのライブラリ環境を引き継がず、モデルと一緒に記録された依存関係定義から環境を構築します。記録漏れがあると起動時に ImportError になります。Aは出力のランダム性の話で起動エラーとは無関係、Cなら実行時のKeyError等になりImportErrorにはなりません、Dなら検索結果が古くなる・取得に失敗するという症状であり、ライブラリのImportErrorは起きません。

問4. チェーンオブジェクトの直列化(シリアライズ)がうまくいかない複雑なGenAIエージェントをMLflowでログしたい。この課題に対応するMLflowの方式はどれか。

  1. models from code(コードベースロギング):チェーンを定義したPythonファイルそのものをモデルとしてログする
  2. temperature を 0 にして再実行する
  3. チェーンを諦めて単一のLLM呼び出しに簡略化する
  4. モデルシグネチャを省略してログする
解答と解説を見る

正解:A

models from code はオブジェクトの pickle 化の代わりに定義コードを保存し、ロード時にコードを実行してチェーンを再構築するため、直列化の問題を回避できます。MLflow 3 ではこれが推奨ロギング方式です。Bは推論パラメータであり直列化とは無関係です。Cは要件を損なう回避策で解決になっていません。Dのシグネチャ省略は直列化の問題を何も解決せず、サービング時の検証も失われるため悪手です。

問5. ツール呼び出しとストリーミング応答に対応した対話型エージェントを新規に開発し、MLflowでログして Model Serving にデプロイしたい。2026年時点で第一候補となる実装インターフェースはどれか。

  1. mlflow.pyfunc.ResponsesAgent を継承し、OpenAI Responses API 互換の入出力で predict(必要に応じて predict_stream)を実装する
  2. mlflow.sklearn.log_model でエージェントを直接ログする
  3. MLflowを使わず、エージェントのコードを手動でサーバーにコピーして運用する
  4. ResponsesAgent はまだ実験的機能のため、必ず素の PythonModel で独自の入出力形式を設計する
解答と解説を見る

正解:A

現行のMLflowでは、エージェント/チェーンの実装インターフェースとして ResponsesAgent が推奨です。OpenAI Responses API 互換の標準形式により、ストリーミング・ツール呼び出し・マルチエージェントに対応し、シグネチャも自動設定されます。Bのsklearnフレーバーはscikit-learn専用です。Cは再現性・バージョン管理・ガバナンスをすべて失います。Dは事実と逆で、従来の PythonModel や ChatAgent も動作はするものの、新規開発の第一候補は ResponsesAgent です。