๐ฏ What You'll Learn Today
LangGraph Tutorial: Building Agent Graphs - Unit 2.2 Exercise 9
This tutorial is also available in Google Colab here or for download here
Joint Initiative: This tutorial is part of a collaboration between AI Product Engineer and the Nebius Academy.
This tutorial demonstrates how to build and configure agent graphs in LangGraph, showing proper node construction, edge configuration, and state management.
Key Concepts Covered
- Graph Construction and Configuration
- Node Implementation
- Edge and Flow Control
- State Management
from typing import Annotated, Literal, TypedDict
!pip install langchain-core
!pip install langgraph
from langchain_core.messages import AIMessage, BaseMessage, HumanMessage
from langgraph.graph import END, START, StateGraph
from langgraph.graph.message import add_messages
Step 1: State Definition
Define state structure for our agent graph.
Why This Matters
Proper state structure is crucial because
- Maintains conversation context
- Tracks execution progress
- Enables tool management
Debug Tips
- State Structure Issues:
- Verify all required fields
- Check type annotations
- Monitor state transitions
class State(TypedDict):
"""State container for agent graph system.
Notes:
- messages tracks conversation flow
- current_step tracks execution state
- tool_name tracks selected tools
- tool_output stores execution results
Attributes:
messages: Conversation history with proper typing
current_step: Current execution phase
tool_name: Currently selected tool
tool_output: Latest tool result
"""
messages: Annotated[list[BaseMessage], add_messages]
current_step: str
tool_name: str | None
tool_output: str | None
Step 2: Node Implementation
Create nodes for the agent graph.
Why This Matters
Node implementation is critical because
- Defines system behavior
- Manages state transitions
- Handles tool interactions
Debug Tips
- Node Implementation Issues:
- Verify state updates
- Check message handling
- Monitor tool selection
def tool_selector(state: State) -> State:
"""Select appropriate tools based on conversation.
Notes:
- Handles initial message
- Implements tool selection logic
- Updates state immutably
Args:
state: Current conversation state
Returns:
Updated state with tool selection
"""
if not state.get("messages"):
return {
**state,
"messages": [HumanMessage(content="What would you like to know?")],
"current_step": "waiting_for_input",
}
last_message = state["messages"][-1].content.lower()
# Tool selection logic
if "weather" in last_message:
tool = "weather_tool"
response = "I'll check the weather for you."
elif "calculate" in last_message:
tool = "calculator_tool"
response = "I'll help you with that calculation."
else:
tool = "search_tool"
response = "I'll search for that information."
return {
**state,
"tool_name": tool,
"messages": state["messages"] + [AIMessage(content=response)],
"current_step": "tool_selected",
}
def tool_executor(state: State) -> State:
"""Execute selected tool and manage results.
Notes:
- Verifies tool selection
- Simulates tool execution
- Updates state with results
Args:
state: Current conversation state
Returns:
Updated state with execution results
"""
tool_name = state.get("tool_name")
if not tool_name:
return state
# Simulate tool execution
if tool_name == "weather_tool":
output = "The weather is sunny and 22ยฐC"
elif tool_name == "calculator_tool":
output = "The result is 42"
else:
output = "Here's what I found from the search"
return {**state, "tool_output": output, "current_step": "tool_executed"}
def result_processor(state: State) -> State:
"""Process and format tool execution results.
Notes:
- Verifies tool output
- Formats response
- Updates conversation
Args:
state: Current conversation state
Returns:
Updated state with processed results
"""
tool_output = state.get("tool_output")
if not tool_output:
return state
response = f"Here's what I found: {tool_output}"
return {
**state,
"messages": state["messages"] + [AIMessage(content=response)],
"current_step": "result_processed",
}
Step 3: Flow Control
Implement flow control logic for the graph.
Why This Matters
Flow control is essential because
- Manages conversation progression
- Handles termination conditions
- Enables proper routing
Debug Tips
- Flow Control Issues:
- Check routing conditions
- Verify state transitions
- Monitor termination
def get_next_step(state: State) -> Literal["continue", "end"]:
"""Determine next step in conversation flow.
Notes:
- Checks current step
- Determines continuation
- Handles termination
Args:
state: Current conversation state
Returns:
Next step identifier
"""
return "end" if state.get("current_step") == "result_processed" else "continue"
Step 4: Graph Construction
Build and configure the agent graph.
Why This Matters
Graph construction is crucial because
- Defines system structure
- Configures execution flow
- Enables proper routing
Debug Tips
- Graph Construction Issues:
- Verify node connections
- Check edge conditions
- Monitor graph compilation
def create_agent_graph() -> StateGraph:
"""Create complete agent graph configuration.
Notes:
- Initializes graph
- Adds all nodes
- Configures edges
- Sets up routing
Returns:
Configured StateGraph
"""
graph = StateGraph(State)
# Add nodes
graph.add_node("tool_selector", tool_selector)
graph.add_node("tool_executor", tool_executor)
graph.add_node("result_processor", result_processor)
# Configure edges
graph.add_edge(START, "tool_selector")
graph.add_edge("tool_selector", "tool_executor")
graph.add_edge("tool_executor", "result_processor")
# Add conditional routing
graph.add_conditional_edges(
"result_processor", get_next_step, {"continue": "tool_selector", "end": END}
)
return graph
Step 5: System Demonstration
Test the agent graph system.
Why This Matters
System demonstration verifies
- Proper execution flow
- Correct state updates
- Expected behavior
def demonstrate_graph():
"""Demonstrate agent graph functionality."""
graph = create_agent_graph()
chain = graph.compile()
# Initialize state
state = {
"messages": [HumanMessage(content="What's the weather like?")],
"current_step": "start",
"tool_name": None,
"tool_output": None,
}
print("Agent Graph Demonstration")
print("========================")
result = chain.invoke(state)
print("\nFinal Conversation:")
for msg in result["messages"]:
speaker = "Human" if isinstance(msg, HumanMessage) else "Assistant"
print(f"{speaker}: {msg.content}")
Common Pitfalls
- Incorrect state structure
- Missing edge conditions
- Improper node connections
- Poor error handling
Key Takeaways
- State management is critical
- Node implementation must be consistent
- Edge configuration defines flow
- Proper testing validates behavior
Next Steps
- Add error handling
- Implement state validation
- Add conversation history
- Enhance tool integration
Expected Output
Agent Graph Demonstration
Final Conversation
Human: What's the weather like?
Assistant: I'll check the weather for you.
Assistant: Here's what I found: The weather is sunny and 22ยฐC
if __name__ == "__main__":
demonstrate_graph()
๐ฌ๐ง Chapter