1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[翻訳] MLflowチュートリアル: ChatModelを使い始める

Posted at

Tutorial: Getting Started with ChatModelの翻訳です。

本書は著者が手動で翻訳したものであり内容の正確性を保証するものではありません。正確な内容に関しては原文を参照ください。

MLflowのChatModelクラスは、プロダクションレディの会話型AIモデルを作成するための標準化された手段を提供します。結果として得られるモデルは、MLflowのトラッキング、評価、ライフサイクル管理機能と完全にインテグレーションされます。これらは、MLflowモデルレジストリで他の人と共有したり、REST APIとしてデプロイしたり、インタラクティブに使うためにノートブックにロードすることができます。さらに、これらは広く導入されているOpenAI chat APIの仕様に互換性があるので、他のAIシステムやツールとの連携が容易になります。

すでにPythonModelに慣れているのであれば、なぜChatModelが必要なのかと不思議に思うかもしれません。生成AIアプリケーションはどんどん複雑になっており、カスタムのPythonModelを用いた入出力、パラメーターのマッピングは困難になることがあります。ChatModelは、会話型AIモデルのために、構造化され、OpenAIと互換性のあるスキーマを提供することで、これをシンプルにします。

ChatModel PythonModel
使用するケース OpenAIの仕様と互換性のある標準チャットスキーマで会話型モデルを開発、デプロイする際に使用。 モデルのインタフェースに対するフルコントロールを必要とする、あるいはモデルの挙動の全ての側面をカスタマイズしたい際に使用。
インタフェース OpenAIのチャットスキーマに固定 モデルの入出力スキーマに対するフルコントロール
セットアップ クイック。定義済みのモデルシグネチャと入力例を用いて、会話型のアプリケーションですぐに利用可能。 カスタム。自分でモデルのシグネチャと入力サンプルを定義する必要がありる。
複雑度 低い。標準化されたインタフェースがモデルのデプロイとインテグレーションをシンプルに。 高い。カスタムのPythonModelのデプロイとインテグレーションはわかりにくくなる場合がある。例えば、MLflowがPythonModelに入力データを渡す前に、入力データをPandasデータフレームに変換するので、モデルはPandasデータフレームを取り扱う必要がある。

学ぶこと

このガイドでは、カスタムの会話型AIモデルを定義するための基本的なChatModel APIの使い方をウォークスルーします。特に、以下のことを学びます:

  1. あなたのアプリケーションロジックをChatModelの入力/出力スキーマにマッピングする方法。
  2. ChatModelでサポートされる定義済みの推論パラメータの使い方。
  3. custom_inputsを用いて、ChatModelにカスタムのパラメータを渡す方法。
  4. カスタムチャットモデルを定義する際のChatModelPythonModelの比較。

これらのポイントを説明するために、このガイドでは例としてローカルにホストされたOllamaモデルを用いて、カスタムのChatModelの構築をウォークスルーします。ビルトインのOllamaモデルフレーバーは存在しないので、MLflowのさまざまなトラッキング、評価、ライフサイクル管理機能をOllamaモデルで使うために、カスタムのChatModelを作成します。

前提条件

  • MLflowのロギングAPIと生成AIの概念に対する習熟度。
  • ChatModelを使うためにMLflowバージョン2.17.0以降がインストールされていること。

ChatModelを理解する: 入力/出力のマッピング

mlflow.pyfunc.ChatModelインタフェースは、あなたのアプリケーションとMLflowのエコシステムの間に存在し、あなたのアプリケーションとMLflowの他の機能との連携や、アクセス可能かつプロダクションレディなフォーマットを用いたモデルのデプロイを容易にする、標準化レイヤーを提供します。

そのためには、カスタムのChatModelを定義する際のキーとなるタスクとして、ChatModelの標準化されたインタフェースにあなたのアプリケーションのロジックをマッピングする必要があります。このマッピングの練習は、カスタムのChatModelを作成する際の重要な部分となります。

カスタムChatModelを使用する際、predictメソッドは以下のように標準化された入力を期待します:

input = {
    "messages": [{"role": "user", "content": "What is MLflow?"}],
    "max_tokens": 25,
}

ここには、メッセージのリストを含むmessagesキー、max_tokenstemperaturetop_pstopのようなオプションの推論パラメータが含まれています。こちらで完全なchat requestオブジェクトの詳細を確認することができます。

