
AWS がリリースした判定専用モデル「Strands Decider 2B」を M4 Mac で試し、Kev・Jev と比べてみた
はじめに
2026-10-01 に、AWS の Strands Labs が判定専用の小型モデル Strands Decider 2B を公開しました。文章を生成せず、与えた選択肢のどれに当たるかを確率付きで返すモデルです。
Kiro Crew は 0.7 で Auto (Jev) モードをプレビュー提供し、判定モデルでプロンプトの複雑さを分類してモデルを振り分けられるようになりました。コミット 3d465a6 では Strands Decider 2B をローカルモデルのプリセットに同梱しており、組み込みが先行して進んでいます。
この記事では、Strands Decider 2B(以下 Decider)を Kiro Crew のモデルルーター用途で評価します。Mac mini(M4 Pro)の GPU と CPU で動かし、Kiro Crew がモデルの振り分けに使う判定文で判定結果と応答時間を比べます。比較相手はローカルの Kev-4B と TypeSafe API の Jev です。
比較相手の Kev は先行記事で紹介しています。
Strands Decider 2B の仕組み
本体は Qwen3.5-2B です。告知ブログによると、次のトークンを出す LM ヘッドを外し、選択肢ごとのスコアを出す pointer head に置き換えています。
M4 Mac で動かす
パッケージは pip install strands-decider でインストールできます。今回は uv で Python 3.12 の仮想環境を作成し、そこへインストールしました。
uv venv sd-venv --python 3.12
uv pip install --python sd-venv/bin/python strands-decider
sd-venv/bin/python -c 'import importlib.metadata as m; print(m.version("strands-decider"), m.version("torch"))'
0.1.0 2.14.1
torch、transformers、peft、fastapi / uvicorn などの依存も含めて 51 パッケージが入り、ほかに追加で入れるものはありません。
サーバーは serve サブコマンドで起動します。GPU(PyTorch の MPS)で動かす場合は --device mps、CPU だけで動かす場合は --device cpu を指定します。
sd-venv/bin/strands-decider serve StrandsAgents/strands-decider-2B-hobson-v19 --device mps --host 127.0.0.1 --port 8012
初回は Hugging Face からモデルの重み(約 4.3 GB)を取得するため、キャッシュが空の状態から起動完了まで 32 秒かかりました。2 回目以降は 5 秒でした。起動後に causal_conv1d が無いため参照実装で動くという案内が出ますが、無視して利用しています。
Kiro Crew の判定文で Kev・Jev と比べる
評価の条件
比べたのは次の 3 モデルです。Decider と Kev は同じ Mac mini で動かし、Jev は API で呼びました。
| 項目 | 内容 |
|---|---|
| 機材 | Mac mini(Apple M4 Pro / メモリ 24GB)、macOS 27.0.1 |
| Strands Decider 2B | strands-decider 0.1.0、torch 2.14.1、--device mps |
| Kev-4B | Kev commit 5920c5f、jaredpalmer/kev-4b、起動ログは on mps via mlx (bfloat16) |
| Jev | https://api.typesafe.ai/v1/systemone、model: jev-latest(応答の model は jev-1.13.0) |
入力は日本語 20 問と、その英訳 20 問です(simple 6 問、medium 7 問、complex 7 問)。想定回答は Kiro Crew の tier 定義に従って Claude Opus 5.5 がモデルの実行前に付け、境界にある設問は想定回答を 2 つまで認めました。この範囲に収まった設問の数を「想定内」と呼びます。
判定文は次の 3 通りです。
- A: 「How complex is this prompt?」の 1 文に、各 tier の短い説明を添えた汎用の判定文
- B: Kiro Crew 3d465a6 の model.route と同じ判定文。tier の定義に加え、「計画や見えない作業を指す依頼は、短くても simple にしない」という趣旨の指示を含み、criteria の値は null
- B_desc: B の criteria に説明文を入れたもの(理由は次の節)
B の instructions の全文は、次の節のリクエスト例に載せています。
評価用 20 問(日本語版)
英語版は日本語版の翻訳で、想定回答は同じです。添付ファイルがある設問(P01 / P12 / P18)は本文の先頭に「(〜を添付)」と書いており、モデルにはこの表記を含む本文だけを渡しました。
P01(expected: simple / accept: simple, medium)
(スクリーンショットを添付)この画像に写っているエラーメッセージを文字に起こして
P02(expected: medium / accept: medium, simple)
今日はここまで。続きは明日やるので、作業メモを残しておいて
P03(expected: simple / accept: simple)
このリポジトリで使っている Node.js のバージョンは?
P04(expected: medium / accept: medium, complex)
その方針はやめて、さっき出してくれた別案で進めて
P05(expected: medium / accept: medium, complex)
A案とC案は進めていい。B案は影響範囲を調べてから決めたいので、まず調査結果だけ出して
P06(expected: complex / accept: complex, medium)
ECSタスクが起動直後に止まる。原因わかる?
P07(expected: simple / accept: simple, medium)
https://example.com/docs/changelog の更新内容を3行で要約して
P08(expected: simple / accept: simple, medium)
utils/date.ts の formatDate 関数を formatDateTime にリネームして、呼び出し箇所もそろえて
P09(expected: complex / accept: complex, medium)
APIのレスポンスが特定の時間帯だけ遅くなる。CloudWatchのメトリクスとアクセスログを見て、原因の候補を挙げて
P10(expected: simple / accept: simple, medium)
この一文「本番環境への反映は、承認フローを経たうえで実施した」で意味は通じる?
P11(expected: medium / accept: medium, complex)
静的サイトの一部のページを、会員登録した人だけが見られるようにしたい。CloudFrontの署名付きCookieで実現できる?
P12(expected: simple / accept: simple, medium)
(下書きを添付)この段落、です・ます調とだ・である調が混ざっているので、です・ます調にそろえて
P13(expected: complex / accept: complex)
Aurora MySQLのメジャーバージョンアップを予定している。ブルー/グリーンデプロイを使う方法と、スナップショットから新しいクラスターを作る方法で、切り替え時の停止時間、ロールバックのしやすさ、アプリ側の接続先変更の要否を比べて、どちらを選ぶべきか教えて
P14(expected: complex / accept: complex, medium)
検証用にEC2を1台起動して、Nginxを入れ、負荷試験ツールで1秒あたりのリクエスト数を3回測って。セキュリティグループは自分のIPからだけ許可すること。終わったらインスタンスは停止ではなく削除して、結果は経過秒と終了コード付きでファイルに残して
P15(expected: medium / accept: medium, simple)
テストコードにコメントを多めに書くのはいいと思う。でも、READMEにまで同じ説明を載せる必要はある? 内容が重複して、更新漏れの原因になる気がする。どう思う?
P16(expected: medium / accept: medium, simple)
このワークフロー、deployジョブに needs: build を付けなくても今まで問題なく動いていた。付ける必要はある?
```yaml
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: make build
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: make deploy
```
P17(expected: complex / accept: complex)
【目的】
先月からS3の請求額が約1.5倍になった原因を特定したい。
Cost Explorerでは、PUTとLISTのリクエスト料金が増えている。一方で、保存しているデータ量はほとんど変わっていない。
【これまでに確認したこと】
- 新しいバケットは作っていない
- バッチ処理の実行間隔を1時間ごとから5分ごとに変えた
- 同じ時期に、ログ転送ツールのバージョンを上げた
【お願い】
1. リクエスト数が増える原因として考えられるものを洗い出して
2. どのバケット・どの処理がリクエストを出しているか、特定する手順を順番に示して
3. 恒久対策の案を、費用の目安付きで出して
P18(expected: complex / accept: complex, medium)
(プルリクエストの差分を添付)このプルリクエストをレビューして。
観点:
- 例外が握りつぶされている箇所がないか
- 同時に実行されたときに競合しないか
- 既存のAPIの互換性を壊していないか
- テストが変更内容を十分にカバーしているか
- 命名とコメントが実装と食い違っていないか
出力形式: 指摘ごとに「ファイル名と行」「問題」「修正案」を1組で書き、重要度を高・中・低で付けること。コードは書き換えず、指摘だけを返して。
P19(expected: medium / accept: medium, complex)
CIのビルドが急に落ちるようになった。昨日までは通っていて、こちらのコードは変えていない。ログを貼るので原因を教えて。
[Container] 2026/09/18 01:12:04.118 Running command python --version
Python 3.9.19
[Container] 2026/09/18 01:12:06.511 Running command pip install -r requirements.txt
Collecting boto3>=1.34
Downloading boto3-1.40.12-py3-none-any.whl (139 kB)
Collecting pyyaml
Downloading PyYAML-6.0.3-cp39-cp39-manylinux_2_17_x86_64.whl (737 kB)
Collecting sample-report-lib
Downloading sample_report_lib-3.0.0.tar.gz (52 kB)
Installing build dependencies: started
Installing build dependencies: finished with status 'done'
Getting requirements to build wheel: started
Getting requirements to build wheel: finished with status 'error'
error: subprocess-exited-with-error
× Getting requirements to build wheel did not run successfully.
│ exit code: 1
╰─> [6 lines of output]
Traceback (most recent call last):
File "<string>", line 14, in <module>
File "setup.py", line 9, in <module>
python_requires=">=3.10",
RuntimeError: sample-report-lib requires Python >=3.10 (running 3.9.19)
[end of output]
error: subprocess-exited-with-error
× Getting requirements to build wheel did not run successfully.
│ exit code: 1
╰─> See above for output.
[Container] 2026/09/18 01:12:19.803 Command did not exit successfully pip install -r requirements.txt exit status 1
[Container] 2026/09/18 01:12:19.809 Phase complete: INSTALL State: FAILED
[Container] 2026/09/18 01:12:19.809 Phase context status code: COMMAND_EXECUTION_ERROR Message: Error while executing command: pip install -r requirements.txt. Reason: exit status 1
P20(expected: complex / accept: complex)
相談。いま検証用と本番用のワークロードが1つのAWSアカウントに同居している。これを検証・ステージング・本番の3アカウントに分けたい。前提と制約は次のとおり。
- 既存リソースはCloudFormationと手作業が混在している。スタックは約40本あり、スタック間でExport/ImportValueの依存が多い
- 本番は24時間稼働で、停止を伴う作業ができるのは月1回の保守枠(深夜2時間)だけ
- RDS(PostgreSQL)には本番データが入っているので、検証アカウントへは匿名化してから渡す必要がある
- 外部の決済サービスからのWebhookを固定IPで受けており、IPを変えるには決済サービス側への事前申請が要る
- ドメインはRoute 53で管理し、証明書はACMで発行している
- 監査の都合で、CloudTrailのログは別の集約用アカウントに集めたい
お願いしたいこと:
1. 移行の順番(どのリソースをどのアカウントへ、どの順で動かすか)を段階に分けて示して
2. 各段階で止まる可能性があるサービスと、止まる時間の目安
3. スタック間の依存を切る進め方。IaCを書き直す範囲と、手作業のまま残す範囲の線引き
4. Webhookの受け口を移すときに、決済サービス側へ事前に申請すべき項目
5. 段階ごとのロールバック方法
6. 想定されるリスクと、事前に確認しておくべき点
まずは全体像を表にまとめてから詳細を書いて。費用の増減も、概算でわかれば知りたい。
criteria が null だと Decider は 422 を返す
Crew の判定文を Crew と同じ形(B、criteria の値が null)で送ると、Kev と Jev は HTTP 200 を返し、Decider だけが HTTP 422 を返しました。
Decider は choice の criteria に、選択肢ごとの説明文(文字列)を必須としています。Kiro Crew 3d465a6 が固定している strands-decider の版でも同じ定義なので、Crew が送る形のままでは通りません。
各選択肢に説明文を入れれば通ります(B_desc)。criteria には Crew の tier 定義(TIER_DESCRIPTIONS)の文字列をそのまま入れ、instructions と state は B と同じにしました。P05 を例にしたリクエストを req_crew.json として保存します。
{
"state": {
"message": "A案とC案は進めていい。B案は影響範囲を調べてから決めたいので、まず調査結果だけ出して"
},
"questions": {
"tier": {
"type": "choice",
"instructions": "How hard is this request for an AI coding assistant? Answer one of: simple = a short, local, mechanical request answerable in one step -- a rename, a lookup, a small edit, a direct factual question; medium = ordinary work over a few files or steps -- write a function, explain some code, fix a bug whose cause is already named; complex = work needing a plan, a trade-off or reasoning across a whole system -- design, architecture, a diagnosis with no named cause, a risky refactor. Being wrong in the two directions does not cost the same. A turn put in a lower tier than it needs gets less room to work in and a worse answer; a turn put higher only costs more. So answer simple only when the request is self-contained and you can see the whole of it -- a request that is a plan, a judgement call, several instructions at once, or that names work you cannot see, is not simple however short it is.",
"criteria": {
"simple": "a short, local, mechanical request answerable in one step -- a rename, a lookup, a small edit, a direct factual question",
"medium": "ordinary work over a few files or steps -- write a function, explain some code, fix a bug whose cause is already named",
"complex": "work needing a plan, a trade-off or reasoning across a whole system -- design, architecture, a diagnosis with no named cause, a risky refactor"
}
}
}
}
curl -s http://127.0.0.1:8012/v1/systemone -H "Content-Type: application/json" -d @req_crew.json
{"model":"strands-decider-2B-hobson-v19","answers":{"tier":{"type":"choice","choice":"complex","probabilities":{"simple":0.1761,"medium":0.2388,"complex":0.5851},"confidence":0.3777}},"usage":{"input_tokens":368,"output_tokens":1},"latency_ms":320.7}
以降の表の B_desc は、3 モデルともこの形式のリクエストです。
判定の一致と応答時間
GPU で 20 問を流した結果です。各条件の前にウォームアップを 1 回送り、集計から除いています。
| モデル | 判定文 | 想定内 ja | 想定内 en | 平均応答 ja | 20 問の所要時間 ja |
|---|---|---|---|---|---|
| Strands Decider 2B(GPU) | A | 19 | 18 | 210 ms | 4.21 秒 |
| Strands Decider 2B(GPU) | B(criteria null) | HTTP 422 | HTTP 422 | — | — |
| Strands Decider 2B(GPU) | B_desc | 20 | 18 | 379 ms | 7.63 / 7.52 秒(2 回) |
| Kev-4B(GPU、MLX) | A | 15 | 14 | 254 ms | 5.09 秒 |
| Kev-4B(GPU、MLX) | B(criteria null) | 16 | 15 | 511 ms | 10.22 秒 |
| Kev-4B(GPU、MLX) | B_desc | 16 | 17 | 604 ms | 12.09 秒 |
| Jev(API ※) | A | 16 | 16 | 205 ms | 4.11 秒 |
| Jev(API ※) | B(criteria null) | 18 | 18 | 210 ms | 4.21 秒 |
| Jev(API ※) | B_desc | 18 | 17 | 196 ms | 3.94 秒 |
平均応答はクライアント側で計測した値です。Decider の B_desc(日本語)は 2 回分 40 件の平均です。
※ Jev は、M4 とは別の Linux ホストから https://api.typesafe.ai/v1/systemone を呼んだネットワーク往復込みの値です。
Crew の判定文を 3 モデルとも通せる B_desc では、日本語で Decider 20、Jev 18、Kev 16 でした。英語では Decider 18、Jev 17、Kev 17 でした。
起動は Decider が 5〜6 秒、Kev が 9 秒でした。メモリは Decider が 5.2 GB、Kev が 10 GB でした。
Decider と Kev は同じ条件で繰り返し実行し、20 問の tier が毎回すべて一致しました。Jev は各条件 1 回だけの実行です。
判定文で何が変わったか
短い判定文(A)では、3 モデルとも P04 を simple と答えて外しました。P04・P05・P06 は「さっきの別案で進めて」「A案とC案は進めて、B案は調査結果だけ」「ECSタスクが起動直後に止まる。原因わかる?」のように、短い文で見えない作業や原因診断を求める依頼です。A で simple と答えて外した設問は、モデルごとに次のとおりです。
| モデル | 日本語 | 英語 |
|---|---|---|
| Strands Decider 2B | P04 | P04・P06 |
| Kev-4B | P04・P05・P09・P14(ほかに P13 を medium) | P04・P05・P06・P11・P14(ほかに P13 を medium) |
| Jev | P04・P05・P06・P19 | P04・P05・P06・P19 |
B_desc に替えると、Decider は日本語の P04、英語の P04・P06 が想定内になりました。ただし英語では P05・P11 が新たに simple で外れました。Kev は B でも B_desc でも P04・P05 を simple と答えたままで、日本語の B_desc では P11・P15 が新たに外れました。Jev は日英とも P04・P05・P06 が想定内になった一方、P11 が新たに外れ、B_desc では P15 も外れました。
応答時間は、ローカルの 2 モデルで約 1.8〜2.4 倍になりました(Decider 210 → 379 ms、Kev 254 → 511 ms(B)・604 ms(B_desc))。
CPU で動かした場合
Decider を --device cpu で起動し、日本語 20 問を流しました。
| モデル | 判定文 | 想定内 | 平均応答 | 20 問の所要時間 | footprint(評価後) |
|---|---|---|---|---|---|
| Strands Decider 2B(CPU) | A | 19 | 3,495 ms | 69.91 秒 | 8.0 GB |
| Strands Decider 2B(CPU) | B_desc | 20 | 3,899 ms | 77.98 秒 | 〃 |
平均応答は GPU の約 17 倍(A)と約 10 倍(B_desc)になりましたが、判定は 40 件すべて GPU と同じ tier でした。判定結果が GPU と変わらないため、メモリの確保と応答速度が許容できるなら、GPU を使わない場合でも振り分け結果の評価は可能でした。
まとめ
Strands Decider 2B を M4 Mac で動かし、Kiro Crew のモデルルーター用判定文で評価したところ、日本語で 20 問すべて、英語で 18 問が、Claude Opus 5.5 が事前に付けた想定回答の範囲に収まりました。
今回の測定では、GPU で動かした Decider の一致は、商用 API の Jev と同等以上でした。応答時間は 0.4 秒弱と Jev の 0.2 秒には及びませんが、プロンプトを外部に出さずに判定できました。
また、同じくローカルで動く Kev-4B と比べると、Decider は一致の数で上回り、応答時間も短く、メモリは約半分、起動も速いので、ローカルの判定役として試しやすいことも確認できました。
今後、Kiro Crew などとの統合や、ライブラリなどの整備が進み、導入しやすくなることに期待したいと思います。









