見出し画像

OpenAI互換ローカルLLMサーバとGUIで最も簡単な評価環境を作成


昨年来、LLMモデルが次々と発表されています。最近のLLMは性能も高くすぐに試したいわけですが、cliはなんだか面倒。ならば、できるだけシンプルなGUIで試すということで、gradioで書きました。

必要なモジュール

gradioだけです。

pip install gradio

llama.cppの構築

OpenAI互換サーバで動かします。

cudaがインストールされていれば以下のどちらかです。

make GGML_CUDA=1

または

cmake -B build -DGGML_CUDA=ON
cmake --build build --config Release

サーバを起動

./llama-server -m models/gemma-2-9b-it-Q4_K_M.gguf --n-gpu-layers 43 --port 8080

事前にHuggingFaceからモデルをダウンロードしてmodelsホルダーに移動させておきます。

最もポピュラーなgemma-2-9b-it-Q4_K_M.ggufです。他のモデルも同様に動かすことができるはずです。

UGIのコード

openai_gradio.pyで保存

import gradio as gr
import openai
from   openai import AsyncOpenAI
import asyncio

# OpenAI APIの設定
client = AsyncOpenAI(
    base_url="http://127.0.0.1:8080/v1",
    api_key="YOUR_OPENAI_API_KEY",  # このままでOK
    )

# OpenAI APIから応答を取得する非同期ジェネレーター関数
async def chat_with_openai(role, user_message, conversation_logs, max_logs=5):
    try:
        # 会話履歴にroleとユーザーメッセージを追加
        messages = [{"role": "system", "content": role}] + conversation_logs + [{"role": "user", "content": user_message}]
        # デバッグ用のメッセージ出力
        print(f"Sending to API: {messages}")
        # ストリーミングリクエストを実行
        stream = await client.chat.completions.create(
            model="gpt-4",
            messages=messages,
            stream=True,
        )
        response_sum = ""
        # ストリーミングで応答を処理
        async for chunk in stream:
            response_chunk = chunk.choices[0].delta.content or ""
            response_sum += response_chunk
            print(response_sum)
            yield response_chunk  # 部分的な応答をストリーミング
        # 全体の応答を保存
        conversation_logs.append({"role": "assistant", "content": response_sum})
        # 会話ログが最大数を超えた場合、古いログを削除
        if len(conversation_logs) > max_logs:
            conversation_logs = conversation_logs[-max_logs:]
    except Exception as e:
        yield f"Error: {str(e)}"

# ユーザーのメッセージを送信し、応答を処理する関数
async def submit_message(role, message, logs):
    role = role or "You are a helpful assistant."  # デフォルトのrole設定
    response_chunks = ""
    # OpenAI APIとストリーミングでやり取り
    async for response_chunk in chat_with_openai(role, message, logs):
        response_chunks += response_chunk
        yield response_chunks, logs  # 応答を順次表示

# Gradio UIの定義
def create_ui():
    with gr.Blocks() as demo:
        with gr.Row():
            role_input = gr.Textbox(label="LLMへのRole", value="You are a helpful assistant.")
            conversation_logs = gr.State(value=[])
            response_output = gr.Textbox(label="応答", interactive=False)
        with gr.Row():
            message_input = gr.Textbox(label="メッセージを入力")
        # エンターキーでメッセージを送信できるようにする
        message_input.submit(
            fn=submit_message,
            inputs=[role_input, message_input, conversation_logs],
            outputs=[response_output, conversation_logs],
            cv1oncurrency_limit=2  # 並行処理の制限
           )
    return demo

# サーバーを起動
if __name__ == "__main__":
    demo = create_ui()
    demo.launch(server_name="127.0.0.1", server_port=8009)

ストリーミングの処理に少々手間がかかりますが、シンプルです。

動かしてみる

python openai_gradio.py

ブラウザでアクセス

ブラウザーからhttp://127.0.0.1:8009をアクセスします。
以下のようにGUIが立ち上がります。

LLMへのRoleはsystemプロンプトで、LLMにどの様に振る舞ってほしいにか記述します。エディタで作成してコピペするのが簡単です。

メッセージを入力のところがユーザの入力です。何でも質問できます。

試しす

LLMへのRoleに「あなたは賢いAIです。userの質問に答えなさい」と入力します。

「お好み焼きの作り方を教えて」と入力して試します。以下のような回答が応答に表示されました。

〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
お好み焼き、いいですね!

材料(2人分)

  • 薄力粉:150g

  • 水:120ml

  • 卵:1個

  • 豚肉 (薄切り):100g

  • 玉ねぎ:1/2個

お好み焼きソース、マヨネーズ、青のり、鰹節、紅しょうが(お好みで)

作り方

  1. ボウルに薄力粉と水を入れて混ぜ、滑らかになったら卵を割り入れてさらに混ぜる。

    • 焦げ付かないように、弱火でじっくりと焼くのがポイントです。

  2. フライパンに油をひいて中火で熱し、生地を流し込む。
    *
    お好み焼きの大きさは好みで調整してください。

  3. 生地の表面に豚肉と玉ねぎを乗せる。

  4. 両面をこんがりと焼き、お好み焼きソース、マヨネーズ、青のり、鰹節、紅しょうがをトッピングして完成!

ポイント

  • 生地はあまり固すぎない方が良いでしょう。

  • 焼き始めは弱火でじっくりと焼き、表面が固まってきたら中火で焼きましょう。

  • 肉や野菜はお好みでアレンジできます。

  • ソースやマヨネーズの量は、自分の好みに合わせて調整してください。

ぜひ、美味しいお好み焼きを召し上がってください!
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜

いいですね。

英訳をする

では英語に翻訳しましょう。LLMへのRoleに「userの入力した日本語を英語に翻訳しなさい」と入力します。 先程、生成された文章をメッセージを入力にコピペします。そしてエンター。

出力された英訳

Okay, here is the Japanese text translated into English:

Okonomiyaki sounds delicious!

Ingredients (for 2 people)

  • All-purpose flour: 150g

  • Water: 120ml

  • Eggs: 1

  • Thinly sliced pork: 100g

  • Onion: 1/2

  • Okonomiyaki sauce, mayonnaise, green laver (aonori), bonito flakes (katsuobushi), pickled ginger (benishoga) (to taste)

Instructions

  1. Mix the all-purpose flour and water in a bowl. Once smooth, crack the egg in and mix well.

    • The key is to cook it over low heat to prevent burning.

  2. Heat oil in a frying pan over medium heat, then pour in the batter.

    • Adjust the size of the okonomiyaki to your liking.

  3. Place the pork and onion on top of the batter.

  4. Cook both sides until golden brown, then top with okonomiyaki sauce, mayonnaise, green laver, bonito flakes, and pickled ginger. It's complete!

Tips

  • The batter shouldn't be too thick.

  • Cook over low heat at the beginning to ensure it cooks through, then increase the heat to medium once the surface is set.

  • Feel free to customize with your favorite meats and vegetables.

  • Adjust the amount of sauce and mayonnaise to your taste.

Enjoy your delicious okonomiyaki!

なかなかの出来。

まとめ

簡単にLLMが評価できる環境が出来上がりました。ぜひ試してください。