Skip to main content
Article
langgraphlangchainagentic-workflowsstate-managementorchestrationpythonmulti-agent

Build Stateful, Cyclical AI Agents with LangGraph

LangGraph helps you build reliable AI agents by defining them as stateful graphs. You'll learn to create workflows with nodes (functions) and edges (logic) to build an agent that can reason, act, and loop until a task is complete.

intermediate30 min4 steps
The play
  1. Define the Agent's State
    First, install the necessary libraries. The core of any LangGraph agent is its state. We'll define a `TypedDict` to represent this state, which will be passed between nodes in our graph. Our state will track the conversation messages.
  2. Create Agent and Tool Nodes
    Nodes are the fundamental building blocks of a LangGraph graph, representing functions or tools. We'll create a 'call_model' node that runs our LLM and a 'call_tool' node that executes a search tool.
  3. Define Edges and Conditional Logic
    Edges connect the nodes. LangGraph's power comes from conditional edges, which route the flow based on the current state. We'll create a function that checks if the LLM's last message contained a tool call, deciding whether to run the tool or end the cycle.
  4. Compile and Run the Agent
    Finally, compile the graph into a runnable object using `.compile()`. You can then invoke it with an initial state. We'll use `.stream()` to see the output from each step of the agent's execution, clearly showing the cyclical, stateful workflow in action.
Starter code
import os
import getpass
from typing import TypedDict, Annotated
import operator
from langchain_core.messages import AnyMessage, HumanMessage, ToolMessage
from langchain_openai import ChatOpenAI
from langchain_community.tools import DuckDuckGoSearchRun
from langgraph.graph import StateGraph, END

# Optional: Set your OpenAI API key
if not os.environ.get("OPENAI_API_KEY"):
    os.environ["OPENAI_API_KEY"] = getpass.getpass("Enter your OpenAI API Key: ")

# 1. Define the state for our agent
class AgentState(TypedDict):
    messages: Annotated[list[AnyMessage], operator.add]

# 2. Define the nodes: agent and tools
tool = DuckDuckGoSearchRun()
llm = ChatOpenAI(model="gpt-4o")

# Bind the tool to the LLM
llm_with_tools = llm.bind_tools([tool])

# Agent node: calls the LLM
def call_model(state: AgentState):
    print("---CALLING MODEL---")
    messages = state['messages']
    response = llm_with_tools.invoke(messages)
    return {"messages": [response]}

# Tool node: executes the search tool
def call_tool(state: AgentState):
    print("---CALLING TOOL---")
    last_message = state['messages'][-1]
    tool_call = last_message.tool_calls[0]
    tool_output = tool.invoke(tool_call['args'])
    print(f"---TOOL OUTPUT: {tool_output[:50]}...---")
    return {"messages": [ToolMessage(content=str(tool_output), tool_call_id=tool_call['id'])]}

# 3. Define the edges: routing logic
def should_continue(state: AgentState) -> str:
    last_message = state['messages'][-1]
    if last_message.tool_calls:
        return "continue"
    else:
        return "end"

# 4. Build and compile the graph
workflow = StateGraph(AgentState)

workflow.add_node("agent", call_model)
workflow.add_node("tool", call_tool)

workflow.set_entry_point("agent")

workflow.add_conditional_edges(
    "agent",
    should_continue,
    {
        "continue": "tool",
        "end": END
    }
)

workflow.add_edge('tool', 'agent')

app = workflow.compile()

# 5. Run the agent
inputs = {"messages": [HumanMessage(content="What is the current capital of Brazil and what was the previous one?")]}
for output in app.stream(inputs, {"recursion_limit": 5}):
    for key, value in output.items():
        print(f"Node '{key}' output:\n{value}\n---")

final_state = app.invoke(inputs, {"recursion_limit": 5})
print("\nFinal Answer:")
print(final_state['messages'][-1].content)
Build Stateful, Cyclical AI Agents with LangGraph — Action Pack