Skip to main content

Stateful Chatbots with Gemini and LangGraph (LangChain)

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 ProLangChain, 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 MemorySaver and StateGraph.

Comments

Popular

Building an MCP Agent with UV, Python & mcp-use

Model Context Protocol (MCP) is an open protocol designed to enable AI agents to interact with external tools and data in a standardized way. MCP is composed of three components: server , client , and host . MCP host The MCP host acts as the interface between the user and the agent   (such as Claude Desktop or IDE) and plays the role of connecting to external tools or data through MCP clients and servers. Previously, Anthropic’s Claude Desktop was introduced as a host, but it required a separate desktop app, license, and API key management, leading to dependency on the Claude ecosystem.   mcp-use is an open-source Python/Node package that connects LangChain LLMs (e.g., GPT-4, Claude, Groq) to MCP servers in just six lines of code, eliminating dependencies and supporting multi-server and multi-model setups. MCP Client The MCP client manages the MCP protocol within the host and is responsible for connecting to MCP servers that provide the necessary functions for the ...

How to Save and Retrieve a Vector Database using LangChain, FAISS, and Gemini Embeddings

How to Save and Retrieve a Vector Database using LangChain, FAISS, and Gemini Embeddings Efficient storage and retrieval of vector databases is foundational for building intelligent retrieval-augmented generation (RAG) systems using large language models (LLMs). In this guide, we’ll walk through a professional-grade Python implementation that utilizes LangChain with FAISS and Google Gemini Embeddings to store document embeddings and retrieve similar information. This setup is highly suitable for advanced machine learning (ML) and deep learning (DL) engineers who work with semantic search and retrieval pipelines. Why Vector Databases Matter in LLM Applications Traditional keyword-based search systems fall short when it comes to understanding semantic meaning. Vector databases store high-dimensional embeddings of text data, allowing for approximate nearest-neighbor (ANN) searches based on semantic similarity. These capabilities are critical in applications like: Question Ans...

Using Gemini API in LangChain: Step-by-Step Tutorial

What is LangChain and Why Use It? LangChain  is an open-source framework that simplifies the use of  Large Language Models (LLMs)  like OpenAI, Gemini (Google), and others by adding structure, tools, and memory to help build real-world applications such as chatbots, assistants, agents, or AI-enhanced software. Why Use LangChain for LLM Projects? Chainable Components : Easily build pipelines combining prompts, LLMs, tools, and memory. Multi-Model Support : Work with Gemini, OpenAI, Anthropic, Hugging Face, etc. Built-in Templates : Manage prompts more effectively. Supports Multi-Turn Chat : Manage complex interactions with memory and roles. Tool and API Integration : Let the model interact with external APIs or functions. Let's Walk Through the Code: Gemini + LangChain I will break the code into  4 main parts , each showcasing different features of LangChain and Gemini API. Part 1: Basic Gemini API Call Using LangChain import os from dotenv import load_dotenv load_dot...