Memory
In AgentScope, memory is used to store historical information, allowing the agent to provide more coherent and natural responses based on context. This tutorial will first introduce the carrier of information in memory, message, and then introduce the functions and usage of the memory module in AgentScope.
About Message
MessageBase
Class
In AgentScope, the message base class is a subclass of Python dictionary,
consisting of two required fields (name
and content
) and an optional
field (url
).
Specifically, the name
field represents the originator of the message,
the content
field represents the content of the message, and the url
field represents the data link attached to the message, which can be a
local link to multi-modal data or a web link.
As a dictionary type, developers can also add other fields
as needed. When a message is created, a unique ID is automatically
generated to identify the message. The creation time of the message is also
automatically recorded in the form of a timestamp.
In the specific implementation, AgentScope first provides a MessageBase
base class to define the basic properties and usage of messages.
Unlike general dictionary types, the instantiated objects of MessageBase
can access attribute values through object_name.{attribute_name}
or
object_name['attribute_name']
.
The key attributes of the MessageBase
class are as follows:
name
: This attribute denotes the originator of the message. It’s a critical piece of metadata, useful in scenarios where distinguishing between different speakers is necessary.content
: The substance of the message itself. It can include text, structured data, or any other form of content that is relevant to the interaction and requires processing by the agent.url
: An optional attribute that allows the message to be linked to external resources. These can be direct links to files, multi-modal data, or web pages.timestamp
: A timestamp indicating when the message was created.id
: Each message is assigned a unique identifier (ID) upon creation.
class MessageBase(dict):
"""Base Message class, which is used to maintain information for dialog,
memory and used to construct prompt.
"""
def __init__(
self,
name: str,
content: Any,
url: Optional[Union[Sequence[str], str]] = None,
timestamp: Optional[str] = None,
**kwargs: Any,
) -> None:
"""Initialize the message object
Args:
name (`str`):
The name of who send the message. It's often used in
role-playing scenario to tell the name of the sender.
However, you can also only use `role` when calling openai api.
The usage of `name` refers to
https://cookbook.openai.com/examples/how_to_format_inputs_to_chatgpt_models.
content (`Any`):
The content of the message.
url (`Optional[Union[list[str], str]]`, defaults to None):
A url to file, image, video, audio or website.
timestamp (`Optional[str]`, defaults to None):
The timestamp of the message, if None, it will be set to
current time.
**kwargs (`Any`):
Other attributes of the message. For OpenAI API, you should
add "role" from `["system", "user", "assistant", "function"]`.
When calling OpenAI API, `"role": "assistant"` will be added
to the messages that don't have "role" attribute.
"""
# id and timestamp will be added to the object as its attributes
# rather than items in dict
self.id = uuid4().hex
if timestamp is None:
self.timestamp = _get_timestamp()
else:
self.timestamp = timestamp
self.name = name
self.content = content
if url:
self.url = url
self.update(kwargs)
def __getattr__(self, key: Any) -> Any:
try:
return self[key]
except KeyError as e:
raise AttributeError(f"no attribute '{key}'") from e
def __setattr__(self, key: Any, value: Any) -> None:
self[key] = value
def __delattr__(self, key: Any) -> None:
try:
del self[key]
except KeyError as e:
raise AttributeError(f"no attribute '{key}'") from e
def to_str(self) -> str:
"""Return the string representation of the message"""
raise NotImplementedError
def serialize(self) -> str:
"""Return the serialized message."""
raise NotImplementedError
# ... [省略代码以简化]
Msg
Class
Msg
class extends MessageBase
and represents a standard message.
Msg
provides concrete definitions for the to_str
and serialize
methods to enable string representation and serialization suitable for the
agent’s operational context.
Within an Agent
class, its reply
function typically returns an instance of
Msg
to facilitate message passing within AgentScope.
class Msg(MessageBase):
"""The Message class."""
def __init__(
self,
name: str,
content: Any,
url: Optional[Union[Sequence[str], str]] = None,
timestamp: Optional[str] = None,
echo: bool = False,
**kwargs: Any,
) -> None:
super().__init__(
name=name,
content=content,
url=url,
timestamp=timestamp,
**kwargs,
)
if echo:
logger.chat(self)
def to_str(self) -> str:
"""Return the string representation of the message"""
return f"{self.name}: {self.content}"
def serialize(self) -> str:
return json.dumps({"__type": "Msg", **self})
About Memory
MemoryBase
Class
MemoryBase
is an abstract class that handles an agent’s memory in a structured way. It defines operations for storing, retrieving, deleting, and manipulating message’s content.
class MemoryBase(ABC):
# ... [code omitted for brevity]
def get_memory(
self,
return_type: PromptType = PromptType.LIST,
recent_n: Optional[int] = None,
filter_func: Optional[Callable[[int, dict], bool]] = None,
) -> Union[list, str]:
raise NotImplementedError
def add(self, memories: Union[list[dict], dict]) -> None:
raise NotImplementedError
def delete(self, index: Union[Iterable, int]) -> None:
raise NotImplementedError
def load(
self,
memories: Union[str, dict, list],
overwrite: bool = False,
) -> None:
raise NotImplementedError
def export(
self,
to_mem: bool = False,
file_path: Optional[str] = None,
) -> Optional[list]:
raise NotImplementedError
def clear(self) -> None:
raise NotImplementedError
def size(self) -> int:
raise NotImplementedError
Here are the key methods of MemoryBase
:
get_memory
: This method is responsible for retrieving stored messages from the agent’s memory. It can return these messages in different formats as specified by thereturn_type
. The method can also retrieve a specific number of recent messages ifrecent_n
is provided, and it can apply a filtering function (filter_func
) to select messages based on custom criteria.add
: This method is used to add a new message to the agent’s memory. It can accept a single message or a list of messages. Each message is typically an instance ofMessageBase
or its subclasses.delete
: This method enables the removal of messages from memory by their index (or indices if an iterable is provided).load
: This method allows for the bulk loading of messages into the agent’s memory from an external source. Theoverwrite
parameter determines whether to clear the existing memory before loading the new set of messages.export
: This method facilitates exporting the stored message from the agent’s memory either to an external file (specified byfile_path
) or directly into the working memory of the program (ifto_mem
is set toTrue
).clear
: This method purges all message from the agent’s memory, essentially resetting it.size
: This method returns the number of messages currently stored in the agent’s memory.
TemporaryMemory
The TemporaryMemory
class is a concrete implementation of MemoryBase
, providing a memory store that exists during the runtime of an agent, which is used as the default memory type of agents. Besides all the behaviors from MemoryBase
, the TemporaryMemory
additionally provides methods for retrieval:
retrieve_by_embedding
: Retrievesmessages
that are most similar to a query, based on their embeddings. It uses a provided metric to determine the relevance and can return the topk
most relevant messages.get_embeddings
: Return the embeddings for all messages in memory. If a message does not have an embedding and an embedding model is provided, it will generate and store the embedding for the message.
For more details about the usage of Memory
and Msg
, please refer to the API references.