また、出力も以下のように標準化されたフォーマットで返却されます:

{
    "choices": [
        {
            "index": 0,
            "message": {
                "role": "assistant",
                "content": "MLflow is an open-source platform for machine learning (ML) and artificial intelligence (AI). It's designed to manage,",
            },
            "finish_reason": "stop",
        }
    ],
    "model": "llama3.2:1b",
    "object": "chat.completion",
    "created": 1729190863,
}

こちらで完全なchat responseオブジェクトの詳細を確認することができます。

これらの入力/出力スキーマは、広く受け入れられているOpenAIの仕様と互換性があるので、いろいろな文脈でのChatModelの活用が用意となります。

このマッピングプロセスをデモンストレーションするために、ネイティブなMLflowフレーバーを持たないOllama llmクライアントを通じて、MetaのLlama 3.2 1Bモデルを記録するために、mlflow.pyfunc.ChatModelの使い方を説明します。

初めてのChatModelの構築

このセクションでは、ローカルにホストされたOllamaモデルをChatModelインタフェースでラッピングします。入出力の取り扱い方を説明するためにシンプルなバージョンを構築し、max_tokenstemperatureのような推論パラメータの取り扱い方法を説明します。

セットアップ: Ollamaのインストールとモデルのダウンロード

  1. こちらからOllamaをインストールします。
  2. Ollamaがインストールされ稼働したら、ollama pull llama3.2:1bを実行してLlama 3.2 1Bモデルをダウンロードします。

ollama run llama3.2:1bでモデルがダウンロードされ、システムで利用できることを検証できます。

> ollama run llama3.2:1b

>>> Hello world!
Hello! It's great to see you're starting the day with a cheerful greeting. How can I assist you today?
>>> Send a message (/? for help)

Ollamaモデルのインタフェースとして、ollama-pythonライブラリを使います。pip install ollamaで環境にインストールします。また、pip install mlflowmlflowをインストールします。

Ollama Pythonライブラリの使用

ChatModelの入出力スキーマにOllamaの入出力スキーマをマッピングするには、はじめにOllamaモデルが期待、返却する入力と出力の種類を理解する必要があります。シンプルなプロンプトでこのモデルにクエリーする方法を示します:

import ollama
from ollama import Options
from rich import print

response = ollama.chat(
    model="llama3.2:1b",
    messages=[
        {
            "role": "user",
            "content": "What is MLflow Tracking?",
        }
    ],
    options=Options({"num_predict": 25}),
)

print(response)

以下の出力が返却されます:

{
    'model': 'llama3.2:1b',
    'created_at': '2024-11-04T12:47:53.075714Z',
    'message': {
        'role': 'assistant',
        'content': 'MLflow Tracking is an open-source platform for managing, monitoring, and deploying machine learning (ML) models. It provides a'
    },
    'done_reason': 'length',
    'done': True,
    'total_duration': 1201354125,
    'load_duration': 819609167,
    'prompt_eval_count': 31,
    'prompt_eval_duration': 41812000,
    'eval_count': 25,
    'eval_duration': 337872000
}

Ollamaの入出力に関して注意すべきことがいくつかあります:

  • ollama.chatメソッドによって期待される引数messagesは、rolecontentのキーを持つディクショナリーのリストです。ChatModel APIによって期待されるChatMessageオブジェクトのリストをディクショナリーのリストに変換する必要があります。
  • パラメータのディクショナリーである引数optionsを通じて、Ollamaに推論パラメータが渡されます。さらに、num_predictにあるように、パラメータ名はChatModelで期待されるパラメータ名と異なっています。ChatModelの推論パラメータをOllamaのオプションにまっっピングする必要があります。
  • 出力の構造はChatModelの出力スキーマと異なっています。これをChatModelの出力スキーマにマッピングする必要があります。

Ollama ChatModelバージョン1: チャットのみ

推論パラメータには対応しませんが、入力/出力のメッセージに対応するシンプルなバージョンのカスタムChatModelからスタートしましょう。これを達成するには以下が必要となります:

  1. mlflow.pyfunc.ChatModelを拡張するクラスを定義します。
  2. Ollamaクライアントの初期化を取り扱うload_contextメソッドを実装します。
  3. 入出力マッピングを取り扱うpredictメソッドを実装します。

