Repository navigation
Conversation
…te the no_think strategy by model
|
Thanks for the contribution. Before we change the fallback behavior, could you provide a real-API before/after reproduction showing that this PR turns a failing request into a successful structured response? The current Gemini regression test increases the number of failed attempts from 4 to 16, but the request still fails. This verifies control flow, rather than demonstrating that the additional fallback attempts are useful. Please also clarify the need for the Finally, making all |
|
Withdrawing this PR — see #3612 for the full reply. You're right that the regression test only shows the ladder continuing (4 → 16 attempts), not that any fallback actually succeeds. I can't produce a real-API before/after from my environment (no Gemini credential, and The third point is fair as well: treating all Closing both. Thanks for the review. |
AgentScope Version
2.0.12dev (main @
2350af9)Description
GeminiChatModelis the only mainline provider without a_get_structured_output_fallback_exceptionsoverride, and its_get_retryable_exceptionsreturns the wide(google.genai.errors.APIError,)(model/_gemini/_model.py:250-258) — the parent of bothClientError(4xx) andServerError(5xx). In the structured-output ladder, the retryable check runs before the fallback check, and retry-exhaustion raises unconditionally (model/_base.py:582). So any 4xx aborts the whole ladder — theauto/no_think/nonestrategies are never tried. Every other provider declares a narrow retryable set whose members never intersect its fallback tuple, so 4xx falls through for them.Changes
model/_base.py(give-up branch): when a retryable exception exhausts its retries but is also fallback-eligible, walk the ladder instead of raising. Providers whose retryable and fallback sets are disjoint (all but Gemini today) are unaffected — the new branch is unreachable for them. A purely transient error that is not fallback-eligible still raises as before.model/_gemini/_model.py: declare_get_structured_output_fallback_exceptions→(errors.ClientError,)so 4xx switches strategies (5xx stay retryable).model/_gemini/_model.py: implement_get_disable_thinking_kwargs, the same gap [Bug]: Ollama structured-output fallback never tries no_think — _get_disable_thinking_kwargs is not overridden #3583/fix(ollama): implement _get_disable_thinking_kwargs so structured-output fallback can disable thinking #3588 fixed for Ollama, gated by model — 2.5 Flash / Flash-Lite acceptthinking_budget: 0, but the pro models reject it with 400 and Gemini 3 deprecatesthinking_budget, so those return{}and keep the server default.Complementary to #3523 (tri-state
thinking_enable): that fix stopped out-of-the-box budget-0 failures for pro models; this adds the structured-output no_think step for the models that support it.Open question for maintainers: with the give-up branch consulting the fallback tuple, a 429 (also a
ClientError) now falls to the next strategy after its retries instead of aborting — bounded extra calls to a rate-limited endpoint. If that is undesirable, the alternative is gating the no_think kwargs more narrowly and leaving the base branch untouched, at the cost of keeping the abort for schema-type 4xx.How to test
Regression cases added to the existing test files:
tests/model_base_test.py::StructuredOutputRetryableFallbackTest— an exception that is both retryable and fallback-eligible walks the ladder after exhausting retries (fails onmain: the ladder aborts);tests/model_gemini_test.py::GeminiStructuredFallbackTest— a mocked 400 walks all four strategies (len(attempts) > (max_retries + 1) * 2; fails onmainwith4 not greater than 8), plus assertions pinning the fallback-exception tuple and the model-gated no_think kwargs.python -m pytest tests/model_base_test.py tests/model_gemini_test.py # 24 + 43 passed.Fixes #3612
Checklist