This section solves the problem of context expansion in long conversations: Use SummarizationMiddleware to compress old messages, Use before_agent middleware to delete messages that should not continue to enter the model.
The most core field in Agent's state is usually messages. The longer the conversation and the more messages there are, the more cost, latency, and context pollution go up. The first step in Module 3 is to learn to control message history.
| question | Performance | Plan for this lesson |
|---|---|---|
| Context too long | The token exceeds the limit or the Use adjustment becomes slow. | SummarizationMiddleware SummaryOld News |
| No Use tool message | After seeing the noise output, the model responded that it was off track. | RemoveMessage deletes the specified message |
| Multiple rounds of memory confusion | Old information and new questions interfere with each other | Keep only necessary messages and summaries |
Not all historical information is worth retaining. What needs to be retained is the "context still needed for the current task", not the complete transcript.
SummarizationMiddlewareAfter the message reaches the trigger condition, the Use model Put old messages are compressed into digests while retaining the most recent original messages.
from langchain.agents.middleware import SummarizationMiddleware
summarize_middleware = SummarizationMiddleware(
model=deepseek_model(),
trigger=("tokens", 100),
keep=("messages", 1),
)
agent = create_agent(
model=deepseek_model(),
checkpointer=InMemorySaver(),
middleware=[summarize_middleware],
)trigger=("tokens", 100)Indicates that Summary is triggered when the number of tokens exceeds the threshold;keep=("messages", 1)Indicates that the original text of the most recent message is retained.
Notebook constructs a fictional conversation: lunar capital, weather, miners, union strike. Finally, ask, “How would you respond if you were the new president?” This question requires old context, but not necessarily a complete verbatim history.
messages = [
HumanMessage(content="What is the capital of the moon?"),
AIMessage(content="The capital of the moon is Lunapolis."),
HumanMessage(content="What is the weather in Lunapolis?"),
AIMessage(content="Skies are clear, with a high of 120C and a low of -100C."),
HumanMessage(content="How many cheese miners live in Lunapolis?"),
AIMessage(content="There are 100,000 cheese miners living in Lunapolis."),
HumanMessage(content="Do you think the cheese miners' union will strike?"),
AIMessage(content="Yes, because they are unhappy with the new president."),
HumanMessage(content="If you were Lunapolis' new president how would you respond to the cheese miners' union?"),
]
response = agent.invoke(
{"messages": messages},
{"configurable": {"thread_id": "1"}},
)The final question relies on the preceding facts, but not on each original expression. A summary can preserve key facts while reducing context length.
The second example shows how to process state before calling Use on the model.@before_agentmiddleware reads the current messages and finds allToolMessage, then returnRemoveMessageinstructions to delete them.
from langchain.messages import RemoveMessage
from langchain.agents.middleware import before_agent
@before_agent
def trim_messages(state: AgentState, runtime: Runtime) -> dict[str, Any] | None:
"""Remove all the tool messages from the state"""
messages = state["messages"]
tool_messages = [m for m in messages if isinstance(m, ToolMessage)]
return {"messages": [RemoveMessage(id=m.id) for m in tool_messages]}RemoveMessage(id=...)Instead of a normal text message, this tells LangGraph to remove the message with the specified id from state.
In the Notebook device troubleshooting example, tool messages include noisy diagnostic text such as "blorp-x7" and "greeble". If the model saw all the raw tool output when the user last asked for temperature, it might be interfered with by unreliable or irrelevant information.
messages = [
HumanMessage(content="My device won't turn on. What should I do?"),
ToolMessage(content="blorp-x7 initiating diagnostic ping…", tool_call_id="1"),
AIMessage(content="Is the device plugged in and turned on?"),
HumanMessage(content="Yes, it's plugged in and turned on."),
ToolMessage(content="temp=42C voltage=2.9v … greeble complete.", tool_call_id="2"),
AIMessage(content="Is the device showing any lights or indicators?"),
HumanMessage(content="What's the temperature of the device?"),
]
agent = create_agent(
model=deepseek_model(),
checkpointer=InMemorySaver(),
middleware=[trim_messages],
)You can delete low-value tool logs, sensitive intermediate data, and API raw responses with messy formats, and only put necessary conclusions and keep them for the model.