> ## Documentation Index
> Fetch the complete documentation index at: https://docs.poly.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Design principles

> Core priorities and practical guidelines for building agents that work well.

export const Quiz = ({questions = []}) => {
  const [selected, setSelected] = useState({});
  const [resetCount, setResetCount] = useState(0);
  const letters = ['A', 'B', 'C', 'D'];
  const handleSelect = (qIdx, optIdx) => {
    if (selected[qIdx] !== undefined) return;
    setSelected(prev => ({
      ...prev,
      [qIdx]: optIdx
    }));
  };
  const handleReset = () => {
    setSelected({});
    setResetCount(c => c + 1);
  };
  if (!questions?.length) return null;
  const getOptionClasses = ({hasAnswered, isThisCorrect, isThisSelected}) => {
    if (!hasAnswered) {
      return {
        btn: 'flex w-full items-center gap-3 py-2.5 px-4 rounded-xl text-sm leading-normal transition-all duration-150 text-left border cursor-pointer border-gray-200 bg-white text-gray-700 hover:border-gray-300 hover:bg-gray-50 hover:shadow-sm dark:border-gray-600 dark:bg-gray-800 dark:text-gray-200 dark:hover:border-gray-500 dark:hover:bg-gray-700',
        badge: 'w-6 h-6 rounded-full text-xs font-bold flex items-center justify-center shrink-0 leading-none transition-all duration-150 bg-gray-100 text-gray-500 dark:bg-gray-700 dark:text-gray-300',
        icon: null
      };
    }
    if (isThisCorrect) {
      return {
        btn: 'flex w-full items-center gap-3 py-2.5 px-4 rounded-xl text-sm leading-normal transition-all duration-150 text-left border cursor-default border-green-400 bg-green-50 text-green-900 font-medium dark:border-green-500 dark:bg-green-950 dark:text-green-100',
        badge: 'w-6 h-6 rounded-full text-xs font-bold flex items-center justify-center shrink-0 leading-none transition-all duration-150 bg-green-500 text-white dark:bg-green-500',
        icon: <svg className="shrink-0 w-4 h-4 text-green-500 dark:text-green-400 ml-auto" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2.5}>
            <path strokeLinecap="round" strokeLinejoin="round" d="M4.5 12.75l6 6 9-13.5" />
          </svg>
      };
    }
    if (isThisSelected) {
      return {
        btn: 'flex w-full items-center gap-3 py-2.5 px-4 rounded-xl text-sm leading-normal transition-all duration-150 text-left border cursor-default border-red-400 bg-red-50 text-red-900 dark:border-red-500 dark:bg-red-950 dark:text-red-100',
        badge: 'w-6 h-6 rounded-full text-xs font-bold flex items-center justify-center shrink-0 leading-none transition-all duration-150 bg-red-500 text-white dark:bg-red-500',
        icon: <svg className="shrink-0 w-4 h-4 text-red-400 dark:text-red-400 ml-auto" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2.5}>
            <path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
          </svg>
      };
    }
    return {
      btn: 'flex w-full items-center gap-3 py-2.5 px-4 rounded-xl text-sm leading-normal transition-all duration-150 text-left border cursor-default border-gray-100 bg-white text-gray-400 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-500',
      badge: 'w-6 h-6 rounded-full text-xs font-bold flex items-center justify-center shrink-0 leading-none transition-all duration-150 bg-gray-100 text-gray-500 dark:bg-gray-700 dark:text-gray-500',
      icon: null
    };
  };
  return <div key={resetCount} className="my-6">
      {questions.map((q, qIdx) => {
    const answer = selected[qIdx];
    const hasAnswered = answer !== undefined;
    const isCorrect = answer === q.correct;
    return <div key={String(qIdx)} className="mb-8">
            <p className="flex items-start gap-2.5 font-semibold text-sm mb-3 mt-0 leading-relaxed text-gray-900 dark:text-gray-100">
              <span className="inline-flex items-center justify-center w-5 h-5 rounded-full bg-gray-800 dark:bg-gray-200 text-white dark:text-gray-900 text-xs font-bold shrink-0 mt-px leading-none">
                {qIdx + 1}
              </span>
              {q.q}
            </p>

            <div className="flex flex-col gap-2">
              {q.options.map((opt, i) => {
      const isThisCorrect = i === q.correct;
      const isThisSelected = i === answer;
      const {btn, badge, icon} = getOptionClasses({
        hasAnswered,
        isThisCorrect,
        isThisSelected
      });
      return <button key={String(i)} type="button" onClick={() => handleSelect(qIdx, i)} className={btn}>
                    <span className={badge}>{letters[i]}</span>
                    <span className="flex-1">{opt}</span>
                    {icon}
                  </button>;
    })}
            </div>

            {hasAnswered ? <div className={`mt-3 py-3 pl-4 pr-3.5 rounded-r-xl text-sm leading-relaxed border-l-4 ${isCorrect ? 'border-green-500 bg-green-50 dark:bg-green-950 dark:border-green-500' : 'border-red-500 bg-red-50 dark:bg-red-950 dark:border-red-500'}`}>
                <span className={`font-semibold ${isCorrect ? '!text-green-800 dark:!text-green-200' : '!text-red-800 dark:!text-red-200'}`}>
                  {isCorrect ? 'Correct.' : 'Not quite.'}
                </span>{' '}
                <span className="!text-gray-700 dark:!text-gray-300">{q.explanation}</span>
              </div> : null}
          </div>;
  })}

      <button type="button" onClick={handleReset} className="mt-1 text-xs text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 underline underline-offset-2 cursor-pointer transition-colors duration-150">
        Reset quiz
      </button>
    </div>;
};

