Skip to main content

Prebuilt middleware

LangChain provides prebuilt middleware for common use cases. Each middleware is production-ready and configurable for your specific needs.

Note

Using Deep Agents (create_deep_agent / createDeepAgent)? Middleware is added through the customization API instead.

Provider-agnostic middleware

The following middleware work with any LLM provider:

MiddlewareDescription
Tool errorCatch tool execution exceptions and convert them to error messages for the model.
Tool retryAutomatically retry failed tool calls with exponential backoff.
Model retryAutomatically retry failed model calls with exponential backoff.
Model fallbackAutomatically fallback to alternative models when primary fails.
SummarizationAutomatically summarize conversation history when approaching token limits.
Human-in-the-loopPause execution for human approval of tool calls.
Model call limitLimit the number of model calls to prevent excessive costs.
Tool call limitControl tool execution by limiting call counts.
PII detectionDetect and handle Personally Identifiable Information (PII).
To-do listEquip agents with task planning and tracking capabilities.
LLM tool selectorUse an LLM to select relevant tools before calling main model.
Provider tool searchDefer tools behind providers' server-side tool search, surfacing them on demand.
Shell toolExpose a persistent shell session to agents for command execution.
FilesystemProvide agents with a filesystem for storing context and long-term memories.
SubagentAdd the ability to spawn subagents.
Rubric grading (Beta)Apply LLM-as-a-judge grading so agents self-evaluate and iterate until a rubric is satisfied.
File searchProvide Glob and Grep search tools over filesystem files.
Context editingManage conversation context by trimming or clearing tool uses.
LLM tool emulatorEmulate tool execution using an LLM for testing purposes.

Tool error

Catch exceptions raised during tool execution and convert them into error ToolMessages that the model can see and recover from, instead of halting the agent run. Tool error is useful for the following:

  • Letting the model retry a failed tool call with corrected arguments.
  • Surfacing controlled, sanitized error messages instead of raw exception details.
  • Preventing unexpected tool exceptions from crashing the agent.

Note

Tool error middleware does not automatically retry failed calls. For retries, compose with Tool retry middleware placed inner (later in the middleware list) and configured with on_failure="error" so that exceptions reach the tool error middleware. See the full example below.

API reference: ToolErrorMiddleware

Note

ToolErrorMiddleware requires langchain>=1.3.14.

from langchain.agents import create_agent
from langchain.agents.middleware import ToolErrorMiddleware


def on_error(exc: Exception, request: ToolCallRequest) -> str | None:
    if isinstance(exc, ValueError):
        return f"`{request.tool_call['name']}` failed with {type(exc).__name__}."
    # propagate everything else


agent = create_agent(
    model="gpt-5.5",
    tools=[your_tools],
    middleware=[ToolErrorMiddleware(on_error)],
)

Configuration options

Tool error full example

Tool retry

Automatically retry failed tool calls with configurable exponential backoff. Tool retry is useful for the following:

  • Handling transient failures in external API calls.
  • Improving reliability of network-dependent tools.
  • Building resilient agents that gracefully handle temporary errors.

API reference: ToolRetryMiddleware

from langchain.agents import create_agent
from langchain.agents.middleware import ToolRetryMiddleware

agent = create_agent(
    model="gpt-5.5",
    tools=[search_tool, database_tool],
    middleware=[
        ToolRetryMiddleware(
            max_retries=3,
            backoff_factor=2.0,
            initial_delay=1.0,
        ),
    ],
)

Configuration options

Full example

Model retry

Automatically retry failed model calls with configurable exponential backoff. Model retry is useful for the following:

  • Handling transient failures in model API calls.
  • Improving reliability of network-dependent model requests.
  • Building resilient agents that gracefully handle temporary model errors.

API reference: ModelRetryMiddleware

from langchain.agents import create_agent
from langchain.agents.middleware import ModelRetryMiddleware

agent = create_agent(
    model="gpt-5.5",
    tools=[search_tool, database_tool],
    middleware=[
        ModelRetryMiddleware(
            max_retries=3,
            backoff_factor=2.0,
            initial_delay=1.0,
        ),
    ],
)

