ローカルLLMを試してみる
書籍ローカルLLM実践入門を参考に試してみる
LLMのモデルファイルの取得
Hugging Faceからダウンロードできる
LLMを選ぶときのポイント
- gguf形式であること
- パラメータ数
- 量子化のビット数
多くの場合、モデルのファイル名に情報が含まれている
LLMプラットフォームのソフトウェア
Jan
Ollama
llama.ccp
LM Studio
AI Toolkit for VS Code
などなど
Janとは
Janは、100%オフラインで動作するオープンソースのChatGPT代替ツールです。
とのこと。
Janを使ってみる
私はM4 MacbookAirなのでMac版をダウンロード・インストールする。
起動したら下記のような画面で表示される。
左上のアイコンで、上から2番目のアイコン(Hub)をクリックすると、LLMをダウンロードする画面が表示される。
Hugging FaceのURLでの検索もできそう。
Googleが提供しているGemma2をダウンロードしてみる。
警告アイコンが表示されているバージョンはSlow on your device
と表示される。私のMacではスペック不足みたい。Defaultにしておく。
ダウンロードが完了したら、左上のアイコンで一番上のアイコン(Thread)をクリックする。
ダウンロードしたモデルが選ばれていることを確認してチャットにテキストを打ち込んで送信してみる。
右上の一番左のアイコン(Thread Settings)でAssistantやModelの設定ができるみたい。
JanをLLMサーバとして動かしてみる
左下のアイコンで、一番上のアイコン(Local API Server)をクリックすると下記の画面が表示される
ここからサーバを起動できる様子
Start Serverボタンをクリックするとサーバが起動する
Stop Serverボタンの下にAPI Playgroundというボタンがある
クリックするとブラウザが立ち上がりAPIドキュメントが表示される
OpenAIと互換性があるとのことで、OpenAI用のライブラリを使って利用できるとのこと。
Ollamaとは
Janと同じくローカルLLMを動かすためのソフトウェア
コマンドラインツール
Ollamaを使ってみる
公式サイトからダウンロードする
ダウンロード後、Ollamaアプリを起動する
ターミナルでバージョンコマンドを実行する
% ollama --version
ollama version is 0.6.6
Llama3.2をダウンロード(ollama pull)してみる
ollama pull llama3.2
pulling manifest
pulling dde5aa3fc5ff: 100% ▕████████████████████▏ 2.0 GB
pulling 966de95ca8a6: 100% ▕████████████████████▏ 1.4 KB
pulling fcc5a6bec9da: 100% ▕████████████████████▏ 7.7 KB
pulling a70ff7e570d9: 100% ▕████████████████████▏ 6.0 KB
pulling 56bb8bd477a5: 100% ▕████████████████████▏ 96 B
pulling 34bb5ab01051: 100% ▕████████████████████▏ 561 B
verifying sha256 digest
writing manifest
success
Llama3.2を起動(ollama run)してみるとメッセージ入力受付状態になる
メッセージを送ってみる
% ollama run llama3.2
>>> こんにちは
こんにちは!どういたしまして?どんな事がしたいのですか?
>>> Send a message (/? for help)
終了するには/bye
を打ち込む or Ctrl + Dコマンドを押す
Ollamaのサーバ機能を使ってみる
Janと同様、OllamaもLLMサーバとして使うことができる
% ollama serve
crulでコマンドを実行してみる
% curl http://localhost:11434/api/generate -d '{"model": "llama3.2", "prompt": "こんにちは"}'
{"model":"llama3.2","created_at":"2025-05-09T15:55:27.49096Z","response":"こんにちは","done":false}
{"model":"llama3.2","created_at":"2025-05-09T15:55:27.515362Z","response":"!","done":false}
{"model":"llama3.2","created_at":"2025-05-09T15:55:27.539749Z","response":"どう","done":false}
{"model":"llama3.2","created_at":"2025-05-09T15:55:27.563165Z","response":"で","done":false}
{"model":"llama3.2","created_at":"2025-05-09T15:55:27.588002Z","response":"した","done":false}
{"model":"llama3.2","created_at":"2025-05-09T15:55:27.612145Z","response":"か","done":false}
{"model":"llama3.2","created_at":"2025-05-09T15:55:27.635641Z","response":"?","done":false}
{"model":"llama3.2","created_at":"2025-05-09T15:55:27.659355Z","response":"何か","done":false}
{"model":"llama3.2","created_at":"2025-05-09T15:55:27.683375Z","response":"相","done":false}
{"model":"llama3.2","created_at":"2025-05-09T15:55:27.707329Z","response":"談","done":false}
{"model":"llama3.2","created_at":"2025-05-09T15:55:27.731449Z","response":"した","done":false}
{"model":"llama3.2","created_at":"2025-05-09T15:55:27.755231Z","response":"い","done":false}
{"model":"llama3.2","created_at":"2025-05-09T15:55:27.779348Z","response":"場合は","done":false}
{"model":"llama3.2","created_at":"2025-05-09T15:55:27.803348Z","response":"お","done":false}
{"model":"llama3.2","created_at":"2025-05-09T15:55:27.827296Z","response":"気","done":false}
{"model":"llama3.2","created_at":"2025-05-09T15:55:27.851341Z","response":"軽","done":false}
{"model":"llama3.2","created_at":"2025-05-09T15:55:27.875593Z","response":"に","done":false}
{"model":"llama3.2","created_at":"2025-05-09T15:55:27.899742Z","response":"話","done":false}
{"model":"llama3.2","created_at":"2025-05-09T15:55:27.923863Z","response":"して","done":false}
{"model":"llama3.2","created_at":"2025-05-09T15:55:27.947794Z","response":"ください","done":false}
{"model":"llama3.2","created_at":"2025-05-09T15:55:27.972483Z","response":"。","done":false}
{"model":"llama3.2","created_at":"2025-05-09T15:55:27.99576Z","response":"","done":true,"done_reason":"stop","context":[128006,9125,128007,271,38766,1303,33025,2696,25,6790,220,2366,18,271,128009,128006,882,128007,271,90115,128009,128006,78191,128007,271,90115,6447,104405,16556,56051,32149,11571,127091,50021,111813,56051,16995,126513,33334,95221,117355,20230,87177,39926,72315,1811],"total_duration":1302024708,"load_duration":680394833,"prompt_eval_count":26,"prompt_eval_duration":112055458,"eval_count":22,"eval_duration":508423375}
上記はストリームで回答が出力されるもの
"stream": false
を指定すると、ストリーム出力をオフにできる
% curl http://localhost:11434/api/generate -d '{"model": "llama3.2", "prompt": "こんにちは", "stream": false}'
{"model":"llama3.2","created_at":"2025-05-10T05:18:47.301139Z","response":"こんにちは!どういたしまして? (Oh, hi! How are you?) I'm here to help with any questions or topics you'd like to discuss. What's on your mind today?","done":true,"done_reason":"stop","context":[128006,9125,128007,271,38766,1303,33025,2696,25,6790,220,2366,18,271,128009,128006,882,128007,271,90115,128009,128006,78191,128007,271,90115,6447,104405,102334,103801,39926,11571,320,12174,11,15960,0,2650,527,499,10380,358,2846,1618,311,1520,449,904,4860,477,13650,499,4265,1093,311,4358,13,3639,596,389,701,4059,3432,30],"total_duration":1133144000,"load_duration":32521583,"prompt_eval_count":26,"prompt_eval_duration":37772208,"eval_count":40,"eval_duration":1062114709}
Web UIライブラリを使ってみる
Chainlit:Pythonのオープンソースライブラリ
下記ライブラリをインストールする
% pip install openai
% pip install chainlit
今回はollamaでLLMサーバを動かし、モデルにはphi4
を使ってみる
from openai import AsyncOpenAI
import chainlit as cl
client = AsyncOpenAI(
base_url="http://localhost:11434/v1",
api_key="dummy"
)
@cl.on_chat_start
def start_chat():
cl.user_session.set(
"history",
[
{
"role": "system",
"content": "あなたは親切なアシスタントです。"
}
]
)
@cl.on_message
async def main(input):
message = cl.Message(content="")
await message.send()
history = cl.user_session.get("history")
history.append({"role": "user", "content": input.content})
stream = await client.chat.completions.create(
model="phi4",
messages=history,
stream=True
)
async for part in stream:
token = part.choices[0].delta.content
if token != "":
await message.stream_token(token)
history.append(
{
"role": "assistant",
"content": message.content
}
)
await message.update()
chainlit run コマンドで上記を記載したpythonファイルを指定して実行する
Web UIが自動で立ち上がる
% chainlit run chainlit_realtime.py
2025-05-10 14:46:45 - Your app is available at http://localhost:8000
2025-05-10 14:46:47 - Translated markdown file for ja not found. Defaulting to chainlit.md.
メッセージを送ってみると、回答がストリームで出力される
エンター押すとすぐにメッセージが送信されてしまうみたい。。