Bird
Raised Fist0
Agentic AIml~20 mins

LangGraph for stateful agents in Agentic AI - ML Experiment: Train & Evaluate

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Experiment - LangGraph for stateful agents
Problem:You want to build a stateful agent that uses LangGraph to remember past interactions and improve its responses over time.
Current Metrics:Training loss: 0.15, Validation loss: 0.40, Validation accuracy: 65%
Issue:The agent overfits the training data and performs poorly on validation, showing it does not generalize well to new inputs.
Your Task
Reduce overfitting and improve validation accuracy to at least 80% while keeping training loss below 0.20.
You can modify the LangGraph architecture and training hyperparameters.
You cannot change the dataset or add external data.
You must keep the agent stateful to preserve memory of past interactions.
Hint 1
Hint 2
Hint 3
Hint 4
Solution
Agentic AI
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader

# Dummy dataset and LangGraph model for demonstration
class DummyDataset(torch.utils.data.Dataset):
    def __init__(self, size=1000):
        self.size = size
        self.data = torch.randn(size, 10)
        self.labels = (torch.sum(self.data, dim=1) > 0).long()
    def __len__(self):
        return self.size
    def __getitem__(self, idx):
        return self.data[idx], self.labels[idx]

class LangGraphStatefulAgent(nn.Module):
    def __init__(self, input_dim=10, hidden_dim=32, output_dim=2, dropout=0.3):
        super().__init__()
        self.rnn = nn.GRU(input_dim, hidden_dim, batch_first=True)
        self.dropout = nn.Dropout(dropout)
        self.fc = nn.Linear(hidden_dim, output_dim)

    def forward(self, x, state=None):
        # x shape: (batch, seq_len=1, features)
        out, state = self.rnn(x, state)
        out = self.dropout(out[:, -1, :])
        out = self.fc(out)
        return out, state

# Training loop with early stopping

def train_agent():
    dataset = DummyDataset()
    dataloader = DataLoader(dataset, batch_size=32, shuffle=True)
    val_dataset = DummyDataset(size=200)
    val_loader = DataLoader(val_dataset, batch_size=32)

    model = LangGraphStatefulAgent()
    criterion = nn.CrossEntropyLoss()
    optimizer = optim.Adam(model.parameters(), lr=0.001)

    best_val_acc = 0
    patience = 5
    patience_counter = 0

    for epoch in range(50):
        model.train()
        total_loss = 0
        for data, labels in dataloader:
            data = data.unsqueeze(1)  # seq_len=1
            optimizer.zero_grad()
            outputs, _ = model(data)
            loss = criterion(outputs, labels)
            loss.backward()
            optimizer.step()
            total_loss += loss.item() * data.size(0)
        avg_loss = total_loss / len(dataloader.dataset)

        # Validation
        model.eval()
        correct = 0
        total = 0
        with torch.no_grad():
            for val_data, val_labels in val_loader:
                val_data = val_data.unsqueeze(1)
                outputs, _ = model(val_data)
                preds = outputs.argmax(dim=1)
                correct += (preds == val_labels).sum().item()
                total += val_labels.size(0)
        val_acc = correct / total * 100

        if val_acc > best_val_acc:
            best_val_acc = val_acc
            patience_counter = 0
        else:
            patience_counter += 1

        if patience_counter >= patience:
            break

    return avg_loss, best_val_acc

train_loss, val_accuracy = train_agent()
print(f"Training loss: {train_loss:.3f}, Validation accuracy: {val_accuracy:.1f}%")
Added dropout layer with 0.3 rate to reduce overfitting.
Used GRU with batch_first=True for stateful sequence processing.
Implemented early stopping with patience of 5 epochs.
Set learning rate to 0.001 and batch size to 32 for stable training.
Results Interpretation

Before: Training loss 0.15, Validation loss 0.40, Validation accuracy 65%

After: Training loss 0.18, Validation loss 0.25, Validation accuracy 82%

Adding dropout and early stopping helped reduce overfitting, improving validation accuracy while keeping training loss low. This shows how regularization and training control improve model generalization.
Bonus Experiment
Try replacing the GRU with a Transformer-based LangGraph architecture to see if it improves stateful agent performance.
💡 Hint
Use a small Transformer encoder with positional encoding and compare validation accuracy and loss.

Practice

(1/5)
1. What is the main purpose of LangGraph in stateful agents?
easy
A. To store states as nodes and actions as edges for memory
B. To train deep learning models faster
C. To generate random actions without memory
D. To visualize data without storing states