Configuration options

Full example

Model fallback

Automatically fallback to alternative models when the primary model fails. Model fallback is useful for the following:

  • Building resilient agents that handle model outages.
  • Cost optimization by falling back to cheaper models.
  • Provider redundancy across OpenAI, Anthropic, etc.

API reference: ModelFallbackMiddleware

from langchain.agents import create_agent
from langchain.agents.middleware import ModelFallbackMiddleware

agent = create_agent(
    model="gpt-5.5",
    tools=[],
    middleware=[
        ModelFallbackMiddleware(
            "gpt-5.4-mini",
            "claude-sonnet-4-6",
        ),
    ],
)

Note

Watch this video guide demonstrating Model Fallback middleware behavior.

Configuration options

Summarization

Automatically summarize conversation history when approaching token limits, preserving recent messages while compressing older context. Summarization is useful for the following:

  • Long-running conversations that exceed context windows.
  • Multi-turn dialogues with extensive history.
  • Applications where preserving full conversation context matters.

Note

Summarization is text-oriented context compression. It does not resize, downsample, or otherwise compress image/audio/video payloads. Recent messages retained by keep still include their original multimodal blocks, while older multimodal messages that are summarized are represented only by the generated text summary. For image-heavy applications, store media in a filesystem or object store and pass URLs or file references through message history.

API reference: SummarizationMiddleware

from langchain.agents import create_agent
from langchain.agents.middleware import SummarizationMiddleware

agent = create_agent(
    model="gpt-5.5",
    tools=[your_weather_tool, your_calculator_tool],
    middleware=[
        SummarizationMiddleware(
            model="gpt-5.4-mini",
            trigger=("tokens", 4000),
            keep=("messages", 20),
        ),
    ],
)

Configuration options

Full example

Human-in-the-loop

Pause agent execution for human approval, editing, or rejection of tool calls before they execute. Human-in-the-loop is useful for the following:

  • High-stakes operations requiring human approval (e.g. database writes, financial transactions).
  • Compliance workflows where human oversight is mandatory.
  • Long-running conversations where human feedback guides the agent.

API reference: HumanInTheLoopMiddleware

The middleware pauses once per model turn by default. Set interrupt_mode="per_call" to pause once per tool call, with each interrupt answered by its ID. See Set the interrupt mode.

Warning

Human-in-the-loop middleware requires a checkpointer to maintain state across interruptions.

from langchain.agents import create_agent
from langchain.agents.middleware import HumanInTheLoopMiddleware
from langgraph.checkpoint.memory import InMemorySaver


def your_read_email_tool(email_id: str) -> str:
    """Mock function to read an email by its ID."""
    return f"Email content for ID: {email_id}"

def your_send_email_tool(recipient: str, subject: str, body: str) -> str:
    """Mock function to send an email."""
    return f"Email sent to {recipient} with subject '{subject}'"

agent = create_agent(
    model="gpt-5.5",
    tools=[your_read_email_tool, your_send_email_tool],
    checkpointer=InMemorySaver(),
    middleware=[
        HumanInTheLoopMiddleware(
            interrupt_on={
                "your_send_email_tool": {
                    "allowed_decisions": ["approve", "edit", "reject"],
                },
                "your_read_email_tool": False,
            }
        ),
    ],
)

Tip

For complete examples, configuration options, and integration patterns, see the Human-in-the-loop documentation.

Note

Watch this video guide demonstrating Human-in-the-loop middleware behavior.

Model call limit

Limit the number of model calls to prevent infinite loops or excessive costs. Model call limit is useful for the following:

  • Preventing runaway agents from making too many API calls.
  • Enforcing cost controls on production deployments.
  • Testing agent behavior within specific call budgets.

API reference: ModelCallLimitMiddleware

from langchain.agents import create_agent
from langchain.agents.middleware import ModelCallLimitMiddleware
from langgraph.checkpoint.memory import InMemorySaver