<Info>
  Read this before the hands-on lessons. It covers **why** agent design works the way it does.
</Info>

## Design priorities

Every design decision should be evaluated against these priorities, **in order**:

<Steps>
  <Step title="1. Complete the task">
    The user must be able to complete their goal. Right integrations, edge-case fallbacks, no dead ends. If the task is impossible, nothing else matters.
  </Step>

  <Step title="2. Make it easy">
    Once the task is possible, remove friction. Each step should be obvious, unnecessary steps should be cut, and the path to completion should be short.
  </Step>

  <Step title="3. Add delight">
    Once it works and it's easy, polish it. Natural pacing, warm tone, good turn-taking.
  </Step>
</Steps>

<Warning>
  **The order matters.** If there's a conflict, the earlier priority wins. A polished agent that can't complete the task is a failure.
</Warning>

### When priorities conflict

Collecting a long reference number by voice has a high transcription error rate. Asking for DTMF (keypad) input is less conversational – but if the alternative is three failed attempts and a handoff, completing the task wins. Use DTMF.

<Quiz
  questions={[
{
q: "A user can complete their task, but the flow asks for information in a confusing order and takes 5 minutes when it should take 2. Which priority is violated?",
options: [
  "Complete the task",
  "Make it easy",
  "Add delight",
  "None – the task gets done",
],
correct: 1,
explanation: "Make it easy. The task completes, so priority 1 is met – but the confusing order and wasted time violate priority 2. Reorder the flow to collect information logically, remove unnecessary steps, and re-test the timing.",
}
]}
/>

## Why sound human

PolyAI agents sound human by design. Not to deceive – because **humans know how to talk to other humans**. Open questions, natural turn-taking, and a human-like voice remove the need for users to learn a new interaction model. Even when users know it's automated, they're more comfortable and more successful when the agent meets them on familiar territory.

## Design guidelines

Use these during design, before build, and when reviewing live conversations. Later lessons reference these by number – they're the shared vocabulary for evaluating agent quality.

### 1. Guide the user

The user should always know what to say next. Two ways to do this:

* **Implicit guidance** – sound conversational, and users respond conversationally. If the agent says "What can I help you with?", most people describe their problem naturally. No instructions needed.
* **Explicit guidance** – tell the user the expected format. "Your order number should be six digits starting with a letter" prevents three rounds of "sorry, I didn't catch that."

Where this matters most: collecting structured data (reference numbers, dates, addresses). If the agent asks "What's your booking reference?" without hinting at format, users guess – and guess wrong.

> **Good:** "Could you read me your booking reference? It's six characters – starts with two letters, then four numbers."
>
> **Bad:** "What's your booking reference?"

### 2. Listen robustly

Real users don't answer one question at a time. They say "tomorrow at 6 for three people" when you asked for the date. They answer "both" when you gave two options. They say "actually, never mind that – can you check my balance instead?" mid-flow.

A well-designed agent handles all of this:

