Memory service: memory across conversations
State carries facts you chose to save, for the conversation that is happening now. Memory is different: it holds finished conversations and lets a later one search them, once you have added them to it.
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.
Pick one to watch it run, step by step.
A first conversation
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.
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")the conversation happened, and is still only a session
Saving it
One call does it. Running the same search either side of that call is what shows you what it changed:
before = await memory.search_memory(app_name="demo", user_id="u1", query="email")
print("searchable before saving:", len(before.memories))
finished = await sessions.get_session(app_name="demo", user_id="u1", session_id=first.id)
await memory.add_session_to_memory(finished)
after = await memory.search_memory(app_name="demo", user_id="u1", query="email")
print("searchable after saving: ", len(after.memories))
print("state on that session: ", dict(finished.state))searchable before saving: 0
searchable after saving: 1
state on that session: {}The conversation had already happened, and the search still found nothing, because a session becomes searchable only when you add it. The state on that session is empty too: state is for the conversation that is running, and this one is over. Memory is what is left of it afterwards, and only what you chose to keep.
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
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.
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())memory found: user said 'I prefer email over phone' answer: You told us you prefer email.
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 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.
| State | Memory | |
|---|---|---|
| What it holds | Facts you chose to save | Whole past conversations |
| How it is read | A template, or a tool reading it | A search, through load_memory |
| Written by | Your code, deliberately | You, when you add a finished session |
| Good for | The order id, the customer's plan | What was said last month |
- 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.