
Trying AWS's Newly Released Judgment-Only Model "Strands Decider 2B" on an M4 Mac and Comparing It with Kev and Jev
This page has been translated by machine translation. View original
Introduction
On 2026-10-01, AWS's Strands Labs released Strands Decider 2B, a small model dedicated to classification. It does not generate text; it returns which of the given choices an input falls under, along with probabilities.
Kiro Crew 0.7 offers an Auto (Jev) mode in preview, which can classify the complexity of a prompt with a classification model and route it to a model. In commit 3d465a6, Strands Decider 2B is bundled in the local model presets, so integration is already moving ahead.
In this article, I evaluate Strands Decider 2B (hereafter Decider) as a model router for Kiro Crew. I run it on the GPU and CPU of a Mac mini (M4 Pro), and compare classification results and response times using the classification prompts Kiro Crew uses to route models. The comparison targets are the local Kev-4B and the Jev TypeSafe API.
Kev, the comparison target, was introduced in a previous article.
How Strands Decider 2B works
The base is Qwen3.5-2B. According to the announcement blog, the LM head that outputs the next token was removed and replaced with a pointer head that outputs a score for each choice.
Running it on an M4 Mac
The package can be installed with pip install strands-decider. This time, I created a Python 3.12 virtual environment with uv and installed it there.
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
51 packages were installed, including dependencies such as torch, transformers, peft, and fastapi / uvicorn, and nothing else needs to be added.
The server is started with the serve subcommand. Specify --device mps to run on the GPU (PyTorch MPS), or --device cpu to run on the CPU only.
sd-venv/bin/strands-decider serve StrandsAgents/strands-decider-2B-hobson-v19 --device mps --host 127.0.0.1 --port 8012
The first run downloads the model weights (about 4.3 GB) from Hugging Face, so it took 32 seconds to finish starting up from an empty cache. From the second time on, it took 5 seconds. After startup, a message appears saying that it runs on the reference implementation because causal_conv1d is missing, but I ignored it and used it as is.
Comparing with Kev and Jev using Kiro Crew's classification prompts
Evaluation conditions
I compared the following three models. Decider and Kev were run on the same Mac mini, and Jev was called via API.
| Item | Details |
|---|---|
| Hardware | Mac mini (Apple M4 Pro / 24GB memory), 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, startup log: on mps via mlx (bfloat16) |
| Jev | https://api.typesafe.ai/v1/systemone, model: jev-latest (the model in the response is jev-1.13.0) |
The inputs are 20 questions in Japanese and their 20 English translations (6 simple, 7 medium, 7 complex). The expected answers were assigned by Claude Opus 5.5 before running the models, following Kiro Crew's tier definitions, and for questions on a boundary up to two expected answers were accepted. I call the number of questions that fall within this range "within expectation."
There are three kinds of classification prompts.
- A: A generic classification prompt consisting of the single sentence "How complex is this prompt?" plus a short description of each tier
- B: The same classification prompt as model.route in Kiro Crew 3d465a6. In addition to the tier definitions, it includes an instruction to the effect of "a request that refers to a plan or to work you cannot see is not simple even if it is short," and the criteria values are null
- B_desc: B with description text filled into the criteria (the reason is in the next section)
The full text of B's instructions is included in the request example in the next section.
20 evaluation questions (Japanese version)
The English version is a translation of the Japanese version, and the expected answers are the same. For questions with attachments (P01 / P12 / P18), the beginning of the body reads "(attached: ...)", and only the body including this notation was passed to the models.
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. 想定されるリスクと、事前に確認しておくべき点
まずは全体像を表にまとめてから詳細を書いて。費用の増減も、概算でわかれば知りたい。
If criteria is null, Decider returns 422
When I sent Crew's classification prompt in the same form as Crew (B, with criteria values set to null), Kev and Jev returned HTTP 200, and only Decider returned HTTP 422.
Decider requires a description string for each choice in the choice's criteria. The version of strands-decider pinned by Kiro Crew 3d465a6 has the same definition, so the form Crew sends as-is does not go through.
It goes through if you put a description in each choice (B_desc). I put Crew's tier definition strings (TIER_DESCRIPTIONS) into criteria as they are, and kept instructions and state the same as B. A request using P05 as an example is saved as 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}
In the tables below, B_desc uses requests in this format for all three models.
Classification agreement and response time
These are the results of running the 20 questions on the GPU. One warm-up request was sent before each condition and excluded from the aggregation.
| Model | Prompt | Within expectation ja | Within expectation en | Avg. response ja | Time for 20 questions ja |
|---|---|---|---|---|---|
| Strands Decider 2B (GPU) | A | 19 | 18 | 210 ms | 4.21 s |
| 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 s (2 runs) |
| Kev-4B (GPU, MLX) | A | 15 | 14 | 254 ms | 5.09 s |
| Kev-4B (GPU, MLX) | B (criteria null) | 16 | 15 | 511 ms | 10.22 s |
| Kev-4B (GPU, MLX) | B_desc | 16 | 17 | 604 ms | 12.09 s |
| Jev (API *) | A | 16 | 16 | 205 ms | 4.11 s |
| Jev (API *) | B (criteria null) | 18 | 18 | 210 ms | 4.21 s |
| Jev (API *) | B_desc | 18 | 17 | 196 ms | 3.94 s |
The average response is the value measured on the client side. Decider's B_desc (Japanese) is the average of 40 requests across 2 runs.
- The Jev values include the network round trip from a Linux host separate from the M4, calling
https://api.typesafe.ai/v1/systemone.
With B_desc, which all three models can handle with Crew's classification prompt, the Japanese results were Decider 20, Jev 18, and Kev 16. In English, they were Decider 18, Jev 17, and Kev 17.
Startup took 5–6 seconds for Decider and 9 seconds for Kev. Memory was 5.2 GB for Decider and 10 GB for Kev.
Decider and Kev were run repeatedly under the same conditions, and the tiers for all 20 questions matched every time. Jev was run only once per condition.
What changed with the classification prompt
With the short classification prompt (A), all three models answered simple for P04 and got it wrong. P04, P05, and P06 are requests such as "Drop that approach and go with the other proposal you gave me earlier," "Go ahead with proposals A and C. For proposal B, I want to check the scope of impact before deciding, so just give me the investigation results first," and "An ECS task stops right after starting. Do you know the cause?" — short sentences that ask for work that can't be seen or for diagnosing a cause. The questions that each model answered simple under A and got wrong are as follows.
| Model | Japanese | English |
|---|---|---|
| Strands Decider 2B | P04 | P04, P06 |
| Kev-4B | P04, P05, P09, P14 (plus P13 as medium) | P04, P05, P06, P11, P14 (plus P13 as medium) |
| Jev | P04, P05, P06, P19 | P04, P05, P06, P19 |
When switched to B_desc, Decider's Japanese P04 and English P04 and P06 came within expectation. However, in English, P05 and P11 newly missed by answering simple. Kev kept answering simple for P04 and P05 with both B and B_desc, and in Japanese B_desc, P11 and P15 newly missed. For Jev, P04, P05, and P06 came within expectation in both Japanese and English, but P11 newly missed, and with B_desc, P15 also missed.
Response time increased by about 1.8–2.4 times for the two local models (Decider 210 → 379 ms, Kev 254 → 511 ms (B) and 604 ms (B_desc)).
Running on the CPU
I started Decider with --device cpu and ran the 20 Japanese questions.
| Model | Prompt | Within expectation | Avg. response | Time for 20 questions | footprint (after evaluation) |
|---|---|---|---|---|---|
| Strands Decider 2B (CPU) | A | 19 | 3,495 ms | 69.91 s | 8.0 GB |
| Strands Decider 2B (CPU) | B_desc | 20 | 3,899 ms | 77.98 s | 〃 |
The average response was about 17 times (A) and about 10 times (B_desc) that of the GPU, but the classifications were the same tiers as the GPU for all 40 requests. Since the results are the same as on the GPU, it was possible to evaluate routing results even without using the GPU, as long as the memory allocation and response speed are acceptable.
Summary
I ran Strands Decider 2B on an M4 Mac and evaluated it with Kiro Crew's model-router classification prompts. All 20 questions in Japanese and 18 in English fell within the range of expected answers assigned in advance by Claude Opus 5.5.
In this measurement, Decider's agreement on the GPU was equal to or better than that of the commercial API Jev. Its response time of just under 0.4 seconds does not match Jev's 0.2 seconds, but it could classify without sending prompts outside.
Compared with Kev-4B, which also runs locally, Decider had more matches, shorter response times, about half the memory, and faster startup, so I also confirmed that it is easy to try as a local classifier.
I hope that integration with Kiro Crew and others, as well as the development of libraries and the like, will progress and make adoption easier.
