> For the complete documentation index, see [llms.txt](/llms.txt).
> A full single-fetch corpus is available at [llms-full.txt](/llms-full.txt).
---
title: Build a customer support agent
description: Search docs, draft replies, wait for review, and turn support outcomes into eval cases.
tags: ["Agents", "RAG", "Evals"]
date: 2026-05-13
last_verified: 2026-05-13
audience: both
---

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

```python
@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.

## Next steps

- [Build a durable human-approval AI workflow](/cookbooks/durable-human-approval-ai-workflow.md)
- [Turn a failed production AI run into an eval](/cookbooks/production-run-to-eval.md)
- [Build a RAG chatbot with memory](/cookbooks/rag-chatbot-memory.md)
