Estimated reading time: 5 minutes
Introduction to LangGraph
LangGraph is a powerful framework by LangChain designed for creating stateful, multi-actor applications with LLMs. It provides the structure and tools needed to build sophisticated AI agents through a graph-based approach.
Think of LangGraph as an architect’s drafting table – it gives us the tools to design how our agent will think and act. Just as an architect draws blueprints showing how different rooms connect and how people will flow through a building, LangGraph lets us design how different capabilities will connect and how information will flow through our agent.
Key Features:
- State Management: Maintain persistent state across interactions
- Flexible Routing: Define complex flows between components
- Persistence: Save and resume workflows
- Visualization: See and understand your agent’s structure
In this tutorial, we’ll demonstrate LangGraph by building a multi-step text analysis pipeline that processes text through three stages:
This pipeline showcases how LangGraph can be used to create a modular, extensible workflow for natural language processing tasks.
Setting Up Our Environment
Before diving into the code, let’s set up our development environment.
Installation
!pip install langgraph langchain langchain-openai python-dotenv
Setting Up API Keys
We’ll need an OpenAI API key to use their models. If you haven’t already, you can get one from https://platform.openai.com/signup.
Check out the Full Codes here
from dotenv import load_dotenv
# Load environment variables from .env file (create this with your API key)
load_dotenv()
# Set OpenAI API key
os.environ[“OPENAI_API_KEY”] = os.getenv(‘OPENAI_API_KEY’)
Testing Our Setup
Let’s make sure our environment is working correctly by creating a simple test with the OpenAI model:
# Initialize the ChatOpenAI instance
llm = ChatOpenAI(model=”gpt-4o-mini”)
# Test the setup
response = llm.invoke(“Hello! Are you working?”)
print(response.content)
Building Our Text Analysis Pipeline
Now let’s import the necessary packages for our LangGraph text analysis pipeline:
from typing import TypedDict, List, Annotated
from langgraph.graph import StateGraph, END
from langchain.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
from langchain.schema import HumanMessage
from langchain_core.runnables.graph import MermaidDrawMethod
from IPython.display import display, Image
Designing Our Agent’s Memory
Just as human intelligence requires memory, our agent needs a way to keep track of information. We create this using a TypedDict to define our state structure: Check out the Full Codes here
text: str
classification: str
entities: List[str]
summary: str
# Initialize our language model with temperature=0 for more deterministic outputs
llm = ChatOpenAI(model=”gpt-4o-mini”, temperature=0)
Creating Our Agent’s Core Capabilities
Now we’ll create the actual skills our agent will use. Each of these capabilities is implemented as a function that performs a specific type of analysis. Check out the Full Codes here
1. Classification Node
”’Classify the text into one of the categories: News, Blog, Research, or Other”’
prompt = PromptTemplate(
input_variables=[“text”],
template=”Classify the following text into one of the categories: News, Blog, Research, or Other.\n\nText:{text}\n\nCategory:”
)
message = HumanMessage(content=prompt.format(text=state[“text”]))
classification = llm.invoke([message]).content.strip()
return {“classification”: classification}
2. Entity Extraction Node
”’Extract all the entities (Person, Organization, Location) from the text”’
prompt = PromptTemplate(
input_variables=[“text”],
template=”Extract all the entities (Person, Organization, Location) from the following text. Provide the result as a comma-separated list.\n\nText:{text}\n\nEntities:”
)
message = HumanMessage(content=prompt.format(text=state[“text”]))
entities = llm.invoke([message]).content.strip().split(“, “)
return {“entities”: entities}
3. Summarization Node
”’Summarize the text in one short sentence”’
prompt = PromptTemplate(
input_variables=[“text”],
template=”Summarize the following text in one short sentence.\n\nText:{text}\n\nSummary:”
)
message = HumanMessage(content=prompt.format(text=state[“text”]))
summary = llm.invoke([message]).content.strip()
return {“summary”: summary}
Bringing It All Together
Now comes the most exciting part – connecting these capabilities into a coordinated system using LangGraph:
Check out the Full Codes here
workflow = StateGraph(State)
# Add nodes to the graph
workflow.add_node(“classification_node”, classification_node)
workflow.add_node(“entity_extraction”, entity_extraction_node)
workflow.add_node(“summarization”, summarization_node)
# Add edges to the graph
workflow.set_entry_point(“classification_node”) # Set the entry point of the graph
workflow.add_edge(“classification_node”, “entity_extraction”)
workflow.add_edge(“entity_extraction”, “summarization”)
workflow.add_edge(“summarization”, END)
# Compile the graph
app = workflow.compile()
Workflow Structure: Our pipeline follows this path:classification_node → entity_extraction → summarization → END
Testing Our Agent
Now that we’ve built our agent, let’s see how it performs with a real-world text example:
Check out the Full Codes here
state_input = {“text”: sample_text}
result = app.invoke(state_input)
print(“Classification:”, result[“classification”])
print(“\nEntities:”, result[“entities”])
print(“\nSummary:”, result[“summary”])
Classification: News Entities: [‘OpenAI’, ‘GPT-4’, ‘GPT-3’] Summary: OpenAI’s upcoming GPT-4 model is a multimodal AI that aims for human-level performance and improved safety, efficiency, and scalability compared to GPT-3.
Understanding the Power of Coordinated Processing
What makes this result particularly impressive isn’t just the individual outputs – it’s how each step builds on the others to create a complete understanding of the text.
- The classification provides context that helps frame our understanding of the text type
- The entity extraction identifies important names and concepts
- The summarization distills the essence of the document
This mirrors human reading comprehension, where we naturally form an understanding of what kind of text it is, note important names and concepts, and form a mental summary – all while maintaining the relationships between these different aspects of understanding.
Try with Your Own Text
Now let’s try our pipeline with another text sample:
Check out the Full Codes here
# Process the text through our pipeline your_result = app.invoke({“text”: your_text}) print(“Classification:”, your_result[“classification”])
print(“\nEntities:”, your_result[“entities”])
print(“\nSummary:”, your_result[“summary”])
Classification: Research Entities: [‘MIT’, ‘Google’] Summary: Recent advancements in quantum computing may threaten current encryption methods while also prompting the development of new quantum-resistant techniques.
Adding More Capabilities (Advanced)
One of the powerful aspects of LangGraph is how easily we can extend our agent with new capabilities. Let’s add a sentiment analysis node to our pipeline:
Check out the Full Codes here
class EnhancedState(TypedDict):
text: str
classification: str
entities: List[str]
summary: str
sentiment: str
# Create our sentiment analysis node
def sentiment_node(state: EnhancedState):
”’Analyze the sentiment of the text: Positive, Negative, or Neutral”’
prompt = PromptTemplate(
input_variables=[“text”],
template=”Analyze the sentiment of the following text. Is it Positive, Negative, or Neutral?\n\nText:{text}\n\nSentiment:”
)
message = HumanMessage(content=prompt.format(text=state[“text”]))
sentiment = llm.invoke([message]).content.strip()
return {“sentiment”: sentiment}
# Create a new workflow with the enhanced state
enhanced_workflow = StateGraph(EnhancedState)
# Add the existing nodes
enhanced_workflow.add_node(“classification_node”, classification_node)
enhanced_workflow.add_node(“entity_extraction”, entity_extraction_node)
enhanced_workflow.add_node(“summarization”, summarization_node)
# Add our new sentiment node
enhanced_workflow.add_node(“sentiment_analysis”, sentiment_node)
# Create a more complex workflow with branches
enhanced_workflow.set_entry_point(“classification_node”)
enhanced_workflow.add_edge(“classification_node”, “entity_extraction”)
enhanced_workflow.add_edge(“entity_extraction”, “summarization”)
enhanced_workflow.add_edge(“summarization”, “sentiment_analysis”)
enhanced_workflow.add_edge(“sentiment_analysis”, END)
# Compile the enhanced graph
enhanced_app = enhanced_workflow.compile()
Testing the Enhanced Agent
enhanced_result = enhanced_app.invoke({“text”: sample_text})
print(“Classification:”, enhanced_result[“classification”])
print(“\nEntities:”, enhanced_result[“entities”])
print(“\nSummary:”, enhanced_result[“summary”])
print(“\nSentiment:”, enhanced_result[“sentiment”])
Classification: News
Entities: [‘OpenAI’, ‘GPT-4’, ‘GPT-3’]
Summary: OpenAI’s upcoming GPT-4 model is a multimodal AI that aims for human-level performance and improved safety, efficiency, and scalability compared to GPT-3.
Sentiment: The sentiment of the text is Positive. It highlights the advancements and improvements of the GPT-4 model, emphasizing its human-level performance, efficiency, scalability, and the positive implications for AI alignment and safety. The anticipation of its release for public use further contributes to the positive tone.
Adding Conditional Edges (Advanced Logic)
Why Conditional Edges?
So far, our graph has followed a fixed linear path: classification_node → entity_extraction → summarization → (sentiment)
But in real-world applications, we often want to run certain steps only if needed. For example:
- Only extract entities if the text is a News or Research article
- Skip summarization if the text is very short
- Add custom processing for Blog posts
LangGraph makes this easy through conditional edges – logic gates that dynamically route execution based on data in the current state.
Check out the Full Codes here
Creating a Routing Function
def route_after_classification(state: EnhancedState) -> str:
category = state[“classification”].lower() # returns: “news”, “blog”, “research”, “other”
return category in [“news”, “research”]
Define the Conditional Graph
conditional_workflow = StateGraph(EnhancedState)
# Add nodes
conditional_workflow.add_node(“classification_node”, classification_node)
conditional_workflow.add_node(“entity_extraction”, entity_extraction_node)
conditional_workflow.add_node(“summarization”, summarization_node)
conditional_workflow.add_node(“sentiment_analysis”, sentiment_node)
# Set entry point
conditional_workflow.set_entry_point(“classification_node”)
# Add conditional edge
conditional_workflow.add_conditional_edges(“classification_node”, route_after_classification, path_map={
True: “entity_extraction”,
False: “summarization”
})
# Add remaining static edges
conditional_workflow.add_edge(“entity_extraction”, “summarization”)
conditional_workflow.add_edge(“summarization”, “sentiment_analysis”)
conditional_workflow.add_edge(“sentiment_analysis”, END)
# Compile
conditional_app = conditional_workflow.compile()
Testing the Conditional Pipeline
OpenAI released the GPT-4 model with enhanced performance on academic and professional tasks. It’s seen as a major breakthrough in alignment and reasoning capabilities.
“””
result = conditional_app.invoke({“text”: test_text})
print(“Classification:”, result[“classification”])
print(“Entities:”, result.get(“entities”, “Skipped”))
print(“Summary:”, result[“summary”])
print(“Sentiment:”, result[“sentiment”])
Classification: News
Entities: [‘OpenAI’, ‘GPT-4’]
Summary: OpenAI’s GPT-4 model significantly improves performance in academic and professional tasks, marking a breakthrough in alignment and reasoning.
Sentiment: The sentiment of the text is Positive. It highlights the release of the GPT-4 model as a significant advancement, emphasizing its enhanced performance and breakthrough capabilities.
Check out the Full Codes here
Now try it with a Blog:
Here’s what I learned from a week of meditating in silence. No phones, no talking—just me, my breath, and some deep realizations.
“””
result = conditional_app.invoke({“text”: blog_text})
print(“Classification:”, result[“classification”])
print(“Entities:”, result.get(“entities”, “Skipped (not applicable)”))
print(“Summary:”, result[“summary”])
print(“Sentiment:”, result[“sentiment”])
Classification: Blog
Entities: Skipped (not applicable)
Summary: A week of silent meditation led to profound personal insights.
Sentiment: The sentiment of the text is Positive. The mention of “deep realizations” and the overall reflective nature of the experience suggests a beneficial and enlightening outcome from the meditation practice.
With conditional edges, our agent can now:
- Make decisions based on context
- Skip unnecessary steps
- Run faster and cheaper
- Behave more intelligently
Conclusion
In this tutorial, we’ve:
LangGraph provides a powerful framework for creating AI agents by modeling them as graphs of capabilities. This approach makes it easy to design, modify, and extend complex AI systems.
Next Steps
- Add more nodes to extend your agent’s capabilities
- Experiment with different LLMs and parameters
- Explore LangGraph’s state persistence features for ongoing conversations
Check out the Full Codes here. All credit for this research goes to the researchers of this project. Also, feel free to follow us on Twitter and don’t forget to join our 100k+ ML SubReddit and Subscribe to our Newsletter.
You may also like NVIDIA’s Open Sourced Cosmos DiffusionRenderer [Check it now]
Nir Diamant is an AI researcher, algorithm developer, and specialist in GenAI, with over a decade of experience in AI research and algorithms. His open-source projects have gained millions of views, with over 500K monthly views and over 50K stars on GitHub, making him a leading voice in the AI community.
Through his work on GitHub and the DiamantAI newsletter, Nir has helped millions improve their AI skills with practical guides and tutorials.