* **Information in any order** – if the user gives name, date, and party size in one sentence, capture all three.
* **Or-questions** – "yes", "no", "both", "neither", "the first one", "whichever's cheaper."
* **Topic switches** – the user can abandon one request and start another without the agent getting confused.
* **Predictable out-of-scope requests** – if users often ask about parking during a restaurant booking, handle it gracefully even if it's not part of the flow.

> A user says "I want to book for tomorrow at 6, there'll be three of us, and my kid has a nut allergy." Your flow collects date, time, party size, and dietary needs separately. The agent should accept all four values from that single utterance and skip ahead.

### 3. Give feedback

Users need to know the agent heard them correctly and that something is happening. Two types:

* **Implicit confirmation** – weave the user's input into the next question. "To look up the booking under 07700 900123, I'll just need your surname." This confirms the phone number without asking "Did you say 07700 900123?"
* **Process feedback** – when something takes time, say so. "Let me pull that up" is better than silence. Silence on a voice call feels like a dropped connection.

Implicit confirmation is almost always better than explicit. Asking "Did you say X?" on every turn doubles the call length and makes the agent sound like a bad phone tree.

> **Implicit:** "Great, so that's a table for three tomorrow at 6. And you mentioned a nut allergy – I'll add that to the booking."
>
> **Explicit (avoid unless critical):** "You said three people. Is that correct?" / "You said tomorrow. Is that correct?" / "You said 6pm. Is that correct?"

Reserve explicit confirmation for high-stakes values – payment amounts, medical details, irreversible actions.

### 4. Support correction

Users make mistakes. They also change their minds. The agent should handle both without restarting the entire flow.

This means:

* **Correct a value** – "Actually, it's the 15th, not the 14th" should update the date without re-collecting everything else.
* **Switch workflows** – if a user starts booking a table and then says "wait, I actually want to cancel a reservation", the agent should pivot cleanly.
* **Undo an action** – if possible, let the user reverse what just happened. If not possible (e.g., an API call already fired), say so clearly.

A common anti-pattern: the agent says "I'm sorry, let's start over" and drops all collected information. This is a design failure – the agent should update only the corrected value and retain everything else.

### 5. Prevent errors

Two parts: confirm before irreversible actions, and plan for things going wrong.

**Before irreversible actions:**

* Booking submissions, payments, cancellations, account changes – always read back the details and get a "yes" before executing.
* This adds one turn to the call, but the cost of undoing an incorrect booking is far higher.

**Plan for failure:**

* APIs time out. Build a fallback ("I wasn't able to process that – let me connect you with someone who can").
* Speech recognition fails. Design retry logic that doesn't sound robotic ("Sorry, I didn't quite catch that. Could you say it one more time?").
* The user gives an answer you didn't expect. Don't dead-end. Route to a sensible default.

> **Good:** "Just to confirm: a table for three on Thursday the 15th at 6pm, with a note about nut allergies. Should I go ahead and book that?"
>
> **Bad:** The agent silently submits the booking after collecting the last field.

<Quiz
  questions={[
{
q: "A user says 'actually, make that 7pm instead of 6.' The agent responds: 'No problem, let's start over. What date would you like?' What guideline does this violate?",
options: [
  "Guideline 1: Guide the user",
  "Guideline 3: Give feedback",
  "Guideline 4: Support correction",
  "Guideline 5: Prevent errors",
],
correct: 2,
explanation: "Guideline 4: Support correction. The user corrected a single value (6pm → 7pm). The agent should update only the time and keep all other collected values – date, party size, dietary notes. Restarting the flow wastes the user's time and signals that the agent can't handle simple changes.",
}
]}
/>

### 6. Act efficiently

Every unnecessary turn costs time, patience, and containment rate. Remove unnecessary steps wherever possible:

* If the user already gave information, don't ask for it again.
* If only one option makes sense, don't present it as a choice – proceed directly.
* If an explanation isn't needed for the user to make a decision, skip it.
* Shorten utterances. "What's your phone number?" not "Could you please provide me with the phone number associated with your account?"

The most common efficiency failure: the agent explains *why* before acting. "In order to look up your booking, I'll need your reference number. Could you please provide that?" Ask directly: "What's your booking reference?"

This is revisited in detail in [Level 3: Writing agent speech](/learn/guides/expert/utterance-design).

### 7. Speak clearly and naturally

Err on the side of informality. Voice agents that sound like legal documents or corporate emails create an unnatural conversational experience and increase user disengagement.

