Build a customer support agent
Search docs, draft replies, wait for review, and turn support outcomes into eval cases.
This cookbook builds a support agent that handles real production concerns: retrieval, customer context, review before send, trace inspection, and evals from resolved tickets.
Scenario
A customer opens a ticket. The agent searches product docs, checks account state, drafts a response, waits for human approval, and records the final outcome for future evaluation.
What you build
- A support-triage workflow.
- Tools for docs search and customer lookup.
- A draft response step with structured output.
- A human-review pause before sending.
- A feedback path into an eval dataset.
Workflow shape
@workflow
async def support_agent_workflow(ctx: WorkflowContext, ticket_id: str) -> SupportOutcome:
ticket = await ctx.step(load_ticket, ticket_id)
account = await ctx.step(load_account_context, ticket.customer_id)
docs = await ctx.step(search_support_docs, ticket.body)
draft = await ctx.step(draft_support_reply, ticket, account, docs)
decision = await ctx.wait_for_signal(
"support_reply_review",
timeout="3d",
metadata={"ticket_id": ticket.id, "draft_id": draft.id},
)
if decision.status != "approved":
return SupportOutcome(status="needs_changes", draft_id=draft.id)
sent = await ctx.step(send_reply_once, ticket.id, draft.id)
await ctx.step(record_support_eval_case, ticket.id, draft.id, sent.id)
return SupportOutcome(status="sent", message_id=sent.id)The agent is useful because every step is visible and recoverable.
Trace review
For each support run, reviewers should see:
- ticket input,
- retrieved docs,
- account context used,
- draft response,
- approval decision,
- final send receipt.
This makes support QA concrete. A bad answer can be traced to a retrieval miss, an account-state error, or a prompt failure.
Eval loop
When a reviewer edits the draft, record the corrected response as an eval case. Later prompt and model changes can replay the same ticket and compare against the approved answer.
Production checks
- Tenant and deployment IDs are included on every direct HTTP call.
- Retrieved docs are stored as trace evidence.
- The send step uses an idempotency key.
- Rejected drafts stop before the send step.
- Reviewer edits can become eval cases.