Google ADKgoogle-adk 2.8 · Python 3.10+
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
28 small wins to finish your pathNext lesson

Memory across conversations

State carries facts you chose to save. Memory is different: it stores whole past conversations and lets an agent search them.

Two objects make it work, and they are created side by side. A session service holds conversations while they happen, and a memory service holds the finished ones.

A first conversation

python
listener = LlmAgent(name="listener", model=PretendModel(replies=[say("Noted.")]),
                    instruction="Listen to the customer.")

runner = Runner(agent=listener, app_name="demo",
                session_service=sessions, memory_service=memory)

Runner rather than InMemoryRunner here, because both services are being passed in explicitly. That is the only difference.

Example
first = await sessions.create_session(app_name="demo", user_id="u1")
said = types.Content(role="user", parts=[types.Part(text="I prefer email over phone")])

async for _ in runner.run_async(user_id="u1", session_id=first.id, new_message=said):
    pass

print("the conversation happened, and is still only a session")

Saving it

Example
finished = await sessions.get_session(app_name="demo", user_id="u1", session_id=first.id)
await memory.add_session_to_memory(finished)

print("saved to memory")

Nothing is remembered automatically. You decide when a finished conversation is worth keeping, which is the right way round: most are not.

Searching it later

python
recaller = LlmAgent(
    name="recaller",
    model=PretendModel(replies=[call("load_memory", query="email"),
                                say("You told us you prefer email.")]),
    instruction="Use memory when the customer refers to something from before.",
    tools=[load_memory],
)

load_memory is a tool ADK ships. It goes in the tools list like any other, and the model calls it with a query.

Example
later = Runner(agent=recaller, app_name="demo",
               session_service=sessions, memory_service=memory)
second = await sessions.create_session(app_name="demo", user_id="u1")
asked = types.Content(role="user", parts=[types.Part(text="How should we contact you?")])

async for event in later.run_async(user_id="u1", session_id=second.id, new_message=asked):
    for part in (event.content.parts if event.content else []):
        if part.function_response:
            for item in part.function_response.response["result"].memories:
                text = "".join(p.text or "" for p in item.content.parts)
                print("memory found:", item.author, "said", repr(text))
        elif part.text:
            print("answer:      ", part.text.strip())

A new conversation found the old one and answered from it. The memory belongs to the user, so a different customer searching the same words finds nothing.

What the in-memory service actually does

It matches keywords. Search for a word that appears in the stored conversation and you get a hit; search for a phrase that means the same thing in different words and you get nothing. Fine for learning, and wrong for production, where the managed memory service searches properly.

StateMemory
What it holdsFacts you chose to saveWhole past conversations
How it is readA template, or a tool reading itA search, through load_memory
Written byYour code, deliberatelyYou, when you add a finished session
Good forThe order id, the customer's planWhat was said last month
Which one you need
Most agents need state and never need memory. Reach for memory when the useful thing is what was said, rather than a fact you could have extracted and stored at the time.
Try it yourself
  • Search for a word that is not in the conversation and print the empty result.
  • Store two conversations and search for something in both.

Slow is fine. Stopping is the only problem.