feat(model_group): Thompson-sample intra-group live routing - #1034
feat(model_group): Thompson-sample intra-group live routing#1034seonghobae wants to merge 7 commits into
Conversation
Live serving selection (ModelGroupRouter.sampled_ranked_member_ids, wired in via _measured_member_order(sample=True) -> _refine_partition, which every _ranked_agents caller funnels through) now draws one Thompson sample per member from its own Beta(alpha, beta) posterior instead of comparing the posterior mean, for any member with at least one real observation. Admin/report reads (get_model_group, list_model_groups) keep calling _measured_member_order with the default sample=False, so they stay exactly deterministic. Traffic consequence: previously, once one group member edged ahead on the posterior-mean score, _all_ subsequent traffic to that group went to it -- a transient failure or a lucky first success could silently starve every sibling member of further observations forever. Now traffic spreads across close competitors in proportion to genuine posterior uncertainty: a member is picked with probability roughly equal to its probability of actually being the best (the classic Thompson Sampling exploration/exploitation balance), so a stronger member still wins most requests while a plausible sibling keeps getting enough real traffic to either confirm or disprove its early read. Members with zero observations are unaffected -- they keep sharing the exact neutral UNOBSERVED_MEMBER_SCORE, unsampled, so a group with no evidence yet still falls back to the caller's static order untouched. The Beta(0, x)/Beta(x, 0) degenerate case (a legal prior_alpha/beta of exactly 0.0 via update_prior, or a custom prior_resolver) falls back to the same closed-form posterior mean _score_locked already uses, instead of raising out of random.betavariate (`alpha and beta must be > 0`). Grounding: Thompson (1933), Biometrika 25(3-4); the empirical case for plain (untuned) Beta-posterior TS over posterior-reshaping in Chapelle & Li (2011), NeurIPS 24; the finite-time near-optimal regret bound for Beta-Bernoulli TS in Agrawal & Goyal (2012), COLT'12 -- confirming the large single-observation variance this ships with (win probability 5/6 for the true winner, dropping to ~1-in-600 in this repo's own success/failure + EWMA-latency score once one member has any timed success) is the intended exploration mechanism, not a defect to damp. Test reconciliation: 5 existing tests that observe exactly one success and one failure across a live-serving group -- ordering that is now sampled instead of deterministic -- seed orchestrator._group_router._rng with a fixed random.Random(0) (verified locally: the success member wins at that seed in every affected fixture) right before their observe_* calls, matching this file's existing convention of reaching into router internals directly. Every other group-bearing test in the repo was traced by hand and needs no change: either it asserts through ranked_member_ids/member_report/member_score directly (untouched methods), calls _measured_member_order positionally so sample defaults to False, has zero real observations on more than one group member (both stay at the shared UNOBSERVED_MEMBER_SCORE), resolves through a downstream price-ordered or single-member path that never reaches sampled_ranked_member_ids, or pins an exact provider model string outside group-alias resolution entirely. Three new unit tests exercise sampled_ranked_member_ids directly: the unobserved/neutral-score contract, the degenerate zero-alpha/beta fallback, and the general 1-in-6 exploration case (a seeded 200-trial win-rate check) that the higher-level integration tests don't have to carry. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Team Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Autonomous loop note: exact head
Called Generated by Claude Code |
There was a problem hiding this comment.
Pull request overview
OpenCode reviewed the current-head product diff. Coverage is a separate gate.
Changed files
contextual_orchestrator/model_group.py— Python module behaviorcontextual_orchestrator/orchestrator.py— Python module behaviordocs/papers/thompson-sampling-model-group-routing.md— operator or user guidancetests/test_model_group.py— regression suitetests/test_multimodal_model_group_http.py— regression suitetests/test_openrouter_uptime.py— regression suite
Changed behavior
flowchart LR
PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
Evidence --> S1["Python: model_group.py (2 files)"]
S1 --> I1["Python module behavior"]
I1 --> R1["Review risk: Python: model_group.py (2 files)"]
R1 --> V1["pytest plus coverage"]
Evidence --> S2["Docs: thompson-sampling-model-group-routing.md"]
S2 --> I2["operator or user guidance"]
I2 --> R2["Review risk: Docs: thompson-sampling-model-group-routing.md"]
R2 --> V2["docs review"]
Evidence --> S3["Test: test_model_group.py (3 files)"]
S3 --> I3["regression suite"]
I3 --> R3["Review risk: Test: test_model_group.py (3 files)"]
R3 --> V3["targeted test run"]
Findings
No source-backed product finding is synthesized from the coverage gate. A coverage miss belongs in the status comment.
- Head SHA:
b03f3b10211e188e81313cba5e1cf641991a6f71 - Workflow run: 33926041351
- Workflow attempt: 1
- Coverage gate:
failure
Review outcome
Coverage is a gate, not the review. This body reviews the changed product files.
Changed-File Evidence Map
flowchart LR
PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
Evidence --> S1["Python: model_group.py (2 files)"]
S1 --> I1["Python module behavior"]
I1 --> R1["Review risk: Python: model_group.py (2 files)"]
R1 --> V1["pytest plus coverage"]
Evidence --> S2["Docs: thompson-sampling-model-group-routing.md"]
S2 --> I2["operator or user guidance"]
I2 --> R2["Review risk: Docs: thompson-sampling-model-group-routing.md"]
R2 --> V2["docs review"]
Evidence --> S3["Test: test_model_group.py (3 files)"]
S3 --> I3["regression suite"]
I3 --> R3["Review risk: Test: test_model_group.py (3 files)"]
R3 --> V3["targeted test run"]
OpenCode Review Overview
Coverage evidence did not pass, so approval is blocked. The formal pull-request review is the source-backed diff review, not this status comment. |
Scope
Live model-group serving now uses Thompson-sampled per-member stability evidence while admin/report reads remain deterministic. The live score keeps this repository's existing physical quantity: sampled stability divided by measured EWMA latency. Members with no completed outcomes retain the existing neutral/static-order cold-start contract.
Exact identity
fa5446294ae7ae69f1c2958aa1ab6c071fa760bcb03f3b10211e188e81313cba5e1cf641991a6f71TDD / review repair
The original implementation was
ad00e1b7695ec153dfac015cba40b87084befa1b.A valid review finding showed that fractional prior replacement can create binary-float drift such as
0.9999999999999999; the prior implementation then truncated one completed Bernoulli outcome to zero and disabled sampled routing for that member.c8223a3e4f10c2c48396359abdbad7520b84e920reproduces the invariant violation after a1.0 -> 0.4prior refresh and asserts both report and routing observation counts remain exactly one.40a5cc41e4e10525e6fdb73f4a7b19682a083e24centralizes integer completed-outcome recovery in_outcome_countand uses it in bothmember_observation_countandmember_report.dabbe13ce5e90fa0e3f9650c42e25884e595b4c4addsdocs/papers/thompson-sampling-model-group-routing.mdwith APA-style primary publication references and implementation/acceptance mapping.The floating-count and research-artifact review threads are resolved on the current head. The research-artifact thread is resolved because the missing artifact itself is now present.
Research boundary
Grounding is Thompson (1933), Chapelle & Li (2011), and Agrawal & Goyal (2012). The COLT result is not claimed as a regret/optimality proof for this repository's composite
Beta stability sample / EWMA latencyscore; its theorem applies to the analyzed stochastic Bernoulli bandit setting. The repository-specific cold-start rule for unobserved members is also documented as a product policy rather than a consequence of Thompson-sampling theory. A buyer-facing optimality claim requires right-cleared traffic/replay evidence for the composite objective.Current gate state
No merge is authorized yet. On exact head
dabbe13c...:CodeQL PRrun33698259878:startup_failurebefore analysis evidenceTests33698258557: queuedSecurity Scan33698258578: queuedSecurity33698258735: queuedSAST Semgrep33698258659: queuedFuzz33698258508: queuedOSV-Scanner PR33698258920: queuedScorecard PR33698258504: non-terminalThe organization runner/control-plane evidence has been handed to canonical owner issue
ContextualWisdomLab/.github#712. This PR does not use no-op retriggers, force-push, self-approval, or required-check weakening. Ordinary merge waits for final exact-head terminal GREEN evidence and valid review resolution.Current exact-head gate
b03f3b10211e188e81313cba5e1cf641991a6f71fa5446294ae7ae69f1c2958aa1ab6c071fa760bc93 passed3399 passed, 2 skippedgit diff --check: passAll review threads are resolved. Fresh hosted Checks and independent current-head review remain required; no predecessor gate evidence transfers.