LangChain LangGraph
Module 1 Module 2 Module 3
Module 3 · Middleware and HITL
1 3.2 Managing Msgs
2 3.3 HITL
3 3.4 Dyn Models
4 3.4 Dyn Prompts
5 3.4 Dyn Tools
6 3.5 Email Agent
SUM Module Summary
HomeLangChainModule 3 · Middleware and HITL3.4 Dyn Models
📓 Notebook 📖 Explained
LANGCHAIN MODULE 3 · LESSON 3.4a

Dynamic Model Selection
wrap_model_call · request.override

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.

1 Why dynamic models are useful

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.

scenemodel strategy
Short conversations, simple questionsStandard models, reducing costs and delays
Long conversations with lots of contextLarge models or longer context models
high stakes reasoningStronger model or dedicated Use model
Core API

@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.

2 Prepare two models

Notebook Prepares two DeepSeek Model objects: standard_model and large_model.

Python
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()
Model objects

Both variables here are LangChain chat model. The difference is only in the model name and the ability Configure.

3 Switch models by message count

Middleware reads request.messages and determines the length of the conversation based on the number of messages. Switch to large model after 10 messages.

Python
@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)
The handler must be called

Middleware still needs to adjust Use after modifying requesthandler(request), otherwise the model call Use will not continue to execute.

4 Attach middleware to the Agent

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.

Python
agent = create_agent(
    model=deepseek_model(),
    middleware=[state_based_model],
    system_prompt="You are roleplaying a real life helpful office intern.",
)
Role of the default model

The default model is Configure; middleware can be overridden conditionally before each model is called Use.

5 Verify short and long conversations

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.

Python
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"])
Debugging approach

Don't just read the answer text. Dynamic model logic should be explicitly verified through metadata, logs, or tracing.

6 Lesson takeaway