Llama-3-ELYZA-JP-8Bを使ってStreamlitでサクッとLLMアプリ開発

# はじめに
こんにちは、新卒社員やってます！@sat01m0です！

突然ですが、みなさん！LLMアプリ開発やっていますか？
私自身これまであまり触れてきてなかったんですけど、
今ローカル環境にモデルをダウンロードして気軽にLLMを動かせるようになっているらしいんですよね！すごすぎ！
ということで、今更ですがLLMアプリの開発をサクッとやってみようと思います！

今回は大規模言語モデル!Llama-3-ELYZA-JP-8Bを使って、ローカル環境でサクッとアプリを作成してみたので共有します！楽しんでください！

https://prtimes.jp/main/html/rd/p/000000046.000047565.html

:::note warn
サクッと動かして遊べる環境を作ってもらいたいので詳しい説明は割愛します🙇‍♂️
:::

# 準備
ディレクトリ構造は以下のようになっています！
```:ディレクトリ構造
- app.py                　　　　　　　　　　　　　　　　　　　　　　　// アプリケーションのコードを記載するファイル 
- docker-compose.yaml   　　　　　　　　　　　　　　　　　　　　　　// (Docker使わない場合不要)
- Dockerfile　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　// (Docker使わない場合不要)
- Llama-3-ELYZA-JP-8B-q4_k_m.gguf 　// インストールしてきたLlamaモデル
- requirements.txt      　　　　　　　　　　　　　　　　　　　　　// インストールするパッケージを記載しているファイル
```
Dockerを使う場合とそうじゃない場合どちらも説明します！
Dockerを用いない場合、**Python3.8.1以上のバージョン**が使える状態にしておいてください！

## Step0：環境構築
今回の開発で用いるPythonのライブラリはrequirements.txtにまとめて記載します！
ライブラリのインストールの際に使うので、こちらのファイルを作成します！
```text:requirements.txt
streamlit
langchain
langchain-community
llama-cpp-python
```
### Dockerを用いる場合
Dockerfile,docker-compose.yamlを以下のように記載しています！
```dockerfile:Dockerfile
FROM python:3.11

WORKDIR /usr/src/app
COPY app.py /usr/src/app
COPY requirements.txt /usr/src/app

RUN apt-get update
RUN pip install --upgrade pip
RUN python -m pip install -r requirements.txt
```

```docker:docker-compose.yaml
version: '3.9'
services:
  app:
    build: .
    volumes:
      - .:/usr/src/app
    ports:
      - '8080:8080'
    command: sh -c "streamlit run app.py --server.port 8080"
```


### Dockerを用いない場合
今回**Python3.11**を使って実装をしています！検証していませんが、LangChainが3.8.1以上のバージョンで使えるので、それ以上であれば大丈夫だと思います！
今回のアプリで使用するライブラリをインストールします！
requairements.txtのあるディレクトリに移動して以下のコマンドを実行します！
```terminal:ターミナル
pip install -r requirements.txt
```

## Step1:Llama-3-ELYZA-JP-8Bモデルをインストール
次に今回用いるモデルのダウンロードをします！
こちらからダウンロードします！

https://huggingface.co/elyza/Llama-3-ELYZA-JP-8B-GGUF/tree/main

ファイルサイズ大きいので少し時間かかります！
![スクリーンショット 2024-07-01 19.37.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817347/2839b150-2b54-3904-c3fd-7a391126118c.png)

ダウンロードが終わったら、先ほどのディレクトリ構造を参考に各ファイルと同じ階層にモデルを移動させています！

## Step2:アプリケーションのソースコードの準備
今回はLangChainのLlamaCppとStreamlitを用いて簡単にアプリを作ってみます！

https://python.langchain.com/v0.2/docs/integrations/llms/llamacpp/

https://streamlit.io/

