LangGraph Chatbot with External Tools (Groq & LangChain)
This repository contains a Jupyter Notebook implementing an agentic chatbot using LangGraph, LangChain, and the Groq API (llama-3.3-70b-versatile). The chatbot dynamically decides whether it needs to fetch information from external sources (such as Wikipedia) to answer user questions, executes those tools, and feeds the results back to the LLM to construct a final response.
🚀 Features
- Stateful Conversational Agent: Utilizes LangGraph's state management with an message-reducing state schema to preserve conversation history.
- Dynamic Tool Invocation: Implements conditional routing (
tools_condition and ToolNode) allowing the LLM to run external search queries autonomously.
- Groq Integration: Powered by Groq's low-latency, high-performance Llama-3.3-70b model.
- Payload Optimization: Automatically strips out reasoning tokens from intermediate messages to reduce prompt sizes and context window consumption.
- Search Capabilities: Configured to query external knowledge via Wikipedia.
📊 Graph Architecture
The conversational agent is structured as a cyclic directed graph (DAG):
graph TD
START((START)) --> Chatbot[Chatbot Node]
Chatbot --> Action{Call Tool?}
Action -- Yes --> Tools[Tool Node: Wikipedia]
Tools --> Chatbot
Action -- No --> END((END))
- START: Receives the user message and appends it to the state.
- Chatbot Node: Evaluates the messages, prepares the payload (filtering reasoning metadata), and invokes the ChatGroq model bound with tools.
- Action (Conditional Edge): Evaluates whether the LLM generated tool calls.
- If yes, routes to the Tools Node.
- If no, routes to END.
- Tools Node: Executes the specified tool (Wikipedia search) and routes the output back to the Chatbot Node to continue the loop.
🛠️ Prerequisites & Setup
1. Installation
Install the required packages in your Python environment:
pip install langgraph langsmith langchain langchain_groq langchain_community wikipedia "arxiv<2.0.0"
(Note: arxiv is pinned to <2.0.0 in the notebook to ensure compatibility with API wrappers).
2. Environment Variables & API Keys
The notebook is configured to run in a Google Colab environment and expects a Groq API Key stored in Colab Secrets under the key name gorq_api_key.
You can set this up as follows:
🔍 Detailed Code Walkthrough
1. Defining the State
The state keeps track of the conversation history. We use the add_messages reducer to append new messages instead of overwriting the state list.
from typing import Annotated
from typing_extensions import TypedDict
from langgraph.graph.message import add_messages
class State(TypedDict):
messages: Annotated[list, add_messages]
2. Integrating Tools
We wrap the Wikipedia API as a LangChain query run tool:
from langchain_community.utilities import WikipediaAPIWrapper
from langchain_community.tools import WikipediaQueryRun
wiki_wrapper = WikipediaAPIWrapper(top_k_results=1, doc_content_chars_max=300)
wiki_tool = WikipediaQueryRun(api_wrapper=wiki_wrapper)
tools = [wiki_tool]
3. Setting Up the LLM
We initialize ChatGroq using Llama 3.3 and bind the tools to it so the model knows they are available.
from langchain_groq import ChatGroq
llm = ChatGroq(groq_api_key=groq_api_key, model_name="llama-3.3-70b-versatile")
llm_with_tools = llm.bind_tools(tools=tools)
4. Defining the Chatbot Node
The chatbot function cleanses the messaging payloads by removing reasoning_content keys from previous model turns before invoking the LLM.
def chatbot(state: State):
messages = []
for m in state["messages"]:
if hasattr(m, "additional_kwargs"):
# Strip reasoning content to keep payloads minimal
m.additional_kwargs.pop("reasoning_content", None)
messages.append(m)
return {"messages": [llm_with_tools.invoke(messages)]}
5. Compiling the Graph
We build the state graph, connect nodes, add conditional routing, and compile the application.
from langgraph.graph import StateGraph, START, END
from langgraph.prebuilt import ToolNode, tools_condition
graph_builder = StateGraph(State)
# Add nodes
graph_builder.add_node("chatbot", chatbot)
graph_builder.add_node("tools", ToolNode(tools=tools))
# Add edges
graph_builder.add_edge(START, "chatbot")
graph_builder.add_conditional_edges("chatbot", tools_condition)
graph_builder.add_edge("tools", "chatbot")
graph_builder.add_edge("chatbot", END)
graph = graph_builder.compile()
🏃 Running the Chatbot
You can stream messages through the compiled graph to observe nodes firing in real-time:
user_input = "Who is Arwin"
events = graph.stream(
{"messages": [("user", user_input)]},
stream_mode="values"
)
for event in events:
event["messages"][-1].pretty_print()
Sample Output Log:
================================ Human Message =================================
Who is Arwin
================================== Ai Message ==================================
Tool Calls:
wikipedia (7kw6dabsx)
Args:
query: Arwin
================================= Tool Message =================================
Name: wikipedia
Page: Martin Melcher
Summary: Martin Melcher... series of business ventures named Arwin...
================================== Ai Message ==================================
Tool Calls:
wikipedia (6r7veghsa)
Args:
query: Arwin Productions
...
================================== Ai Message ==================================
Arwin is likely referring to Arwin Hawkhauser, a character from the Disney Channel Original Series "The Suite Life of Zack & Cody". He is the hotel's engineer and a friend of the main characters...
📄 License
This project is open-source. Feel free to copy, modify, and use it in your own applications!