Easier to read with cream paper, a tint, more contrast or larger text? Choose your colours and text, once, for every page.

Free lesson

Handing over from AI to a person

After this lesson: I can design the point where a person takes over.

60 min lesson6 commandsAI coding agent lab: use opencode to explain and fix code, and check its work

Asking for a person, and getting a loop

A customer types "let me talk to a person". The chatbot replies "I can help with that!" and asks the same question again. The customer closes the app and rings the shop.

A good feature knows when to stop. The hand over is a part of the design, not a failure of it.

By the end of this lesson

Note

I can design the point where a person takes over.

Key words

WordWhat it means
Hand overpassing a conversation to a person
Triggera rule that starts a hand over
Context notewhat the person is told so nobody repeats
Queuethe list of people waiting for a person
Returngiving the conversation back to the model

The cells students fill in are left blank in this preview.

Four triggers decide when to hand over

Write the triggers as rules, so they can be tested. Four are common. The person asked for a human. The topic is one a model must not decide, such as a refund. The model's confidence is low. The chat has run too many turns.

The first one must always work. Nobody should have to argue with a machine to reach a person.

The note and the wait

The person who takes over should not ask the customer to start again. Hand across a short note: the reasons, the last message and the number of turns.

Tell the customer how long the wait is, using a real number. When the person finishes, decide whether the chat returns to the model or closes.

A common mistake

Warning

Many people think handing over means the AI feature failed, so they make it hard to reach a person. It is the other way. A quick, clear hand over keeps the customer. Make it easy to ask, and send the context across.

Write the model helper, part 1

Command
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const base = process.env.AI_URL || \"http://ai:4000\";' '// The token counts of a reply, or null when the reply carries none.' 'function count(data, name) {' '  return data.usage && typeof data.usage[name] === \"number\" ? data.usage[name] : null;' '}' > model.js"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Write the model helper, part 2

Command
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function ask(messages, sample, max) {' '  try {' '    const res = await fetch(base + \"/v1/chat/completions\", {' '      method: \"POST\",' '      headers: { \"content-type\": \"application/json\", authorization: \"Bearer lab\" },' '      body: JSON.stringify({ model: \"lab\", messages: messages, max_tokens: max || 100 }),' '      signal: AbortSignal.timeout(30000),' '    });' '    if (res.ok === false) throw new Error(\"status \" + res.status);' '    const data = await res.json();' '    const text = data.choices[0].message.content;' '    return { text, inTokens: count(data, \"prompt_tokens\"), outTokens: count(data, \"completion_tokens\"), recorded: false };' '  } catch (error) {' '    console.log(\"Recorded sample: no model answered (\" + error.message + \").\");' '    return { text: sample, inTokens: null, outTokens: null, recorded: true };' '  }' '}' 'module.exports = { ask };' >> model.js"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Write the trigger checker, part 1

Command
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { ask } = require(\"./model\");' 'const RULES = { maxTurns: 6, minConfidence: 50, topics: [\"refund\", \"complaint\"] };' 'const CHATS = [' '  { id: \"c1\", turns: 3, confidence: 90, topic: \"hours\", asked: false, last: \"When do you open?\" },' '  { id: \"c2\", turns: 4, confidence: 80, topic: \"refund\", asked: false, last: \"I want my money back.\" },' '  { id: \"c3\", turns: 8, confidence: 40, topic: \"delivery\", asked: false, last: \"It still has not come.\" },' '  { id: \"c4\", turns: 2, confidence: 95, topic: \"hours\", asked: true, last: \"Let me talk to a person.\" },' '];' > handover.js"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Write the trigger checker, part 2

Command
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function reasons(c) {' '  const out = [];' '  if (c.asked) out.push(\"asked\");' '  if (RULES.topics.includes(c.topic)) out.push(\"topic\");' '  if (c.confidence < RULES.minConfidence) out.push(\"confidence\");' '  if (c.turns > RULES.maxTurns) out.push(\"turns\");' '  return out;' '}' >> handover.js"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Write the trigger checker, part 3

Command
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' '  for (const c of CHATS) {' '    const why = reasons(c);' '    console.log(c.id + \" \" + (why.length > 0 ? \"hand over \" + why.join(\"+\") : \"stay with the model\"));' '  }' '  const note = CHATS[2];' '  console.log(\"note \" + JSON.stringify({ id: note.id, reasons: reasons(note), last: note.last, turns: note.turns }));' '  const msg = \"Write one short line telling a customer a person is taking over and they need not repeat themselves.\";' '  const reply = await ask([{ role: \"user\", content: msg }], \"A person is taking over now. You do not need to repeat anything.\", 30);' '  console.log(\"customer sees: \" + reply.text);' '}' 'main();' >> handover.js"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Run the trigger checker

Command
docker exec -w /home/node/project agent node handover.js

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

One possible output

LineWhat it shows
c1 stay with the modelNo trigger fired
c2 hand over topicA refund is a topic for a person
c3 hand over confidence+turnsTwo triggers at once
c4 hand over askedThe customer asked, so always
note {"id":"c3",...}What the person is handed

The cells students fill in are left blank in this preview.

About this lab and its source: AI coding agent lab: use opencode to explain and fix code, and check its work

Teaching a class? Set this module for your students with a teacher guide, marked assignments and a lab for every student.