Skip to content
dgem has moved to github.com/GoogleCloudPlatform/dgem. Docs are moving to googlecloudplatform.github.io/dgem; this site stays up during the move.

EXP-23: dgem vs Strands Decider 2B (Model Comparison)

The first comparison run under the standard process in Comparing dgem with Another Decision Model. Evidence level E2 (lab head-to-head) on every suite, E3 on the frozen sets, and E1 for Strands’ own published JevBench run.

  • Date: 2026-10-03.
  • Strands Decider 2B v19:
    • Weights: StrandsAgents/strands-decider-2B-hobson-v19 @ bb282d7.
    • Code: strands-labs/strands-decider @ 890947e.
    • Base: Qwen/Qwen3.5-2B-Base @ b1485b2.
    • Calibrated checkpoint as shipped, 4,096-token window.
    • Served on Cloud Run, 1× RTX PRO 6000.
    • Profile: benchmarks/competitors/strands-decider-2b.json.
  • dgem:
    • Serving image v0.2.0 (027b68e) on the Vertex AI G4 dedicated endpoint (1× RTX PRO 6000), samples=1.
  • Receipts: benchmarks/runs/20261003-compare-strands-v19.
    • The run uses matrix v2 format (report.md and summary.json there are regenerated by scripts/bench_matrix.py report).

  1. dgem is more accurate on general decisions. The two are level on tasks Strands was trained on.
    • JevBench public (231 items, 3 runs): dgem 194 / 194 / 195, Strands 169 / 169 / 169 (McNemar p = 3.5e-4). On the hard tier (111 items) dgem scores 67% and Strands 50%.
    • On items from datasets in Strands’ training mix (n = 142): Strands 85.9%, dgem 85.2%.
    • On items with no known relation to its training data (n = 2,346): dgem 72.5%, Strands 62.7%.
    • Frozen sets (one scored run each): MASSIVE (51 languages) dgem 82.8% vs 67.2%; XNLI dgem 70.0% vs 63.7%; typed-decisions dgem 71.8% vs 60.2%.
  2. The comparison found a dgem defect.
    • Two yes/no questions in one request whose correct answers have opposite polarity tend to get the same answer.
    • On a 51-case tool-call gate built from Strands’ own agent example, dgem’s two answers matched in 34–40 cases (gold: 7) and it scored 58%, against 86% for Strands.
    • Asked one question per request, dgem scores 100 of 102.
    • Now PROP-19 and the matrix v2 suite gate_mixed_noul.
  3. Calibration: Strands is cautious, dgem is sharp but overconfident off its development suites.
    • On JevBench, Strands has the lower ECE (0.048 vs 0.071). dgem has the lower Brier score (0.224 vs 0.348) and the higher AUROC (0.877 vs 0.806).
    • With one held-out temperature (T ≈ 1.5), dgem’s pooled ECE falls from 0.069 to 0.028. Strands’ falls from 0.037 to 0.031.
    • Out of domain, Strands rarely reaches 0.9 confidence (XNLI 0.1% of answers), while raw dgem is 74% correct at ≄ 0.9 on XNLI. See PROP-20.
  4. Latency: Strands is faster on short inputs, dgem on long inputs, many questions and under load.
    • Server p50 for one question over about 200 tokens: Strands 34 ms, dgem 54 ms.
    • Over about 3,800 tokens: Strands 118 ms, dgem 62 ms. The crossover is about 1,700 tokens.
    • Peak throughput with 5 questions per request: dgem 321 decisions/s, Strands 66.
  5. Determinism and cold start favour Strands.
    • Strands returned identical probabilities on all 1,509 repeated requests. dgem changed 6.4% of answers.
    • Strands cold-starts in 38 s on Cloud Run.
  6. Strands’ own numbers reproduce.
    • The official JevBench harness at the commit Strands pinned matches its published per-task predictions on 229 of 231 tasks (169 correct vs 167 published).

Strands Decider 2B v19dgem
ModelQwen3.5-2B torso (1.9B dense), LM head removedDiffusionGemma 26B-A4B MoE (3.8B active), NVFP4
Decision trainingRank-16 LoRA plus a ~1M-parameter pointer head on 21 public short-task datasets plus multi-step and generated dataNone (zero-shot, policy templates)
ReadoutPointer head; each question scored independently over a shared state prefixLetter readout per slot; all questions read jointly on one canvas
Option limit25526 natively; more through dgem systemone serve bracket routing
Calibration as servedTemperature per question type, fitted on its own held-out short tasksRaw restricted-softmax probabilities
Hardware hereCloud Run, 1× RTX PRO 6000Vertex AI G4, 1× RTX PRO 6000
  • Same requests: both models received the same /v1/systemone bodies.
  • Same scoring: one scorer recomputes every metric from the returned distributions. We never use the servers’ confidence fields.
  • Runs: core suites ran 3 times per model, in parallel. The frozen sets ran once on Strands (it is deterministic) and twice on dgem.
  • Latency client: in the same region, with keep-alive HTTPS.

