How to Implement Memory Compression in AgentScope for Long Conversations
AgentScope's memory compression feature automatically summarizes older dialogue when token usage exceeds a configurable threshold, allowing ReAct agents to maintain extended conversations within model context limits while preserving recent interactions.
AgentScope provides a built-in memory compression mechanism that helps ReAct agents handle long conversations without hitting token limits. This feature, implemented in the ReActAgent class located in src/agentscope/agent/_react_agent.py, automatically triggers summarization of historical messages when the conversation exceeds a specified token threshold, storing the compressed summary for future context retrieval.
Architecture of Memory Compression in AgentScope
The memory compression system consists of several coordinated components that work together to manage long conversation contexts.
Core Components
-
ReActAgent.CompressionConfig– A Pydantic configuration class defined insrc/agentscope/agent/_react_agent.py(lines 107-173) that controls compression parameters including threshold, recent message retention count, prompts, models, and formatters. -
_compress_memory_if_needed– The orchestration method insrc/agentscope/agent/_react_agent.py(lines 1110-1175) that executes each reasoning iteration, determines whether compression is required, and coordinates the entire workflow. -
_BaseMemory– The abstract base class insrc/agentscope/memory/_working_memory/_base.py(lines 14-30) that maintains the_compressed_summarystring and providesupdate_compressed_summaryandupdate_messages_markmethods. -
Concrete Memory Implementations – In-memory, Redis, and SQLAlchemy backends all respect the
COMPRESSEDmark and prepend stored summaries when building prompts. The in-memory implementation is located insrc/agentscope/memory/_working_memory/_in_memory_memory.py(lines 73-91). -
Token Counter – User-supplied implementations of
TokenCounterBase(such asCharTokenCounter) defined insrc/agentscope/token/__init__.pythat estimate token usage for prompts.
Enabling Memory Compression in Your Agent
To activate memory compression, instantiate a CompressionConfig and pass it to your ReActAgent.
Step 1: Configure Compression
from agentscope.agent import ReActAgent
from agentscope.token import CharTokenCounter
compression_cfg = ReActAgent.CompressionConfig(
enable=True, # turn the feature on
trigger_threshold=2000, # token count that triggers compression
agent_token_counter=CharTokenCounter(),
keep_recent=3, # keep the latest 3 messages uncompressed
# optional: custom prompts / model / formatter
)
Step 2: Initialize the Agent
agent = ReActAgent(
name="Assistant",
sys_prompt="You are a helpful assistant.",
model=my_chat_model,
formatter=my_formatter,
compression_config=compression_cfg,
)
If you omit compression_model, the agent's main model will be used for summarization. Supplying a cheaper summarizer (such as gpt-3.5-turbo) reduces operational costs while maintaining performance.
How Memory Compression Works Step-by-Step
The _compress_memory_if_needed method in src/agentscope/agent/_react_agent.py orchestrates the compression workflow during each reasoning iteration.
-
Collect Uncompressed Messages – The method fetches all messages not already marked
COMPRESSEDfrom the working memory. -
Determine the Keep-Recent Window – It traverses the message list backward, preserving tool-use and result pairs intact until
keep_recentmessages are counted. -
Token-Count Check – The selected messages plus the system prompt are formatted, and
agent_token_counter.count(prompt)is invoked. If the count exceedstrigger_threshold, compression triggers. -
Build Compression Prompt – The system uses either the user-provided
compression_promptor the default hint, formatted withcompression_formatter(or the agent's main formatter). -
Call Compression Model – The LLM (or
compression_model) executes withstructured_model=self.compression_config.summary_schema, returning a structured object containing fields such astask_overview,current_state, etc. -
Render Summary – The structured fields are interpolated into
summary_templateto create a single<system-info>block. -
Store Summary and Mark Messages –
memory.update_compressed_summary(summary)saves the rendered block, andmemory.update_messages_mark(msg_ids, new_mark=_MemoryMark.COMPRESSED)tags the original messages for exclusion from future prompts. -
Subsequent Reasoning Calls – When the agent builds the next prompt, the compressed summary is automatically prepended (see the
if prepend_summary and self._compressed_summarybranch in concrete memory implementations such assrc/agentscope/memory/_working_memory/_in_memory_memory.py).
Customizing the Compression Output
You can tailor the summarization output by adjusting prompts, templates, and schemas.
Custom Prompts and Templates
Override compression_prompt to steer the summary style, and modify summary_template to change the markup structure:
compression_cfg = ReActAgent.CompressionConfig(
enable=True,
trigger_threshold=2000,
agent_token_counter=CharTokenCounter(),
compression_prompt="Summarize the conversation history focusing on user goals and blockers.",
summary_template=(
"<system-info>\n"
"## Task Overview\n{task_overview}\n"
"## Current State\n{current_state}\n"
"</system-info>"
),
)
Custom Schema
Provide a Pydantic model subclassing BaseModel if you need additional fields:
from pydantic import BaseModel, Field
class MySummarySchema(BaseModel):
task_overview: str = Field(..., max_length=300)
current_state: str = Field(..., max_length=300)
risks: str = Field(..., max_length=200) # extra field
compression_cfg = ReActAgent.CompressionConfig(
enable=True,
trigger_threshold=2000,
agent_token_counter=CharTokenCounter(),
summary_schema=MySummarySchema,
summary_template=(
"<system-info>"
"# Overview\n{task_overview}\n"
"# State\n{current_state}\n"
"# Risks\n{risks}\n"
"</system-info>"
),
)
Complete Implementation Example
The following example demonstrates a full setup with an async interaction loop:
from agentscope.agent import ReActAgent
from agentscope.model import OpenAIChatModel
from agentscope.formatter import OpenAIChatFormatter
from agentscope.token import CharTokenCounter
from agentscope.message import Msg
# 1️⃣ Build the agent with compression enabled
agent = ReActAgent(
name="Friday",
sys_prompt="You are a helpful assistant.",
model=OpenAIChatModel(model_name="gpt-4o-mini"),
formatter=OpenAIChatFormatter(),
compression_config=ReActAgent.CompressionConfig(
enable=True,
trigger_threshold=1500, # compress after ~1500 tokens
agent_token_counter=CharTokenCounter(),
keep_recent=2, # keep the last 2 turns unchanged
),
)
# 2️⃣ Simulate a long conversation
for i in range(25):
user_msg = Msg("user", f"Message #{i}: " + "Lorem ipsum " * 30, "user")
reply = await agent(user_msg) # async context (inside an async fn)
print(reply.content[0].text) # display assistant response
After the 1500-token threshold is crossed, the agent automatically sends a summarization request to the model, stores the resulting <system-info> block, and continues the dialogue using the compacted context.
Key Source Files for Memory Compression
Understanding the codebase helps with debugging and customization:
| File | Purpose |
|---|---|
src/agentscope/agent/_react_agent.py |
Core ReAct agent implementation containing CompressionConfig (lines 107-173) and _compress_memory_if_needed (lines 1110-1175). |
src/agentscope/memory/_working_memory/_base.py |
Abstract base class (lines 14-30) defining _compressed_summary storage and update methods. |
src/agentscope/memory/_working_memory/_in_memory_memory.py |
In-process memory implementation (lines 73-91) handling summary prepending. |
src/agentscope/memory/_working_memory/_redis_memory.py |
Redis-backed memory with identical compression semantics. |
src/agentscope/memory/_working_memory/_sqlalchemy_memory.py |
SQLAlchemy-backed persistence respecting compression marks. |
src/agentscope/token/__init__.py |
Token counter abstractions including CharTokenCounter and TokenCounterBase. |
tests/memory_compression_test.py |
Unit tests demonstrating end-to-end compression behavior. |
Best Practices for Memory Compression
Follow these guidelines to optimize your implementation:
| Situation | Recommendation |
|---|---|
| Very large histories with many tool-use/result pairs | Increase keep_recent to keep whole interaction blocks together; otherwise pairs could split across the summary boundary. |
| Cost constraints | Supply a lightweight compression_model (e.g., gpt-3.5-turbo) while using a larger model for the main task. |
| Non-textual content (images, audio) | The current implementation only summarizes text; ensure prompts explicitly ignore multimodal blocks or provide a custom formatter that strips them. |
| Custom token counting | Implement TokenCounterBase.count(prompt: list[dict]) -> int using provider-specific tokenization (e.g., tiktoken for OpenAI). |
| Debugging | Set logging level to INFO to see "Memory compression is triggered …" messages emitted from _compress_memory_if_needed. |
Summary
Memory compression in AgentScope provides a robust solution for handling extended conversations:
- Configuration-driven: Use
ReActAgent.CompressionConfigto set thresholds, token counters, and retention policies insrc/agentscope/agent/_react_agent.py. - Automatic execution: The
_compress_memory_if_neededmethod triggers summarization whentrigger_thresholdis exceeded, using the configuredagent_token_counter. - Flexible storage: Compressed summaries are stored in
_BaseMemoryimplementations (in-memory, Redis, or SQLAlchemy) and automatically prepended to subsequent prompts viaupdate_compressed_summary. - Customizable output: Adjust
compression_prompt,summary_template, andsummary_schemato control summarization style and content structure.
By implementing these components, you can maintain long-running agent conversations without exceeding model context windows or incurring excessive costs.
Frequently Asked Questions
What triggers memory compression in AgentScope?
Memory compression triggers when the token count of uncompressed messages plus the system prompt exceeds the trigger_threshold specified in CompressionConfig. The _compress_memory_if_needed method performs this check during each reasoning iteration using the configured agent_token_counter to estimate usage.
How does AgentScope decide which messages to compress?
The system preserves the most recent messages based on the keep_recent parameter, ensuring tool-use and result pairs remain intact by traversing the message list backward. Older messages beyond this window are marked as COMPRESSED via update_messages_mark and excluded from future prompts, replaced by the generated summary stored in _compressed_summary.
Can I use a different model for compression than for the main task?
Yes. While the agent's main model is used by default, you can specify a dedicated compression_model in CompressionConfig. This allows you to use a smaller, cheaper model such as gpt-3.5-turbo for summarization while reserving larger models for the primary reasoning task.
What happens to the compressed summary in persistent memory backends?
The compressed summary is stored in the _compressed_summary attribute of the memory instance, whether using in-memory (_in_memory_memory.py), Redis (_redis_memory.py), or SQLAlchemy (_sqlalchemy_memory.py) backends. When building prompts, the memory implementation automatically prepends this summary if prepend_summary is enabled, ensuring continuity across conversation turns.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →