strands-decider
3 TagsUpdated Apache-2.0by Strands Agents
Strands Agents' decision model: a LoRA and a pointer head on Qwen3.5-2B base. Each question is one row with a line per option, every option scored at the end of its own line, and the probabilities are calibrated with the authors' temperature for each question type. Up to 255 options.
ollaya run strands-decider --preset triage "I was charged twice for my subscription this month and want a refund."curl http://localhost:11435/api/decide \
-H "Content-Type: application/json" \
-d '{
"model": "strands-decider",
"state": "I was charged twice for my subscription this month and want a refund.",
"questions": {
"department": {
"type": "choice",
"instructions": "Which team should handle this?",
"criteria": {
"billing": "Payments, invoices and refunds",
"technical": "Bugs, errors and outages",
"account": "Login, profile and settings"
}
},
"refund": {
"type": "noul",
"instructions": "Is the customer asking for a refund?"
}
}
}'# Already using a TypeSafe SDK? Set TYPESAFE_BASE_URL=http://localhost:11435 instead.
import requests
response = requests.post(
"http://localhost:11435/api/decide",
json={
"model": "strands-decider",
"state": "I was charged twice for my subscription this month and want a refund.",
"questions": {
"department": {
"type": "choice",
"instructions": "Which team should handle this?",
"criteria": {
"billing": "Payments, invoices and refunds",
"technical": "Bugs, errors and outages",
"account": "Login, profile and settings"
}
},
"refund": {
"type": "noul",
"instructions": "Is the customer asking for a refund?"
}
}
},
)
answers = response.json()["answers"]
print(answers["department"]["choice"], answers["refund"]["noul"])const response = await fetch("http://localhost:11435/api/decide", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
model: "strands-decider",
state: "I was charged twice for my subscription this month and want a refund.",
questions: {
department: {
type: "choice",
instructions: "Which team should handle this?",
criteria: {
billing: "Payments, invoices and refunds",
technical: "Bugs, errors and outages",
account: "Login, profile and settings"
}
},
refund: {
type: "noul",
instructions: "Is the customer asking for a refund?"
}
}
}),
});
const { answers } = await response.json();
console.log(answers.department.choice, answers.refund.noul);Models
View all| Name |
|---|
| strands-deciderlatest4.8 GB · 4096 ctx · English |
| strands-decider:2b4.8 GB · 4096 ctx · English |
| strands-decider:2b-fp164.8 GB · 4096 ctx · English |
Readme
Strands Decider is a decision model by Strands Agents: a LoRA adapter on Qwen3.5-2B base plus a small pointer head, released under Apache-2.0 with its code at strands-labs/strands-decider. For each question it lays out the state, the question and one line per option, then scores every option at the end of its own line against the question, in one forward pass. It never generates text.
Models
| Tag | Base | Checkpoint | Params | JevBench public (upstream) |
|---|---|---|---|---|
strands-decider:latest, strands-decider:2b | Qwen3.5-2B base | v1, 2026-10 (strands-decider-2B-qwen3.5-v1-2610) | 2B | 180 / 231 tasks, ECE 0.072 |
The JevBench number is from the model card, served at a 4,096-token window. Measured by Ollaya on an RTX 5090: 0.745 macro accuracy on Bespoke Labs' public benchmark (3,880 questions, pooled ECE 0.039, 133 ms per question) and 0.616 on the 400 typed-decisions states.
Usage
ollaya run strands-decider --preset triage "My order never arrived and support ignores me. Refund me today or I'm switching to your competitor."Point any TypeSafe client at http://localhost:11435 and set the model to strands-decider.
Speed
- RTX 5090, through the HTTP API (Ollaya Bench): five-question triage requests take 98 ms at the median.
- State length: every question reads the whole state again, so the cost grows with the number of questions times the state length.
How it works
- One row per question. The state comes first, then the question with a header for its type and one numbered line per option, then
<answer>. The pointer head compares the last token of each option's line with the last token of the row. - Calibrated. The scores are divided by the temperature the authors fitted for each question type: 0.86 for choice, 1.83 for score and 1.07 for noul.
- Weights. The files download from Hugging Face, pinned to a commit and verified by sha256: the base weights from Qwen's repository, the adapter and
head.safetensorsfrom Strands Agents'. The adapter is applied at run time, not merged, so every file stays byte for byte the authors'. Ollaya hosts only the ONNX graph (10 MB). - Parity. Ollaya's Rust runtime matches upstream
strands_deciderin fp32: identical token rows and option positions, the same rejections and the same decision on all 650 test questions, probabilities within 2.8e-6. - fp16 tag.
strands-decider:2b-fp16computes the trunk in fp16 on NVIDIA GPUs, with the norms, the recurrent state, the attention softmax and the heads in fp32 (how): 72 ms for five questions on the RTX 5090 instead of 98 ms, 649 of 650 decisions the same asstrands-decider:2bon the parity set, and 0.615 on typed decisions. On a CPU usestrands-decider:2b.
Limits
- Choice criteria. Give
choicecriteria as an object of 2 to 255 options ({"refund": null, ...}). A plain list is rejected, as upstream does. Scores take 2 to 10 levels. - Context. A row is fitted to 4,096 tokens: a long question keeps its end, a long state its beginning. A request whose cut would remove an option is rejected.
- Not ported. Images (upstream's
--visionpath).