少なくともこのシンプルなバージョンのカスタマイズの大部分は、predictメソッドで行われます。predictメソッドを実装する際には、以下の標準化された入力を活用します:

  • messages: ChatMessageオブジェクトのリスト
  • params: 推論パラメータを含むChatParamsオブジェクト

そして、ChatChoiceオブジェクトのリストと(オプションの)利用データや他のメタデータから構成されるデータクラスであるChatCompletionResponseオブジェクトを返却する必要があります。

これらがOllamaの入出力にマッピングしなくてはならないものです。今のところは、入出力メッセージのみを取り扱うシンプルなバージョンとなります:

# if you are using a jupyter notebook
# %%writefile ollama_model.py
from mlflow.pyfunc import ChatModel
from mlflow.types.llm import ChatMessage, ChatCompletionResponse, ChatChoice
from mlflow.models import set_model
import ollama


class SimpleOllamaModel(ChatModel):
    def __init__(self):
        self.model_name = "llama3.2:1b"
        self.client = None

    def load_context(self, context):
        self.client = ollama.Client()

    def predict(self, context, messages, params=None):
        # Prepare the messages for Ollama
        ollama_messages = [msg.to_dict() for msg in messages]

        # Call Ollama
        response = self.client.chat(model=self.model_name, messages=ollama_messages)

        # Prepare and return the ChatCompletionResponse
        return ChatCompletionResponse(
            choices=[{"index": 0, "message": response["message"]}],
            model=self.model_name,
        )


set_model(SimpleOllamaModel())

上のコードでは、Ollamaの入力にChatModelの入力、Ollamaの出力をChatModelの出力スキーマにマッピングしました。特に:

  • ChatModelの入力スキーマにおけるmessagesキーは、ChatMessageオブジェクトのリストとなります。これをOllamaで期待される入力であるrolecontentキーのディクショナリーのリストに変換しました。
  • predictメソッドが返却するChatCompletionResponseは、ChatCompletionResponseデータクラスを用いて作成する必要がありますが、期待されるスキーマにマッチするディクショナリーとして、ネストされたメッセージやチョイスデータを提供することもできます。MLflowは自動的にこれらのディクショナリーを適切なデータクラスオブジェクトに変換します。我々のケースでは、ChatCompletionResponseを作成しましたが、ディクショナリーとしてチョイスとメッセージを提供しちえます。

ノートブックの環境では、%%writefileマジックコマンドでollama_model.pyと呼ばれるファイルにモデルを保存し、set_model(SimpleOllamaModel())を呼び出すことができます。これは、こちらで詳細を確認できる「models from code」のモデルロギングのアプローチです。

これで、以下のように作成したモデル定義を含むファイルへのパスを指定することで、MLflowにこのモデルを記録することができます:

import mlflow

mlflow.set_experiment("chatmodel-quickstart")
code_path = "ollama_model.py"

with mlflow.start_run():
    model_info = mlflow.pyfunc.log_model(
        "ollama_model",
        python_model=code_path,
        input_example={
            "messages": [{"role": "user", "content": "Hello, how are you?"}]
        },
    )

繰り返しになりますが、モデルを記録するためにmodels-from-codeアプローチを採用しているので、python_modelパラメータにモデル定義を含むファイルへのパスを指定しています。これで、モデルをロードして試すことができます:

loaded_model = mlflow.pyfunc.load_model(model_info.model_uri)