Practical rules:

* Use contractions: "I'll", "we're", "that's"
* Use short sentences. One idea per sentence.
* Avoid filler preambles: "In order to assist you with your request" → cut.
* Avoid hedging: "I believe", "It seems like", "I think" → state the fact or say you don't know.
* Match how real humans speak, not how they write.

| Avoid                                                   | Prefer                        |
| ------------------------------------------------------- | ----------------------------- |
| "Could you please provide me with your account number?" | "What's your account number?" |
| "I apologize for the inconvenience."                    | "Sorry about that."           |
| "I'm going to go ahead and process that for you."       | "Done." or "All set."         |

This is the guideline that matters most for voice. Long, formal sentences create awkward pacing and make users more likely to interrupt or disengage.

This is revisited in detail in [Level 3: Writing agent speech](/learn/guides/expert/utterance-design).

### 8. Behave consistently

Users build expectations fast. If the agent is warm and casual in the greeting, it should stay that way throughout the call. If it uses "we" to refer to the company, it should always use "we."

Consistency applies to:

* **Voice** – same voice model, same speed, same warmth throughout the call.
* **Phrasing style** – if you use contractions, always use them. If you don't, never use them.
* **Response length** – if most answers are 1-2 sentences, a sudden 5-sentence answer feels wrong.
* **Turn-taking rhythm** – if the agent usually waits for a pause before speaking, one instance of cutting the user off is jarring.

The one exception: **deliberate mode shifts**. Reading a legal disclaimer in a different tone signals "this part is important and different." That's intentional inconsistency with a purpose.

### 9. Be flexible

Not every user fits the happy path. Design for the edges:

* **Can't receive SMS** – offer an alternative (email, verbal read-back, transfer to a human).
* **Can't spell their name** – accept phonetic spelling, offer letter-by-letter confirmation.
* **Doesn't have the expected information** – "I don't have my booking reference" should not dead-end the conversation. Offer lookup by name, date, or phone number.
* **Accessibility** – some users need more time, repeat information, or have speech patterns that challenge ASR. The agent should be patient.

The test: can *every* user who has a legitimate reason to call actually complete their task? If any common user profile is locked out, the design fails guideline 1 (complete the task) as well.

### 10. Adapt to the user

Use what you know. If the system has context about the user – their account, their recent activity, their location – use it to skip steps and personalize the conversation.

Examples:

* Caller has a cancelled flight → "I can see your flight was cancelled. Are you calling about rebooking?"
* Caller authenticated via IVR → don't ask for their account number again.
* Caller is on a mobile number you recognize → "Is this about the account ending in 4821?"
* Return caller in the last 24 hours → "Are you calling back about the same issue?"

This saves time and signals competence. However, avoid surfacing information in a way that feels intrusive – if you reference data the user didn't expect you to have, briefly explain the source ("I can see from your account that...").

The risk of *not* adapting: the agent asks for information it already has, which wastes time and makes the user feel like they're talking to a system, not a service.

<Quiz
  questions={[
{
q: "You're about to submit a restaurant booking via API. What should the agent do first?",
options: [
  "Submit immediately to minimize call time",
  "Confirm all collected details back to the user before submitting",
  "Ask if the user wants to add more details",
  "Transfer to a live agent for final confirmation",
],
correct: 1,
explanation: "Booking submissions are irreversible (Guideline 5: Prevent errors). Read back all collected details – date, time, party size, special requests – and get explicit confirmation before calling the API. One extra turn is cheaper than undoing a wrong booking.",
}
]}
/>

<Quiz
  questions={[
{
q: "A user says 'I want to book a table for tomorrow at 6, and there'll be three of us – oh, and my kid has a nut allergy.' Your flow asks for date, time, and party size one at a time. What should happen?",
options: [
  "Ignore the extra info and ask each question sequentially",
  "Accept all provided information at once and skip already-answered questions",
  "Ask the user to repeat each piece separately",
  "Transfer to a live agent because the input is too complex",
],
correct: 1,
explanation: "Guideline 2 (listen robustly): accept information in any order and combination. The user gave date, time, party size, and dietary info in one sentence – capture all four, skip the questions they've already answered, and move straight to confirmation.",
}
]}
/>

***

<Tip>
  Ready to build? Start with [Level 1: Get started](/learn/guides/get-started).
</Tip>
