Customer Service Assistant

Multi-agent travel booking assistant with flight and hotel search

Get Code

The customer-service template is a multi-agent system wired around a durable conversation entity. A routing agent classifies the incoming message and hands off to a specialist — billing, shipping, or technical — and certain actions (refunds, escalations) pause the workflow until a human operator approves them. The per-conversation state lives in an entity, so every follow-up message resumes the same durable context.

What you’ll build

  • A routing agent that classifies incoming messages and hands off to the right specialist
  • Specialist agents for billing, shipping, and technical support, each with their own tool set
  • A Conversation entity that persists messages, customer info, and open actions across turns
  • Human-in-the-loop approval gates using ctx.wait_for_user() for refunds and escalations

Requirements

  • Python 3.10+
  • OPENAI_API_KEY or ANTHROPIC_API_KEY
  • Optional: API keys for your CRM, payment processor, and order system (the template ships with mocked versions)
  • The AGNT5 CLI

Install

curl -LsSf https://agnt5.com/cli.sh | bash

Setup

Scaffold the project

agnt5 create customer_service support-bot
cd support-bot

Set environment variables

export OPENAI_API_KEY=sk-...

Install dependencies

uv sync
pip install -e .

Start a conversation

agnt5 dev up
agnt5 invoke handle_message --input '{
  "conversation_id": "conv_123",
  "customer_id": "cus_abc",
  "message": "My order never arrived and I want a refund."
}'

How it works

Every incoming message is routed into a workflow keyed by conversation_id. The workflow loads (or creates) a Conversation entity for that id — the entity is the durable source of truth for message history, the assigned specialist, and any pending approvals. The routing agent reads the latest message, picks a specialist, and calls into that specialist agent via ctx.invoke(). Specialists have scoped tool sets: billing can issue refunds, shipping can look up tracking, technical can file bug reports.

Actions that cross a policy threshold — refunds over $50, account closures, manager escalations — pause the workflow with ctx.wait_for_user(). The runtime checkpoints the pending state and waits. An operator reviewing the queue in Studio (or hitting the approvals API) resolves the gate, and the workflow resumes exactly where it stopped. Between messages, the entity keeps state durable: a follow-up hours later hits the same conversation, with the same specialist already assigned, and no context lost.

Entities are keyed, single-writer state containers. Two messages for the same conversation are serialized automatically — you never have to reason about concurrent writes to the same conversation’s history.

Key files

  • worker.py — Registers the workflow, the three specialist agents, and the entity.
  • entities/conversation.py — The Conversation entity: message log, assigned specialist, pending approvals.
  • agents/router.py — The routing agent’s prompt and classification logic.
  • agents/billing.py, agents/shipping.py, agents/technical.py — Specialist agents with their tools.
  • approvals.py — The wait_for_user gate for refunds and escalations.

Customize

Add a specialist. Create a new agent module, register its tools, and add a route in agents/router.py. The entity and workflow don’t change.

Tune the approval threshold. approvals.py encodes the policy. Change the refund ceiling or add new gates (large order cancellations, VIP escalations).

Swap the classifier. The router is an LLM prompt by default. For higher-volume deployments, replace it with a small fine-tuned classifier or a rules engine — the handoff contract stays the same.

Next steps