result = loaded_model.predict(
    data={
        "messages": [{"role": "user", "content": "What is MLflow?"}],
        "max_tokens": 25,
    }
)
print(result)
{
    "choices": [
        {
            "index": 0,
            "message": {
                "role": "assistant",
                "content": "MLflow is an open-source platform for model deployment, monitoring, and tracking. It was created by Databricks, a cloud-based data analytics company, in collaboration with The Data Science Experience (TDEE), a non-profit organization that focuses on providing high-quality, free machine learning resources.\n\nMLflow allows users to build, train, and deploy machine learning models in various frameworks, such as TensorFlow, PyTorch, and scikit-learn. It provides a unified platform for model development, deployment, and tracking across different environments, including local machines, cloud platforms (e.g., AWS), and edge devices.\n\nSome key features of MLflow include:\n\n1. **Model versioning**: Each time a model is trained or deployed, it generates a unique version number. This allows users to track changes, identify conflicts, and manage multiple versions.\n2. **Model deployment**: MLflow provides tools for deploying models in various environments, including Docker containers, Kubernetes, and cloud platforms (e.g., AWS).\n3. **Monitoring and logging**: The platform includes built-in monitoring and logging capabilities to track model performance, errors, and other metrics.\n4. **Integration with popular frameworks**: MLflow integrates with popular machine learning frameworks, making it easy to incorporate the platform into existing workflows.\n5. **Collaboration and sharing**: MLflow allows multiple users to collaborate on models and tracks changes in real-time.\n\nMLflow has several benefits, including:\n\n1. **Improved model management**: The platform provides a centralized view of all models, allowing for better model tracking and management.\n2. **Increased collaboration**: MLflow enables team members to work together on machine learning projects more effectively.\n3. **Better model performance monitoring**: The platform offers real-time insights into model performance, helping users identify issues quickly.\n4. **Simplified model deployment**: MLflow makes it easy to deploy models in various environments, reducing the complexity of model deployment.\n\nOverall, MLflow is a powerful tool for managing and deploying machine learning models, providing a comprehensive platform for model development, tracking, and collaboration.",
            },
            "finish_reason": "stop",
        }
    ],
    "model": "llama3.2:1b",
    "object": "chat.completion",
    "created": 1730739510,
}

これで、標準化され、OpenAIと互換性のあるフォーマットでチャットのレスポンスを受け取りました。しかし、何かおかしいです: max_tokensを25に設定したのに、レスポンスは25トークン以上となっています!なぜでしょうか?

我々のカスタムChatModelでは、まだ推論パラメータに対応していません: ChatModelとOllamaフォーマット間での入力/出力のメッセージのマッピングに加え、二つのフォーマット間の推論パラメータをマッピングする必要があります。カスタムChatModelの次のバージョンではこれに対応します。

推論パラメーターを受け付けるChatModelの構築

多くのLLMでは、レスポンスに含めるトークン数を制限するmax_tokensやレスポンスの「創造性」を調整するtemperatureのように、レスポンスの生成方法を制御する推論パラメータをサポートしています。ChatModel APIでは、一般的に使用される推論パラメータの多くに対するビルトインのサポートが提供されており、このセクションではどのように設定、活用するのかを設営します。

ChatModelへのパラメータの引き渡し

ChatModelを使う際、入力のメッセージと共にパラメータが引き渡されます:

result = model.predict(
    {
        "messages": [{"role": "user", "content": "Write a story"}],
        "max_tokens": 100,
        "temperature": 0.7,
    }
)

こちらでサポートされるパラメータの完全なリストを確認できます。さらに、次のセクションでカバーするcustom_inputsキーを通じて、ChatModelに任意の追加パラメータを渡すことができます。

カスタムPyFuncモデルにおけるパラメータの取り扱いとの比較

PyFuncモデルでの推論パラメータに慣れているのであれば、ChatModelにおけるパラメータの取り扱いにはいくつかのキーとなる違いがあることに気づくことでしょう:

ChatModel PyFunc
パラメータはpredictに引き渡されるmessagesキーを含むdataディクショナリーの一部となります。 パラメータはparamsキーワード引数としてpredictに引き渡されます。
ChatModelクラスでは、一般的に使われるチャットモデルパラメータ(max_tokenstemperaturetop_pなど)は事前に定義されています。 開発者によってパラメータは選択、設定されます。
一般的なチャットモデルパラメータをサポートするために、モデルシグネチャは自動で設定されます。 モデルシグネチャでパラメータを明示的に定義する必要があります。

まとめると、ChatModelによって推論パラメータの設定と利用が簡単になることに加えて、ある程度の柔軟性と引き換えに、標準化され、OpenAIと互換性がある出力フォーマットが提供されます。

それでは、推論パラメータを取り扱うカスタムChatModelを設定しましょう。

Ollama ChatModelバージョン2: 推論パラメータを用いたチャット