agent = create_agent(
    model="gpt-5.5",
    checkpointer=InMemorySaver(),  # Required for thread limiting
    tools=[],
    middleware=[
        ModelCallLimitMiddleware(
            thread_limit=10,
            run_limit=5,
            exit_behavior="end",
        ),
    ],
)

Note

Watch this video guide demonstrating Model Call Limit middleware behavior.

Configuration options

Tool call limit

Control agent execution by limiting the number of tool calls, either globally across all tools or for specific tools. Tool call limits are useful for the following:

  • Preventing excessive calls to expensive external APIs.
  • Limiting web searches or database queries.
  • Enforcing rate limits on specific tool usage.
  • Protecting against runaway agent loops.

API reference: ToolCallLimitMiddleware

from langchain.agents import create_agent
from langchain.agents.middleware import ToolCallLimitMiddleware

agent = create_agent(
    model="gpt-5.5",
    tools=[search_tool, database_tool],
    middleware=[
        # Global limit
        ToolCallLimitMiddleware(thread_limit=20, run_limit=10),
        # Tool-specific limit
        ToolCallLimitMiddleware(
            tool_name="search",
            thread_limit=5,
            run_limit=3,
        ),
    ],
)

Note

Watch this video guide demonstrating Tool Call Limit middleware behavior.

Configuration options

Full example

PII detection

Detect and handle Personally Identifiable Information (PII) in conversations using configurable strategies. PII detection is useful for the following:

  • Healthcare and financial applications with compliance requirements.
  • Customer service agents that need to sanitize logs.
  • Any application handling sensitive user data.

Note

With apply_to_output=True, PIIMiddleware also redacts streamed wire output—text deltas, tool-call args, tool outputs, and state snapshots—via a registered stream transformer. Requires langchain>=1.3.2. See Register transformers on middleware.

API reference: PIIMiddleware

from langchain.agents import create_agent
from langchain.agents.middleware import PIIMiddleware

agent = create_agent(
    model="gpt-5.5",
    tools=[],
    middleware=[
        PIIMiddleware("email", strategy="redact", apply_to_input=True),
        PIIMiddleware("credit_card", strategy="mask", apply_to_input=True),
    ],
)

Custom PII types

You can create custom PII types by providing a detector parameter. This allows you to detect patterns specific to your use case beyond the built-in types.

Three ways to create custom detectors:

  1. Regex pattern string - Simple pattern matching

  2. Custom function - Complex detection logic with validation

import re

from langchain.agents import create_agent
from langchain.agents.middleware import PIIMatch, PIIMiddleware


# Method 1: Regex pattern string
agent1 = create_agent(
    model="gpt-5.5",
    tools=[],
    middleware=[
        PIIMiddleware(
            "api_key",
            detector=r"sk-[a-zA-Z0-9]{32}",
            strategy="block",
        ),
    ],
)

# Method 2: Compiled regex pattern
agent2 = create_agent(
    model="gpt-5.5",
    tools=[],
    middleware=[
        PIIMiddleware(
            "phone_number",
            detector=re.compile(r"\+?\d{1,3}[\s.-]?\d{3,4}[\s.-]?\d{4}"),
            strategy="mask",
        ),
    ],
)

# Method 3: Custom detector function
def detect_ssn(content: str) -> list[PIIMatch]:
    """Detect SSNs with validation."""
    matches: list[PIIMatch] = []
    pattern = r"\d{3}-\d{2}-\d{4}"
    for match in re.finditer(pattern, content):
        ssn = match.group(0)
        # Validate: first 3 digits shouldn't be 000, 666, or 900-999
        first_three = int(ssn[:3])
        if first_three not in [0, 666] and not (900 <= first_three <= 999):
            matches.append({
                "type": "ssn",
                "value": ssn,
                "start": match.start(),
                "end": match.end(),
            })
    return matches

agent3 = create_agent(
    model="gpt-5.5",
    tools=[],
    middleware=[
        PIIMiddleware(
            "ssn",
            detector=detect_ssn,
            strategy="hash",
        ),
    ],
)

Custom detector function signature:

