Technical guide
Switching LLM providers mid-conversation in LangChain: what breaks, and why
LangChain's promise is that a model is a string: change anthropic:... to openai:... or ollama:... and the agent carries on. For a new conversation that is true. For a conversation already in progress it often is not, and the failure can lock the thread so that every later message fails. These are the four problems we hit making model switching safe for every Olano agent, from the one that bricks a thread to the one that only costs start-up time.
Why a running thread is different
A LangGraph thread is saved as a list of messages, and each message carries content in the shape the provider that wrote it produced. When the next turn runs, the whole list is sent to the current model. Switch provider mid-thread and the new model receives the old provider's messages on every turn from then on - not once, every time, because the checkpoint replays them. If the new provider cannot read even one of them, the thread is not failing intermittently. It is bricked.
Problem 1: content blocks the new provider rejects
Modern chat messages are not plain strings; their content is a list of typed blocks. Anthropic's models write thinking blocks for extended reasoning and tool_use blocks for tool calls, and accept images as {"type": "image", "source": {...}}. OpenAI's reasoning models produce reasoning items. Other providers use other shapes.
Each provider's integration converts LangChain messages into its own wire format, and some are strict. ChatOllama's converter accepts a handful of block types - text, tool use, image URLs and LangChain's standard data blocks - and raises ValueError: Unsupported message content type on anything else. So a thread that started on Claude with extended thinking, then moved to a local Ollama model, fails on every message from the switch onwards. The same happens with an image a user sent earlier, if your application stored it in Anthropic's format.
The fix is to sanitise at the conversion point rather than rewriting history. Subclass the chat model and override the one method that converts messages for the wire, so all of its entry points - invoke, stream and their async forms - pass through it. In it: drop reasoning blocks (no provider accepts another's reasoning back), translate images into the shape this provider understands, degrade anything else unknown to text, and pass supported blocks through untouched so a normal turn costs nothing extra. The checkpoint keeps the original messages; only what goes on the wire changes, so switching back loses nothing. Olano builds every Ollama model through such a subclass for exactly this reason.
Problem 2: a model with no known context window
Each LangChain chat model can carry a profile, a dictionary of capabilities that includes max_input_tokens. The profiles come from a table shipped inside each provider's package, so a model released after the package was published has none. Usually that only means a capability check is skipped. In Deep Agents it changes how conversations are summarised.
Deep Agents' summarisation sizes itself from the profile. With a known window it summarises when the conversation reaches 85% of the window and keeps the most recent 10%. Without one it falls back to fixed values: summarise at 170,000 tokens and keep the last 6 messages. Six messages is a few tool calls. The visible symptom is an agent on a brand-new model that forgets the start of a short session - nothing errors, it simply loses the thread.
Fix it at model construction: if the model's profile has no max_input_tokens, set it from a source you trust - your own model catalogue, or the provider's documentation. Better still, configure summarisation explicitly in tokens or fractions of the window so a missing profile cannot change behaviour silently. Olano attaches the window from its synced model catalogue whenever the package lacks one, and resolves summarisation from a per-deployment and per-agent policy, never from the message-count fallback.
Problem 3: the same setting, spelled differently
A parameter that works on one provider can be accepted and silently ignored on another.
| Setting | Most providers | Exceptions to watch |
|---|---|---|
| Maximum output length | max_tokens | Google's ChatGoogleGenerativeAI uses max_output_tokens; ChatOllama uses num_predict and has no max_tokens field at all. |
| Reasoning effort | A provider-specific parameter, where supported | Which levels exist varies by model, not only by provider; offering a level the model does not support either errors or is dropped. |
| Model availability check | Importing the integration package | Importing can be slow or have side effects; check with importlib.util.find_spec instead. |
The dangerous case is a setting that is accepted and ignored: an output cap set as max_tokens on a model that reads num_predict appears to work in configuration and does nothing at runtime. Map settings to each provider's spelling in one place, applied to every model you build, and test that the provider-specific field is set rather than that the generic one was passed. For reasoning effort, derive the offered levels from the model itself - its package profile first, your catalogue second - so no part of your interface can offer a level another part drops.
Problem 4: provider packages are not free to import
Supporting many providers means installing many integration packages, and some are heavy. Importing one can load hundreds of modules and take half a second or more, and in the past at least one registered a vendored protobuf definition that collided with another provider's package and crashed with a TypeError - not the ImportError that code guarding an optional import usually catches. Libraries above you can also import provider packages eagerly to support optional features.
Three habits keep this under control. Test whether a provider is installed with importlib.util.find_spec(), which does not execute the package. Import a provider's package only when an agent actually uses that provider. And measure: the memory and start-up time of a process that never touches a provider should not include it. In Olano, deferring provider imports that the agent framework made eagerly cut the first agent's start-up memory by more than half.
Retries are provider-specific too
One last difference that only shows under load. The retry behaviour you get depends on the SDK under each integration: the official OpenAI SDK retries 408, 409, 429 and 5xx responses and connection errors, other SDKs differ, and a gateway in front of several providers can relay an upstream failure as a 4xx that no SDK retries. Decide which failures are transient for your setup, retry those around the single model call with jittered back-off, and never retry a credit or billing refusal (it only delays an honest message) or an authentication error (it needs a person, not a loop). The streaming guide covers the one retry that must never happen: after the user has seen output.
A switching checklist
Before you let users change an agent's model mid-thread: sanitise content blocks at the conversion point for every strict provider; make sure every model has a context window, from its profile or your catalogue; set summarisation explicitly; map output and reasoning settings to each provider's spelling; and run a thread that has used every provider you support through every other one, with images and reasoning enabled, as an automated test.
FAQ
Why does ChatOllama raise 'Unsupported message content type'?
Its message converter accepts only a few content block types - text, tool use, image URLs and LangChain's standard data blocks. A thread that earlier ran on another provider can contain thinking, reasoning, tool result or Anthropic-style image blocks, and those are replayed on every turn. Sanitise the messages at the conversion point, by subclassing ChatOllama, rather than rewriting the saved thread.
Can I change the model of a LangChain agent in the middle of a conversation?
Yes, with care. The saved thread is sent to the new model on every turn, so content blocks the new provider cannot read must be translated or dropped on the way out, the new model needs a known context window, and provider-specific settings such as the output cap must be mapped to the new provider's parameter names.
Why does my Deep Agents agent forget the start of a short conversation?
If the model has no max_input_tokens in its LangChain profile, which happens for models newer than the provider package, Deep Agents falls back to summarising at 170,000 tokens and keeping only the last 6 messages. Set the model's context window explicitly, or configure summarisation in tokens or fractions rather than relying on the fallback.
How do I set the maximum output tokens for Gemini or Ollama in LangChain?
Most chat models take max_tokens, but ChatGoogleGenerativeAI uses max_output_tokens and ChatOllama uses num_predict. ChatOllama has no max_tokens field, so a cap set under that name has no effect. Map the setting to each provider's own parameter in one place.
How should I check whether a LangChain provider package is installed?
Use importlib.util.find_spec() with the package's module name. It confirms the package is present without importing it, which avoids the start-up cost and any import-time side effects of provider packages your agent may never use.
Related reading
The rest of the LangChain series, and where to go next.
Powered by LangChain: how Olano is built
Which layer of the LangChain stack does what inside an Olano agent, and what Olano adds on top.
Debugging LangChain agents: a field guide
Debug mode, LangSmith traces, stream modes, state history, loop limits and fake models.
Debugging LangGraph checkpointers
Thread ids, lost memory after a restart, event-loop errors, Postgres setup, encryption and deletes.
Debugging LangChain streaming
Leaked tokens from nested model calls, garbled replies, missing paragraph breaks and dropped connections.
Multi-model AI agents
Why one business system ends up on several models, and how to choose per task.
Checked 13 October 2026 against LangChain 1.4, langchain-core 1.6, LangGraph 1.2 and Deep Agents 0.7. Olano is an independent company that builds on LangChain's open-source libraries; it is not affiliated with or endorsed by LangChain, Inc. Library behaviour changes between releases, and the LangChain documentation is the primary source. If we have described something wrongly, write to support@olano.ai and we will correct this page.
Want model choice without the migration bugs?
Every Olano agent can change model from the dashboard without losing its threads. Tell us which models you use today and we will say what moving would look like.