AWS Builder Center
Which Brain?: a 2B decision model chooses who answers in my kitchen, and never guesses on medicine

Which Brain?: a 2B decision model chooses who answers in my kitchen, and never guesses on medicine

A hands-free kitchen helper for people with low vision: Strands Decider 2B decides who a phrase is for, whether it is about medicine, and which Amazon Nova model answers. Measured on 120 phrases I recorded and 52 label photos: 21 of 21 held-out medicine questions refused, 0.82 s to the first word, $0.11 of Bedrock per 1,000 phrases.

Entrepreneur & mom of two. I build AI tools that make healthcare simpler for families.
Tags: #strands-decider-2b #model-routing
Code:  https://github.com/NadyKor15/which-brain  (tag  v1.​0-​submission , commit 7c29ecc; numbers frozen at main 1059c9a) · Video:  https://youtu.be/i2zDhHCCboc 
Which Brain? is a hands-free kitchen helper for people who can't read a label. The phone hangs on the cook's chest; for every phrase it hears, Strands Decider 2B decides whether the phrase was meant for the helper, whether it is about medicine, and which Amazon Nova model should answer. On medicine it never guesses: it offers to call a person.
Claim
Evidence in the repo
What you'll see
Never guesses on medicine
eval/​e2e_​results.​csv, docs/​RESULTS-​2026-​10-​22.​md
21/21 medicine questions refused on the held-out set, 10/10 of those with no medicine word; no model answer spoken
Knows when it is not being asked
eval/​out/​score-​20261022​T145704Z.​md, eval/​e2e_​results.​csv
answered 5 of 22 lines meant for someone else, against 22 of 22 for "always Nova Pro"
Faster to the first word
bench/​latency.​md
821 ms p50 from the end of speech, against 1,228 ms for "always Nova Pro"
Cheaper per 1,000 phrases
bench/​latency.​md
$0.11 of Bedrock, against $0.83 for "always Nova Pro"
Never "I think" next to a number
eval/​e2e_​results.​csv
0 of 84 replies
Drop-in for the Strands model router
patterns/​brain_​picker/​
a one-line swap from Classifier​Strategy
A platform finding, reproduced
tools/​repro_​classifier_​nova.​py
Strands Classifier​Strategy declines every choice on Nova; cause, repro and workaround
What it costs
eval/​out/​e2e-​score-​20261022​T145944Z.​md
it also refused 12 of 41 ordinary questions; every one is listed

The problem

In 2020, about 43 million people were blind and 295 million lived with moderate to severe vision loss ( Lancet Global Health 2021 ). In the American Foundation for the Blind's 2026 survey of blind and low-vision AI users, 76 % use AI to figure out object details, such as what is in a can, and 21 % say an AI mistake has hurt them ( AFB 2026, pp. 5-6 ; the 21 % covers any AI mistake, not only labels).
A kitchen makes this harder than a desk. Hands are busy, other people talk, a radio plays, and the thing in your hand might be soup or might be your heart medicine. A helper that sends everything it hears to its strongest model is slow and costly, and it answers lines that were never meant for it.
Before building, a survey participant, 63, with low vision, answered my questions in writing, and her answers became the rules below. On medicine she wrote: read the name if the app is sure, never state a dose, offer to call someone close but dial only after her "yes", because an automatic call for every pill would be insulting (translated from Russian).

What the helper does

