CrewAICrewAI 1.15 · Python 3.10 to 3.13
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
32 small wins to finish your pathNext lesson

Memory: remember and recall

Memory stores short facts with a vector for each, and recall finds the closest ones to a question. Scopes keep one customer's facts apart from another's.

Every crew so far forgot the customer as soon as it finished. CrewAI's Memory class keeps facts on disk between runs. It needs two things: an embedder, which turns text into a list of numbers so that similar texts get similar numbers, and a model for the analysis it does when you leave details out.

Exampleembed.py
import hashlib
import math


def word_hash(texts):
    vectors = []
    for text in texts:
        vector = [0.0] * 64
        for word in text.lower().split():
            word = word.strip(".,?!")
            vector[int(hashlib.md5(word.encode()).hexdigest(), 16) % 64] += 1.0
        length = math.sqrt(sum(x * x for x in vector)) or 1.0
        vectors.append([x / length for x in vector])
    return vectors

word_hash is an embedder you can read. Each word adds 1 to one of 64 slots, chosen by a hash of the word, and the list is scaled to length 1. Texts that share words point the same way. A real embedder understands that "email" and "contacted" are related; this one only matches words.

Examplememory_desk.py
from crewai import Memory
from crewai.events import crewai_event_bus
from embed import word_hash
from shop_llm import ShopLLM

memory = Memory(llm=ShopLLM(model="shop"), embedder=word_hash)

Any function that takes a list of texts and returns a list of vectors can be the embedder. Without one, Memory uses OpenAI's embeddings, which need a key. The records are stored with LanceDB in a .crewai/memory folder under the current directory.

Remembering

Examplememory_desk.py, continued
with crewai_event_bus.scoped_handlers():
    memory.remember("Asha prefers email, not phone calls.",
                    scope="/customer/asha", categories=["preference"], importance=0.8)
    memory.remember("Asha's order A17 shipped on 3 March.",
                    scope="/customer/asha", categories=["order"], importance=0.5)
    memory.remember("Ravi's order C40 is waiting for stock.",
                    scope="/customer/ravi", categories=["order"], importance=0.5)

Each fact is given a scope, a path like a folder, plus categories and an importance. With all three supplied, no model call is needed; leave them out and Memory asks its model to choose them. Each save prints two panels from a background thread; scoped_handlers sets CrewAI's own listeners aside for the block, so this lesson's output stays readable.

Recalling

Example
for match in memory.recall("How does Asha want to be contacted?", limit=2, depth="shallow"):
    print(round(match.score, 2), match.record.content)

recall ranks records by a score that blends how similar they are, how recent, and how important. depth="shallow" is a plain vector search with no model call. The top match shares "Asha" with the question and has the higher importance. The second is Ravi's order, which is not about Asha at all: similarity from counting words is rough, and with every record new, a small difference in it decides the order. Scopes fix that.

Example
print(memory.tree())
for match in memory.recall("order status", scope="/customer/ravi", depth="shallow"):
    print(match.record.content)

tree shows the scopes as a hierarchy with their record counts. A recall inside /customer/ravi cannot see Asha's records at all, which is how a desk keeps customers apart.

Remember, then recall
savedsame embedderclosest firstremember(text)with a scopeword_hash64 numbers per textThe store.crewai/memoryrecall(query)shallow searchThe matchesscore and record
Hover or tap a piece to see what it is and which lesson built it.
Trace a recall

Pick one to watch it run, step by step.

Saving and asking go through the same embedder, which is why the two can be compared at all.

A crew takes memory=memory too. It then asks its model to pull facts out of each task's output and recalls them before later tasks, which is more than a stand-in model can do well.

Try it yourself
  • Recall "When did A17 ship?" and compare the scores.
  • Remember a fact without scope and print memory.tree().
  • Call memory.forget(scope="/customer/ravi") and print the tree again.

Every expert started right here.