「料金が二重に引き落とされた」「ログインできない」「営業時間を知りたい」。問い合わせを受け付けるアプリなら、まず内容を分けて、担当する処理へ渡したいところです。
この分類を、自分のパソコンで動くAIに任せられるのが JEFF です。文章と選択肢の説明を渡すと、その中から分類結果を返します。今回は「料金」「技術的な問題」「その他」の3つに問い合わせを分けるところまで、順に進めます。
Pythonのコードをファイルに保存して実行するため、プログラミングを始めたばかりの人も対象にしています。MacとWindowsの両方のコマンドを載せました。自分のOSに合う部分を使ってください。
JEVとの違いは?
JEVはTypeSafe AIが提供する商用の判定サービス、JEFFはそのAPI形式に対応した別のOSSです。
| 比較 | JEV(Jev) | JEFF |
|---|---|---|
| 提供者 | TypeSafe AI | Logan Markewich氏 |
| 実行場所 | 提供元のAPIへ接続 | 自分のPC・サーバー |
| 準備 | APIキーを取得 | Python環境とモデルをインストール |
| 費用 | API利用料 | 外部推論APIの料金は不要。PC・電力・運用費は必要 |
| 精度 | 公開比較では複雑な推論で優位 | 単純な分類の候補。複雑な推論では精度が下がる |
| 保守 | 提供元が担当 | 自分で起動・更新・管理 |
両方とも、Yes/No、選択肢による分類、段階評価に使えます。JEFFはJEV用の公式SDKを利用できますが、内部モデルや判定結果まで同じではありません。
選ぶ目安は、準備の手軽さと判定精度を重視するならJEV、ローカル実行と自分での管理を重視するならJEFFです。
JEFFは何をするもの?
JEFFは、Logan Markewich氏が公開しているオープンソースの判定用サーバーです。内部では約4億パラメータのGLiFormerというAIモデルを使います。「モデル」は、文章から特徴を読み取って判定するための学習済みデータと処理の仕組み、と考えると分かりやすいです。
例えば、次のように使います。
| 渡すもの | 内容 |
|---|---|
| 判定したい文章 | 今月の料金が二重に引き落とされました。 |
| 質問 | この問い合わせはどの分類に当てはまりますか? |
| 選択肢 | 料金/技術的な問題/その他 |
| アプリが受け取るもの | 選ばれた分類のキー。例えば billing
|
JEFFは返信文を作るチャットアプリではありません。分類結果を受け取ったPythonプログラムが、「料金の担当へ回す」といった処理を行います。返信文も必要なら、その後で文章を生成するAIを呼ぶ構成にできます。
使える判定は次の3種類です。
| 名前 | できること | 例 |
|---|---|---|
Noul |
Yes/Noを判定する | 料金に関する問い合わせか? |
Choice |
用意した選択肢から選ぶ | 料金/技術的な問題/その他 |
Score |
順序のある基準で評価する | 緊急度を低/中/高の基準で評価する |
今回は、結果と処理の対応が分かりやすい Choice から始めます。
JEFFはTypeSafeの商用サービス「Jev」のAPI形式に対応しており、公式のPython SDKを使って呼び出せます。APIはプログラム同士の呼び出し窓口、SDKはその呼び出しを書くための道具です。同じ呼び出し形式でも、JEFFとJevの判定精度や確率の意味は同一ではありません。
どんなときにメリットがある?
分類する方法はJEFFだけではありません。比較する方法によって、利点も変わります。
キーワード判定と比べる:言い換えを分類したいとき
Pythonで次のように書く方法は、準備が少なく、動作も軽いです。
if "返金" in text:
category = "billing"
ただ、この条件だけでは「返金」という単語のない「解約したのにお金が引き落とされた」を拾えません。逆に「返金画面でログインエラーが出る」は、技術的な問題として扱いたいかもしれません。
JEFFは、文章と選択肢の説明をモデルで処理します。そのため、キーワードの有無だけでは分けにくい言い換えや文脈を扱う候補になります。実際にうまく分かれるかは、使う文章で確認する必要があります。
番号や固定のコードで分類できる場合は、通常の条件分岐のほうが扱いやすいです。JEFFを導入するメリットは、自然な文章の意味で分けたい場合にあります。
生成AIに分類文を書かせる方法と比べる:結果をコードで使いたいとき
生成AIに「分類名だけ答えて」と頼む方法では、回答の文字列を読み取る処理が必要になります。例えば「料金」と「料金関連の問い合わせです」を同じ分類として扱うための工夫です。
JEFFでは、あらかじめ billing、tech_support、other といったキーを決め、その結果をSDKのプロパティから取り出せます。後に続く if 文を書きやすいのが利点です。
なお、生成AI側にもJSON Schemaなどで出力形式を指定できるサービスがあります。「生成AIは必ず形式が崩れる」とは言えません。JEFFの特徴は、分類に必要な結果を返す仕組みを、ローカルに用意できることです。通信失敗や入力エラーへの対応は別途必要です。
外部の有料APIと比べる:分類を繰り返したいとき
外部APIで1件ごとに分類すると、そのサービスの料金体系に応じて費用がかかります。JEFFを自分のPCで動かす場合は、判定のたびに外部の推論APIへ料金を払う必要がありません。
また、クライアントとサーバーを同じPCで動かせば、判定する文章を外部の推論APIへ送る構成を避けられます。ただし、インストールやモデルのダウンロードにはインターネット接続が必要です。
PCのメモリ、電力、準備や保守の手間はかかります。数件だけ試すなら外部APIのほうが手軽な場合もあり、クラウドでJEFFを動かすならサーバー代も比較に含めます。
速度は「生成しない仕組み」と「実際の測定」を分けて考える
JEFFは返答の文章を順に生成する処理を行わないため、短い分類の待ち時間を減らす候補になります。ただし、入力の長さ、質問数、GPUの有無で速度は変わります。複数の質問をまとめて送っても、設定によってはモデルを複数回通します。
作者のベンチマークには、ローカルMPSでstandard tierの中央値が108msという測定があります。一方、同資料では長い入力やCPU実行で遅くなる例も報告されています。中央値は測定値を小さい順に並べた中央の値で、平均値ではありません。
この数字は、自分のPCや日本語の問い合わせでも100msになるという保証には使えません。導入するときは、現在使っている方法と、同じ入力・同じ件数で比較します。
今回用意するもの
サーバーを起動した窓と、問い合わせを送る窓の2つを使います。ここでいうサーバーは、自分のPCで待機して、Pythonからの質問に答えるプログラムです。別のPCを買う必要はありません。
| 用意するもの | 役割 |
|---|---|
| MacまたはWindows PC | JEFFとサンプルを動かす |
| インターネット接続 | ソフトウェアとモデルのダウンロードに使う |
| Git | JEFFのプログラム一式を取得する |
| uv | Pythonと必要なライブラリを用意する |
| テキストエディター | Pythonコードを保存する |
Apple SiliconのMacでは、MPSという仕組みでGPUを使えます。Windowsでは、まずCPUで起動する手順にします。NVIDIA GPUの設定はこの記事の範囲に含めません。
モデル以外にも関連ソフトウェアをダウンロードするため、ストレージは数GB以上の余裕を用意してください。これは公式の最低容量・最低メモリを示すものではありません。モデル読み込みでメモリ不足になる場合は、他のアプリを閉じるなどの調整が必要です。
1. コマンドを入力する窓を開く
Macでは、Spotlightで「ターミナル」を検索して開きます。
Windowsでは、スタートメニューから「PowerShell」を開きます。以下のWindows用コマンドはPowerShell向けです。コマンドプロンプトやGit Bashとは書き方が異なるので、混ぜないようにしてください。
コード枠のコマンドを入力してEnterを押します。複数行の手順は、上から順番に実行してください。
2. Gitとuvを用意する
Mac
まずGitが使えるか確認します。
git --version
バージョンが表示されれば、そのまま進めます。開発者ツールのインストールを求められた場合は、画面に従ってインストールしてください。必要なら次のコマンドでCommand Line Toolsのインストールを開始できます。
xcode-select --install
続いて、uv公式のインストーラーを実行します。公式サイトから取得したスクリプトを実行するコマンドです。
curl -LsSf https://astral.sh/uv/install.sh | sh
完了したらターミナルを閉じて開き直し、確認します。
uv --version
Homebrewをすでに使っている場合は、インストーラーの代わりに brew install uv でも導入できます。
Windows
Gitが使えるか確認します。
git --version
見つからない場合は、Git for Windowsからインストーラーを取得してインストールします。完了後はPowerShellを開き直してください。
uvは、Windowsのパッケージ管理コマンドWinGetを使ってインストールできます。
winget install --id=astral-sh.uv -e
WinGetが使えない場合は、uv公式のWindows向けインストーラーを使います。
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
こちらは公式サイトから取得したスクリプトを実行します。組織のPCでインストールを制限されている場合は、管理者の案内に従ってください。
PowerShellを開き直して、確認します。
uv --version
3. JEFFのプログラムを取得する
保存先をホームフォルダーにそろえます。
Mac:
cd ~
git clone https://github.com/logan-markewich/jeff.git
cd jeff
Windows:
Set-Location $HOME
git clone https://github.com/logan-markewich/jeff.git
Set-Location jeff
git clone がプログラム一式を取得する操作です。その後の cd または Set-Location で、作業場所を jeff フォルダーへ移します。
以降のコマンドは、このフォルダーの中で実行します。すでに同名のフォルダーがある場合は、今回の取得先を変えるか、既存のJEFFフォルダーを使ってください。
4. Pythonの仮想環境を作り、ライブラリをインストールする
仮想環境は、このプロジェクト専用のPythonとライブラリを使うための環境です。他のPythonプロジェクトとライブラリのバージョンを分けられます。別のOSや仮想マシンを起動するものではありません。
今回は、JEFFフォルダー内の .venv に仮想環境を作ります。uvはPythonの用意と仮想環境の作成、ライブラリのインストールに使います。その後は、仮想環境を有効にした窓で python や jeff を直接実行します。
Python 3.12と仮想環境を用意する
Mac・Windows共通です。JEFFフォルダーで実行します。
uv python install 3.12
uv venv --python 3.12 .venv
確認時点のJEFFは、Python 3.12系を指定しています。1行目でPythonを用意し、2行目でそれを使う仮想環境を作ります。
前の手順ですでに uv sync を実行していた場合も、通常は .venv が作成されています。その場合は作り直さず、次の有効化へ進んでください。仮想環境の作成は初回だけです。
仮想環境を有効にする
Mac(標準のzsh、またはbash):
source .venv/bin/activate
Windows(PowerShell):
.\.venv\Scripts\Activate.ps1
Windowsで「スクリプトの実行が無効」と表示される場合は、自分で管理するPCなら、現在のPowerShellの窓だけに適用する設定で再度試せます。
Set-ExecutionPolicy -Scope Process -ExecutionPolicy RemoteSigned
.\.venv\Scripts\Activate.ps1
組織のPCでは管理者の方針に従ってください。組織のポリシーで制限されている場合、この設定では変更できないことがあります。
有効化すると、入力行の先頭に環境名が表示されることがあります。見た目だけでなく、次のコマンドでも確認します。Mac・Windows共通です。
python -c "import sys; print(sys.executable); print('仮想環境:', sys.prefix != sys.base_prefix)"
Pythonのパスに jeff/.venv/ または jeff\.venv\ が含まれ、仮想環境: True と表示されれば、この環境のPythonを使っています。
有効にした仮想環境へライブラリを入れる
uv sync --active --extra dev
--active は、有効にした仮想環境へインストールする指定です。JEFF本体と必要なライブラリを、プロジェクトの依存関係に従ってそろえます。現行プロジェクトでは、標準で入る開発用の依存グループにTypeSafe SDKも含まれています。
確認します。
python --version
python -c "from typesafe_sdk import TypeSafeClient; print('SDK OK')"
Python 3.12系のバージョンと SDK OK が表示されれば、次へ進めます。以降も、この窓では仮想環境を有効にしたまま作業してください。
5. 判定に使うモデルをダウンロードする
Mac・Windows共通です。
hf download knowledgator/gliformer-large-v1 --local-dir models/gliformer-large-v1
Hugging Faceというモデル配布サイトから、学習済みモデルを取得します。保存先はJEFFフォルダー内の models/gliformer-large-v1 です。
初回はダウンロードに時間がかかります。エラーなくコマンドが終わってから、次に進んでください。この保存先はJEFFの標準設定と合わせています。
6. JEFFサーバーを起動する
Mac
JEFF_HOST=127.0.0.1 JEFF_API_KEYS=devkey jeff
JEFFは、利用可能な実行環境をCUDA、MPS、CPUの順に選びます。Apple SiliconのMacでは通常MPSが選ばれます。
Windows
最初はGPU設定を増やさず、CPUで起動します。
$env:JEFF_HOST = "127.0.0.1"
$env:JEFF_API_KEYS = "devkey"
$env:JEFF_DEVICE = "cpu"
jeff
GPUを使う設定は後から追加できます。CPUでの速度は、この後の手順で実際に確認してください。
起動コマンドの意味
| 設定 | 意味 |
|---|---|
JEFF_HOST=127.0.0.1 |
同じPCからだけ接続する待ち受け先にする |
JEFF_API_KEYS=devkey |
呼び出す側が提示する確認用の鍵を設定する |
jeff |
有効にした仮想環境のJEFFを実行する |
devkey は今回の練習用です。TypeSafeのアカウントから発行するキーではなく、JEFF側で自分が設定する値です。
モデル読み込みの後に、サーバーの待ち受け開始を示す表示が出るまで待ちます。ターミナルが入力待ちに戻らないのは、サーバーが動いているためです。この窓は開いたままにします。
7. 起動したか確認する
別のターミナルまたはPowerShellを開きます。
Mac:
curl http://127.0.0.1:8000/healthz
Windows:
Invoke-RestMethod -Uri "http://127.0.0.1:8000/healthz"
/healthz は起動状態を確認する窓口です。接続エラーにならず応答が返ることを確認します。その後、実際に分類できるかを試します。
127.0.0.1 は「このPC自身」を指すアドレスで、8000 は接続先を区別するポート番号です。
8. Pythonで問い合わせを分類する
2つ目の窓でも、JEFFフォルダーへ移動し、同じ仮想環境を有効にします。有効化は窓ごとに必要です。 サーバー用とクライアント用で別々の仮想環境を作る必要はありません。
Mac:
cd ~/jeff
source .venv/bin/activate
open .
Windows:
Set-Location "$HOME\jeff"
.\.venv\Scripts\Activate.ps1
explorer .
フォルダーが開いたら、テキストエディターで新しいファイルを作り、以下の内容を example.py という名前で保存します。文字コードはUTF-8にしてください。
Windowsのメモ帳なら、保存時に「ファイルの種類」を「すべてのファイル」にして、example.py.txt にならないようにします。Macのテキストエディットなら、先に「フォーマット」から「標準テキストにする」を選びます。
from time import perf_counter
from typesafe_sdk import Choice, TypeSafeClient
# 自分のPCで起動したJEFFへ接続する
client = TypeSafeClient(
api_key="devkey",
base_url="http://127.0.0.1:8000",
)
text = "今月の料金が二重に引き落とされました。確認をお願いします。"
started = perf_counter()
result = client.system_one(
text,
{
"category": Choice(
instructions="問い合わせの主な内容を分類してください。",
criteria={
"billing": "料金、請求、支払い、返金に関する問い合わせ",
"tech_support": "ログインできない、エラー、不具合に関する問い合わせ",
"other": "上記以外の問い合わせ",
},
),
},
)
elapsed_ms = (perf_counter() - started) * 1000
category = result.choices["category"].choice
print("入力:", text)
print("分類:", category)
print(f"呼び出し時間: {elapsed_ms:.1f} ms")
# JEFFの判定を受けて、通常のPythonコードで処理を分ける
if category == "billing":
print("料金担当へ回します。")
elif category == "tech_support":
print("技術サポートへ回します。")
else:
print("総合窓口で確認します。")
保存できたら、2つ目の窓で実行します。Mac・Windows共通です。
python example.py
料金の問い合わせとして分類された場合、次のような内容が表示されます。
手元のMacbook M2 Proでは、初回は3秒ほどかかっていますが、そのあとは安定しています。
入力: 今月の料金が二重に引き落とされました。確認をお願いします。
分類: billing
呼び出し時間: 3373.1 ms
料金担当へ回します
(.venv) jeff % python example.py
入力: 今月の料金が二重に引き落とされました。確認をお願いします。
分類: billing
呼び出し時間: 195.4 ms
料金担当へ回します。
(.venv) jeff % python example.py
入力: 今月の料金が二重に引き落とされました。確認をお願いします。
分類: billing
呼び出し時間: 187.3 ms
料金担当へ回します
このサンプルは、振り分け先を画面に表示するだけです。メールを送信したり、担当者へ通知したりする機能はまだありません。
コードでは何をしている?
TypeSafeClient に渡した base_url が、問い合わせを送る先です。今回は自分のPCのJEFFを指定しています。
system_one() の最初の引数が判定する文章、2つ目が質問の定義です。"category" は質問に付けた名前で、結果を取り出すときにも使います。
criteria の左側にある billing などが、プログラムで扱う分類のキーです。右側の日本語は、その分類が何を意味するかをモデルへ伝える説明です。
result.choices["category"].choice で選ばれたキーを取り出し、通常の if 文へ渡します。AIに任せるのは文章の分類で、その後の処理はPythonで決めています。
表示した時間はSDK呼び出し全体の経過時間です。モデルの計算時間だけを測っているわけではなく、初回と2回目以降でも変わる可能性があります。
9. 入力を変えて、得意・不得意を確認する
text = ... の文章を書き換えて保存し、同じコマンドで実行できます。
いきなり実際の問い合わせを自動処理する前に、次のような文章で試してください。右側はテストするときに人が決める分類例であり、JEFFの実測結果ではありません。
| 試す文章 | 人が想定する分類例 | 確認すること |
|---|---|---|
| ログインするとエラーが出ます。 | tech_support |
はっきりした不具合を拾えるか |
| お店は何時まで開いていますか? | other |
料金・不具合以外を分けられるか |
| 解約したのに、またお金が引かれました。 | billing |
「請求」という単語なしでも分類できるか |
| 返金ページを開くとエラーになります。 | tech_support |
料金の単語につられないか |
| 料金も気になるし、ログインもできません。 | 運用ルールで決める | 複数の問題を1分類にする基準があるか |
最後のような文章は、人でも担当を迷う場合があります。複数の問題があるときにどちらを優先するか、先に決めておく必要があります。
少数の成功例だけで、日本語全体の精度は判断できません。実際の用途に近い文章、言い換え、曖昧な例を用意し、人が付けた分類と比べます。間違いを修正するために使った文章とは別の文章でも確認すると、特定の例に合わせすぎていないか見やすくなります。
公式ベンチマークにも複雑な推論で精度が下がる結果があります。日本語の業務データで使える精度かどうかは、別に検証する必要があります。
10. Yes/Noの判定も試す
分類が動いたら、example.py の内容を次のコードに置き換えると Noul を試せます。
from typesafe_sdk import Noul, TypeSafeClient
client = TypeSafeClient(
api_key="devkey",
base_url="http://127.0.0.1:8000",
)
result = client.system_one(
"今月の料金が二重に引き落とされました。",
{
"is_billing": Noul(
instructions="料金、請求、支払い、返金に関する問い合わせですか?"
),
},
)
answer = result.nouls["is_billing"]
print("料金に関する問い合わせか:", answer.noul)
print("返された確率値:", answer.probability)
実行方法は同じです。
python example.py
True はYes、False はNoです。確率値も返りますが、その値を「この割合で必ず正解する」と解釈しないでください。しきい値を使って処理を分けるなら、自分のデータで、誤判定との関係を確認します。
Score も使えますが、元記事のように「低・中・高が必ず整数の0・1・2になる」とは扱わず、導入時にはSDKとJEFFの返す評価値・確率分布を確認してください。今回は最初の分類に必要な範囲に絞ります。
うまく動かないとき
| 症状 | 確認・対処 |
|---|---|
git や uv が見つからない |
インストール後に窓を開き直し、バージョン確認をやり直します。 |
| Pythonのバージョンに関するエラー |
uv python install 3.12 を実行し、JEFFフォルダーでPython 3.12の仮想環境を有効にし、uv sync --active --extra dev をやり直します。 |
No module named typesafe_sdk |
その窓で .venv を有効にしたか、手順4のPythonのパスを確認します。必要なら uv sync --active --extra dev を再実行します。 |
hf や jeff が見つからない |
仮想環境を有効にし、uv sync --active --extra dev が完了したか確認します。 |
| モデルが見つからない | JEFFフォルダーで起動しているか、モデルのダウンロードが完了したか確認します。 |
| 接続できない/Connection refused | 1つ目の窓でサーバーが起動済みか、読み込み中やエラー停止ではないか確認します。 |
| 401エラー | サーバーの JEFF_API_KEYS と、Pythonの api_key が同じか確認します。 |
| ポート8000を使えない | そのポートを使っている既存のJEFFなどを確認します。ポートを変えるなら、サーバーの JEFF_PORT とPythonの接続先の両方を変えます。 |
example.py が見つからない |
保存先がJEFFフォルダーか、ファイル名が example.py.txt になっていないか確認します。 |
| 日本語が文字化けする | PythonファイルをUTF-8で保存したか確認します。 |
| 読み込み中にメモリ不足になる | 他のアプリを閉じて再度試します。PCの資源が足りない場合は、より余裕のある環境が必要です。 |
MacでMPS関連のエラーになる場合は、CPUに切り替えて起動を試せます。
JEFF_HOST=127.0.0.1 JEFF_API_KEYS=devkey JEFF_DEVICE=cpu jeff
ただし、GPU実行と同じ速度になるわけではありません。
終了と、次回の起動
使い終わったら、サーバーを動かしている1つ目の窓で Ctrl+C を押します。サーバーが終了したら、各窓で次のコマンドを実行して仮想環境を無効にできます。
deactivate
仮想環境のファイルやインストールしたライブラリは消えません。この窓で使うPythonの設定を元に戻す操作です。
次回は、フォルダーへ移動し、仮想環境を有効にして起動します。
Mac:
cd ~/jeff
source .venv/bin/activate
JEFF_HOST=127.0.0.1 JEFF_API_KEYS=devkey jeff
Windows:
Set-Location "$HOME\jeff"
.\.venv\Scripts\Activate.ps1
$env:JEFF_HOST = "127.0.0.1"
$env:JEFF_API_KEYS = "devkey"
$env:JEFF_DEVICE = "cpu"
jeff
Windowsで有効化を制限された場合は、手順4の対処を確認してください。
2つ目の窓でも同じフォルダーへ移動して仮想環境を有効にし、python example.py を実行します。仮想環境とモデルが残っていれば、毎回作成・インストール・ダウンロードをやり直す必要はありません。
Windowsで設定した $env:... は、そのPowerShellのプロセスに対する設定です。新しい窓では、起動時に再び設定してください。
自分のアプリに組み込むなら
問い合わせの振り分けのように、間違いを人が訂正できる用途から始めると、精度を確認しながら使えます。次は、今回の print() を自分のアプリ内の担当別処理へ置き換える段階です。
外部公開や実運用では、認証キーの管理、通信失敗時の扱い、誤分類を人が見直す経路も必要になります。コマンド実行やデータ削除の許可に利用する場合は、JEFFの判定だけで許可せず、許可リストや権限制限などの仕組みを組み合わせてください。
まずは、自分の用途でよく出る問い合わせを数件、サンプルの text に入れてみてください。どの言い方で分類が変わるかを見ると、キーワード判定を置き換える価値があるか判断しやすくなります。
