DS DevShelfHub Projects · AI tools
Tutorials / LangChain / Reference / Decorators / @before_model
Decorator langchain.agents

@before_model: Reference Guide

By DevShelfHub

Middleware hook running before model processes messages.

What is @before_model?

@before_model is a middleware decorator that registers a function to run before each language model call inside a LangChain agent. The hook receives the full agent state dict, can mutate it freely, and must return the (modified) state. This makes it the central extension point for controlling what the model sees — trimming conversation history to control token cost, injecting retrieved context from a vector store, adding system instructions dynamically, or blocking requests that violate access control rules.

The most common production use is message history trimming. Long agent conversations accumulate messages and eventually exceed the model's context window or inflate token costs. A @before_model hook that keeps only the last N messages solves this at the middleware layer without changing the agent's core logic. A subtler version uses a summarization approach: when the history exceeds a threshold, summarize the oldest messages into a single summary message and keep only that plus the recent messages.

RAG injection is another powerful use. You can extract the user's latest message from state["messages"][-1].content, run a retrieval query against a vector store, and prepend the retrieved context as a SystemMessage or HumanMessage before the model call. This pattern decouples retrieval from the main agent graph — the agent's nodes never need to know about the retrieval step. Like @after_model, each hook must return the state dict; multiple hooks compose in registration order.

Use Cases

  • Trim history
  • Inject RAG
  • Validate input
  • Optimize tokens
  • Cost control
  • Access control

Key Features

  • Pre-model hook
  • State access
  • Preprocessing
  • Token counting
  • RAG support
  • Composable

When NOT to Use

For post-processing—use @after_model.

Notes

Never replace the entire messages list with an empty list

state["messages"] = [] discards all history including the system prompt and tool results from prior turns. The model then has no context. Use negative indexing to keep a window: state["messages"] = state["messages"][-N:] preserves the most recent N messages while trimming the oldest.

RAG injection should preserve the system message at index 0

If your agent has a system message as the first message, injecting context at index 0 shifts the system message to index 1, which some models treat differently. Insert context at index 1 (after the system message): state["messages"].insert(1, SystemMessage(content=context)).

Token counting is character-approximate unless you use tiktoken

Rough budget checks using len(message.content) undercount non-ASCII text and overcount English by about 4×. For accurate token budgeting, use tiktoken: enc = tiktoken.encoding_for_model("gpt-4o-mini"); tokens = sum(len(enc.encode(m.content)) for m in msgs).

Hooks are synchronous — offload heavy retrieval to a background thread if needed

The middleware system is synchronous. A slow retrieval call in @before_model blocks the entire agent turn. If your retrieval takes more than ~100ms, consider caching the retrieval result or running it outside the agent loop and injecting the pre-fetched context into initial state.

Import

python
from langchain.agents import before_model

How to Apply

python
@before_model
def trim(state):
    state['messages'] = state['messages'][-10:]
    return state

What It Enables

  • Message trimming
  • Context injection
  • Validation
  • Token optimization

Code Examples

Trim history to last 10 messages

python
from langchain.agents import before_model
@before_model
def trim(state):
    state['messages'] = state['messages'][-10:]
    return state

Inject RAG context before model call

python
from langchain.agents import before_model
from langchain_core.messages import SystemMessage
@before_model
def inject_rag(state):
    query = state['messages'][-1].content
    docs = retriever.invoke(query)
    context = "\n".join(d.page_content for d in docs)
    state['messages'].insert(0, SystemMessage(content=f'Context:\n{context}'))
    return state

Token-budget guard using tiktoken

python
from langchain.agents import before_model
import tiktoken
enc = tiktoken.encoding_for_model("gpt-4o-mini")
def token_count(msgs):
    return sum(len(enc.encode(m.content)) for m in msgs)
@before_model
def budget_guard(state):
    while token_count(state['messages']) > 3000:
        state['messages'].pop(1)  # Remove oldest non-system
    return state

Integration Patterns

agent = create_agent(model, middleware=[hook])
Runs before invoke()

Common Mistakes

❌ @before_model def hook(s): s['msgs'] = [] # Lost context

✅ @before_model def hook(s): s['msgs'] = s['msgs'][-10:]

Browse the full LangChain API reference index to explore more classes, methods, and decorators, or start with the LangChain introduction tutorial for end-to-end context on building with @before_model and the wider framework.

@before_model FAQ

What does @before_model do in LangChain?

Middleware hook running before model processes messages. @before_model is a middleware decorator that registers a function to run before each language model call inside a LangChain agent. The hook receives the full agent state dict, can mutate it freely, and must return the (modified) state. This makes it the central extension point for controlling what the model sees — trimming conversation history to control token cost, injecting retrieved context from a vector store, adding system instructions dynamically, or blocking requests t…

Which package provides @before_model?

DevShelfHub documents @before_model from the langchain.agents package. Pin your installed LangChain version and match imports to the snippet on this page.

When should I use @before_model?

Use @before_model when your LangChain agents, workflows, or pipelines need the behavior described in this guide.

When should I avoid using @before_model?

For post-processing—use @after_model.

How do I apply @before_model in Python?

Apply @before_model as a decorator above your function definition. Import it from from langchain.agents import before_model and annotate the function you want to wrap. See the code examples on this page for a complete working snippet.

Where can I explore more LangChain API reference pages?

Open the LangChain API reference index on DevShelfHub to browse classes, methods, and decorators, each with runnable examples, parameters, common mistakes, and cross-links.