
判断特化型AI「Jev」互換のOSSモデル「Kev」を Docker上で試してみた
はじめに
「Jev」は、料金の安さとレスポンスの速さで注目されている判断特化型 AI です。
その Jev と同じ API を実装した OSS の判断特化型 AI(デシジョンモデル)「Kev」が、Apache-2.0 ライセンスで公開されています。複数のサイズがあり、最小の Kev-0.8B(Qwen3.5-0.8B-Base ベース)は GPU のない環境でも動作するとされています。
今回は、初代 M1 Mac(メモリ 16GB、CPU 8 コア)に Linux を入れた環境の Docker 上で、Kev-0.8B を試した結果を紹介します。
Kev の API とモデルサイズ
Kev は jaredpalmer/kev で開発されているデシジョンモデルです。Jev と同じ POST /v1/systemone を受け付けるので、TypeSafe の SDK はエンドポイントの変更だけで利用できます。
モデルサイズは 0.8B / 4B / 9B / 27B の 4 つです。README は 4B を標準として薦めていますが、4B 以上はメモリ 32GB の Mac か GPU が前提とされています。CPU で実用的な速度が出るのは最小の 0.8B なので、この記事では 0.8B を評価しています。
動作環境
| 項目 | 値 |
|---|---|
| OS | Fedora Linux Asahi Remix 44(aarch64) |
| CPU | Apple M1 / 8 コア(性能コア 4 + 高効率コア 4) |
| メモリ | 16GB |
| Docker イメージ | arm64 python:3.12-slim(torch 2.8.0+cpu) |
macOS ではなく Linux で動かしているため、GPU(Metal)は使えず、PyTorch は CPU 経路になります。
Docker で Kev-0.8B を起動する
バージョンとモデルを固定するため、公式リポジトリのソースをビルドして起動します。
docker run -d --name kev-server \
-p 127.0.0.1:8009:8009 \
-e KEV_API_KEY=localkey \
-e OMP_NUM_THREADS=4 \
python:3.12-slim \
sh -c "
apt-get update -qq && apt-get install -qq -y git build-essential g++
pip install --quiet uv
git clone --quiet https://github.com/jaredpalmer/kev /kev
cd /kev && git checkout --quiet f153596
uv sync --quiet --extra serve
uv run python -m kev.serve --run jaredpalmer/kev-0.8b --host 0.0.0.0 --port 8009
"
f153596 は執筆時点の最新コミットです。モデル jaredpalmer/kev-0.8b は起動時に自動でダウンロードされ、認証は要りません。依存の解決とモデルの取得を含めて、起動までに約 90 秒かかりました。
Fetching 9 files: 100%|██████████| 9/9 [00:02<00:00]
Loading weights: 100%|██████████| 320/320 [00:00<00:00]
INFO: Started server process [1434]
INFO: Application startup complete.
INFO: Uvicorn running on http://0.0.0.0:8009 (Press CTRL+C to quit)
起動後に /v1/models を呼び出すと、実行構成が返ります。
run=jaredpalmer/kev-0.8b device=cpu backend=torch dtype=float32 temperature=2.3510958125672174
応答に含まれる確率は、checkpoint ごとに同梱された temperature で校正された値です。表示されている 2.35 は 0.8B 用です。
KEV_API_KEY を設定する
Kev は KEV_API_KEY が未設定だと認証なしで応答します(kev/serve.py、commit f153596)。
API_KEY = os.environ.get("KEV_API_KEY") # unset = open server; set = require Authorization: Bearer <key>
未設定のコンテナでは、認証ヘッダなしでも誤ったキーでも 200 が返りました(キーを設定すると、認証ヘッダなしでは 401 でした)。先の起動コマンドでは -e KEV_API_KEY=localkey でキーを渡しています。
また、既定のバインド先は 127.0.0.1 ですが、Docker で使うには --host 0.0.0.0 が必要です。その代わりに -p 127.0.0.1:8009:8009 で、ホスト側の待ち受け先をループバックに絞っています。
Dockerfile でモデルまで焼き込む
毎回 clone と uv sync を待ちたくない場合は、ビルド時にモデルまで焼き込んだイメージにします。この形では、起動までに約 30 秒でした。
Dockerfile-kev とビルド・起動コマンド
Dockerfile-kev として保存します。
FROM python:3.12-slim
RUN apt-get update -qq \
&& apt-get install -qq -y --no-install-recommends git build-essential g++ \
&& rm -rf /var/lib/apt/lists/*
RUN pip install --no-cache-dir uv==0.9.7
RUN git clone https://github.com/jaredpalmer/kev /kev
WORKDIR /kev
RUN git checkout f153596
RUN uv sync --extra serve
# ビルド時にモデルを焼き込む(初回起動を待たない)
RUN uv run python -c "from huggingface_hub import snapshot_download; snapshot_download('jaredpalmer/kev-0.8b')"
# KEV_API_KEY と OMP_NUM_THREADS は ENV に焼かず docker run -e で渡す
# KEV_API_KEY : 未設定だと無認証で応答するため必ず渡す。ENV に書くと docker build が SecretsUsedInArgOrEnv を警告する
# OMP_NUM_THREADS : 適値はホストの CPU 構成で変わる
EXPOSE 8009
CMD ["uv", "run", "python", "-m", "kev.serve", \
"--run", "jaredpalmer/kev-0.8b", "--host", "0.0.0.0", "--port", "8009"]
docker build -f Dockerfile-kev -t kev-local .
docker run -d --name kev-server -p 127.0.0.1:8009:8009 -e KEV_API_KEY=localkey -e OMP_NUM_THREADS=4 kev-local
API で質問を投げる
POST /v1/systemone に、判定対象のテキスト(state)と質問(questions)を渡します。回答形式は質問ごとに type で指定します。選択肢から選ぶ choice、はい・いいえを 1 つの確率で返す noul、段階評価の score の 3 形式があります。choice なら criteria に選択肢を並べます。認証には、起動時に設定した KEV_API_KEY を Bearer トークンとして渡します。
まず choice を 1 問だけ聞く例です。
curl -s -X POST http://localhost:8009/v1/systemone \
-H "Authorization: Bearer localkey" \
-H "Content-Type: application/json" \
-d '{
"state": "インフラ設計のレビューをしたい",
"model": "kev-latest",
"questions": {
"skill": {
"type": "choice",
"instructions": "Which skill fits this message?",
"criteria": {
"aidlc-infrastructure-design": null,
"aidlc-bugfix": null,
"aidlc-market-research": null,
"none": null
}
}
}
}'
{
"model": "kev-latest",
"answers": {
"skill": {
"type": "choice",
"choice": "aidlc-infrastructure-design",
"confidence": 0.705,
"probabilities": {
"aidlc-infrastructure-design": 0.7788,
"aidlc-bugfix": 0.0078,
"aidlc-market-research": 0.0016,
"none": 0.2118
}
}
},
"usage": {
"input_tokens": 39,
"output_tokens": 89
},
"latency_ms": 1029.4
}
応答の形も Jev と同じで、choice と probabilities を持ちます。confidence は正答率ではなく、README が (p_max − 1/K) / (1 − 1/K) と定義する値です(K は選択肢の数)。
サポートチケットの振り分けを想定して、担当部署(choice)、エスカレーションの要否(noul)、怒りの度合い(score)を 1 リクエストで聞いた応答です。
{
"model": "kev-latest",
"answers": {
"department": {
"type": "choice",
"choice": "shipping",
"confidence": 0.2625,
"probabilities": {"returns": 0.338, "shipping": 0.5083, "billing": 0.1537}
},
"escalate": {"type": "noul", "noul": 0.4363},
"frustration": {
"type": "score",
"score": 1.3551,
"legend": {"0": "Calm", "1": "Frustrated", "2": "Very angry"},
"probabilities": {"0": 0.041, "1": 0.5629, "2": 0.3961},
"confidence": 0.3444
}
},
"usage": {"input_tokens": 102, "output_tokens": 180},
"latency_ms": 994.8
}
コンテナに割り当てるリソース
必要なメモリの下限
docker run --memory の値を変えて起動した結果です。
| 制限 | 結果 |
|---|---|
| 4 GB | 起動・応答 OK(使用量の実測 3.516 GiB) |
| 3.5 GB | OOMKilled(重み読み込み中、ExitCode 137、12 秒で停止) |
既定の fp32 では重みが 0.8B × 4 byte = 約 3.2GB(3.0GiB)で、バッファが加わって 3.5GiB 強でした。コンテナには 4GB 以上のメモリを割り当てます。
参考:CPU の設定で変わる応答時間
M1 CPU で測定した latency_ms です。プロンプトキャッシュの影響を除くため、いずれも同じ入力を初めて送ったときの値です(測定回数は列見出しに示します)。
| 設定 | 質問1・初回(3回の範囲) | 質問5・初回(1回) |
|---|---|---|
| 既定(8スレッド, fp32) | 1760–2068 ms | 3728 ms |
OMP_NUM_THREADS=4 |
591–624 ms | 2073 ms |
KEV_DTYPE=bf16(既定スレッド) |
13315–13597 ms | 32753 ms |
KEV_DTYPE=fp16(既定スレッド) |
10768–11038 ms | 19145 ms |
スレッド数は性能コアの数に合わせます。既定の 8 スレッドから OMP_NUM_THREADS=4 にすると、質問 1 件では約 3 倍速くなりました。起動時に OMP_NUM_THREADS=4 を渡しているのはこのためです。
dtype は既定の fp32 が最速です。KEV_DTYPE=bf16 は既定スレッド同士の比較で 7.6 倍遅くなりました。M1 の CPU は bf16 の演算命令を備えず、低精度の行列積が最適化されないためです。fp16 でも 6 倍遅くなりました。
一方、bf16 にすると必要なメモリは減り、0.8B は 2GB 制限でも、4B は 11GB 制限でも起動できました。ただし、bf16 で動かした 4B の応答時間は 26〜93 秒でした。CPU 環境で 4B を使うことは、応答時間が長いため見送ることとしました。
回答の精度を確かめる
README のモデル表(commit f153596)では、new sources(development 列)の精度が Kev-0.8B で 0.648、Kev-4B で 0.817、Jev で 0.857 です。ただし、Jev の学習データが不明なため、統制された比較ではないとも注記されています。
手元では、5 ケース(回答 7 個)を 0.8B と 4B に同じ形式で投げ、正解が一意に決まる 3 件を表に示します。
| ケース | Kev-0.8B | Kev-4B |
|---|---|---|
| skill 選択(明確な依頼) | aidlc-infrastructure-design 0.779 ✓ | aidlc-infrastructure-design 0.721 ✓ |
| entailment(正解 insufficient) | contradicted 0.911 ✗ | insufficient 0.996 ✓ |
| knowledge(正解 nitrogen) | nitrogen 0.801 ✓ | nitrogen 0.979 ✓ |
入力に判断の手がかりが明示されている分類、たとえば明確な依頼に対するスキル選択や知識問題(knowledge)では、0.8B も 4B と同じ回答を返しました。一方、文の含意を判定するような推論が必要な問題(entailment)では、0.8B は誤答に 0.9 を超える確率を割り当てました。これは README で confident errors と呼ばれている失敗です。確率が高くても、正しい回答とは限りません。
まとめ
Jev と API 互換性のある OSS の Kev は、モデルサイズや性能の制限はありますが、CPU のみ、4GB メモリの Docker 環境上でも動作することが確認できました。
今回は実行環境の制限で最小モデルを評価しましたが、GPU を積んだホストや、Apple Silicon ネイティブ(MLX)が使える macOS 環境があれば、より高性能なモデルも動作する可能性があります。
判定や分類に特化したモデルを評価したい、あるいは推論時の入力データを外部 API に送信したくない場合などに Kev をお試しください。








