Search⌘ K
AI Features

Customizing Agents with Middleware

Explore how to customize LangChain agents using middleware to extend default behaviors such as retrying failed tool calls, summarizing message history, logging model latency, and pausing for human approval. This lesson helps you integrate reusable middleware hooks into create_agent for more robust and flexible AI agent workflows.

create_agent constructs the model-and-tools loop that we previously implemented manually: invoke the model, execute any requested tools, and continue until the model returns no further tool calls. By default, the agent follows this standard loop. Middleware lets us extend it to log model calls, automatically retry transient tool failures, summarize or trim message history before it exceeds context limits, and pause configured tool calls for human review. A custom StateGraph could also implement these behaviors, but middleware lets us add them directly to the agent created by create_agent.

Why middleware?

Middleware exposes hooks at specific stages of the agent loop, allowing us to inspect, modify, or wrap model and tool execution. It provides an alternative to using the default behavior unchanged or implementing a custom StateGraph. We can retain create_agent while adding the required behavior through reusable middleware.

We pass middleware to create_agent as a list:

graph = create_agent(
model="openai:gpt-5",
tools=[get_weather],
middleware=[SomeMiddleware()],
)
Middleware is passed as a list to create_agent

Custom middleware supports two hook styles: node-style hooks that run at specific lifecycle points, such as before or after the agent or model, and wrap-style hooks that run around each model or tool call and control how the underlying handler executes.

Node-style hooks: before_model and after_model

before_model runs right before the model is called; after_model runs right after. The simplest way to write one is with a decorator:

from langchain.agents.middleware import before_model
@before_model
def log_before_model(state, runtime):
print(f"About to call the model with {len(state['messages'])} messages")
Logging the message count before every model call
  • Line 1: We import the before_model decorator from langchain.agents.middleware.

  • Lines 3–5: The decorated function receives the current state (the same dict-like state our hand-built nodes received) and a runtime object, and ...