The detector function must accept a string (content) and return matches:

Returns a list of PIIMatch objects:

from langchain.agents.middleware import PIIMatch


def detector(content: str) -> list[PIIMatch]:
    return [
        {
            "type": "custom_type",
            "value": "matched_text",
            "start": 0,
            "end": 12,
        },
        # ... more matches
    ]

Tip

For custom detectors:

  • Use regex strings for simple patterns
  • Use RegExp objects when you need flags (e.g., case-insensitive matching)
  • Use custom functions when you need validation logic beyond pattern matching
  • Custom functions give you full control over detection logic and can implement complex validation rules

Configuration options

To-do list

Equip agents with task planning and tracking capabilities for complex multi-step tasks. To-do lists are useful for the following:

  • Complex multi-step tasks requiring coordination across multiple tools.
  • Long-running operations where progress visibility is important.

Note

This middleware automatically provides agents with a write_todos tool and system prompts to guide effective task planning.

API reference: TodoListMiddleware

from langchain.agents import create_agent
from langchain.agents.middleware import TodoListMiddleware

agent = create_agent(
    model="gpt-5.5",
    tools=[read_file, write_file, run_tests],
    middleware=[TodoListMiddleware()],
)

Note

Watch this video guide demonstrating To-do List middleware behavior.

Configuration options

LLM tool selector

Use an LLM to intelligently select relevant tools before calling the main model. LLM tool selectors are useful for the following:

  • Agents with many tools (10+) where most aren't relevant per query.
  • Reducing token usage by filtering irrelevant tools.
  • Improving model focus and accuracy.

This middleware uses structured output to ask an LLM which tools are most relevant for the current query. The structured output schema defines the available tool names and descriptions. Model providers often add this structured output information to the system prompt behind the scenes.

API reference: LLMToolSelectorMiddleware

from langchain.agents import create_agent
from langchain.agents.middleware import LLMToolSelectorMiddleware

agent = create_agent(
    model="gpt-5.5",
    tools=[tool1, tool2, tool3, tool4, tool5, ...],
    middleware=[
        LLMToolSelectorMiddleware(
            model="gpt-5.4-mini",
            max_tools=3,
            always_include=["search"],
        ),
    ],
)

Configuration options

Defer selected tools behind model providers' server-side tool search, so the model discovers them on demand instead of receiving every tool schema up front. Provider tool search is useful for:

  • Reducing context bloat when using many tools.
  • Improving tool selection accuracy by surfacing only relevant tools.

Note

Requires a model with server-side tool search support: Anthropic (Claude Sonnet 4+/Opus 4+/Haiku 4.5+) or OpenAI (gpt-5.5+). Other providers raise a ValueError.

API reference: ProviderToolSearchMiddleware

from langchain.agents import create_agent
from langchain.agents.middleware import ProviderToolSearchMiddleware

agent = create_agent(
    model="anthropic:claude-opus-4-8",
    tools=[get_weather, lookup_order],
    middleware=[
        ProviderToolSearchMiddleware(searchable_tools=["lookup_order"]),
    ],
)

Configuration options

Full example

Shell tool

Expose a persistent shell session to agents for command execution. Shell tool middleware is useful for the following:

  • Agents that need to execute system commands
  • Development and deployment automation tasks
  • Testing and validation workflows
  • File system operations and script execution

Warning

Security consideration: Use appropriate execution policies (HostExecutionPolicy, DockerExecutionPolicy, or CodexSandboxExecutionPolicy) to match your deployment's security requirements.

Note

Limitation: Persistent shell sessions do not currently work with interrupts (human-in-the-loop). We anticipate adding support for this in the future.

API reference: ShellToolMiddleware

from langchain.agents import create_agent
from langchain.agents.middleware import (
    ShellToolMiddleware,
    HostExecutionPolicy,
)

agent = create_agent(
    model="gpt-5.5",
    tools=[search_tool],
    middleware=[
        ShellToolMiddleware(
            workspace_root="/workspace",
            execution_policy=HostExecutionPolicy(),
        ),
    ],
)

Configuration options

Full example

Filesystem middleware

Context engineering is a main challenge in building effective agents. This is particularly difficult when using tools that return variable-length results (for example, web_search and RAG), as long tool results can quickly fill your context window.

FilesystemMiddleware from Deep Agents provides four tools for interacting with both short-term and long-term memory:

  • ls: List the files in the filesystem
  • read_file: Read an entire file or a certain number of lines from a file
  • write_file: Write a new file to the filesystem
  • edit_file: Edit an existing file in the filesystem
from langchain.agents import create_agent
from deepagents.middleware.filesystem import FilesystemMiddleware

# FilesystemMiddleware is included by default in create_deep_agent
# You can customize it if building a custom agent
agent = create_agent(
    model="claude-sonnet-4-6",
    middleware=[
        FilesystemMiddleware(
            backend=None,  # Optional: custom backend (defaults to StateBackend)
            system_prompt="Write to the filesystem when...",  # Optional custom addition to the system prompt
            custom_tool_descriptions={
                "ls": "Use the ls tool when...",
                "read_file": "Use the read_file tool to..."
            },  # Optional: Custom descriptions for filesystem tools
            tools=["read_file", "ls", "glob", "grep"],  # Optional: Allowlist restricting which filesystem tools are exposed
        ),
    ],
)

Short-term vs. long-term filesystem

By default, these tools write to a local "filesystem" in your graph state. To enable persistent storage across threads, configure a CompositeBackend that routes specific paths (like /memories/) to a StoreBackend.

from langchain.agents import create_agent
from deepagents.middleware import FilesystemMiddleware
from deepagents.backends import CompositeBackend, StateBackend, StoreBackend
from langgraph.store.memory import InMemoryStore

store = InMemoryStore()

agent = create_agent(
    model="claude-sonnet-4-6",
    store=store,
    middleware=[
        FilesystemMiddleware(
            backend=CompositeBackend(
                default=StateBackend(),
                routes={"/memories/": StoreBackend()}
            ),
            custom_tool_descriptions={
                "ls": "Use the ls tool when...",
                "read_file": "Use the read_file tool to..."
            }  # Optional: Custom descriptions for filesystem tools
        ),
    ],
)

When you configure a CompositeBackend with a StoreBackend for /memories/, any files prefixed with /memories/ are saved to persistent storage and survive across different threads. Files without this prefix remain in ephemeral state storage.

Subagent

Handing off tasks to subagents isolates context, keeping the main (supervisor) agent's context window clean while still going deep on a task.

The subagents middleware from Deep Agents allows you to supply subagents through a task tool.

from langchain.tools import tool
from langchain.agents import create_agent
from deepagents.middleware.subagents import SubAgentMiddleware


@tool
def get_weather(city: str) -> str:
    """Get the weather in a city."""
    return f"The weather in {city} is sunny."

agent = create_agent(
    model="claude-sonnet-4-6",
    middleware=[
        SubAgentMiddleware(
            default_model="claude-sonnet-4-6",
            default_tools=[],
            subagents=[
                {
                    "name": "weather",
                    "description": "This subagent can get weather in cities.",
                    "system_prompt": "Use the get_weather tool to get the weather in a city.",
                    "tools": [get_weather],
                    "model": "gpt-5.5",
                    "middleware": [],
                }
            ],
        )
    ],
)

A subagent is defined with a name, description, system prompt, and tools. You can also provide a subagent with a custom model, or with additional middleware. This can be particularly useful when you want to give the subagent an additional state key to share with the main agent.

For more complex use cases, you can also provide your own prebuilt LangGraph graph as a subagent.

from langchain.agents import create_agent
from deepagents.middleware.subagents import SubAgentMiddleware
from deepagents import CompiledSubAgent
from langgraph.graph import StateGraph

# Create a custom LangGraph graph
def create_weather_graph():
    workflow = StateGraph(...)
    # Build your custom graph
    return workflow.compile()

weather_graph = create_weather_graph()