推論パラメータを持つChatModelのセットアップはわかりやすいものとなっています: 入力メッセージのように、Ollamaクライアントで期待されるフォーマットに推論パラメータをマッピングする必要があります。Ollamaクライアントでは、推論パラメータはoptionsディクショナリーとしてモデルに渡されます。カスタムChatModelを定義する際に、paramsキーワード引数を通じて、predictに渡される推論パラメータにアクセスすることができます。ここでの仕事は、Ollamaクライアントのoptionsディクショナリーにpredictメソッドのparamsディクショナリーをマッピングすることです。Ollamaでサポートされているオプションのリストはこちらで確認することができます。

# if you are using a jupyter notebook
# %%writefile ollama_model.py

import mlflow
from mlflow.pyfunc import ChatModel
from mlflow.types.llm import ChatMessage, ChatCompletionResponse, ChatChoice
from mlflow.models import set_model
import ollama
from ollama import Options


class OllamaModelWithMetadata(ChatModel):
    def __init__(self):
        self.model_name = None
        self.client = None

    def load_context(self, context):
        self.model_name = "llama3.2:1b"
        self.client = ollama.Client()

    def _prepare_options(self, params):
        # Prepare options from params
        options = {}
        if params:
            if params.max_tokens is not None:
                options["num_predict"] = params.max_tokens
            if params.temperature is not None:
                options["temperature"] = params.temperature
            if params.top_p is not None:
                options["top_p"] = params.top_p
            if params.stop is not None:
                options["stop"] = params.stop

            if params.custom_inputs is not None:
                options["seed"] = int(params.custom_inputs.get("seed", None))

        return Options(options)

    def predict(self, context, messages, params=None):
        ollama_messages = [
            {"role": msg.role, "content": msg.content} for msg in messages
        ]
        options = self._prepare_options(params)

        # Call Ollama
        response = self.client.chat(
            model=self.model_name, messages=ollama_messages, options=options
        )

        # Prepare the ChatCompletionResponse
        return ChatCompletionResponse(
            choices=[{"index": 0, "message": response["message"]}],
            model=self.model_name,
        )


set_model(OllamaModelWithMetadata())

以前のバージョンからの変更点を示します:

  • paramsディクショナリーからmax_tokenstemperaturetop_pstopをOllamaクライアントのoptionsディクショナリーのnum_predicttemperaturetop_pstopにマッピングしました(Ollamaではmax_tokensで期待されるパラメータ名が異なることに注意してください)。
  • Ollamaクライアントのchatメソッドにoptionsディクショナリーを引き渡しました。paramsからoptionsへのマッピングを取り扱う新たなプライベートメソッド_prepare_optionsを作成していることに注意してください。カスタムロジックに対応しつつも、コードをきれいで整理した状態に保つためにカスタムのChatModelにメソッドを追加することができます。
  • seedの値がparamsディクショナリーにあるかどうかcustom_inputsをチェックしています。これは次のセクションで詳細を説明します。

これで、以前と同じように、MLflowにこのモデルを記録し、ロードし、試すことができます:

code_path = "ollama_model.py"

with mlflow.start_run():
    model_info = mlflow.pyfunc.log_model(
        "ollama_model",
        python_model=code_path,
        input_example={
            "messages": [{"role": "user", "content": "Hello, how are you?"}]
        },
    )

loaded_model = mlflow.pyfunc.load_model(model_info.model_uri)

result = loaded_model.predict(
    data={
        "messages": [{"role": "user", "content": "What is MLflow?"}],
        "max_tokens": 25,
    }
)
print(result)

以下が返却されます:

{
    "choices": [
        {
            "index": 0,
            "message": {
                "role": "assistant",
                "content": "MLflow is an open-source platform that provides a set of tools for managing and tracking machine learning (ML) model deployments,",
            },
            "finish_reason": "stop",
        }
    ],
    "model": "llama3.2:1b",
    "object": "chat.completion",
    "created": 1730724514,
}

これで、ChatModelの入力スキーマからmax_tokensをOllamaクライアントのnum_predictパラメーターに適切にマッピングし、期待したトークン数のレスポンスを受け取っています。

カスタムパラメータの引き渡し

ビルトインの推論パラメータに含まれていないカスタムパラメータを引き渡したい場合にはどうしたらいいのでしょうか?ChatModel APIはそのままのモデルに引き渡されるキーバリューペアのディクショナリーを受け付けるcustom_inputsキーを通じてそれを行う方法を提供します。キーとバリューの両方は文字列である必要があるので、predictメソッドで型変換に対応する必要が出てくることがあります。上の例では、custom_inputsディクショナリーにseedキーを追加することで、カスタムのseedの値をOllamaモデルが使えるように設定しました:

if params.custom_inputs is not None:
    options["seed"] = int(params.custom_inputs.get("seed", None))

これを含めたことで、predictメソッドのcustom_inputsキーを通じて、seedの値を引き渡すことができます。同じシード値で複数回predictメソッドをコールすると、常に同じレスポンスを受け取ります。

result = loaded_model.predict(
    data={
        "messages": [{"role": "user", "content": "What is MLflow?"}],
        "max_tokens": 25,
        "custom_inputs": {"seed": "321"},
    }
)

print(result)

以下が返却されます:

{
    "choices": [
        {
            "index": 0,
            "message": {
                "role": "assistant",
                "content": "MLflow is an open-source software framework used for machine learning model management, monitoring, and deployment. It's designed to provide",
            },
            "finish_reason": "stop",
        }
    ],
    "model": "llama3.2:1b",
    "object": "chat.completion",
    "created": 1730724533,
}

ティップ

ChatModelの使用 vs. 定義

ChatModelを使う際にデータを引き渡す方法と、ChatModelを定義する際にデータにアクセスする方法の間には重要な違いがあります。

インスタンスが作成されたChatModelを使う際には、メッセージ、パラメータなどのすべての引数は単一のディクショナリーとしてpredictメソッドに引き渡されます。

model.predict({"messages": [{"role": "user", "content": "Hello"}], "temperature": 0.7})

一方、カスタムChatModelのpredictメソッドを定義する際には、別々のmessagesparams引数を通じてデータにアクセスします。ここで、messagesChatMessageオブジェクトのリストであり、paramsChatParamsオブジェクトとなります。この違いを理解すること、すなわちユーザーには統合された入力、開発者には構造化されたアクセス、はChatModelを効果的に取り扱うためには重要なこととなります。

PyFuncとの比較

ChatModel APIを通じてチャットモデルをセットアップすることと、PythonModel APIを用いることのいくつかのメリットとトレードオフを説明するために、PythonModelとして上述のモデルを実装するとどうなるのかを見てみましょう。

Ollamaモデルバージョン3: カスタムPyFuncモデル

# if you are using a jupyter notebook
# %%writefile ollama_pyfunc_model.py

import mlflow
from mlflow.pyfunc import PythonModel
from mlflow.types.llm import (
    ChatCompletionRequest,
    ChatCompletionResponse,
    ChatMessage,
    ChatChoice,
)
from mlflow.models import set_model
import ollama
from ollama import Options
import pandas as pd
from typing import List, Dict


class OllamaPyfunc(PythonModel):
    def __init__(self):
        self.model_name = None
        self.client = None

    def load_context(self, context):
        self.model_name = "llama3.2:1b"
        self.client = ollama.Client()

    def _prepare_options(self, params):
        options = {}
        if params:
            if "max_tokens" in params:
                options["num_predict"] = params["max_tokens"]
            if "temperature" in params:
                options["temperature"] = params["temperature"]
            if "top_p" in params:
                options["top_p"] = params["top_p"]
            if "stop" in params:
                options["stop"] = params["stop"]
            if "seed" in params:
                options["seed"] = params["seed"]

        return Options(options)

    def predict(self, context, model_input, params=None):
        if isinstance(model_input, (pd.DataFrame, pd.Series)):
            messages = model_input.to_dict(orient="records")[0]["messages"]
        else:
            messages = model_input.get("messages", [])

        options = self._prepare_options(params)
        ollama_messages = [
            {"role": msg["role"], "content": msg["content"]} for msg in messages
        ]

        response = self.client.chat(
            model=self.model_name, messages=ollama_messages, options=options
        )

        chat_response = ChatCompletionResponse(
            choices=[
                ChatChoice(
                    index=0,
                    message=ChatMessage(
                        role="assistant", content=response["message"]["content"]
                    ),
                )
            ],
            model=self.model_name,
        )

        return chat_response.to_dict()


set_model(OllamaPyfunc())