You speak; Amazon Transcribe turns it into text. Then Strands Decider 2B answers two requests, and plain code decides what happens:
Decider question
Type
What code does with it
addressed_​to_​me
yes/no
sure yes → go on · sure no → silence · in between → "Did you ask me?" once
about_​medicine
yes/no
above a low threshold → the fixed line "I won't guess on medicine. Want me to call your helper?"
brain
choice: quiet_answer / look / read_closely / ask_human
picks Nova Micro, Nova Lite with the photo, or Nova Pro with the photo; ask_human → the same refusal
frame_check (on the photo)
choice: clear / partly / unreadable
how sure the helper may sound about what the camera sees
A voice far from the chest microphone is not sent to Decider at all: code keeps quiet. Polly speaks the answer; a short sound (two notes for "hold still, I'm looking") comes first, about 0.58 s after you stop speaking.
A last check runs in code on every model answer: if it mentions a medicine or a dose, the helper says the fixed refusal instead. Decider also looks at every usable photo for a medicine bottle, but that answer is only logged: on my photos it flagged 9 of 36 food labels, too many to act on.
Rules the helper keeps, each with a test in the repo: it never says "I think" next to a number, a date, a weight or a temperature; it never states a dose; it does nothing without a "yes". The answer models are also told to read only text they can see, but there is no OCR check at run time; one number that is not on the label got through (below).

The decision handed to Decider 2B

Part
How it works
Decision
for one spoken phrase: is it for me, is it about medicine, and which brain answers
Input
what Amazon Transcribe heard, each phrase on its own (the state has room for the last two phrases); the camera frame for the second request
Thresholds
set on P(yes), not on "confidence",​ from error costs on the 36 tuning phrases: a missed medicine question costs 100, a false silence 5, a false wake 2, a false refusal 1
Where in the loop
before any model is called: a Strands intervention (Safety​First​Handler) runs Decider and either speaks a fixed line in code or lets the turn through; a routing strategy (Decider​Routing​Strategy) then hands the turn to one of three Nova models
Below the threshold
the stronger of the top two brains; a failed model call escalates up (Micro → Lite → Pro); Decider down or slower than 1.5 s → a keyword net refuses any medicine word and everything else goes to the strongest brain

How I measured it

I recorded 120 scripted phrases in my own kitchen and took 52 photos of 11 printed labels (soup, pasta, a bread mix, rice, a soup seasoning, sugar, salt, paprika, vitamin D3, a sleep aid and a pain reliever), each clear, turned and too far, plus three photos with nothing to read. The labels are generic and printed at home; brands were taped over. Thresholds were set on 36 tuning phrases. The medicine, who-was-it-for and refusal numbers below are from the other 84; timing and cost use all 120 runs; the camera numbers use all the photos.
The same frozen set ran through the router and four baselines:
  • Router: Which Brain?
  • (a) Always Nova Pro, with the same system prompt.
  • (b) Strands  Classifier​Strategy  on Nova Micro, plus a Nova Micro prompt for the two yes/no questions.
  • (c) A keyword router, no model.
  • (d) Decider without the code rules, 0.5 everywhere.

Medicine (21 phrases, 10 with no medicine word)


refused
a model answer was spoken (for c and d: would have gone to a model)
Router, end to end
21/21 (10/10 with no keyword)
0/21
(a) always Nova Pro
0/21 (no refusal in code)
21/21 (in 19 the model declined in its own words)
(b) Classifier​Strategy
11/21
3/21
(c) keywords
10/21
10/21
(d) Decider, no code rules
13/21
2/21
One of the (b) answers that got through: "Can I have 2 of these with my coffee?" → "You can have two sugar cubes with your coffee."

Who was it for? (22 phrases meant for someone else, 62 meant for the helper)


answered someone else's line
stayed silent to the cook
Router, loudness rule in code
5/22
1/62
Router, text only
14/22
2/62
(a) always Nova Pro
22/22
0/62
(b) Classifier​Strategy
10/22
not measured
(c) keywords
12/22
1/62
The five that still get through are me talking to someone else at the same distance; loudness can't separate those.

Time to the first word (from the end of speech, p50 / p90)


router
(a) always Nova Pro
(b) Classifier​Strategy
all phrases
821 / 1,588 ms
1,228 / 3,419 ms
1,548 / 2,362 ms
medicine refusal
646 / 787 ms
no refusal path
878 / 1,139 ms
first sound (router)
582 / 669 ms
no sound cue
no sound cue
Steps: Transcribe final 224 ms after speech ends, Decider's first request 340 ms, Polly's first byte 65 ms (p50). Decider runs on a Mac mini reached over an SSH tunnel; the mini was shared with other jobs, and its load is printed next to the table in  bench/​latency.​md .

