When designing AI chatbots, a key architectural choice is whether to make your chatbot stateless or stateful. Here's what that means and why it matters.
Stateless Chatbots
Stateless chatbots treat every user input as an isolated message. They do not remember previous interactions. This can be simple to implement but lacks conversational memory, making complex or context-driven dialogue harder to handle.
Stateful Chatbots
Stateful chatbots maintain memory across interactions, which allows them to provide personalized and coherent responses. They are ideal for tasks like long-form conversations, remembering user preferences, or task-driven agents.
Building a Stateful Chatbot with Gemini + LangGraph
Below is a complete example of how to build a stateful chatbot using Gemini 2.5 Pro, LangChain, and LangGraph. This chatbot can remember prior messages using a memory saver, and supports graph-based workflows for flexibility.
# Import required libraries
import os
from dotenv import load_dotenv # Load environment variables from .env file
from typing import Sequence
from typing_extensions import Annotated, TypedDict
from langchain_google_genai import ChatGoogleGenerativeAI # Gemini model from LangChain
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.messages import HumanMessage, BaseMessage
from langgraph.graph.message import add_messages # For managing chat messages in a state
from langgraph.checkpoint.memory import MemorySaver # In-memory state persistence
from langgraph.graph import StateGraph, MessagesState, START, END # Workflow graph primitives
# Load environment variables
load_dotenv(".env")
api_key = os.getenv("GOOGLE_API_KEY")
# Initialize Gemini model
llm_pro = ChatGoogleGenerativeAI(
model='gemini-2.5-pro-exp-03-25', # Use a powerful, context-aware Google model
temperature=0.5 # Balanced creativity
)
# Create a prompt template with system message and placeholder for past messages
prompt = ChatPromptTemplate.from_messages(
[
('system', 'You are an agent who is expert in deep learning.'),
MessagesPlaceholder(variable_name="messages"), # Past messages go here
]
)
# Define a state that keeps track of all messages
class State(TypedDict):
messages: Annotated[Sequence[BaseMessage], add_messages]
# Create a runnable chain from the prompt to the LLM
runnable = prompt | llm_pro
# Generator function used by the graph node
def generator(state: State):
response = runnable.invoke(state) # Run the model with current state
return {"messages": [response]} # Return the new message to append
# Build the LangGraph stateful workflow
workflow = StateGraph(state_schema=State)
workflow.add_edge(START, "model") # Define the path: start → model
workflow.add_node("model", generator) # Add model node
# Create a memory manager for persistent conversation
memory = MemorySaver()
app = workflow.compile(checkpointer=memory)
# Set a thread ID to uniquely identify the user's session
config = {"configurable": {"thread_id": "user_124"}}
# Step 1: Say your name
input_data = {"messages": [HumanMessage("Hi, I'm Mark.")]}
output = app.invoke(input_data, config)
output["messages"][-1].pretty_print() # Should respond and remember the name
# Step 2: Ask a new question, AI should remember "Mark"
input_data = {"messages": [HumanMessage("Explain the A* algorithm.")]}
output = app.invoke(input_data, config)
output["messages"][-1].pretty_print() # Personalized response using memory
Output
================================== Ai Message ==================================
Hi Mark! It's nice to meet you.
As a deep learning expert agent, I'm ready to help with any questions or tasks you might have related to:
* Neural network architectures (CNNs, RNNs, Transformers, etc.)
* Frameworks like TensorFlow, PyTorch, Keras
* Training, optimization, and evaluation techniques
* Specific applications (computer vision, NLP, etc.)
* Theoretical concepts
* Or anything else in the realm of deep learning!
What can I help you with today?
================================== Ai Message ==================================
Okay, Mark! Let's break down the **A\* (pronounced "A-star") algorithm**.
In simple terms, A\* is a popular and widely used **pathfinding** and **graph traversal** algorithm. Its main goal is to efficiently find the **shortest path** (or least-cost path) between a starting node (point) and a target node (point) in a graph or grid.
Think of it like giving directions using GPS: it doesn't just explore randomly; it tries to find the *best* route considering both the distance already traveled and an estimate of the distance remaining.
Here's a more detailed breakdown:
**1. The Core Idea:**
...
* **Optimality:** If the heuristic `h(n)` is admissible, A\* is guaranteed to find the least-cost path. If the heuristic is also consistent, the algorithm is more efficient.
* **Efficiency:** Generally much more efficient than uninformed search algorithms like Breadth-First Search (BFS) or Dijkstra's algorithm (when finding a path to a *single* goal) because the heuristic guides the search towards the goal. However, its memory usage can be high as it needs to store the Open and Closed sets.Summary
- LangChain: Python framework to connect LLMs with prompts and memory.
- LangGraph: Enables graph-based memory-aware workflows for agents.
- Gemini 2.5 Pro: Advanced Google Generative AI model integrated via LangChain.
- Stateful chatbot: Remembers past messages using
MemorySaverandStateGraph.
Comments
Post a Comment