Preflight finding. The stock strands-decider serve returned different answers under concurrent requests: one item moved by 0.82 probability, while serial runs were identical. All Strands results therefore come from the stock server plus a lock around the engine’s evaluate(); the lock changes no numerics. This is why the process now starts with scripts/compare/preflight.py.

SuitenStrands’ exposure (data/sources.md)
JevBench public231not trained on (Strands ranks itself on it)
calibration suite507 of 15 subsets trained on, 4 near
intents (banking77, clinc150 slices)60trained (train split; our items are test rows)
tool-call gate (new, ours; author-labelled)51 × 2unseen
typed-decisions test2,000 decisionsunseen
MASSIVE test, 51 languages5,100English is its calibration set; others near
XNLI test, 15 languages4,500near (MNLI trained)
option order739 × 4 orderingsemotion and MASSIVE-en are its calibration sets

SuiteStrands v19dgemPaired (run 1)
JevBench, 3 runs169 / 169 / 169194 / 194 / 195dgem only right 36, Strands only right 11, p = 3.5e-4
JevBench, official harness169191 / 191 / 195
JevBench easy / standard / hard (mean of 3)48 / 65 / 5648 / 71.7 / 74.7
calibration suite38 / 38 / 3847 / 45 / 46p = 0.012
intents ≀ 26 options53 / 53 / 5352 / 51 / 52p = 1
intents with banking77 at 30 options52 / 52 / 52 (native)48 / 49 / 47 (bracket routing)p = 0.34
typed-decisions60.2%71.8% / 72.3%
MASSIVE, 51 languages67.2%82.8% / 82.3%dgem ahead on 50 languages, tied on English
XNLI, 15 languages63.7%70.0% / 69.9%

By Strands’ training exposure (first run, same items for both):

ExposurenStrandsdgem
trained (same dataset)14285.9%85.2%
its calibration set (MASSIVE-en)10089.0%89.0%
near (related task trained)9,51565.3%76.7%
unseen2,34662.7%72.5%
  • JevBench families, largest dgem leads (mean of 3 runs): multi_hop +5.3, long_policy +5.0, judge_hard +3.0, policy +3.0, adversarial +3.0.
  • Strands leads on ambiguous (−1.0) and tradeoff (−0.3).
  • MASSIVE: Strands’ weakest languages are low-resource scripts, e.g. Burmese 0.27 vs 0.90 and Amharic 0.34 vs 0.76.

Pool A = JevBench + calibration suite + intents ≀ 26, run 1, n = 341. Held-out = 5-fold temperature fitted out of sample.

Strands v19dgem
ECE10 as served0.0370.069
ECE10, held-out global temperature0.031 (T ≈ 1.05)0.028 (T ≈ 1.5)
Brier (multiclass)0.3330.215
AUROC (confidence vs correct)0.7870.852
Answers at ≄ 0.9 / accuracy there31% / 96.3%79% / 94.8%
Accuracy at 80% coverage82.8%94.5%

Out of domain, the two fail in opposite directions:

SuiteStrands: ECE / AUROC / share at ≄ 0.9dgem: ECE / AUROC / share at ≄ 0.9 (accuracy there)
typed-decisions0.096 / 0.626 / 3%0.180 / 0.771 / 69% (82.6%)
MASSIVE0.142 / 0.871 / 55%0.101 / 0.914 / 81% (92.8%)
XNLI0.035 / 0.685 / 0.1%0.227 / 0.616 / 78% (74.2%)
  • dgem wants T ≈ 1.5 overall and a larger temperature for yes/no questions (1.6–1.9 in pool A, about 3 with the gate suite included).
  • Strands’ shipped temperatures transfer well to JevBench. A per-bucket refit still helps it on long option lists (T ≈ 1.5) and score items (T = 0.5).

5. The tool-call gate and dgem’s cross-slot coupling

Section titled “5. The tool-call gate and dgem’s cross-slot coupling”

The gate suite generalizes Strands’ agent example (examples/strands/tool_call_intervention.py) to 51 authored cases, using their exact question wording, true/false criteria and state rendering. There are three kinds of case:

