1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
18 small wins to finish your pathNext lesson →
Background memory with ReflectionExecutor
Extracting after every message is slow and wasteful. ReflectionExecutor runs a store manager in the background, after a delay that restarts when new messages arrive.
asha = {"configurable": {"user_id": "asha", "thread_id": "chat-1"}}
with ReflectionExecutor(manager, store=store) as executor:
future = executor.submit({"messages": [{"role": "user", "content": "My name is Asha. I moved to Pune."}]}, config=asha, after_seconds=1)
print("right after submit:", len(store.search(("memories", "asha"))))
future.result()
print("after it ran:", len(store.search(("memories", "asha"))))submit returns at once with a Future. The work runs on a worker thread after after_seconds, so the reply to the customer is not delayed. future.result() waits for it, which a real app would not do.
Debouncing
Submits are keyed by thread_id. A new submit for the same thread before the delay ends cancels the pending one, so a customer typing five quick messages causes one extraction over the full conversation, not five. Pick a delay longer than the gap between messages in a normal conversation, often minutes.
Two details the source shows
- Outside a LangGraph node,
submitneedsconfig=with the ids; inside a graph it reads the current config itself. - The worker is a normal thread, not a daemon, so a script that never calls
shutdown()waits for it at exit. Thewithblock shuts it down.
Try it yourself
- Submit twice for the same thread within the delay and check how many times extraction ran.
- Remove
future.result()and print the count at the end of thewithblock. - Submit for two different
thread_ids.
This is what real progress feels like.