# Wrap it in a CompiledSubAgent
weather_subagent = CompiledSubAgent(
    name="weather",
    description="This subagent can get weather in cities.",
    runnable=weather_graph
)

agent = create_agent(
    model="claude-sonnet-4-6",
    middleware=[
        SubAgentMiddleware(
            default_model="claude-sonnet-4-6",
            default_tools=[],
            subagents=[weather_subagent],
        )
    ],
)

In addition to any user-defined subagents, the main agent has access to a general-purpose subagent at all times. This subagent has the same instructions as the main agent and all the tools it has access to. The primary purpose of the general-purpose subagent is context isolation—the main agent can delegate a complex task to this subagent and get a concise answer back without bloat from intermediate tool calls.

Rubric grading

Note

RubricMiddleware requires deepagents>=0.6.5. It is in beta; the API may change in the future.

Some tasks have a clear definition of "done" that an agent cannot reliably hit on the first try. RubricMiddleware lets you declare what done looks like as a rubric and have the agent self-evaluate and iterate until the rubric is satisfied or a maximum iteration cap is hit.

API reference: RubricMiddleware

GoogleOpenAIAnthropicOpenRouterFireworksBasetenOllama

from deepagents import RubricMiddleware, create_deep_agent
from langgraph.checkpoint.memory import InMemorySaver

agent = create_deep_agent(
    model="google_genai:gemini-3.6-flash",
    middleware=[
        RubricMiddleware(
            model="anthropic:claude-haiku-4-5",
            max_iterations=3,
        ),
    ],
    checkpointer=InMemorySaver(),
)

For full configuration options, streaming events, and a complete code generation example, see Grading rubrics.

Provide Glob and Grep search tools over a filesystem. File search middleware is useful for the following:

  • Code exploration and analysis
  • Finding files by name patterns
  • Searching code content with regex
  • Large codebases where file discovery is needed

API reference: FilesystemFileSearchMiddleware

from langchain.agents import create_agent
from langchain.agents.middleware import FilesystemFileSearchMiddleware

agent = create_agent(
    model="gpt-5.5",
    tools=[],
    middleware=[
        FilesystemFileSearchMiddleware(
            root_path="/workspace",
            use_ripgrep=True,
        ),
    ],
)

Configuration options

Full example

Context editing

Manage conversation context by clearing older tool call outputs when token limits are reached, while preserving recent results. This helps keep context windows manageable in long conversations with many tool calls. Context editing is useful for the following:

  • Long conversations with many tool calls that exceed token limits
  • Reducing token costs by removing older tool outputs that are no longer relevant
  • Maintaining only the most recent N tool results in context

API reference: ContextEditingMiddleware, ClearToolUsesEdit

from langchain.agents import create_agent
from langchain.agents.middleware import ContextEditingMiddleware, ClearToolUsesEdit

agent = create_agent(
    model="gpt-5.5",
    tools=[],
    middleware=[
        ContextEditingMiddleware(
            edits=[
                ClearToolUsesEdit(
                    trigger=100000,
                    keep=3,
                ),
            ],
        ),
    ],
)

Configuration options

Full example

LLM tool emulator

Emulate tool execution using an LLM for testing purposes, replacing actual tool calls with AI-generated responses. LLM tool emulators are useful for the following:

  • Testing agent behavior without executing real tools.
  • Developing agents when external tools are unavailable or expensive.
  • Prototyping agent workflows before implementing actual tools.

API reference: LLMToolEmulator

from langchain.agents import create_agent
from langchain.agents.middleware import LLMToolEmulator

agent = create_agent(
    model="gpt-5.5",
    tools=[get_weather, search_database, send_email],
    middleware=[
        LLMToolEmulator(),  # Emulate all tools
    ],
)

Configuration options

Full example

Provider-specific middleware

These middleware are optimized for specific LLM providers. See each provider's documentation for full details and examples.

Anthropic

Prompt caching, bash tool, text editor, memory, and file search middleware for Claude models.

AWS

Prompt caching middleware for Amazon Bedrock models.

OpenAI

Content moderation middleware for OpenAI models.