Dify ( Docker Desktop ) + LM Studio ( Local LLM ELYZA-JP ) で ゲームブックのチャットを動かそうとしたメモ

# 概要

[Difyでゲームもどき作ってみました](https://koyoy.com/difygame/) が面白そうだった。「GPT-4 Omni Mini」の契約も面倒だなぁ。 せっかくゲーミングPC買ったのでローカルで動かしてみよう、と試したメモ。 結論からいうとGPT-4o mini には勝てなさそう。

# 環境

- プロセッサ: 13th Gen Intel(R) Core(TM) i7-13700K   3.40 GHz
- 実装RAM: 64.0 GB
- NVIDIA GeForce RTX 4070 Ti
- Windows 11 Home 23H2 22631.4391
- docker-desktop v4.34.2 
- LM-Studio 0.3.5
- Dify Version 0.10.2 (Docker)

# LM-Studioの準備
## インストール
[LM Studio](https://lmstudio.ai/)からインストーラをダウンロード。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/e60f1957-fc4e-e4d9-b09d-1355ab31455c.png)

ダウンロードした`LM-Studio-0.3.5-Setup.exe`を起動し、手順に沿ってインストールする。

## ローカルLLM ELYZA-JP のモデル設定

左の検索から、`elyza/Llama-3-ELYZA-JP-8B-GGUF`を選択。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/f565d68e-df53-230f-6cfa-88b12930085a.png)

モデルのダウンロードを行う。 4Gあるのでしばし時間がかかる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/11e85064-b44f-c568-c13d-ec71a22393b6.png)

## APIサーバの起動

スタートを押す

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/49772955-3273-11ef-ea73-87886104aa7d.png)

下記のようになったら稼動している。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/f9a7fbea-4043-b3f0-d579-2ba4da97daf3.png)

# Dify
## インストール
[github](https://github.com/langgenius/dify/blob/main/README_JA.md)からリポジトリをclone。手順に従って`.env`の設定を行い、`docker compose up`で起動する。

## モデルプロバイダの登録
設定からモデルプロバイダの設定を選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/ed7fdcb6-6f96-3a98-4715-5a7b3751935e.png)

OpenAI-API-compatibleを選択。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/b3b0df01-121e-a58b-2df4-7350db4a33f3.png)

- 必要欄を埋めて保存
  - Model Nameに任意の名前（今回は`lm-studio`とした)
  - API endpoint URL に `http://host.docker.internal:1234/v1` 

※Difyをdockerで動かしているので、localhostをdockerから見たIP(`host.docker.interval`)に読み替える必要がある。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/1b2d878f-6bcd-4fce-8ea8-bd021741b477.png)

## DSLの読み込み
[Difyでゲームもどき作ってみました](https://koyoy.com/difygame/) で配布しているDSLをインポートする。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/6990b4f2-18f1-4294-bc7a-623188b43207.png)

インポートしたものの編集を行う。

設定した`lm-studio`をモデルに使用する。表示されなかればログアウトしてからログインしなおすと表示される。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/5fde6a0b-fd9a-c0be-38e8-59ef17a902e8.png)

# 実行

プレビューを行ってみる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/da011e19-264f-d332-f86f-7fe58b25d3b4.png)

チャットの開始に「スタート」といったら英語になってしまった。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/f7afc0cc-54d0-af90-1777-8859a0b68817.png)


質問を変えたら日本語になったが、話がいっこうに進まない。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/bfeb14de-1b73-68d0-ba77-e41cbbabffef.png)

# ChatGPTと比較

ChatGPTはちゃんとゲームブック進めてくれる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/8b616f10-ecb9-6ea0-1fcb-c9ddf8c45af2.png)

# エラー
遭遇したエラーをのこしておく。

```
### An error occurred during credentials validation: HTTPConnectionPool(host='localhost', port=1234): Max retries exceeded with url: /v1/chat/completions (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f244275f6a0>: Failed to establish a new connection: [Errno 111] Connection refused'))
```

これは、下記のようにURLを `localhost`としているのが問題。 ( Dify は docker上で動いているので、localhostは自身を指してしまう）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/66644ef9-921a-72f6-d20a-ed9db5421f76.png)


# 参考

[Difyでゲームもどき作ってみました](https://koyoy.com/difygame/) 

[DifyでローカルLLMを使ってみよう！](https://note.com/jolly_dahlia842/n/n41bf7cf085fd)

[「GPT-4」を上回る日本語性能のLLM「Llama-3-ELYZA-JP」を開発しました](https://note.com/elyza/n/n360b6084fdbd)
[【初心者向け】最近のローカル日本語LLM【ローカル万歳】](https://note.com/catap_art3d/n/n0a0f4262d80c)
[Dockerコンテナ内からホストのlocalhostにアクセスする](https://zenn.dev/gladevise/articles/access-localhost-from-docker-container)