๐ฏ What You'll Learn Today
LangGraph Tutorial: Building Agent Graphs - Unit 2.2 Exercise 9
Try It Yourself
๐ข Joint Initiative
This tutorial is part of a collaboration between AIPE and 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()