KindMeaningargs_groundedpremature
Ggrounded and ready to callyesno
Uthe tool argument was guessednoyes
Agrounded, but something is left to confirmyesyes
Mean correct of 3 runsStrandsdgem
args_grounded G (21) / U (23) / A (7)20 / 23 / 310.3 / 23 / 3.7
premature G (21) / U (23) / A (7)14 / 22 / 621 / 1.0 / 0.7
both answers the same label (gold 7 of 51)1134–40

Post-hoc diagnostics (one run each, designed after the result):

Variantdgem correct of 102dgem: same label in both answers
both questions in one request5936
one question per request1005
both in one request, no true/false criteria6831
dgem systemone serve --noul-mode choice9510
  • On typed-decisions (200 yes/no pairs in one request), dgem’s rate of matching answers equals gold (138 vs 139). The defect needs related wording with opposite answers.
  • Strands is immune by construction: each question is evaluated independently. The flip side is that it cannot use a real dependency between questions.

Measured from a Cloud Run job in the same region, 100 requests per mode.

InputStrands server / wall p50 (ms)dgem server / wall p50 (ms)
~200 tokens, 1 question34 / 4454 / 62
~1,000 tokens42 / 5757 / 68
~2,000 tokens65 / 8058 / 69
~3,800 tokens118 / 13262 / 74
~500-token state, 1 / 5 / 10 / 20 yes/no questions35 / 72 / 73 / 8855 / 56 / 58 / 59
Throughput (≄ 256 requests per cell)Strandsdgem
1 question, 1 / 16 / 32 workers22.6 / 27.3 / 27.4 req/s16.1 / 83.9 / 83.5 req/s
5 questions, peak66 decisions/s321 decisions/s
cold start on Cloud Run38 s (21 s of it in the first request, which looks like kernel compilation)none on the dedicated endpoint; about 2.5 min on Cloud Run
  • Strands’ time grows linearly with input length. A request with more than one question pays a second forward pass, after which extra questions are nearly free.
  • dgem’s time is dominated by fixed denoising steps.
  • Strands’ stock server serves one request at a time; dgem batches inside vLLM.
  • On the same GPU, dgem’s cost per decision at saturation is 3–5× lower. Strands can also run on much cheaper hardware (CPU, Mac), which was not measured here.
  • Measurement note. A first latency pass caught transient load on the shared dgem endpoint (about 100–120 ms on five modes). Those modes were repeated, and both passes are in the study receipts.

  • Size class. 1.9B dense vs 26B-A4B MoE: this is not a same-size comparison. The in-domain parity shows what fine-tuning buys a small model; the out-of-domain gap shows what a large zero-shot base buys.
  • Hardware. Strands targets RTX 3090, Mac and CPU deployments. Both models here ran on an RTX PRO 6000.
  • The gate suite is ours: n = 51, labelled by the author, not independently reviewed. The coupling finding rests on the diagnostics, not on the headline count.
  • dgem nondeterminism (6.4% of answers change between identical requests) means single dgem runs carry about ±3 items of noise on JevBench.

#FindingTypeDestination
1Two yes/no answers with opposite polarity collapse to one label on one canvasBug + hypothesisissue; PROP-19
2No suite would have caught (1)Coveragematrix v2 gate_mixed_noul, gate_mixed_noul_single
3Raw confidence too high off the development suites; yes/no needs a larger THypothesisPROP-20
4A small fine-tuned model matches dgem in its own domainHypothesisPROP-21, PROP-22
56.4% answer changes between identical requestsHypothesisPROP-23
6Wide options lose to native 30-option handlingHypothesisPROP-24
7First-shown bias on emotion (45% vs 30.5% gold)HypothesisPROP-26
8Calibration and intent suites could not run on a competitorCoveragematrix v2 calib_systemone, intents_systemone; tier TC

Upstream feedback for Strands Decider:

  • The server’s results under concurrent requests (and a lock as the minimal fix).
  • Warming kernels at boot to shorten the first request.

Terminal window
scripts/compare/preflight.py --competitor strands=<STRANDS_URL>#profile=strands-decider-2b
scripts/bench_matrix.py --matrix benchmarks/matrix/matrix_v2.json run --tier TC \
--target dgem=<VERTEX_INVOKE_BASE> --baseline dgem \
--competitor strands=<STRANDS_URL>#profile=strands-decider-2b --competitor-workers 1 --label compare-strands
scripts/compare/report.py benchmarks/runs/<date>-compare-strands

The receipts in benchmarks/runs/20261003-compare-strands-v19 were produced by the study harness that tier TC replaces, then exported into matrix format. A confirming TC run is queued in the register.