This section uses middleware to select the model at run time: short conversations make Use the standard model, long conversations switch to the larger model.
The same Agent does not necessarily need to use the same model every time. For short questions, you can use the cheap and fast standard model, and for long context or complex tasks, you can switch to a stronger model.
| scene | model strategy |
|---|---|
| Short conversations, simple questions | Standard models, reducing costs and delays |
| Long conversations with lots of context | Large models or longer context models |
| high stakes reasoning | Stronger model or dedicated Use model |
@wrap_model_call can intercept the request before the model is called Use, and use request.override(model=...) to replace the model called Use this time.
Notebook Prepares two DeepSeek Model objects: standard_model and large_model.
from langchain.agents.middleware import wrap_model_call, ModelRequest, ModelResponse
from typing import Callable
large_model = deepseek_model("deepseek-v4-pro")
standard_model = deepseek_model()Both variables here are LangChain chat model. The difference is only in the model name and the ability Configure.
Middleware reads request.messages and determines the length of the conversation based on the number of messages. Switch to large model after 10 messages.
@wrap_model_call
def state_based_model(
request: ModelRequest,
handler: Callable[[ModelRequest], ModelResponse],
) -> ModelResponse:
"""Select model based on State conversation length."""
message_count = len(request.messages)
if message_count > 10:
model = large_model
else:
model = standard_model
request = request.override(model=model)
return handler(request)Middleware still needs to adjust Use after modifying requesthandler(request), otherwise the model call Use will not continue to execute.
A default model is still passed when Agent Create, but the actual Use will be overwritten by middleware. The system prompts the Agent to play the role of an office intern.
agent = create_agent(
model=deepseek_model(),
middleware=[state_based_model],
system_prompt="You are roleplaying a real life helpful office intern.",
)The default model is Configure; middleware can be overridden conditionally before each model is called Use.
Notebook runs a short question and a long conversation with more than 10 messages respectively, and prints the response metadata.model_name, confirm whether the model is switched conditionally.
response = agent.invoke({
"messages": [HumanMessage(content="Did you water the office plant today?")]
})
print(response["messages"][-1].response_metadata["model_name"])
response = agent.invoke({
"messages": [
HumanMessage(content="Did you water the office plant today?"),
AIMessage(content="Yes, I gave it a light watering this morning."),
HumanMessage(content="Has it grown much this week?"),
AIMessage(content="It's sprouted two new leaves since Monday."),
HumanMessage(content="Are the leaves still turning yellow on the edges?"),
AIMessage(content="A little, but it's looking healthier overall."),
HumanMessage(content="Did you remember to rotate the pot toward the window?"),
AIMessage(content="I rotated it a quarter turn so it gets more even light."),
HumanMessage(content="How often should we be fertilizing this plant?"),
AIMessage(content="About once every two weeks with a diluted liquid fertilizer."),
HumanMessage(content="When should we expect to have to replace the pot?"),
]
})
print(response["messages"][-1].response_metadata["model_name"])Don't just read the answer text. Dynamic model logic should be explicitly verified through metadata, logs, or tracing.
wrap_model_callIt is the interception point before and after the model is adjusted to Use.request.overrideYou can replace the model used this time.