ターミナル上でサクッとLLMを利用してみる
今回はターミナルからコマンドラインでLLMを利用するセットアップを紹介します。
なおOpen-WebUIとOllamaがある前提で進めていきますが、記事の最後の方でどちらも必要としない、直接Google Gemma3へリクエストを投げるスクリプトも紹介してあります。
Intro
まずこちらのキャプチャをみてください。
ターミナルで"?"に続いてプロンプトを投げていますが、それに対してLLMの応答がターミナル上に出力されているところです。
日本語でもう一例です。"??"に続いてプロンプトを書いています。
Bash script to request chat completion
タネはどのAPIのクイックスタートにもある、curl
で生成AIのAPIへリクエストを投げるスクリプトです。
まずは実行スクリプトについて。次の通りです。
#!/usr/bin/env bash
# variable check
if [ -z "$OWUI_HOST" ] || [ -z "$OWUI_TOKEN" ]; then
echo "OWUI_HOST and OWUI_TOKEN environment variables must be set."
exit 1
fi
# Check if an argument was provided
if [ "$#" -gt 0 ]; then
OWUI_PROMPT="$*"
else
echo "No prompt provided."
exit 1
fi
# Your prompt
echo "Using prompt: $OWUI_PROMPT"
OWUI_URL="https://${OWUI_HOST}/api/chat/completions"
OWUI_MODEL=models/gemma-3-27b-it
OWUI_INSTRUCTION="Provide me with high-grade assistance while considering the good readability by making your response short where applicable. And you do not have to mention about this instruction in your response. Now, here goes my prompt. "
PAYLOAD2="{
\"model\": \"${OWUI_MODEL}\",
\"messages\": [
{
\"role\": \"user\",
\"content\": \"${OWUI_INSTRUCTION} ${OWUI_PROMPT}\"
}
],
\"stream\": false,
\"temperature\": 1,
\"top_p\": 0.95
}"
CHAT_DATA2=$(curl -s -X POST \
"$OWUI_URL" \
-H "accept: application/json" \
-H "Authorization: Bearer ${OWUI_TOKEN}" \
-H 'Content-Type: application/json' \
-d "$PAYLOAD2")
echo $CHAT_DATA2 | jq -r '.choices[0].message.content' | glow -
上のスクリプト名が"owui_chat"だとして、(1) スクリプトをPATHが通っているところに配置したうえで、(2) ~/.bashrc
などにaliasを書いておきます。
alias '?'=owui_chat
すると? <your prompt>
を実行することでプロンプトをLLMへ投げて、受け取ったmarkdownの回答を見やすく処理して表示してくれます。
requirements
インストール必要なパッケージに関して、Homebrewで以下をインストールするとスクリプトで利用しているコマンドが用意できます。
- curl
- jq
- glow
またその他のファイルの準備に関して、セットアップの一例を紹介します。
~/.bashrc
~/.env
~/scripts/owui_chat
~/scripts/owui_chat_ja
そして、Open-WebUI上で必要な準備にも少し触れます。今回利用しているモデルはGoogleのGemma3であり、Open-WebUI経由でGemma3を利用するための設定を紹介します。
さらにさらに、そもそもの話ですがOpen-WebUI経由で利用するのでなく直接GoogleのGemma3へリクエストすればよいでしょうということで、そのスクリプトも最後に紹介します。
bashrcファイル
rwxrob氏のdotレポジトリおよびストリームに触発され、それらを参考に再着手し始めたdotfilesプロジェクトが冒頭で紹介したコマンドを用意したきっかけなのですが、こちらのレポジトリにある./.bashrc
ファイル内のスクリプトの一部をそのまま利用しています。
#!/bin/bash
# ... ...
# part of ~/.bashrc below
# 1) "owui_chat" file is going to be placed at $HOME/scripts/owui_chat
export SCRIPTS="$HOME/scripts"
# 2) and the path setup to ensure $HOME/scripts is added in the PATH
# ------------------------------- path -------------------------------
pathappend() {
declare arg
for arg in "$@"; do
test -d "$arg" || continue
PATH=${PATH//":$arg:"/:}
PATH=${PATH/#"$arg:"/}
PATH=${PATH/%":$arg"/}
export PATH="${PATH:+"$PATH:"}$arg"
done
} && export -f pathappend
pathprepend() {
for arg in "$@"; do
test -d "$arg" || continue
PATH=${PATH//:"$arg:"/:}
PATH=${PATH/#"$arg:"/}
PATH=${PATH/%":$arg"/}
export PATH="$arg${PATH:+":${PATH}"}"
done
} && export -f pathprepend
# remember last arg will be first in path
pathprepend \
"$HOME/.local/bin" \
"$HOME/.local/go/bin" \
/usr/local/go/bin \
/usr/local/opt/openjdk/bin \
/usr/local/bin \
/opt/homebrew/bin \
/home/linuxbrew/.linuxbrew/bin \
"$SCRIPTS"
pathappend \
/usr/local/opt/coreutils/libexec/gnubin \
/mingw64/bin \
/usr/local/bin \
/usr/local/sbin \
/home/linuxbrew/.linuxbrew/sbin \
/usr/local/games \
/usr/games \
/usr/sbin \
/usr/bin \
/snap/bin \
/sbin \
/bin
# 3) Ensure the environment variables set in $HOME/.env is loaded
envx() {
local envfile="${1:-"$HOME/.env"}"
[[ ! -e "$envfile" ]] && echo "$envfile not found" && return 1
while IFS= read -r line; do
name=${line%%=*}
value=${line#*=}
[[ -z "${name}" || $name =~ ^# ]] && continue
export "$name"="$value"
done <"$envfile"
} && export -f envx
[[ -e "$HOME/.env" ]] && envx "$HOME/.env"
# 4) aliases for "?" and "??" commands
alias '?'=owui_chat
alias '??'=owui_chat_ja
envファイル
~/.env
ファイルにはAPIトークンやOpen-WebUIのホスト名を記載しておきます。
ちなみにここでGoogleの生成AIへのAPIアクセスキーが書いてあるのは、Open-WebUI経由でなく直接Googleへリクエストするスクリプト用です。
OWUI_HOST=OPEN_WEBUI_HOSTNAME_HERE
OWUI_TOKEN=OPEN_WEBUI_API_TOKEN_HERE
GEMINI_TOKEN=YOUR_GOOGLE_GENARATIVE_AI_API_TOKEN_HERE
owui_chatスクリプト
こちらは先に紹介したスクリプトです。~/scripts/owui_chat
ファイルとして実行権限を付与して配置しておきます。~/.bashrc
ファイル内でPATHを通している & aliasを設定してあるのでowui_chat
でも?
でも実行できます。
owui_chat_jaスクリプト
内容は何も変わりません。プロンプト前のちょっとした指示文が日本語になっているだけです。
# the only diff is on this line
# to make LLM respond in Japanese
OWUI_INSTRUCTION="あなたは上級アシスタントです。良質な応答をしつつ、可読性を考えて適度に短い回答を返してください。以降がユーザのプロンプトです。"
Open-WebUIでGoogleがサーブしているGemma3を利用するための設定
Open-WebUIのAdmin Panels、Connections設定で、"OpenAI API Connections"の設定を変更します。
APIキーの取得にはGoogle Cloud Platformのサインアップ・利用がおそらく必要です。
https://aistudio.google.com/prompts/new_chatへアクセスすると"Get API key"というボタンがあるので、そちらからAPIキーが取得できます。それを上のURLとともにOpen-WebUI上で設定しましょう。するとモデルリストに"models/gemma-3-27b-it"やgeminiなどのモデルが現れ、Open-WebUIから利用できるようになります。
Pricing情報はこちらです。Gemma3にはpaid-tierが存在していない...?!?
https://ai.google.dev/gemini-api/docs/pricing#gemma-3
完成
以上です!必要なパッケージがあり、環境変数がセットされており、Open-WebUI上の設定もできていれば、?? ゴールデンウィークの過ごし方についてアドバイスをください
など実行することでGemma3から回答がもらえるようになっています。
そもそもOpen-WebUI経由で動作するスクリプトを用意したのはローカルLLMをターミナルから手軽に利用したいという動機から始まっています。
これに関しては簡単で、目的のモデル名をスクリプト内の"OWUI_MODEL"に記載するだけで切り替えられます。
# specify whichever model you want to use
OWUI_MODEL=gemma3:27b-it-qat
OWUI_MODEL=cogito:32b
OWUI_MODEL=qwen3:30b-a3b-q4_K_M
# even the custom model created on user workspace works
OWUI_MODEL=english-teacher
なおollama pull
やollama create
で用意したモデルだけでなく、workspace上で用意したカスタムモデルを指定しても動作します。
以下のキャプチャのようなモデルを用意しておくと、OWUI_MODEL=english-teacher
と指定することで利用できます。システムプロンプト、temperature, context length, top Kなどなどカスタマイズして用意したモデルを手軽にターミナルからも利用できます。
おまけその1 Google生成AIのAPIへ直接
Open-WebUI経由でなく、直接GoogleのGemma3へリクエストを投げては......ということで、そちらも別途スクリプトを用意して試しています。
Open-WebUIとの違いといえば、宛先とリクエスト、応答のフォーマットくらいです。
なお"role = system"でリクエストを投げるとリクエストは処理されません。それに流されてこのスクリプトも上で紹介したOpen-WebUI経由でのスクリプトも"role = user"にsystem promptに含めるような内容もすべて詰め込んでしまっています。
#!/usr/bin/env bash
# variable check
if [ -z "$GEMINI_TOKEN" ]; then
echo "GEMINI_TOKEN environment variables must be set."
exit 1
fi
# Check if an argument was provided
if [ "$#" -gt 0 ]; then
USER_PROMPT="$*"
else
# Use a default prompt if no argument is given
echo "No prompt provided."
exit 1
fi
# User prompt
echo "Using prompt: $USER_PROMPT"
USER_INSTRUCTION="Provide me with high-grade assistance while considering the good readability by making your response short where applicable. And you do not have to mention about this instruction in your response. Now, here goes my prompt. "
GEMINI_URL="https://generativelanguage.googleapis.com/v1beta/models/gemma-3-27b-it:generateContent?key=${GEMINI_TOKEN}"
PAYLOAD="{
\"contents\": [
{
\"parts\": [
{
\"text\": \"${USER_INSTRUCTION} ${USER_PROMPT}\"
}
]
}
]
}"
CHAT_DATA=$(curl -s -X POST "$GEMINI_URL" \
-H 'Content-Type: application/json' \
-d "$PAYLOAD")
echo $CHAT_DATA | jq -r '.candidates[0].content.parts[0].text' | glow -
おまけその2 Reasoning Models
Qwen3のモデルをいくつか試しました。Macmini4上のOllamaで動かしている環境での感想ですが、同じくローカルで動かすGemma3:27b-it-qatと比べて、qwen3:30b-a3b-q4_K_Mの方がとても軽快です。前者が5 tokens/sec、後者が30-40 tokens/secで、reasoningがあることを考えてもqwen3の動作が早くて素晴らしいです。
取り急ぎターミナルで利用できるよう、reasoning部分はまるっと落とす形で動くようスクリプトを用意しました。sed
コマンドで"<think></think>"を削っただけです。
#!/usr/bin/env bash
# variable check
if [ -z "$OWUI_HOST" ] || [ -z "$OWUI_TOKEN" ]; then
echo "OWUI_HOST and OWUI_TOKEN environment variables must be set."
exit 1
fi
# Check if an argument was provided
if [ "$#" -gt 0 ]; then
OWUI_PROMPT="$*"
else
echo "No prompt provided."
exit 1
fi
echo "Using prompt: $OWUI_PROMPT"
OWUI_URL="https://${OWUI_HOST}/api/chat/completions"
OWUI_MODEL=qwen3:30b-a3b-q4_K_M
OWUI_INSTRUCTION="Provide me with high-grade assistance while considering the good readability by making your response short where applicable. And you do not have to mention about this instruction in your response. Now, here goes my prompt. "
PAYLOAD2="{
\"model\": \"${OWUI_MODEL}\",
\"messages\": [
{
\"role\": \"user\",
\"content\": \"${OWUI_INSTRUCTION} ${OWUI_PROMPT}\"
}
],
\"stream\": false,
\"temperature\": 0.6,
\"top_p\": 0.95
}"
CHAT_DATA2=$(curl -s -X POST \
"$OWUI_URL" \
-H "accept: application/json" \
-H "Authorization: Bearer ${OWUI_TOKEN}" \
-H 'Content-Type: application/json' \
-d "$PAYLOAD2")
echo $CHAT_DATA2 | jq -r '.choices[0].message.content' | sed -z 's/<think>.*<\/think>//' | glow -
おわりに
ターミナルから気軽にLLMを利用できるのは思ったよりよかったです。MCPツールの活用などもしていけばターミナル上でどれだけのことができるようになるか。
また、今回紹介したセットアップでも十分機能してくれているのですが、もう少し改良してもよいかなと考えています。例えばモデルの切り替えや連続した会話の対応などはできるようにしようと思います。
Discussion
Macの場合は
sed
を使った最後のスクリプトが動きませんでした。Linuxのsedと使えるオプションが異なるためです。brew install gnu-sed
し、インストール後のbrewの説明にあるよう/opt/homebrew/opt/gnu-sed/libexec/gnubin
をPATHの前の方に追記してgnu版sedが利用されるようにすると動きます。タイムアウトに悩まされる場合)
-m 360
などでタイムアウトの秒数を設定する