Support Agent Example¶
This example demonstrates a human-in-the-loop support agent workflow with conditional routing and external event handling.
Overview¶
The support agent graph:
- Classifies the user's request and tags it
- Routes based on whether human approval is needed
- Waits for external approval if the request involves refunds or legal issues
- Drafts a response based on the classification and approval status
- Finalizes the response with reviewer attribution
flowchart TD
A[classify_request] -->|needs_human| B{Wait for approval}
A -->|auto| C[draft_reply]
B --> C
C --> D[finalize_reply]
State Model¶
from pydantic import BaseModel, Field
class SupportState(BaseModel):
user_message: str
needs_human: bool = False
approved: bool | None = None
reviewer: str | None = None
draft_response: str | None = None
final_response: str | None = None
tags: list[str] = Field(default_factory=list)
Node Handlers¶
classify_request¶
Analyzes the user message and determines if human review is needed:
def classify_request(state: SupportState) -> dict:
text = state.user_message.lower()
tags = sorted(set(state.tags) | {
"refund" if "refund" in text else "general",
})
return {
"needs_human": "refund" in text or "legal" in text,
"tags": tags,
}
route_after_classify¶
Conditional routing based on classification:
def route_after_classify(state: SupportState) -> RouteDecision:
if state.needs_human and state.approved is not True:
return RouteDecision.wait_for_event(
event_name="approval",
resume_node="draft_reply",
note="awaiting human approval",
)
return RouteDecision.next("draft_reply")
draft_reply and finalize_reply¶
Generate and finalize the response:
def draft_reply(state: SupportState) -> dict:
if state.needs_human and not state.approved:
return {"draft_response": "Your request requires manual review."}
if "refund" in state.tags:
return {"draft_response": "We have queued your refund review."}
return {"draft_response": "Thanks for reaching out."}
def finalize_reply(state: SupportState) -> dict:
suffix = f" Reviewer: {state.reviewer}." if state.reviewer else ""
return {"final_response": f"{state.draft_response}{suffix}".strip()}
Graph Definition¶
from azure_functions_durable_graph import ManifestBuilder
builder = ManifestBuilder(
graph_name="support_agent",
state_model=SupportState,
version="0.1.0",
metadata={"example": True, "profile": "approval"},
)
builder.set_entrypoint("classify_request")
builder.add_node("classify_request", classify_request, route=route_after_classify)
builder.add_event_handler("approval", merge_approval_event)
builder.add_node("draft_reply", draft_reply, next_node="finalize_reply")
builder.add_node("finalize_reply", finalize_reply, terminal=True)
registration = builder.build()
Running the Example¶
Wire it into your function_app.py:
from azure_functions_durable_graph import DurableGraphApp
from examples.support_agent.graph import registration
runtime = DurableGraphApp()
runtime.register_registration(registration)
app = runtime.function_app
Start a run¶
curl -X POST http://localhost:7071/api/graphs/support_agent/runs \
-H "Content-Type: application/json" \
-d '{"input": {"user_message": "I need a refund for order #1234"}}'
Send approval event¶
When the orchestration pauses for approval:
curl -X POST http://localhost:7071/api/runs/{instance_id}/events/approval \
-H "Content-Type: application/json" \
-d '{"approved": true, "reviewer": "alice@example.com"}'
Check final status¶
Expected final state includes:
{
"state": {
"user_message": "I need a refund for order #1234",
"needs_human": true,
"approved": true,
"reviewer": "alice@example.com",
"draft_response": "We have queued your refund review.",
"final_response": "We have queued your refund review. Reviewer: alice@example.com.",
"tags": ["refund"]
}
}
Key Patterns Demonstrated¶
- Conditional routing:
route_after_classifypicks different paths based on state - External events:
wait_for_eventpauses orchestration until human input arrives - Event handlers:
merge_approval_eventprocesses external event payload into state - State merging: each handler returns partial updates merged into the state model