🛠️

DifyからXinferenceを利用するための環境構築手順-Xinferenceインストール編

2024/11/23に公開

2024.12.14 追記

2024年11月23日に当記事を初回公開後に、再度同じ手順で環境構築したところ想定通りに動作しない、具体的にはXinferenceの起動後のモデルのダウンロードが成功しない、ということが分かりましたので当記事を一部修正しました。
動作しない原因は、この手順のDockerfileでapt installするライブラリが不足していることでした。Xinferenceは最近になってV0.1X系からV1.X系に大幅アップデートしています。今後もXinferenceは頻繁なアップデートが予想されるため、Dockerイメージをビルドしなおす際には合わせてDockerfile等の見直しが必要となる可能性があります。

はじめに

この記事では、Dify上でモデルプロバイダーとして利用するXinference(Xoribits)のローカル環境へのインストールについての手順について解説します。
後続作業として、今回構築したXinferenceをDifyから利用するための設定を行う手順も必要ですが、こちらは今後別途記事化する予定です。

Difyとは

Difyとは生成AIアプリケーションを開発およびサービスとして公開するためのプラットフォームサービスです。Difyではードでアプリケーションを開発できるため、プログラムコードを組けるメンバーが少ない状況でも生成AIアプリケーションを組織やチームに提供できるようになります。
また、 DifyはローカルLLMを含む多数のモデルプロバイダー(OpenAIのGPTやGoogleのGemini、Ollamaなど)を選択・利用することができます。
https://dify.ai/jp

Difyの利用方法は公式としては、

  • Difyの開発元であるlangGenius社が有償サービスとして提供するSaaS版
  • 公開されているGithubからソースコードをcloneして自分のローカル環境で稼働させるコミュニティ版

の2種類があります。
今回はコミュニティ版を自社サーバー内でDockerコンテナとして稼働させる環境を構築する状況を想定しています。

Xinferenceとは

https://github.com/xorbitsai/inference

Xinference(またはxorbits)とは、ローカルLLMを実行するためのプラットフォームです。
Xinference自体をローカル環境にインストールして使用します。
Xinference内に様々なLLMをインストールすることにより、ローカル環境に閉じた環境でLLMを実行することができるようになります。
当環境では、Difyで様々なローカルLLMを使用できるようにするために、Xinferenceを通じてローカルLLMを使用します。

なぜXinferenceを使用するのか

DifyではRAGの仕組みを簡単に構築できる機能も備えています。RAGの検索精度向上テクニックの一つとしてリランキングハイブリッド検索という仕組みあるのですが、Difyでこれらを行うためにはそれに対応したモデルプロバイダーを選択する必要があります。その選択肢の一つとしてXinferenceがあるため、今回Xinferenceを利用することとしました。
Difyのモデルプロバイダーリストはこちら

前提およびなぜこの手順になったのか

改めて、ここでいうローカル環境とは、Difyが動作するVMのことを指しています。

前提1:Google CloudのCOSを利用している

Difyが動作するVMとしてGoogle Compute Engineを利用し、かつGoogle CloudのContainer Optimized OS(COS)で稼働していることを前提としています。

前提2:インターネット上のリポジトリへのアクセス

今回の環境構築のためには、ローカル環境からDockerHubやHuggingface等のインターネット上のリポジトリにアクセスできる必要があります。

制約1:COSの仕様

OS内ではaptやpip等のパッケージマネージャの利用は推奨されていません。
そのためPythonのバージョンアップをすることができません。
COSではPython3.6がインストールされていますが、こちらは古いため、新しめのサービスは動作しないことが多いです。

制約2:Xinferenceの仕様

基本的にはPythonで実行されます。
Dockerコンテナで利用する方法もありますが、そのためにはVMにGPUが必要です。当環境ではGPUを利用することが出来ないため、Dockerコンテナで稼働させない手順を採用しました。

解決策

制約1,2を踏まえて、Python3.11 slimイメージをベースにしてdockerコンテナを作成し、その中でXinferenceを起動することとしました。

手順

前置きが長くなりましたが、ここからは実際にXinferenceをインストールおよび起動するための手順です。

Xinference作業用ディレクトリを作成し、そこに移動する

mkdir /mnt/stateful_partition/Xinference
cd /mnt/stateful_partition/Xinference

Xinference起動とLLM起動用のシェルスクリプトを作成する

vi start.sh

このシェルスクリプトはこの後作成するコンテナの起動のタイミングで同時に実行したい処理を記述します。
もしxinferenceで実行させたいLLMがある場合は、このスクリプトに処理を追加してください。今回の例では、bge-reranker-v2-m3を導入しています。

#!/bin/bash

# 改行コードをLFに変換 (Windowsでの環境構築対応)
sed -i 's/\r$//' "$0"

