Building a Personal AI Assistant That Remembers:
LangGraph, Mem0, and FalkorDB Explained
How I built a full-stack AI assistant with persistent conversations, agent orchestration, and graph-based long-term memory.
Building a Personal AI Assistant That Remembers: LangGraph, Mem0, and FalkorDB Explained
How I built a full-stack AI assistant with persistent conversations, agent orchestration, and graph-based long-term memory.
Would you keep a personal assistant that forgets everything about you after every conversation? Imagine having to explain who you are, what you prefer, and what you discussed every single time you talk to it. Most of us wouldn’t want that.
Yet, that’s exactly how an AI system without memory feels: every conversation starts from scratch. Memory is what transforms an AI from a tool that simply answers questions into an assistant that learns from context, remembers what’s important, and makes every interaction feel more personal.
Introduction: What If Your AI Assistant Remembered You?
Imagine opening an AI assistant and saying:
“I have three days free. Can you suggest a trip for me?”
A generic assistant can suggest destinations. But a more personal assistant could also consider what you told it yesterday: perhaps you prefer peaceful places, enjoy nature, and want to keep your travel budget low.
The difference is context.
Most people don’t want to repeat their preferences, goals, and ongoing work every time they start a new conversation. They want an assistant that can use relevant information from previous interactions.
That is the idea behind my Personal Assistant project.
I built a full-stack AI assistant using React, FastAPI, LangGraph, Mem0, PostgreSQL, FalkorDB, Qdrant, and the OpenAI API. I also used LangSmith for agent observability.
The most interesting part of this project is not just generating responses. It is understanding how conversation state, long-term memory, and graph-based storage can work together.
In this article, I’ll explain the system in simple language, why I chose each component, how FalkorDB fits into the design, and how to test whether an assistant actually remembers information across conversations.
Figure 1: The overall architecture of the Personal Assistant. Add your verified architecture diagram at this location.
1. The Problem: An Intelligent Model Can Still Feel Forgetful
A language model can understand questions, write code, explain concepts, and generate useful answers. But that does not mean it automatically remembers everything a user told it in previous sessions.
Consider a simple example.
On Monday, you tell an assistant:
“I am learning Java, building AI projects, and prefer explanations with practical examples.”
On Tuesday, you open a new conversation and ask:
“Help me plan what to learn next.”
If the assistant cannot access the relevant information from Monday, you have to explain yourself again.
There are several ways to approach this problem, but each has trade-offs.
Approach 1: Send the entire conversation history
The application can resend earlier messages with every request.
This can work for short conversations, but the history keeps growing. Large prompts can increase latency, cost, and context-management complexity.
Approach 2: Store every message in a database
This makes conversation history persistent, but storing a message does not automatically make its important information available to a future conversation.
The application still needs a way to find and use relevant information.
Approach 3: Build a dedicated memory layer
A memory layer can identify useful information, store it, and retrieve it when a later request needs it.
This is the approach I explored in my project.
The key lesson is that conversation history, agent state, and long-term memory solve different problems.
The Personal Assistant has a web interface where users can chat with the assistant, create conversations, and reopen previous conversations.
Behind the interface, a FastAPI backend processes requests and invokes a LangGraph workflow. The application uses PostgreSQL for persistent conversation data and LangGraph checkpoints, while Mem0 manages long-term memory through the configured FalkorDB and Qdrant integrations.
Here is the technology stack:
Component Technology Why it is used Frontend React + Vite Builds the chat interface Backend Python + FastAPI Handles requests and application logicAgent orchestrationLangGraphCoordinates stateful agent executionConversation persistencePostgreSQLStores conversations, messages, and checkpointsLong-term memoryMem0Manages memory extraction and retrievalGraph databaseFalkorDBStores graph-based memory dataVector databaseQdrantSupports vector-based retrievalLanguage modelOpenAI APIGenerates responses and supports agent tasks Observability LangSmith Helps trace and debug agent execution
I chose separate components because each one has a clear responsibility. This also makes it easier to identify which part of the system is responsible when something goes wrong.
Let’s follow a message through the application.
Step 1: The user sends a message
The React frontend collects the user’s message and sends it to the backend.
Step 2: FastAPI processes the request
FastAPI receives the message together with identifiers for the user and conversation.
These identifiers matter because the system needs to distinguish the current conversation from the user’s longer-term information.
Step 3: LangGraph coordinates the agent
LangGraph manages the configured workflow. Depending on the implementation, the workflow may load conversation state, retrieve memories, invoke the language model, and persist updated state.
Instead of placing every operation inside one large function, an agent graph can organize the process into separate nodes and transitions.
When the memory retrieval path is invoked, the application can request relevant information through Mem0.
That information can be included in the context used by the language model to produce a more personalized answer.
Step 5: The application saves the conversation
The backend persists the conversation messages. LangGraph’s PostgreSQL checkpointer separately manages the graph state required for stateful execution.
Step 6: The response returns to the frontend
The frontend displays the answer, allowing the user to continue the conversation or open another thread.
The exact ordering of memory retrieval and updates depends on the workflow implemented in the application. The important design principle is to keep these responsibilities separate.
4. Why I Used LangGraph
LangGraph is the orchestration layer of my Personal Assistant.
A basic language-model call is relatively straightforward: send a prompt and receive an answer. A more capable assistant may need to perform several operations, such as classifying a request, loading context, retrieving information, calling tools, and updating state.
LangGraph provides a way to organize these operations into a stateful workflow.
For example, a conceptual agent workflow might look like this:
Input → Context loading → Memory retrieval → Response generation → Persistence
This is a simplified representation. The actual nodes, transitions, and conditional paths should be documented from the running application’s graph.
Why does state matter?
Suppose a user says:
“My project uses Java.”
Then asks:
“Can you explain how to implement a binary search tree?”
The assistant may need the earlier context to understand the user’s preferred programming language.
LangGraph checkpointing can preserve state associated with a conversation thread. That is useful for continuity within the thread, but it should not be confused with cross-thread long-term memory.
LangGraph documents these concepts through its persistence and memory features.
Reference: LangGraph persistence documentation.
5. Short-Term Memory vs. Long-Term Memory
This distinction is central to the project.
Short-term memory: What is happening in this conversation?
Short-term memory helps the assistant maintain context within an ongoing interaction.
In my application, PostgreSQL supports persistent conversation history and LangGraph checkpointing.
For example, within one conversation, the assistant may need to retain the user’s earlier question, the answer already provided, and the context needed for the next turn.
The conversation store and checkpoint system serve different purposes:
- The application conversation store supports listing, reopening, and managing conversations.
- LangGraph checkpoints preserve the state needed for stateful graph execution.
Both can use PostgreSQL without being the same data structure.
Long-term memory: What should remain useful later?
Long-term memory is about information that can be useful beyond the current conversation.
Examples include:
- A user’s stable preferences
- An ongoing project
- A recurring constraint
- A previously established goal
The purpose is not to preserve every sentence forever. It is to make relevant information available when it helps answer a future request.
Mainly, there are Three Types of LTM:
- Semantic Memory(Stores the facts about the user)
- Procedural memory (stores the instructions provided by the user, like Think Step by step)
- perodic memory(Learn from past interations)
This is where Mem0 fits into my architecture.
6. Why Mem0?
Mem0 is the long-term memory management layer in my project.
A memory system needs to handle two important operations:
Writing memory: Extract or identify useful information and store it.
Reading memory: Retrieve relevant information when a future request needs it.
For example, a user might say:
“I prefer budget-friendly trips and peaceful nature destinations.”
The memory integration may extract useful information from that interaction and store it.
Later, when the user asks for travel advice, the application can retrieve relevant memories and make them available to the agent.
That process is different from simply replaying the entire conversation transcript.
Mem0 provides memory-management functionality that can be integrated with an existing agent framework. It does not replace LangGraph’s orchestration role.
Get Rbisnnoii’s stories in your inbox
Join Medium for free to get updates from this writer.
Reference: How to create AI agents with long-term memory — Mem0.
7. Why FalkorDB Is Important to This Project
One of the most interesting components of this architecture is FalkorDB.
FalkorDB is a graph database. Instead of representing information only as rows in tables or independent vector records, a graph represents information through nodes and relationships.
Consider a simplified example:
- A user has a travel preference.
- That preference relates to a particular travel style.
- A destination offers activities associated with that style.
- A future recommendation may benefit from those connections.
A graph can represent relationships between these entities.
What does a graph look like?
A conceptual graph could look like this:
User → Travel Preference → Nature-Focused Travel
The nodes represent entities or pieces of information. The edges represent relationships between them.
This example explains the idea; it does not claim that the current application uses these exact labels.
Figure 2: Insert a screenshot or diagram of the actual FalkorDB schema here.
1. Relationships become explicit
A graph can represent how different pieces of information connect. This can be useful when an answer depends on more than one isolated fact.
2. Relationships can be queried
FalkorDB supports graph queries through its Cypher-style query interface. Developers can inspect nodes and relationships directly.
3. Memory becomes easier to investigate
When debugging, I can inspect the configured graph to determine what has actually been stored instead of relying only on the text displayed in the chat interface.
4. It provides a foundation for more advanced retrieval
As a project grows, graph relationships can support queries involving connected entities and information. The usefulness of those queries depends on the actual schema and retrieval logic.
How FalkorDB fits with Mem0
Mem0 is responsible for memory-management operations. FalkorDB provides graph storage through the configured integration.
This distinction matters: Mem0 is not the same thing as FalkorDB. One manages memory operations; the other stores graph data.
Mem0 acts as the memory-management layer, while FalkorDB provides graph-based storage for entities and their relationships. The mem0-falkordb integration allows FalkorDB to be used as Mem0's graph backend.
Installation
Install both Mem0 and the FalkorDB plugin:
pip install mem0ai
pip install mem0-falkordbQuick Start Example
Here’s a complete example to get you started:
from mem0_falkordb import register
register()from mem0 import Memoryconfig = {
"graph_store": {
"provider": "falkordb",
"config": {
"host": "localhost",
"port": 6379,
"database": "mem0",
},
},
"llm": {
"provider": "openai",
"config": {"model": "gpt-4o-mini"},
},
}m = Memory.from_config(config)# Add memories for a user
m.add("I love pizza", user_id="alice")
m.add("Alice is a software engineer", user_id="alice")
m.add("Alice works on AI projects", user_id="alice")# Search the memory
results = m.search("what does alice like?", user_id="alice")
print(results)
If FalkorDB represents relationships, why does the architecture also include Qdrant?
Qdrant is a vector database. Vector retrieval helps find information that is semantically similar to a query, even when the wording is different.
For example, a user might have expressed a preference for “quiet places surrounded by nature.” Later, the user may ask for a “peaceful outdoor getaway.”
A vector search system can help identify semantically related information.
Graph retrieval and vector retrieval address different needs:
FalkorDBQdrantRepresents nodes and relationshipsStores vectors for similarity-based retrievalSupports graph-oriented queriesSupports nearest-neighbour searchUseful for connected informationUseful for semantically related information
The configured Mem0 integration determines how these storage systems are used. Their presence does not automatically mean every query searches both databases; that depends on the implemented retrieval path.
9. A Simple Example: How the Assistant Can Remember
Let’s use a fictional user named Alex.
Conversation 1: Alex shares preferences
Alex says:
“I prefer budget-friendly trips, quiet destinations, and nature-focused experiences. I usually have three days for a trip.”
The application processes the conversation. If its memory-update path runs successfully, the long-term memory integration can extract and store useful information.
At this stage, I would verify that the information was actually saved.
Conversation 2: Alex opens a new thread
Later, Alex opens a separate conversation and asks:
“I have three days free. Can you suggest a trip that would suit me?”
The assistant has two possible sources of information:
- The new message itself
- Relevant long-term memories retrieved for Alex
If the memory integration retrieves the earlier preferences and the agent uses them, the response can reflect those preferences without requiring Alex to repeat them.
This is the key idea behind a memory-aware assistant.
How I validate the behaviour
I test the feature in two separate steps:
- Confirm that the first interaction produces a stored memory in the configured graph or memory storage.
- Confirm that the second thread retrieves and uses that memory.
A database record alone does not prove retrieval. Likewise, a personalised response alone does not prove memory was used, because the model might have guessed the preference.
For stronger evidence, I inspect the actual graph data and, where available, the memory retrieval logs or LangSmith trace.
10. How I Inspect FalkorDB During Development
Direct database inspection is useful when debugging memory behavior.
First, list the graphs available in the running FalkorDB instance. Then select the graph actually used by the application’s active configuration.
A read-only Cypher query can inspect existing nodes:
MATCH (n)
RETURN labels(n), properties(n)
LIMIT 25To inspect relationships:
MATCH (a)-[r]->(b)
RETURN labels(a), type(r), labels(b), properties(r)
LIMIT 25These are inspection queries. They do not create records or imply that a particular schema exists in the application.
It is also important to verify the graph name. A query against an old test graph could show records that are unrelated to the current demo.
For a reproducible demo, I use a dedicated test identity and confirm which graph receives the memory updates.
11. Challenges I Encountered
Building the application required coordinating several components, each with its own configuration and failure modes.
Separating conversation storage from memory
A conversation can remain available in PostgreSQL even when long-term memory was never extracted or retrieved.
Testing these features separately makes debugging easier.
Managing database configuration
The backend must use the intended database endpoints and graph names. A misconfigured graph name can make it appear that memory is missing when the application is actually writing to another graph.
Handling language-model connectivity
The agent depends on external model calls. A connection failure at a LangGraph node can interrupt a request even when the databases are functioning normally.
Verifying memory rather than assuming it
One of the biggest lessons is that a memory system should be tested as a complete workflow: extraction, storage, retrieval, and use in the final response.
A convincing demonstration needs evidence from more than one layer.
12. What I Want to Improve Next
The current architecture provides a foundation for further development. Potential next steps include:
- Evaluation of memory relevance, latency, and reliability
These are future improvements rather than claims that every capability is already implemented.
Conclusion: Memory Is More Than Storage
Building this Personal Assistant changed how I think about AI applications.
A useful assistant needs more than a strong language model. It needs a way to maintain state, persist useful information, retrieve relevant context, and keep the different responsibilities of the system separate.
LangGraph coordinates the agent workflow. PostgreSQL supports conversation persistence and checkpoints. Mem0 manages long-term memory operations. FalkorDB provides graph-based storage, while Qdrant supports vector retrieval.
The most important lesson is simple:
An assistant does not become useful merely by storing more information. It becomes useful when it can retrieve the right information, at the right time, for the right user.
That is the capability I am exploring with this project, and the foundation I want to continue improving.
Project Links
This is the solution I have built with FalkorDB for the GraphHacks Hackathon:
References
- How to create AI agents with long-term memory — Mem0
- LangGraph persistence documentation
- FalkorDB official website
- FalkorDB documentation
Let’s Connect:
Here I also documented my Hackathon Daily Journey:





