Memory

Agents within the Agent framework have memory. This guide explains how this memory works and how to use it.

The memory is essentially a list and dictionary based storage system. It is used to store and retrieve information that is relevant to the agent’s current state. This can be things like observations the agent has received from the environment, recent thoughts is had, or the previous actions it took. Intrinsic functions (see guide) interact with the memory, modifying its state and retrieving information from it to perform their objectives.

The memory is made up of entries called MemoryEntry :

class MemoryEntry(BaseModel):
    """A class to represent a memory entry with creation time, content, and associated tags.

    Attributes:
        created_at (datetime): The time when the memory entry is created. Default is the current time.
        content (Any): The main content or body of the memory entry.
        tags (Union[Set[MemKey], List[MemKey]]): A set or list of tags associated with the memory entry.
    """

    created_at: datetime = datetime.now()
    content: Any
    tags: set[MemKey]

Keeping track of creation time and adding tags enables the user to retrieve specific memory entries based on these properties. Creation time allows the agent to retrieve memory entries based on recency, while the tags enable the retrieval of a specific thought or a broader range of thoughts matching the tags.

We detail some of the most commonly used core memory methods such as storing and retrieval.

Memory store

Any content can easily be stored in the memory by calling the memory.store method, which takes the content and the tag(s) to assign to the memory entry:

def store(self, content: Any, tags: MemKey | list[MemKey]) -> None:
    """Stores a new entry in the memory.

    Parameters:
        content (Any): The main content or body of the memory entry.
        tags (MemKey | List[MemKey]): A list of tags associated with the memory entry.
    """

An example of storing an agent’s observation in the memory:

agent.memory.store(observation, MemKey.OBSERVATION)

Memory retrieve

The full functionality of the memory is really exposed through the retrieval functions. The memory.retrieve method is used to retrieve a single memory entry based on its tags and creation time:

def retrieve(self, tags: MemKey | list[MemKey] | dict[MemKey, float]) -> Any:
    """Retrieves the content of the best matching memory entry based on the given tags and their respective weights.
    Returns the latest memory entry if multiple memory entries have the same score. If no scores are given, the default score
    will be 1.0.

    Parameters:
        tags (MemKey | List[MemKey] | dict[MemKey, float]): Tags with optional weights to retrieve the best matching memory entry.

    Returns:
        Any: The content of the best matching memory entry or None if the max calculated weight was =< 0
    """

This method will return the best matching entry among those that have tags in common with the request. Weights can be provided along with the tags in dictionary format to specify the importance of each tag in the retrieval process. The sum of weights of tags present in the memory entry can then be used to select the best entry. If multiple entries have equal score, the most recent one is returned.

Memory retrieve all

memory.retrieve_all works in a very similar way to memory.retrieve , but instead of returning the single best matching entry, it returns all entries whose score is equal to the best score:

def retrieve_all(self, tags: MemKey | list[MemKey] | dict[MemKey, float]) -> list[Any]:
"""Retrieves the content of all memory entries that have the highest score based on the given tags
and their respective weights.

Parameters:
    tags (MemKey | List[MemKey] | dict[MemKey, float]): Tags with optional weights to retrieve
    the best matching memory entry.

Returns:
    list[Any]: A list containing the content of all memory entries that have the highest matching score,
    or an empty list if that score is <=0
"""

This is useful when say you want to retrieve all past observations and actions to pass to the agent as a trajectory.

Memory keys

A crucial element of the memory is the MemKey enum, which defines the set of memory keys which can be used to interact with the memory. This enum is used to define the tags that can be used for any memory operations, from storing to retrieval. Any keys currently defined in the enum can be used. The current state of this enum is provided below for convenience:

class MemKey(str, Enum):
    """An enumeration to represent the keys used in the memory."""

    # Generic keys
    AVAILABLE_ACTIONS = "_available_actions"  # Available actions for the agent to choose from
    EXTERNAL_ACTION = "_action"  # External actions the agent has taken
    NEXT_PLANNED_ACTION = "_next_planned_action"  # Next action the agent plans to take
    OBSERVATION = "_text_obs"  # Observations the agent has observed from the task
    RAW_ACTION_OUTPUT = "_raw_action_output"  # Raw outputs from the LLM
    REWARD = "_reward"  # Reward received from the environment by the agent at each timestep
    TASK_CATEGORY = "_task_category"  # Category of the task (only for some environments)
    THOUGHT = "_thought"  # Thoughts produced by the agent

    # Reflect keys
    REFLECTION = "_reflection"  # Reflections produced by the agent

    # Least-to-most keys
    SUBPROBLEM = "_subproblem"  # Subproblems produced by the agent

    # Self-consistency keys
    NEXT_PLANNED_ACTION_DIVERSE = "_next_possible_action_diverse"  # Diverse set of next possible actions (for SC)

    # # Swift-Sage keys
    # NEXT_PLANNED_ACTION_BUFFER = "_next_planned_action_buffer"  # Buffer of next actions to take (for SwiftSage)

    # RAG keys
    DB_QUERY = "_db_query"
    RAG_RETRIEVAL = "_rag_retrieval"

    # Google search keys
    GOOGLE_QUERY = "_google_query"  # Query used for google search
    LINK_RETRIEVED = "_link_retrieved"  # Link retrieved from google search
    NUM_CHUNKS = "_num_chunks"  # Number of chunks to summarize google search
    SNIPPET_RETRIEVED = "_snippet_retrieved"  # Snippet retrieved from google search
    SUMMARIZED_TEXT = "_summarized_text"  # Summarized text from google search
    TEXT_RETRIEVED = "_text_retrieved"  # Text retrieved from google search
    TITLE_RETRIEVED = "_title_retrieved"  # Title retrieved from google search

    # Trajectory keys
    FULL_EPS_REWARDS = "_full_eps_rewards"  # Full list of rewards of the agent for the current episode
    FULL_EPS_TRAJECTORY = "_full_eps_trajectory"  # Full trajectory of the agent for the current episode
    TRAJECTORY = "_trajectory"  # Agent trajectory by timestep

Any tags you want to give to memory entries must be defined in this enum. This is to ensure that the memory is used consistently and without error across the framework. As such, if you want to use a new custom tag, you must first add it to this enum. It can then be used as desired.

Further information

Only a subset of memory operation were presented above. For a full list of memory operations, see the Memory class in memory.py.