Using adaptive router with mixed Anthropic+Other providers #31973
Replies: 4 comments 1 reply
|
can i see your configuration? |
|
@suranjanotti The error you're referring to ("multi-turn thinking block") comes from Anthropic's conversation protocol, where thinking blocks are cryptographically signed and must be preserved across turns. Those signatures are part of the conversation state, so simply dropping or rewriting request parameters won't make an invalid conversation valid again. :contentReference[oaicite:0]{index=0} In your setup, the adaptive router is selecting between:
These providers have different conversation semantics. If one turn is handled by Anthropic and the next turn is routed to (or from) a different provider, the message history may contain provider-specific content (e.g. Anthropic thinking blocks) that another provider doesn't understand—or vice versa.
A few things I'd check
My suspicionFrom what I can tell, the adaptive router currently makes routing decisions per request, but I couldn't find documentation stating that it normalizes or removes provider-specific conversation artifacts (such as Anthropic thinking blocks) when switching providers mid-conversation. :contentReference[oaicite:2]{index=2} If that's the case, then this is less a configuration issue and more a limitation (or bug) when mixing providers with incompatible conversation formats. RecommendationIf you need multi-turn conversations today, I'd recommend keeping each conversation pinned to a single provider family (e.g. all Anthropic or all OpenAI-compatible) and using the adaptive router to select the provider at conversation start, rather than allowing it to switch providers between turns. If you can reproduce this with:
(or vice versa) and the only difference is the provider switch, then I'd consider that a strong candidate for a LiteLLM bug or unsupported edge case. One question: are you routing every turn through the adaptive router, or is only the initial request routed and subsequent turns intended to stay on the selected model? That distinction will help determine whether this is expected behavior or a routing regression. If this solves your problem, feel free to mark it as the accepted answer so others can find it easily. |
|
The issue is not What's actually happening When you use Claude with The The adaptive router breaks this in two ways:
Fix is to isolate extended thinking models into their own model group Do not mix Anthropic extended thinking models with other providers in the same adaptive router group. Create a dedicated group for thinking-enabled Claude calls: Then route thinking-enabled conversations exclusively to If you need redundancy for extended thinking calls, then use fallback only within Anthropic models of the same capability tier but not cross-provider: Why |
|
Building on @dlanov's answer — that diagnosis is right. Two supplements that might help you confirm and mitigate: The fingerprint you'll see in your logsWhen the router mangles a thinking block, the failure surfaces as:
From the LiteLLM proxy client side you'll get a Minimal reproductionIsolates the failure mode without your full router config in the loop: import litellm
litellm.set_verbose = True
MODEL = "anthropic/claude-opus-4-5"
resp1 = litellm.completion(
model=MODEL,
thinking={"type": "enabled", "budget_tokens": 4000},
messages=[{"role": "user", "content": "Think about 2+2 briefly, then answer."}],
)
# grab the assistant reply verbatim, including the signed thinking block
prior = resp1.choices[0].message.model_dump()
# turn 2, correct path — echo the prior message unchanged
resp2_ok = litellm.completion(
model=MODEL,
thinking={"type": "enabled", "budget_tokens": 4000},
messages=[
{"role": "user", "content": "Think about 2+2 briefly, then answer."},
prior,
{"role": "user", "content": "Now do 3+3."},
],
)
# turn 2, the router-mangling scenario — strip content blocks a naive router
# doesn't understand, watch it fail
mangled = dict(prior)
mangled["content"] = [b for b in prior["content"] if b.get("type") != "thinking"]
resp2_broken = litellm.completion( # raises BadRequestError with "thinking" in the body
model=MODEL,
thinking={"type": "enabled", "budget_tokens": 4000},
messages=[
{"role": "user", "content": "Think about 2+2 briefly, then answer."},
mangled,
{"role": "user", "content": "Now do 3+3."},
],
)If Migrating a conversation that's already in the broken stateIf a running conversation is already mangled (mixed history, some thinking blocks preserved, some dropped), you can't retroactively repair it — Anthropic validates against the current history the model sees. Cleanest recovery: strip all |
Uh oh!
There was an error while loading. Please reload this page.
Hi!
Has anyone managed to make the adaptive router work with anthropic provider? It seems all responses from Anthropic are cryptographically signed and adding the drop_params or modify_params doesn't fix the multi-turn thinking block errors that Anthropic provider returns.
All reactions