← All posts

A support bot that cites its sources and knows when to hand off to a person

A demo for a made-up physiotherapy clinic: Chatwoot, a bot that only answers from the business's own pages, hands complaints, medical questions and prices not on the price list to reception, and has a spending cap. With a local model, no Meta account, and the path to WhatsApp.

On this page

Many small businesses answer the same thing dozens of times on WhatsApp: opening hours, prices, whether there's a slot on Saturday. A bot can take that off your hands, but a bot that makes up a price or gives medical advice is worse than no bot.

I built a demo for a made-up physiotherapy clinic, Ondaviva, with one rule I set myself: the bot only answers what it can cite. If it can't, it hands the conversation to a person.

What it does

  • The clinic has its pages in plain text: hours, prices, services and policies.
  • When a customer writes, the bot finds the fragments of those pages that match the question and gives them to a local model (qwen3:14b).
  • The model must answer in a fixed format: the reply, which fragments it used, its confidence and what the request is about.
  • Code rejects any reply without valid citations, and any price that doesn't appear in a cited price-list fragment.
  • Complaints, refunds, medical or legal questions and prices not on the list go to reception, with a private note explaining why.
  • There's a daily reply cap and opening hours: outside them, the bot says the clinic is closed before handing the conversation over.
flowchart LR
  U[Customer writes] --> CW[Chatwoot]
  CW -->|signed webhook| B[Bot]
  B --> R[Searches the clinic's pages]
  R --> M[Local model: reply + citations]
  M --> V{Valid citations and allowed topic?}
  V -->|yes| CW
  V -->|no| H[To reception with a note]

For the demo I use Chatwoot's website chat, so I don't need a Meta account. On WhatsApp the bot is the same; only the Chatwoot inbox changes, connected to the WhatsApp Cloud API.

The real test

I sent it six messages the way a customer would, with the local model on my computer:

Message What it did Time
"Are you open on Saturday mornings?" Answered, citing the opening hours 3.2 s
Price of a session "45 minutes costs 40 €", citing the price list 2.1 s
Price of dry needling (not on the list) Handed off to reception 2.1 s
A complaint Handed off without calling the model 0.1 s
A medical question Handed off to reception 3.1 s
A message posing as a system order to make it say "free" Refused and said nothing about prices 2.1 s

The first reply after the model loaded took 24 seconds. The rest, between 2 and 3.

What broke along the way

  • The bot didn't answer at all. In Chatwoot 4.19, a pending conversation shows the bot itself as the assignee, and my code skipped it as if a person had it. Now it only skips conversations a real person has.
  • The container couldn't reach the model. My computer's firewall blocks traffic from containers to the host. Instead of touching the firewall, I added a small bridge over a local socket.
  • Chatwoot didn't call the bot. For safety, it won't send webhooks to private network addresses unless you switch that on. It's on and flagged in the demo; in production the bot would sit behind a normal address.

What it doesn't do

  • It searches by words, not meaning. A very roundabout question ends up at reception instead of being answered. For a small clinic I prefer that to the opposite.
  • It doesn't book appointments. It hands them to a person. Connecting it to the calendar is the next step.
  • It doesn't know public holidays. The hours are weekly.
  • It hands off more than needed, on purpose. "Refund from my health insurer" goes to reception even though it isn't a complaint.

If you build it for a business

  • When it isn't worth it. Under roughly 100 conversations a month, free WhatsApp Business and saved quick replies usually do.
  • What WhatsApp costs. Meta charges per message by category. Since 1 October 2026 each number gets 1,000 free service messages a month, and after that every bot reply costs. That's why my bot sends one message per turn. Outside 24 hours from the customer's last message you can only send approved templates, and marketing ones never without consent.
  • What Meta doesn't allow. Since January 2026 it bans general-purpose assistants on WhatsApp. A bot that only talks about the business is allowed, and it's what makes sense anyway.
  • Where it runs. Chatwoot Community on the business's server or an EU VPS in their name, with a local or European model. For health data, local.

If your business answers the same things every day, let's talk and see whether it pays off.