Adding Human in the Loop to your Chatbot using LangGraph | Beginner's Guide | Part 4
- Pratibha
- Jun 12
- 7 min read
In our previous blogs, we built a LangGraph-powered chatbot that could use tools like web search, maintain memory and hold contextual conversations with users across sessions. But even the smartest bots need help sometimes.

What happens when the AI isn't confident enough to proceed?What if your chatbot needs to escalate a decision to a human before acting?Or maybe, you want to keep a human in control for critical operations?
That’s exactly where Human-in-the-Loop (HITL) systems come into play.
In this post, we’ll take our chatbot to the next level by:
Adding human fallback support to the graph using interrupt
Understanding how LangGraph lets humans pause, resume, and guide the chatbot
Building a conversational agent that knows when to ask for help
But before we dive into code, let’s understand why HITL matters in AI systems.
Why Human-in-the-Loop (HITL) Is a Game-Changer in AI Systems
While automation is powerful, it’s rarely perfect. Most real-world AI systems work best when combined with human oversight—especially in domains like healthcare, legal, finance, customer service, or high-risk decision-making.
Automation Alone Has Limitations
AI models like GPT-4 can answer a wide range of questions, but they’re still probabilistic systems. This means:
They can hallucinate facts.
They can’t always verify sensitive information.
They lack common sense or nuanced judgment in unfamiliar edge cases.
When a bot is unsure or when the stakes are high, we don’t want it guessing.
Human in the Loop = Safer, Smarter, More Reliable
By incorporating humans as part of the loop, we gain:
Accuracy: Humans can validate or correct AI-generated outputs.
Accountability: Human decisions can be logged, reviewed, and audited.
Control: Automation can be paused or rerouted to a human operator when confidence is low or user intent is ambiguous.
Trust: End users feel more comfortable knowing there’s a human option behind the curtain.
This model is especially useful in AI agents and chatbots where:
Tasks may need manual approval.
Users might expect a “real person” for complicated queries.
Tool calls might require human intervention (e.g., confirming a payment or booking).
HITL in LangGraph
LangGraph provides a native way to interrupt execution and wait for a human decision, thanks to its interrupt() mechanism. When the model determines that a human should take over, LangGraph will:
Pause the graph execution.
Expose a message or query to the human.
Resume the flow once the human responds.
This fits beautifully into multi-turn conversations, agent workflows, and tool-based bots—while giving you complete control over how and when humans are looped in.
What We’ll Build — A LangGraph Chatbot That Knows When to Ask for Help
In this tutorial, we’ll extend our memory-enabled LangGraph chatbot from the previous blog by giving it the power to pause and request human input when it encounters a query that requires human assistance.
Specifically, we’ll build a chatbot that:
Responds to general user messages as before (e.g., questions, greetings).
Uses tools (like TavilySearch) when it detects a need for external information.
Recognizes when it needs human help and triggers a pause in execution.
Waits for a human to provide a response (asynchronously).
Resumes the conversation from the exact point where it was paused once a human responds.
This is made possible by combining:
MemorySaver — to retain conversation state across steps and threads.
interrupt() — to pause the graph and await human input.
ToolNode and conditional routing — to manage whether to respond directly, call a tool, or escalate to a human.
Reminder: This code builds directly on top of the LangGraph chatbot we previously created with memory and tool usage. If you haven’t seen that, check out the last blog here to get up and running.
Once complete, you’ll have a chatbot capable of escalating edge cases like this:
User: I need expert guidance for building an AI agent. Could you request assistance for me?
Chatbot: [Requests human input]
Human (later): “Check out LangGraph. It’s reliable and extensible for agent workflows.”
Chatbot: Great! I’ve shared the expert recommendation with you.
This kind of system is invaluable when deploying LLMs in enterprise apps, customer support, internal assistants, or regulated industries where judgment, oversight, and escalation paths are necessary.
Setup & Prerequisites — Let’s Get Ready to Build!
Before we dive into the code, let’s make sure you’ve got everything set up. Don’t worry—it’s quick!
What You’ll Need:
Python 3.9+ installed
A working OpenAI API key (for GPT-4.1)
Access to Jupyter Notebook or any Python IDE
Prior chatbot code from our previous blog — since this is built on top of it
Install Required Packages:
Let’s install the required dependencies. We’ll be using LangChain, LangGraph, and the langchain-tavily tool for search:
pip install -U "langchain[openai]" langgraph langchain-tavily
Note: If you haven’t set up your OpenAI API key before, you can do so like this:
export OPENAI_API_KEY="sk-..." # Mac/Linux # or set OPENAI_API_KEY="sk-..." # Windows
Now, let’s break down the code we’re using in this tutorial — step by step — to see how it all comes together. Buckle up!
Step-by-Step Code Walkthrough — Let’s Build the HITL Chatbot
Step 1: Initialise the Language Model
import os
from langchain.chat_models import init_chat_model
os.environ["OPENAI_API_KEY"] = "sk-..."
llm = init_chat_model("openai:gpt-4.1")
We start by importing and initializing the chat model. We’re using GPT-4.1 here, but feel free to use GPT-3.5 or another model if needed.
Setting the environment variable ensures your API key is picked up securely.
Step 2: Define the Tools (Including the Human in the Loop)
from langchain_tavily import TavilySearch
from langchain_core.tools import tool
from typing_extensions import TypedDict
from typing import Annotated
from langgraph.types import Command, interrupt
We bring in:
TavilySearch: A search tool to answer factual queries from the web.
@tool: A decorator to define tools.
interrupt: This is our hero! It allows the graph to pause and wait for human intervention.
Now we define a custom tool:
@tool
def human_assistance(query: str) -> str:
"""Request assistance from a human."""
human_response = interrupt({"query": query})
return human_response["data"]
This tool does something amazing: when invoked, it stops the chatbot and raises a signal (interrupt) that waits until a human provides a response. Once you manually resume the graph, it continues from where it left off.
Step 3: Define State and Set Up the Graph
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
class State(TypedDict):
messages: Annotated[list, add_messages]
We define the structure of our conversation state. messages is a list that will store user inputs, assistant responses, and tool outputs.
Now we build the graph:
graph_builder = StateGraph(State)
This will help us wire up nodes, tools, memory, and flow logic.
Step 4: Add Our Chatbot Logic
def chatbot(state: State):
message = llm_with_tools.invoke(state["messages"])
assert len(message.tool_calls) <= 1
return {"messages": [message]}
This function is the core of the bot. It:
Feeds the message list to the LLM (with tools attached).
Returns the assistant response and any tool calls it generates.
We disable parallel tool calls (assert len(...)) because LangGraph doesn't resume multiple tool calls cleanly after a human interruption.
Step 5: Bind Tools and Wire It Up
tools = [TavilySearch(max_results=2), human_assistance] llm_with_tools = llm.bind_tools(tools)
from langgraph.prebuilt import ToolNode, tools_condition
graph_builder.add_node("chatbot", chatbot) graph_builder.add_node("tools", ToolNode(tools=tools)) graph_builder.add_conditional_edges("chatbot", tools_condition) graph_builder.add_edge("tools", "chatbot") graph_builder.add_edge(START, "chatbot")
This sets up:
The chatbot node to handle LLM responses.
The tools node to run either the Tavily tool or human assistance based on the response.
Routing logic using tools_condition, which decides if a tool should be called.
Edges that define the flow of control from chatbot → tool → chatbot (loop), starting from START.
Step 6: Add Memory (Same as Before)
from langgraph.checkpoint.memory import MemorySaver
memory = MemorySaver()
graph = graph_builder.compile(checkpointer=memory)
Just like in our previous tutorial, we use MemorySaver to:
Keep track of messages.
Isolate memory per thread_id.
Resume exactly where we left off, even after an interrupt.
Remember: MemorySaver is in-memory only (great for testing). For real deployments, use Redis or other backends.
Step 7: Test It Out!
Let’s run the chatbot and trigger the human-in-the-loop mechanism:
user_input = "I need some expert guidance for building an AI agent. Could you request assistance for me?"
config = {"configurable": {"thread_id": "1"}}
events = graph.stream( {"messages": [{"role": "user", "content": user_input}]}, config, stream_mode="values", )
for event in events:
if "messages" in event: event["messages"][-1].pretty_print()
Output:

