Langgraph Agentic Chatbot
Agentic Chatbot with LangGraph
This project demonstrates how to build a modular, extensible chatbot using LangGraph, LangChain, and Ollama. The notebook walks through building a basic chatbot, adding tools, memory, streaming, and human-in-the-loop capabilities.
Table of Contents
- Basic Chatbot
- Visualizing the Graph
- Chatbot with Tools
- Adding Memory
- Streaming
- Human in the Loop
- Requirements
- Usage
Basic Chatbot
Define the agent state and a simple chatbot node:
from typing import Annotated
from typing_extensions import TypedDict
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
from langchain_ollama import ChatOllama
class AgentState(TypedDict):
messages: Annotated[list, add_messages]
model = ChatOllama(model="granite3.3:2b", temperature=0)
def chatbot(state: AgentState) -> AgentState:
response = model.invoke(state["messages"])
return {"messages": [response]}
graph = StateGraph(AgentState)
graph.add_node("chatbot", chatbot)
graph.set_entry_point("chatbot")
graph.add_edge("chatbot", END)
app = graph.compile()
Visualizing the Graph
You can visualize the graph structure:
from IPython.display import Image, display
try:
display(Image(app.get_graph().draw_mermaid_png()))
except Exception:
pass
Chatbot with Tools
Add tools such as search and math functions:
from dotenv import load_dotenv
load_dotenv()
from langchain_tavily import TavilySearch
def multiply(a: int, b: int) -> int:
"""Multiply a and b"""
return a * b
tools = [TavilySearch(max_results=2), multiply]
model_with_tools = model.bind_tools(tools)
def tool_calling_llm(state: AgentState) -> AgentState:
return {"messages": model_with_tools.invoke(state["messages"])}
from langgraph.prebuilt import ToolNode, tools_condition
graph = StateGraph(AgentState)
graph.add_node("tool_calling_llm", tool_calling_llm)
graph.add_node("tools", ToolNode(tools))
graph.add_edge(START, "tool_calling_llm")
graph.add_conditional_edges("tool_calling_llm", tools_condition)
graph.add_edge("tools", "tool_calling_llm")
app = graph.compile()
Adding Memory
Enable memory to persist conversation context:
from langgraph.checkpoint.memory import MemorySaver
memory = MemorySaver()
app = graph.compile(checkpointer=memory)
Streaming
Stream responses for real-time feedback:
config = {"configurable": {"thread_id": "2"}}
for chunk in app.stream({"messages": "Hello, my name is Rikki and I like software"}, config, stream_mode="updates"):
print(chunk)
Human in the Loop
Allow the agent to request human assistance:
from langgraph.types import Command, interrupt
from langchain_core.tools import tool
@tool
def human_assistance(query: str) -> str:
"""Request assistance from a Human"""
human_response = interrupt({"query": query})
return human_response["data"]
search = TavilySearch(max_results=2)
tools = [search, human_assistance]
model_with_tools = model.bind_tools(tools)
graph = StateGraph(AgentState)
graph.add_node("chatbot", tool_calling_llm)
graph.add_node("tools", ToolNode(tools))
graph.add_conditional_edges("chatbot", tools_condition)
graph.add_edge("tools", "chatbot")
graph.add_edge(START, "chatbot")
app = graph.compile(checkpointer=memory)
Requirements
- Python 3.8+
- LangGraph
- LangChain
- Ollama
- Tavily (for search tool)
- python-dotenv
Install dependencies:
pip install langgraph langchain langchain-ollama langchain-tavily python-dotenv
Usage
Open and run the notebook chatbot/chatbot.ipynb for interactive examples and to explore each feature step by step.
Tip:
- Configure your
.envfile with the necessary API keys for Ollama and Tavily. - Extend the