🐙

【学習ログ】ローカルでGPT OSSを動かす準備 #3 Phi4-miniの実行環境構築とカスタムプロンプト対応

に公開

はじめに

前回の記事(#2 ローカルマシンの容量チェックとDocker環境の準備)では、LLM実行に必要なローカル環境の準備を行った。

今回は、実際にMicrosoftのPhi4-miniモデルを使った実行環境を一から構築し、カスタムプロンプトで対話できるようにするまでの実装を記録する。

具体的には、Docker ComposeとOllamaを使ってローカル環境でLLMを実行し、コマンドラインから任意のプロンプトを送信できるシステムを構築した。

Ollamaとは

Ollamaは、ローカル環境でLLMを簡単に実行できるオープンソースツールである。

以下のような特徴がある:

  • 簡単なモデル管理: ollama pull model-nameでモデルをダウンロード
  • API提供: REST APIとOpenAI互換APIを提供
  • 軽量実行: 量子化による軽量化でローカル実行を最適化
  • 豊富なモデル対応: Llama、Mistral、Phi、Gemmaなど主要なOSSモデルをサポート

インストール方法

macOS/Linux

# 公式インストールスクリプト
curl -fsSL https://ollama.com/install.sh | sh

Windows

公式サイトからインストーラーをダウンロードして実行

なぜOllamaを選んだのか

  • 環境分離: Dockerコンテナ内で実行することでホストマシンへの影響を最小化
  • API互換性: OpenAI APIと互換性があるため、既存のクライアントライブラリが使用可能
  • モデル管理: コマンド一つでモデルのダウンロードと管理が可能
  • 開発効率: 複雑な依存関係の解決が不要

今回は、環境の分離と再現性を重視してDockerベースでOllamaを実行する構成を採用した。

全体アーキテクチャ

構築したシステムは以下のような構成になっている:

┌─────────────────┐    ┌─────────────────┐
│   start.sh      │────│   main.py       │
│  (起動スクリプト)  │    │  (Python実行部)   │
└─────────────────┘    └─────────────────┘
           │                      │
           └──────────┬───────────┘
                      │
        ┌─────────────▼─────────────┐
        │      Docker Compose      │
        │  ┌─────────┐ ┌─────────┐  │
        │  │ Ollama  │ │   App   │  │
        │  │Container│ │Container│  │
        │  └─────────┘ └─────────┘  │
        └───────────────────────────┘

各コンポーネントの役割

  • start.sh: ユーザーからのプロンプトを受け取り、Docker環境を起動する
  • main.py: Ollamaサーバーと通信してLLMに推論リクエストを送信する
  • Ollama Container: LLMモデル(Phi4-mini)をホスティングするサーバー
  • App Container: main.pyが実行されるPython環境

なぜPhi4-miniを選んだのか

モデル選択の基準

  • サイズ: 約2.5GB(ローカル環境で扱いやすいサイズ)参考
  • メモリ要件: 4GB程度のメモリで実行可能
  • 性能: Phi2より改善された推論能力が期待される

軽量モデルでの学習メリット

  • 高速な実験サイクル
  • リソース消費量の抑制
  • 開発環境での気軽な試行

実装の詳細

1. Dockerによる環境構築

まず、LLMを実行するためのDocker環境をdocker-compose.ymlで定義した:

version: '3.8'

services:
  ollama:
    image: ollama/ollama:latest
    container_name: ollama
    ports:
      - "11434:11434"
    volumes:
      - ollama_data:/root/.ollama
    environment:
      - OLLAMA_HOST=0.0.0.0
    deploy:
      resources:
        limits:
          memory: 4G  # Phi4-mini用にメモリを増量
        reservations:
          memory: 1G
    restart: unless-stopped

  app:
    build: .
    container_name: gpt-oss-app
    depends_on:
      - ollama
    environment:
      - PYTHONUNBUFFERED=1

2. Python実行環境の準備

requirements.txtでPython依存関係を管理:

openai>=1.0.0
requests>=2.25.0

DockerfileでPython環境をコンテナ化:

FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY main.py .
CMD ["python", "main.py"]

3. LLM実行部分の実装(main.py)

Ollamaサーバーとの通信とLLMへのリクエスト送信を行うメインプログラム:

import sys
import time
import requests
from openai import OpenAI

def wait_for_ollama():
    """Ollamaサーバーが準備できるまで待機"""
    max_retries = 30
    retry_interval = 2
    
    for i in range(max_retries):
        try:
            response = requests.get("http://ollama:11434/api/tags", timeout=5)
            if response.status_code == 200:
                print("Ollamaサーバーが準備できました")
                return True
        except requests.exceptions.RequestException:
            pass
        
        print(f"Ollamaサーバーの準備を待機中... ({i+1}/{max_retries})")
        time.sleep(retry_interval)
    
    return False

def main():
    # コマンドライン引数からプロンプトを取得
    if len(sys.argv) > 1:
        user_prompt = " ".join(sys.argv[1:])
    else:
        user_prompt = "こんにちは!簡単な挨拶をしてください。"
    
    # Ollamaサーバーの準備を待機
    if not wait_for_ollama():
        print("Ollamaサーバーに接続できませんでした")
        return
    
    # OpenAIクライアントでOllamaサーバーに接続
    client = OpenAI(
        base_url="http://ollama:11434/v1",
        api_key="ollama",  # ダミーキー
    )
    
    # LLMに推論リクエスト
    try:
        response = client.chat.completions.create(
            model="phi4-mini",
            messages=[{"role": "user", "content": user_prompt}],
            max_tokens=100,
            temperature=0.7,
        )
        print("レスポンス:")
        print(response.choices[0].message.content)
    except Exception as e:
        print(f"エラー: {e}")

※ ダミーキーはそのままでOK。

4. 起動スクリプトの作成(start.sh)

ユーザーインターフェースとして、コマンドライン引数を受け取って環境を起動するスクリプト:

#!/bin/bash

# 引数の処理
if [ $# -gt 0 ]; then
    USER_PROMPT="$*"
    echo "カスタムプロンプト: $USER_PROMPT"
else
    echo "デフォルトプロンプトを使用"
fi

# Docker環境の起動
docker compose up --build -d

echo "Ollamaサーバーの起動を待機中..."
sleep 10

# Phi4-miniモデルのダウンロード確認
if docker exec ollama ollama list | grep -q "phi4-mini"; then
    echo "Phi4-miniモデルは既にダウンロード済み"
else
    echo "Phi4-miniモデルをダウンロード中... (約2.5GB)"
    docker exec ollama ollama pull phi4-mini
fi

# アプリケーション実行
if [ -n "$USER_PROMPT" ]; then
    docker compose run --rm app python main.py "$USER_PROMPT"
else
    docker compose run --rm app python main.py
fi

echo "使用方法: ./start.sh \"あなたの質問やリクエスト\""

使用方法

実行例

# カスタムプロンプトで実行
./start.sh "Pythonでソートアルゴリズムを説明して"

# デフォルトプロンプト(挨拶)で実行
./start.sh

実行の流れ

  1. Docker Composeでコンテナ群を起動
  2. Ollamaサーバーの準備完了を待機
  3. Phi4-miniモデルの存在確認・ダウンロード
  4. 指定されたプロンプトでLLMに推論リクエスト
  5. 結果を表示して終了

まとめ

Phi4-miniを使ったローカルLLM実行環境を構築し、コマンドラインからカスタムプロンプトを送信できるシステムを実装した。

Docker ComposeとOllamaを組み合わせることで、複雑な依存関係を隠蔽しつつ、実用的な実行環境を構築できた。

しかし、実際にPhi4-miniを動かしてみた結果、期待していたほどのアウトプット品質は得られなかった。 レスポンスの精度や有用性が想定を下回ったため、今後はより性能の高いモデル(例:Llama系、Qwen系など)への切り替えを検討する必要がある。

このような品質評価も含めて、ローカル環境でLLMを実際に動かすことの価値が確認できた。

ソース

https://github.com/atsushimemet/gpt-oss-learning

Discussion