MLflowを使って簡単にLLMOpsを導入しよう！

## はじめに

みなさん、LLMOpsは何で構築していますか。

Azure系のサービスやLangSmithなど様々な回答があると思いますし、自作のLLMOps環境を構築している方々の少なくないと思います。

今回はLLMOps構築の一つの選択肢として、MLflowを紹介したいと思います。

## MLflowとは
MLflowはLLMOpsのみならず、MLOpsを構築できるオープンソースプラットフォームです。

https://mlflow.org/#core-concepts

LLMOpsに求められる基本的な実験の記録や評価を実施できますし、セルフホストで実行可能という特徴があります。

## MLflowを使ってみる
### 環境構築
まずは必要なライブラリをインストールします。

```bash
(venv) % pip install mlflow==2.14.0rc0
(venv) % pip install langchain==0.2.1 langchain-openai==0.1.8 langchain-community==0.2.1 tiktoken==0.7.0 
```

:::note 
Azure OpenAIをLangChain経由で使うため、LangChain系のライブラリをインストールしています。
:::

次にLLMを用意します。筆者はAzure OpenAIを使うので、事前にAzure AI Serviceを作り、モデルをデプロイします。

そしてプログラムでAzure OpenAIを使うためにAPIキーとエンドポイントを環境変数に追加します。

```bash 
% export AZURE_OPENAI_API_KEY={}
% export AZURE_OPENAI_ENDPOINT={}
```

### MLflowの立ち上げ
MLflowの立ち上げは簡単で、MLflowをインストールした環境で以下のコマンドを実行してください。

```bash 
(venv) % mlflow ui --port 9000 --backend-store-uri sqlite:///mlruns.db
```

`--port`でMLflowのポート番号を指定できます。
`--backend-store-uri`でMLflowのログや設定情報を保存するDBを指定します。事前にDBを作成する必要はなく、初回は自動で作成してくれます。

ちなみにDBを指定しない場合はmlrunsディレクトリが自動で作成され、mlruns配下に情報が格納されます。(DBの指定の仕方は他にも環境変数` MLFLOW_TRACKING_URI`を設定する方法があります。)

正常に実行が完了している場合は、http://127.0.0.1:9000/ にアクセスすると、以下のような画面が出てきます。

![スクリーンショット 2024-06-22 19.29.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487820/fd825b36-40a5-1e7f-427f-2a4d157c8e11.png)


### MLflowの使い方1:オートログ
LangChainを使う場合は、MLflowに対して自動で実験を記録する設定を導入することができます。以下サンプルコードです。

```python 
from langchain_openai import AzureChatOpenAI
import mlflow

mlflow.set_tracking_uri("http://localhost:9000")
mlflow.set_experiment("Test0001")
mlflow.langchain.autolog()

llm = AzureChatOpenAI(
    openai_api_version="2024-05-01-preview",#自身のAPI　versionを入力してください。
    azure_deployment="gpt-35-turbo",#モデルデプロイ名を入力してください。
    model_version="0301"#自身のモデルversionを入力してください。
)

output = llm.invoke("Say, Hello.")
```

上記プログラムを実行すると、画面左側のUIのExperimentsにTest0001が追加され、Traceに情報が保存されています。


![スクリーンショット 2024-06-22 19.38.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487820/ef488421-fffd-16fe-1a94-69e2f174e440.png)

ここでReqeust IDをクリックするとリクエストの詳細を確認できます。

![スクリーンショット 2024-06-22 19.42.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487820/bc398d25-f28e-8d1d-f03d-a70423e32203.png)

:::note 
LangChainで複数の処理をチェインする場合は、各処理の入出力や経過時間を確認できます。
:::

プログラムを少し解説します。

```python 
mlflow.set_experiment("Test001")
```

上記の`mlflow.set_experiment`で実験を設定します。引数で設定した名前の実験がなければ、新たに実験を作成できます。

```python 
mlflow.langchain.autolog()
```

上記の`mlflow.langchain.autolog()`でLangChainでの実行を自動でロギングすることができます。
詳細は以下ドキュメントをご覧ください。

https://mlflow.org/docs/latest/python_api/mlflow.langchain.html


### MLflowの使い方2:デコレータを使う方法

上記で説明した`mlflow.langchain.autolog()`を使わない場合は、デコレータを使って以下のように記述できます。


```python 
from langchain_openai import AzureChatOpenAI
import mlflow

mlflow.set_tracking_uri("http://localhost:9000")
mlflow.set_experiment("Test0002")

llm = AzureChatOpenAI(
    openai_api_version="2024-05-01-preview",
    azure_deployment="gpt-35-turbo",
    model_version="0301"
)

@mlflow.trace(span_type="func")
def run(llm, text):
    return llm.invoke(text)

output = run(llm, "Say, Hello.")
```
上記のようにプログラムを実行すると、先ほどと同様に結果を記録できます。

また以下のように関数を独立させて記述することもできます。

```python 
from langchain_openai import AzureChatOpenAI
import mlflow

mlflow.set_tracking_uri("http://localhost:9000")
mlflow.set_experiment("Test0003")

llm = AzureChatOpenAI(
    openai_api_version="2024-05-01-preview",
    azure_deployment="gpt-35-turbo",
    model_version="0301"
)

@mlflow.trace(span_type="func")
def llm_run(llm, text):
    return llm.invoke(text)

@mlflow.trace(span_type="func")
def run(llm, text):
    return llm_run(llm,text)

output = run(llm, "Say, Hello.")
```

上記のように記述すると、それぞれの関数の処理を区別してMLflowに記録することができます。このように記述することで、（今後関数を増やす場合においても）複数の関数の入出力をMLflowで記録できます。


![スクリーンショット 2024-06-23 1.23.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487820/a5fb4790-75ac-2b37-0e3b-71d59e08688f.png)


`mlflow.trace()`のドキュメントを以下に載せておきます。今回は解説していないですが、`with`を使って記述することも可能です。

https://mlflow.org/docs/latest/python_api/mlflow.html?highlight=mlflow%20trace#mlflow.trace

:::note w
各処理を関数化している場合はwithを使うよりもデコレータを使った方が楽に記述できるはずです。
:::


## おわりに
いかがだったでしょうか。

MLflowをLLMOpsとして使うという日本語記事が少なかったので、記事を投稿してみました。

好評であれば、評価の部分も記事執筆したいと思います。

また筆者はまだまだMLflowを熟知しているわけではないので、誤っている点等あればコメントいただけると大変助かります。

## おまけ
MLflowのほかにLLMOps関連で筆者が知っているものは以下です。適宜追加していきます。

https://www.wandb.jp/

https://mlflow.org/

https://langfuse.com/

https://www.langchain.com/langsmith

https://www.openlayer.com/

https://www.langtrace.ai/

https://arize.com/llm/

https://phoenix.arize.com/

https://azure.microsoft.com/en-us/products/ai-studio