これは、上でChatModelを定義した方法と非常に似ており、実際のところ、同じOllamaモデルをサービングするのにこのPythonModelを使うことができます。しかし、いくつかの重要な違いが存在します:

  • 最終的には入力は単なるメッセージのリストであるにもかかわらず、入力データをpandasデータフレームとして取り扱う必要がありました。
  • 事前に定義されているChatParamsオブジェクトとして推論パラメータを受け取るのではなく、paramsディクショナリーを受け取っています。この結果の一つは、他の推論パラメータとは個別にseedを取り扱う必要がないということでした: これらはPythonModel APIにおいては、すべてがカスタムのパラメータとなります。
  • ChatCompletionResponseではなく、ChatCompletionResponseをディクショナリーに変換するためにchat_response.to_dict()を呼び出す必要がありました。これは、ChatModelでは自動的に対応されます。

モデルを記録する際に最大の違いのいくつかに直面します:

code_path = "ollama_pyfunc_model.py"

params = {
    "max_tokens": 25,
    "temperature": 0.5,
    "top_p": 0.5,
    "stop": ["\n"],
    "seed": 123,
}
request = {"messages": [{"role": "user", "content": "What is MLflow?"}]}

with mlflow.start_run():
    model_info = mlflow.pyfunc.log_model(
        "ollama_pyfunc_model",
        python_model=code_path,
        input_example=(request, params),
    )

カスタムのPythonModelでは、入力サンプルを用いてモデルシグネチャが推定できるように、入力サンプルを手動で定義する必要があります。これは、標準的なOpenAI互換の入力/出力/パラメータのスキーマに準拠するように自動的にシグネチャを設定するChatModel APIとの大きな違いとなります。入力サンプルに基づいたモデルシグネチャの自動推定に関しては、GenAI model signature exampleをご覧ください。

また、モデルのpredictメソッドの呼び出し方法にも特筆すべき違いがあります: メッセージを含むディクショナリーではなく、paramsキーワード引数を通じて、ディクショナリーとしてパラメータが引き渡されます。

loaded_model = mlflow.pyfunc.load_model(model_info.model_uri)

result = loaded_model.predict(
    data={"messages": [{"role": "user", "content": "What is MLflow?"}]},
    params={"max_tokens": 25, "seed": 42},
)
print(result)

これは以下を返却します:

{
    "choices": [
        {
            "index": 0,
            "message": {
                "role": "assistant",
                "content": "MLflow is an open-source platform for machine learning (ML) and deep learning (DL) model management, monitoring, and",
            },
            "finish_reason": "stop",
        }
    ],
    "model": "llama3.2:1b",
    "object": "chat.completion",
    "created": 1731000733,
}

まとめると、ChatModelは標準化され、OpenAI互換の入出力にフォーカスすることで、カスタムチャットモデルの定義に対してより構造化されたアプローチを提供します。ChatModelのスキーマと螺っぽいんぐするアプリケーション間での入力/出力スキーマをマッピングするためのちょっとしたセットアップの手間はありますが、入力/出力/パラメータのスキーマの定義が多くの場合困難になるタスクに対応しなくてはならない完全にカスタムのPythonModelよりも取り扱いが簡単になる場合があります。一方、PythonModelのアプローチは、最大の柔軟性を提供しますが、開発者は入力/出力/パラメータのマッピングロジックのすべてを手動で対応する必要があります。

まとめ

このガイドでは、以下のことを学びました:

  • あなたのアプリケーションロジックをChatModelの入力/出力スキーマにマッピングする方法。
  • ChatModelでサポートされる定義済みの推論パラメータの使い方。
  • custom_inputsを用いて、ChatModelにカスタムのパラメータを渡す方法。
  • カスタムチャットモデルを定義する際のChatModelPythonModelの比較。

これで、ChatModel APIが何であって、カスタムチャットモデルを定義する際にどのように使えるのかについて感触がつかめたかと思います。

ChatModelには、この入門ガイドでカバーしていない以下のようなその他の機能があります:

  • 特にモデルが複数のコンポーネントやLLMのAPIを呼び出すモデルにおいて、あなたのチャットモデルをデバッグ、モニタリングする際に有用なMLflow Tracingのネイティブサポート。
  • 外部設定ファイルを用いたモデル設定のカスタマイズのサポート。

これらの機能や、ChatModel APIのその他の高度な機能を学ぶにはこちらのガイドをご覧ください。

1
0
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
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?