LangChain & LangGraph for AI Agents
Back to LangGraph for Stateful Agents & Human-in-the-Loop

Case 2 — Stateful Support Agent with Cycle Capping

End-to-end support agent with tools, memory, and a clean state graph.

63 minutesProject submission
🎯 Free Guest Mode: You are learning for free. Sign in to save your completion progress and quiz answers.

Assignment Instructions

Executive Briefing: An enterprise e-commerce platform requires a tier-1 support agent that handles order status queries, delivery tracking, and returns. If a customer problem cannot be solved autonomously or an adversarial user attempts to trap the agent in an infinite loop, the agent must cap its resolution cycles at 3 turns, route to an escalate_to_human node, and terminate gracefully with a ticket summary.


1. Enterprise Scenario & Requirements

Linear chains break when agents face non-deterministic conversations or failed tool runs. Using LangGraph:

  1. Shared State Schema: Create a SupportState TypedDict containing messages: Annotated[list[BaseMessage], operator.add], customer_id: str, iteration_count: int, and escalated: bool.
  2. Conditional Router: Implement a conditional edge function route_next_step that inspects the latest message. If tools are requested and iteration_count < 3, route to ToolNode. If iteration_count >= 3, route to escalate.
  3. Loop Defense: Guarantee that under no circumstances does the graph loop infinitely.
  4. State Compilation: Compile the StateGraph and demonstrate clean transitions using mock order database tools.

2. Explicit Deliverables

  1. state.py: Typed state schema with message reducers and iteration counters.
  2. graph.py: Complete StateGraph compilation with nodes (agent, tools, escalate) and conditional edges.
  3. test_support_agent.py: Automated tests demonstrating: (a) instant 1-turn resolution, (b) 2-turn resolution requiring follow-up tool execution, and (c) adversarial prompt triggering 3-cycle cap and human escalation.
  4. trace_visualization.png / graph_ascii.txt: Rendered LangGraph topology.

3. Starter Code & Scaffold

from typing import TypedDict, Annotated, Literal
from langchain_core.messages import BaseMessage, HumanMessage, AIMessage
import operator
from langgraph.graph import StateGraph, END
from langgraph.prebuilt import ToolNode

class SupportState(TypedDict):
    messages: Annotated[list[BaseMessage], operator.add]
    customer_id: str
    iteration: int
    escalated: bool

def agent_node(state: SupportState):
    # LLM reasoning step: increment iteration counter
    new_iter = state.get("iteration", 0) + 1
    # Mock LLM call or real ChatOpenAI call
    return {"iteration": new_iter}

def escalate_node(state: SupportState):
    msg = AIMessage(content="Your request has been escalated to a human tier-2 supervisor. Ticket #7192 created.")
    return {"messages": [msg], "escalated": True}

def router_condition(state: SupportState) -> Literal["tools", "escalate", "__end__"]:
    if state["iteration"] >= 3:
        return "escalate"
    last_message = state["messages"][-1]
    if hasattr(last_message, "tool_calls") and last_message.tool_calls:
        return "tools"
    return "__end__"

4. 100-Point Grading Rubric

CriterionPointsExcellent (25 pts)Acceptable (15 pts)Needs Work (5 pts)
State Reducers & Schema25 ptsAnnotated[list, operator.add] correctly preserves conversation history across nodes.State updates work but overwrite previous messages.Untyped state dictionary without schema validation.
Conditional Edge Routing25 ptsRouting function deterministically maps state attributes to correct destination nodes.Routing functions correctly for happy path only.Hardcoded static edges instead of conditional routing.
Cycle Capping Defense25 ptsHard iteration limit (3 turns) strictly enforced; zero infinite loop vulnerabilities.Loop limit exists but fails under edge-case prompts.No loop protection; graph hangs on circular tasks.
Escalation Delivery25 ptsEscalation node produces structured ticket metadata and user-friendly handover message.Escalation terminates without recording ticket context.Graph terminates abruptly without notifying user.
Checking your access…