At this point, the chatbot recognises it needs help and calls the human_assistance tool. Execution is paused.
Now we (a human!) respond manually:
human_response = ( "We, the experts are here to help! We'd recommend you check out LangGraph to build your agent. " "It's much more reliable and extensible than simple autonomous agents." )
from langgraph.types import Command
human_command = Command(resume={"data": human_response})
events = graph.stream(human_command, config, stream_mode="values")
for event in events: if "messages" in event:
event["messages"][-1].pretty_print()
Output:

Boom! The graph resumes, processes your input, and continues the chat. You’ve just experienced a full human-in-the-loop workflow.
Peek into the Bot’s Brain — Inspecting Memory State
LangGraph makes it super easy to inspect the current state of a conversation — even when human input has interrupted the flow. This is especially helpful for debugging or just satisfying your curiosity!
Here's how you can peek under the hood:
snapshot = graph.get_state(config)
snapshot.next
The get_state() function returns the entire current memory of the graph, including:
The message history for the given thread_id
Any intermediate outputs from tools
What step the bot will execute next
If you check snapshot.next, you'll see where the graph is planning to go after human input. It’s like seeing the next move on a chessboard.
This is incredibly useful if your workflow feels "stuck" and you want to understand what LangGraph is waiting for.
Visualise Your Workflow with Mermaid
LangGraph can generate a diagram of your workflow to show how your nodes connect — great for documentation or just visual learners (like us!).
Try running this:
from IPython.display import Image, display
try: display(Image(graph.get_graph().draw_mermaid_png()))
except Exception: # Optional — requires Graphviz and Mermaid setup pass
Output:

This will output a neat visual map of your graph:
You’ll see START → chatbot → tools → chatbot → ... → END
Tool calls (like human assistance or Tavily) are neatly integrated
It’s also helpful to understand loops and conditions at a glance
If this doesn’t render on your machine, no worries — just make sure graphviz and mermaid-cli are installed via your system or notebook kernel.
Recap:
You’ve officially leveled up! Here's a summary of what you’ve achieved in this tutorial:
You started with a memory-powered chatbot from the previous blog
You introduced a Human-in-the-Loop (HITL) tool using LangGraph's interrupt()
You learned how to pause your chatbot and resume with external (human) input
You inspected graph state and message history with get_state()
You visualized the control flow of your chatbot graph like a pro
The beauty of LangGraph is in how easy it makes building structured, traceable, and flexible LLM workflows — and now you've added human-level decision making on top of it. Bravo! 👏
You may also like these blogs:
Building an intelligent, tool-powered AI system with human feedback in the loop? We’d love to help. Codersarts specializes in real-world AI development and can assist with: LangChain & LangGraph integrations, Toolchains, RAG systems, agents, and more. Building scalable, production-grade workflows

Comments