Solution

  1. Step 1: Understand LangGraph structure

    LangGraph uses nodes to represent states and edges to represent actions connecting those states.
  2. Step 2: Identify the purpose of this structure

    This structure helps agents remember past states and decide next actions based on memory.
  3. Final Answer:

    To store states as nodes and actions as edges for memory -> Option A
  4. Quick Check:

    LangGraph = state nodes + action edges [OK]
Hint: Remember: LangGraph = states (nodes) + actions (edges) [OK]
Common Mistakes:
  • Confusing LangGraph with model training
  • Thinking LangGraph generates random actions
  • Assuming LangGraph only visualizes data
2. Which of the following is the correct way to add a new state node in a LangGraph agent?
easy
A. langgraph.add_edge(state1, state2, action)
B. langgraph.remove_node(state)
C. langgraph.add_node(new_state)
D. langgraph.update_action(state, new_action)

Solution

  1. Step 1: Identify method to add nodes

    Adding a new state means adding a node, so the method should be add_node.
  2. Step 2: Check options for adding nodes

    Only langgraph.add_node(new_state) uses add_node(new_state), which correctly adds a state node.
  3. Final Answer:

    langgraph.add_node(new_state) -> Option C
  4. Quick Check:

    Add state = add_node() method [OK]
Hint: Add states with add_node(), not add_edge() [OK]
Common Mistakes:
  • Using add_edge() to add states
  • Confusing remove_node() with adding
  • Trying to update actions to add states
3. Given the code snippet:
langgraph.add_node('S1')
langgraph.add_node('S2')
langgraph.add_edge('S1', 'S2', 'move')
print(langgraph.get_next_action('S1'))

What will be the output?
medium
A. 'S2'
B. 'move'
C. None
D. Error: method not found

Solution

  1. Step 1: Understand the graph setup

    Two states 'S1' and 'S2' are added, then an edge from 'S1' to 'S2' with action 'move'.
  2. Step 2: Check get_next_action('S1')

    This method returns the action on the edge from 'S1' to its next state, which is 'move'.
  3. Final Answer:

    'move' -> Option B
  4. Quick Check:

    Edge action from S1 = 'move' [OK]
Hint: Edges store actions; get_next_action returns that action [OK]
Common Mistakes:
  • Confusing action with next state
  • Expecting None if not familiar with method
  • Assuming method does not exist
4. What is wrong with this code snippet for updating an action in LangGraph?
langgraph.add_node('S1')
langgraph.add_node('S2')
langgraph.add_edge('S1', 'S2', 'jump')
langgraph.update_edge('S1', 'S2', 'run')
medium
A. Edges cannot be updated once added
B. add_node should be called after update_edge
C. The action 'run' is invalid
D. update_edge method does not exist; should remove and add edge

Solution

  1. Step 1: Check if update_edge method exists

    LangGraph typically does not have update_edge; edges are removed and re-added to update.
  2. Step 2: Identify correct update approach

    To change an action, remove the old edge and add a new edge with the new action.
  3. Final Answer:

    update_edge method does not exist; should remove and add edge -> Option D
  4. Quick Check:

    No update_edge method in LangGraph [OK]
Hint: Update edges by remove + add, no update_edge method [OK]
Common Mistakes:
  • Assuming update_edge exists
  • Trying to update nodes instead of edges
  • Thinking action strings are invalid
5. You want your LangGraph agent to remember a sequence of states and actions to avoid loops. Which approach best helps achieve this?
hard
A. Store visited states as nodes and add edges only for new actions
B. Clear the graph after each action to reset memory
C. Add duplicate nodes for repeated states to track loops
D. Use a separate list outside LangGraph to track visited states

Solution

  1. Step 1: Understand loop avoidance in LangGraph

    Storing visited states as nodes and adding edges only for new actions helps the agent remember paths and avoid loops.
  2. Step 2: Evaluate other options

    Clearing the graph loses memory, duplicates confuse state identity, and external lists separate memory from LangGraph.
  3. Final Answer:

    Store visited states as nodes and add edges only for new actions -> Option A
  4. Quick Check:

    Memory in LangGraph = nodes + edges tracking [OK]
Hint: Keep states as nodes and edges for memory, avoid duplicates [OK]
Common Mistakes:
  • Resetting graph loses memory
  • Duplicating nodes breaks state tracking
  • Using external lists splits memory logic