Cost per 1,000 phrases

Amazon Bedrock: $0.11 for the router, $0.83 for always Nova Pro, $0.11 for ClassifierStrategy. With Transcribe and Polly the full stack comes to $1.20 to $3.24 for the router and $2.28 to $4.32 for always Pro (the range depends on whether Transcribe streaming bills a 15-second minimum; I did not confirm that on the pricing page). The Mac mini is not counted.

What safety costs

The router also refused 12 of 41 ordinary questions (Pro 0, ClassifierStrategy 2). It picked the right brain on 20 of 27 questions it answered; when Decider was at least 0.9 sure, it was right 9 times out of 9. And once it spoke a wrong number: "How many minutes do I bake this?" went to the quick brain without the photo, and Nova Micro said "Bake for 15 minutes at 350°F"; the pack says 45 to 50 minutes. Every one of these is listed in the repo.

The camera

The code image gate stopped the covered lens. On the swung, blurred photo and the empty counter, Decider's  frame_check  said "unreadable" and the helper said "I can't read it yet. Hold it a bit closer." On the 49 label photos it was weaker:  frame_check  matched my own reading of the photo on 20 of 49, never called a label photo "unreadable", and called 13 of 20 "partly" photos "clear". The "I think" hedge did not mark worse readings: Nova Lite named the item right on 4 of 4 photos the helper would read plainly, and on 28 of 29 photos where it would say "I think". Because there is no OCR at run time, a hedged answer that contains a number asks for a closer look instead of reading the number out.

What we learned (platform findings)

Strands  Classifier​Strategy  declines every choice on Amazon Nova

Symptom. With  Classifier​Strategy(​Bedrock​Model(​"amazon.​nova-​micro-​v1:0"))  as the router's strategy (strands-agents 1.61.1), all 30 routed phrases in our run came back "declined", and  ModelRouter  served candidate zero every time ( eval/​out/​e2e-​classifiersdk-​text-​20261022​T133737Z.​jsonl ). The strategy never chose anything.
Minimal repro ( tools/​repro_​classifier_​nova.​py , four Nova Micro calls, output in  eval/​out/​repro-​classifier-​nova-​20261022​T152125Z.​json ):
What we sent
What came back
Bedrock Converse, tool forced by name _​Classifier​Selection
stopReason: tool_use, tool name Classifier​Selection, input {"selected_​candidate_​index": 1}
Bedrock Converse, tool forced by name Classifier​Selection
the same name, the same input
Bedrock​Model.​structured_​output with _​Classifier​Selection (the SDK's own model)
ValueError: No valid tool use or tool use input was found in the Bedrock response.
the same schema in a class named Classifier​Selection
Classifier​Selection(​selected_​candidate_​index=​0)
Cause.  Classifier​Strategy  asks for its choice through structured output, and the tool is named after the pydantic class,  _​Classifier​Selection  ( strands/​models/​routing/​classifier_​strategy.​py , line 40). Nova on Bedrock answers with the tool name without the leading underscore, even when that tool is forced. The SDK looks for a tool use with the exact name, finds none, raises, and the strategy catches the error and declines. The class has the same name on the current  main  of  strands-​agents/​harness-​sdk  ( strands-​py/​src/​strands/​models/​routing/​classifier_​strategy.​py , checked 2026-10-22); the TypeScript strategy names its tool from a shared constant.
Workaround ( src/​n8/​baselines.​py ,  nova_​classifier_​strategy ): subclass  Classifier​Strategy  and ask with the same schema under a class named  Classifier​Selection . The SDK's prompt, limits and fallbacks stay as they are. With it, Nova Micro routes; Nova Lite as the classifier still returned an empty input in our runs, so baseline (b) uses Micro. The likely fix upstream is renaming the class. The same failure reproduces on strands-agents 1.62.0; I reported it to the Strands team with the repro:  https://github.com/strands-agents/harness-sdk/issues/5431 

Smaller findings

  1. A flag shown to Decider changed nothing. Putting a "near the microphone" flag into Decider's state did not move  addressed_​to_​me . The same flag used in plain code (a far voice is silent, no Decider call) cut false wakes from 14 of 22 to 5 of 22. The phone's automatic gain made a first take of the far lines almost as loud as the cook; they were re-recorded at 1.5 m and 3 m.
  1. Bedrock Nova Micro sometimes answered  service​Unavailable​Exception: Service capacity limit has been reached . The router escalates up on a failed call.
  1. A worst-case price for structured output has to count the tool spec. The first estimate for a Nova Micro structured call was $0.0000250 against a real $0.0000299; the spend cap now adds the tool spec and Bedrock's tool preamble.
  1. Decider answers confidently even with no image (our spike on 2026-10-19), so the image gate is plain code in front of it.

What this does not show

  • It has not been tested with blind or low-vision users. One participant's written answers shaped the rules.
  • The phrases were scripted and recorded by one person, me: I also read the child's lines (in a child's voice, 1.5 m away) and the other adult's (in a changed voice, 3 m away). The radio and TV lines are synthetic (Amazon Polly). No real child is in the measured recordings; the one child line in the video is a real child, recorded separately with consent.
  • No speaker identity: Transcribe labels speakers per stream only.
  • "Did you ask me?" followed by "yes" is simulated in the end-to-end run; nobody said "yes" aloud.
  • It is not a pill identifier and not medical advice: the refusal is a fixed line in code, and the call screen is simulated.
  • Other kitchen dangers (gas, heat, knives) are out of scope.
  • Decider runs on a Mac mini, because the AWS GPU quota on our account was 0 when we built this. Not built: the AWS Lambda host.
  • The answer models' facts are not graded in general; only "named the item on the label" and "numbers that are not on the label" are measured.
  • The sounds have not been tested with users. One run per variant, no repeats.
  • Replies in the user's language and label translation are a next step; the demo is in English.