# xinference-local を起動し、PID を保存
/usr/local/bin/xinference-local --host 0.0.0.0 --port 9997 &
local_pid="$!"

# xinference-local が起動するまで待機
while ! curl -s --fail http://0.0.0.0:9997/v1/cluster/auth > /dev/null; do
  echo "Waiting for xinference-local to start..."
  sleep 1
done

# モデルを起動
if ! /usr/local/bin/xinference launch --model-name bge-reranker-v2-m3 --model-type rerank; then
  echo "Error launching model."
  kill "$local_pid" # xinference-local を停止
  exit 1
fi

# xinference-local の終了を待機 (必要に応じて)
wait "$local_pid"

echo "xinference finished."

Dockerfileを作成する

vi Dockerfile

Dockerfileの内容

後続作業のdocker image build実行時に使用するDockerfileを以下のように作成します。

FROM python:3.11-slim

# インストールに必要なパッケージを指定
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
    build-essential \
    libffi-dev \
    libssl-dev \
    zlib1g-dev \
    libncurses5-dev \
    libgdbm-dev \
    libnss3-dev \
    libpam-dev \
    python3-dev \
    python3-pip \
    git \
    curl \
    libglib2.0-dev \
    libx11-dev \
    pkg-config \
    && \
    rm -rf /var/lib/apt/lists/*

# OpenCVとNumPyを明示的にインストール
RUN apt-get update && apt-get install -y python3-opencv python3-numpy

# xinferenceをインストール
RUN pip install --no-cache-dir xinference[all]

# xinferenceが使用する環境変数を設定
ENV XINFERENCE_HOME=/models

# モデルやログを格納するフォルダをコンテナ内に作成。このフォルダはコンテナバインドにより永続化させる。
RUN mkdir -p /models

COPY start.sh /start.sh
RUN chmod +x /start.sh

# CMD に start.sh を指定
ENTRYPOINT ["bash", "/start.sh"]

2023.12.14時点の修正内容

2024.11.23時点のDockerfileに対して以下の修正を行うことで、モデルをダウンロード出来ない問題が解決しました。Xinferenceのバージョンアップに伴い、今後も類似の見直しが発生する可能性があります。

  1. libglib2.0-dev のインストール:libgthread-2.0.so.0が不足しているというエラーが出たのでそれを解決するため、libglib2.0-dev をインストールする必要があります。また、OpenCVに必要な、他のライブラリも追加します。

  2. OpenCVのインストール: xinference[all] のインストールによって間接的に OpenCV がインストールされていると思われますが、この方法では依存関係が正しく解決されない場合があります。そのため、OpenCV を明示的にインストールすることにしました。特に、python3-opencv パッケージを使用すると、システムレベルで必要なライブラリが適切にインストールされます。

  3. numpy の明示的なインストール: numpy も cv2 と同様に、xinference[all] に含まれている可能性がありますが、明示的にインストールすることで、バージョンの制御や依存関係の解決がより確実になります。

  4. --no-cache-dir オプションの追加: pip install 時に --no-cache-dir オプションを追加することで、キャッシュの影響を排除し、常に最新のパッケージを取得するようにします。これは、依存関係の競合を避けるために重要です。

Dockerfileで定義した処理の解説(Xinference関連部分のみ)

'# xinferenceをインストール
RUN pip install --no-cache-dir xinference[all]

この定義ではXinferenceで使用可能な全ての推論エンジンをインストールしていますが、自分が利用したい推論エンジンだけをインストールすることも可能です。

`# xinferenceが使用する環境変数を設定
ENV XINFERENCE_HOME=/models

この定義ではDockerコンテナ内の/modelsというディレクトリにダウンロードしたモデルや出力ログを格納するように定義していますが、ここはご自身の設計方針に合わせて変更してください

Xinferenceのインストールや環境変数に関する詳細はこちらの公式解説も参照してください。
https://inference.readthedocs.io/en/stable/getting_started/installation.html
https://inference.readthedocs.io/en/stable/getting_started/environments.html#xinference-home

Dockerfileを元にdockerイメージをビルドする

docker image build --tag xinference:V1 .

参考
docker image hisotry <イメージ名>コマンドにより、dockerイメージで何が追加されたかを確認できます。

dockerイメージが想定どおり作成されたことを確認する

docker image ls xinference:V1

ビルドしたdockerイメージを元にコンテナを起動する

--restart=alwaysオプションをつけているので、VM起動時にコンテナも一緒に起動する挙動となります。
したがってこのコマンドは最初の1回実行するだけでよくなります。
--neworkオプションの引数はDifyが動作するコンテナと同じdockerネットワークグループを指定しています。これによりDifyとXinferenceがネットワークグループ内で通信できるようになります。

--volumeオプションでは、ローカル環境とdockerコンテナ内のボリュームをバインドしています。今回はdockerコンテナ内では/modelsというディレクトリを指定しています。ここは任意のディレクトリで構いませんが、Dockerfileで指定しているENV XINFERENCE_HOME=/modelsとは合わせる必要があります。

docker container run -d --restart=always --name xinference-container --volume /mnt/stateful_partition/Xinference/models:/models --network docker_default xinference:V1

コンテナが起動されたことを確認する

docker container ls
CONTAINER ID   IMAGE                              COMMAND                   CREATED             STATUS
     PORTS                                      NAMES
7cfd8a7a1ad0   xinference:V1                      "bash /start.sh"          About an hour ago   Up About an hour                                                        xinference-container
5ca947c43b73   nginx:latest                       "sh -c 'cp /docker-e…"   8 hours ago         Up About an hour
    0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp   docker-nginx-1
3e3c9edc14fb   langgenius/dify-api:0.13.2         "/bin/bash /entrypoi…"   8 hours ago         Up About an hour
    5001/tcp                                   docker-worker-1
e97f7c97598b   langgenius/dify-api:0.13.2         "/bin/bash /entrypoi…"   8 hours ago         Up About an hour
    5001/tcp                                   docker-api-1
27c408975fd1   ubuntu/squid:latest                "sh -c 'cp /docker-e…"   8 hours ago         Up About an hour
    3128/tcp                                   docker-ssrf_proxy-1
1887355de241   postgres:15-alpine                 "docker-entrypoint.s…"   8 hours ago         Up About an hour (healthy)   5432/tcp                                   docker-db-1
74e2cd78a2cd   semitechnologies/weaviate:1.19.0   "/bin/weaviate --hos…"   8 hours ago         Up About an hour
                                               docker-weaviate-1
139f7ae1d0db   redis:6-alpine                     "docker-entrypoint.s…"   8 hours ago         Up About an hour (healthy)   6379/tcp                                   docker-redis-1
96a82191d8d5   langgenius/dify-web:0.13.2         "/bin/sh ./entrypoin…"   8 hours ago         Up About an hour
    3000/tcp                                   docker-web-1
8d8d97aa29b8   langgenius/dify-sandbox:0.2.10     "/main"                   8 hours ago         Up About an hour (healthy)                                              docker-sandbox-1

XinferenceコンテナがDifyコンテナ群と同じdockerネットワークグループに入っていることを確認する

このように、xinferenceコンテナとDifyコンテナ群が同じdockerネットワークグループに入ってることを確認します。この状態により、それぞれがネットワークグループ内でコンテナ名を使って通信できるようになります。

docker network inspect docker_default

[
    {
        "Name": "docker_default",
        "Id": "<マスク済み>",
        "Created": "2024-12-13T18:04:51.604115873Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "<マスク済み>",
                    "Gateway": "<マスク済み>"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "139f7ae1d0db4fd220ab66aedf3979e193c46434730a8bb74f3001def7fd8a4d": {
                "Name": "docker-redis-1",
                "EndpointID": "de822fb33861482f9a634b6b558f58e70fff7ff46e49e59027e6f8fae66b05d4",
                "MacAddress": "02:42:ac:12:00:06",
                "IPv4Address": "<マスク済み>",
                "IPv6Address": ""
            },
            "7cfd8a7a1ad091bb9d0b42f45bb2425a20db029f7be649b1e6a48205cae23e28": {
                "Name": "xinference-container",
                "EndpointID": "3b52a1cd0cb3aa923b3d4ba9c1a6d2b83ed56f908cc169b1d85acbf293299ab8",
                "MacAddress": "02:42:ac:12:00:0a",
                "IPv4Address": "<マスク済み>",
                "IPv6Address": ""
            },
~~~他のDifyコンテナ群の記述は割愛~~~

        },
        "Options": {},
        "Labels": {
            "com.docker.compose.network": "default",
            "com.docker.compose.project": "docker",
            "com.docker.compose.version": "2.29.1"
        }
    }
]

xinferenceの動作確認

xinferenceの動作確認やインストールおよび稼働しているLLMを調べるときには、xinference-containerの中に入ってください。

コンテナの中に入ってXinferenceで起動中のモデルを確認する

docker exec -it xinference-container /bin/bash
xinference list

UID                 Type    Name
------------------  ------  ------------------
bge-reranker-v2-m3  rerank  bge-reranker-v2-m3

ログの確認

ホスト側からdockerコンテナのログを参照する場合

docker container logs xinference-container

dockerコンテナの中に入ってログを参照する場合

docker exec -it xinference-container /bin/bash
cd /models/logs
*このディレクトリ以降のディレクトリにxinferenceのログが出力されます

後続作業

これでXinference環境の作成と起動は終了です。この後は、Dify側でモデルプロバイダーとしてXinferenceを指定する作業を経るとDifyでXinferenceを利用できるようになります。

https://zenn.dev/delisit/articles/fb9384fab09aa4

Discussion