今回軽く遊べるコードを用意してみました！app.pyに以下を記載します！
```python:app.py
# 各ライブラリのインポート
import streamlit as st
from langchain_community.llms import LlamaCpp

# モデルの準備、プロンプト編集する部分
def use_model(text):
    # 使用するモデルの名前
    MODEL_NAME = "Llama-3-ELYZA-JP-8B-q4_k_m.gguf"
    # モデルの準備
    llm = LlamaCpp(
        model_path=MODEL_NAME,
    )
    # プロンプト編集部分
    prompt = "あなたは誠実で優秀な日本人のアシスタントです。特に指示が無い場合は、常に日本語で回答してください。{}。".format(text)
    # モデルの実行
    return llm.invoke(prompt)
# UI(チャットのやり取りの部分)
def main():
    # タイトル
    st.title("LLMアプリ")
    # 入力フォームと送信ボタンのUI
    st.chat_message("assistant").markdown("何か聞きたいことはありませんか？")
    text = st.chat_input("ここにメッセージを入力してください")

    # チャットのUI
    if text:        
        st.chat_message("user").markdown(text)
        st.chat_message("assistant").markdown(use_model(text))

if __name__ == "__main__":
    main()
```

## Step3：レッツ実行！
準備お疲れさまでした！実際に動かしてみましょう！以下のコマンドを実行します！
### Dockerを用いる場合
```terminal:ターミナル
docker compose up
```
### Dockerを用いない場合
```terminal:ターミナル
streamlit run app.py --server.port 8080
```

localhost:8080にアクセスしてこのようなページが見られたら成功です！![スクリーンショット 2024-07-01 21.01.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817347/0c484dfd-f3f7-da53-f62d-e477dabf630d.png)

やったー！早速何か入力してみましょう！

#### "焼き肉の美味しい焼き方を教えて"
<img  width="550" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817347/16db0ad0-7db4-ddf6-7332-df5a4179af91.png">

#### "創造力をつけるために大事なことを教えて"

<img width="550" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817347/d01ddbc9-555e-d8bd-347d-dea397c0c951.png">

雑談が下手すぎますね。。。
自分のプロンプトや出力方法では、途中で区切れちゃったり、"|Answer"がついちゃってたりしてますが、とりあえず動きそうです！

## プロンプトについて
今回のアプリでは、huggingfaceのドキュメントにならって、"あなたは誠実で優秀な日本人のアシスタントです。特に指示が無い場合は、常に日本語で回答してください。"の後に、ユーザが入力したテキストをくっつけるようにしています。
```python: app.py(プロンプトの部分)
prompt = "あなたは誠実で優秀な日本人のアシスタントです。特に指示が無い場合は、常に日本語で回答してください。{}。".format(text)
```

https://huggingface.co/elyza/Llama-3-ELYZA-JP-8B-GGUF

app.pyのpromptの部分を編集すると求めた回答に近づけるように工夫ができると思います！


試しにPythonについて教えてくれるように修正してみました！
promptの部分を以下のように変更してみて聞いてみました。
```python:app.py(プロンプトの部分)
prompt = "あなたは新人開発者にPythonのコードの書き方を教えることができる誠実で優秀な日本人のアシスタントです。特に指示が無い場合は、常に日本語で回答してください。{}。".format(text)
```
#### プロンプト変更前

<img width="550" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817347/2167f432-560c-3056-2dc2-a8bebe192c4e.png">


#### プロンプト変更後
<img width="550" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817347/26e0b552-99b0-f4f2-2188-a44525fa7ce6.png">


プロンプトを変更することでheadやgroupbyなど具体的に返してくれるかどうかが変わってきそうです！
手元で色々動かしてみて好みの回答が得られるように遊んでみてください！

# おわりに
大規模言語モデル!Llama-3-ELYZA-JP-8Bを使って、ローカル環境でサクッとアプリを作成してみました！
プロンプトの実験とかやったことなかったものに手軽に触れられてよかったです！
今回はチャットが続かない仕様であったり、プロンプトもあまり工夫していなかったりとやり込めていない部分が多々あるので、続きはみなさんの環境で実験してみてください!LLMに触れるきっかけになれば幸いです！
最後まで読んでいただきありがとうございました(^^)ﾉｼ