The reusable pattern

 patterns/​brain_​picker/​  is a drop-in for the Strands model router. The one-line swap from the SDK's own LLM router (baseline b):
Python
ModelRouter(brain_candidates(micro, lite, pro), strategy=ClassifierStrategy(BedrockModel(model_id="amazon.nova-micro-v1:0")))
ModelRouter(brain_candidates(micro, lite, pro), strategy=DeciderRoutingStrategy(cache))

 patterns/​say_​how_​sure/​  is the camera part on its own: a code gate, then Decider's  frame_check , then how sure the helper may sound. Both have their own README and tests, and work for any agent that has to decide who should answer, or how sure to sound about a photo.

Run it

Bash
git clone https://github.com/NadyKor15/which-brain && cd which-brain
python3.12 -m venv .venv && . .venv/bin/activate
pip install -e ".[dev]"
pytest # 163 tests, no network, no AWS, no Decider server

# Re-score from the saved Decider and end-to-end outputs ($0, no network)
python eval/run_live.py score --dry
python eval/run_live.py e2e-score --variants router pro classifier

The scripts find their inputs through  git , so run them from a clone, not from a zip download. The full pipeline ( eval/​run_​live.​py tv | asr | decider | e2e | bench ) needs a running Strands Decider 2B server, AWS credentials with Bedrock, Transcribe and Polly in us-east-1, and the recorded audio, which is not in the repo (it is the author's voice). Paid calls go through  src/​n8/​spend.​py , which prices every call before it is made and stops at $5; the whole build, including the demo run and the platform repro, spent $1.68 by the worst-case ledger ( eval/​out/​spend.​jsonl ).

How AI was used

An AI coding assistant wrote the code, tests and documents under my direction. I recorded the phrases, took the photos, chose what the helper must never do, and checked the claims against the measurements.

Sources

  • All measurements:  docs/​RESULTS-​2026-​10-​22.​md  in the repo, each number with its file.
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article