- Remembering a user’s name or other personal details across conversations
- Retaining facts from one session for use in another
- Keeping details about a repository’s style guide for later reference
- Maintaining project-specific information across multiple interactions
- Enabling “soft” collaboration between agents through a shared knowledge base
How Memory Works
ControlFlow memories are implemented as context-specific vector stores that permit agents to add and query information using natural language. Each memory object has a “key” that uniquely identifies it and partitions its contents from other vector stores for easy retrieval. For example, you might have a different memory store for each user, agent, project, or even task, used to persist information across multiple interactions with that object. Agents can be provided with multiple memory modules, allowing them to access different sets of memories simultaneously.Creating Memory Modules
To create a memory object, you need to provide akey
and instructions
. The key
uniquely identifies the memory module so it can be accessed later. The instructions
explain what kind of information should be stored, and how it should be used.
ControlFlow does not include any vector database dependencies by default to keep the library lightweight, so you must install and configure a provider before creating a memory object.To run the examples with minimal configuration, run
pip install chromadb
to install the dependency for the default Chroma provider. To change the default, see the default provider guide.Assigning Memories
Like tools, memory modules can be provided to either agents or tasks. When provided to an agent, it will be able to access the memories when executing any task. When provided to a task, the memories will be available to any assigned agents. The choice of where to assign a memory module depends entirely on your preference and the design of your application; when the workflow is compiled the behavior is identical.Assigning to an Agent
Assigning to a Task
Assigning Multiple Memories
You can assign multiple memories to an agent or task. When this happens, the agent or task will have access to all of the modules and be able to store and retrieve information from each of them separately.Sharing Memories
Remember that you can provide the same memory module to multiple agents or tasks. When this happens, the memories are shared across all of the agents and tasks.Memories are partitioned by
key
, so you can provide different instructions to different agents for the same module. For example, you might have one agent that you encourage to record information to a memory module, and another that you encourage to read memories from the same module.Configuration
Key
Thekey
is crucial for accessing the correct set of memories. It must be provided exactly the same way each time to access an existing memory. Keys should be descriptive and unique for each distinct memory set you want to maintain.
Instructions
Theinstructions
field is important because it tells the agent when and how to access or add to the memory. Unlike the key
, instructions can be different for the same memory key across different Memory objects. This allows for flexibility in how agents interact with the same set of memories.
Good instructions should explain:
- What kind of information the memory is used to store
- When the agent should read from or write to the memory
- Any specific guidelines for formatting or categorizing the stored information
Provider
Theprovider
is the underlying storage mechanism for the memory. It is responsible for storing and retrieving the memory objects.
The default provider is “chroma-db”, which uses a local persistent Chroma database. Run
pip install chromadb
to install its dependencies, after which you can start using memories with no additional configuration.Installing provider dependencies
To configure a provider, you need to install its package and either configure the provider with a string value or create an instance of the provider and pass it to the memory module.ControlFlow does not include any vector database dependencies by default, in order to keep the library lightweight.
Provider | Required dependencies |
---|---|
Chroma | chromadb |
pip install chromadb
to use the Chroma provider.
Configuring a provider with a string
For straightforward provider configurations, you can pass a string value to theprovider
parameter that will instantiate a provider with default settings. The following strings are recognized:
Provider | Provider string | Description |
---|---|---|
Chroma | chroma-ephemeral | An ephemeral (in-memory) database. |
Chroma | chroma-db | Uses a persistent, local-file-based database, with a default path of ~/.controlflow/memory/chroma . |
Chroma | chroma-cloud | Uses the Chroma Cloud service. The CONTROLFLOW_CHROMA_CLOUD_API_KEY , CONTROLFLOW_CHROMA_CLOUD_TENANT , and CONTROLFLOW_CHROMA_CLOUD_DATABASE settings are required. |
chromadb
is installed, the following code will create a memory module that uses an ephemeral Chroma database:
Configuring a Provider instance
For more complex configurations, you can instantiate a provider directly and pass it to the memory module. For example, the Chroma provider accepts aclient
parameter that allows you to customize how the Chroma client connects, as well as a collection_name
parameter to specify the name of the collection to use.
Configuring a default provider
You can configure a default provider to avoid having to specify a provider each time you create a memory module. Please see the guide on default providers for more information.Example: Storing Weather Information
In this example, we’ll create a memory module for weather information and use it to retrieve that information in a different conversation. Begin by creating a memory module, assigning it to a task, and informing the task that it is 70 degrees today:Example: Slack Customer Service
Suppose we have an agent that answers questions in Slack. We are going to equip the agent with the following memory modules:- One for each user in the thread
- One for common problems that users encounter
Best Practices
- Use descriptive, unique keys for different memory sets
- Provide clear, specific instructions to guide agents in using the memory effectively
- Consider the lifespan of memories - some may be relevant only for a single session, while others may persist across multiple runs
- Use multiple memory objects when an agent needs to access different sets of information
- Leverage shared memories for collaborative scenarios where multiple agents need access to the same knowledge base
- Regularly review and update memory instructions to ensure they remain relevant and useful