← Blog

Chat agents

Telegram-agent voor een crypto-belastingkantoor: triage

Een Nederlands crypto-belastingkantoor klopte in februari bij ons aan met een Telegram-inbox die elke maart vastliep. We bouwden een agent die antwoordt wat hij kan en doorzet wat hij niet kan.

Jacob Molkenboer· Oprichter · A Brand New Company· 5 jun 2026· 9 min
Messing bureaubel, gevouwen telegrambriefjes met linnen touw en groen labeltje, leren onderlegger, lakzegel op ivoorpapier.

Op een zondagavond eind februari stuurde de managing partner van een Nederlands crypto-belastingkantoor ons een screenshot door. Het was hun belangrijkste Telegram-groep: 312 ongelezen berichten, drie vastgepinde herinneringen over CSV-exports, en één enkele vraag, weggestopt bij bericht 244, die luidde: "Moet ik een bridge tussen twee L2's opgeven?"

De aangiftedeadline was 1 mei. Het kantoor had veertien mensen. Ongeveer 600 klanten, vrijwel allemaal met een voorkeur voor Telegram boven e-mail. De partner had zijn zaterdagochtend besteed aan scrollen, niet aan adviseren. Hij stelde de juiste vraag: "Kan een bot dit voor ons lezen, maar niet de echte vragen beantwoorden?"

Dat is de post. We hebben die bot gebouwd. Vier weken later ging hij live. Dit zit erin, en dit hadden we beter kunnen doen.

De vorm van een belastingkantoor-inbox

Het eerste wat je met een supportkanaal doet, is het lezen. Niet scannen. Een week lang elk bericht lezen. Dat deden we hier en we taggen ze stuk voor stuk. De verdeling was niet subtiel.

Ongeveer 64% van de berichten was helemaal geen belastingvraag. Het waren varianten op vijf dingen:

  • "Heb je mijn export ontvangen?"
  • "Welke exchanges ondersteunen jullie?"
  • "Wat is de deadline?"
  • "Kan ik vrijdag documenten langsbrengen?"
  • "Status van mijn aangifte?"

De overige 36% waren echte belastingvragen. ETH bridgen van L1 naar een L2. Loss harvesting op een gedelist token. Of een wrapped-asset positie bij het unwrappen een belastbaar moment oplevert. Of een airdrop inkomen is in het jaar van binnenkomst of het jaar van vesting.

Die vragen vereisen een geregistreerde belastingadviseur. Geen model. Ook geen model met een confidence threshold. Een mens, met beroepsaansprakelijkheidsverzekering, die het antwoord heeft afgetekend. De Nederlandse regels voor fiscaal advies en de beroepsaansprakelijkheidsverzekering van het kantoor eisen dat allebei.

De opdracht was nooit "alles beantwoorden". De opdracht was "beantwoord de 64%, herken de 36% in minder dan drie seconden, en haal snel een mens in de chat".

Het gebruikelijke doel omdraaien

De meeste chat-agent projecten proberen auto-resolution te maximaliseren. Voor een gereguleerd kantoor is dat een gevaarlijk doel. Wij draaiden het om. De taken van de bot, op volgorde:

  1. Beantwoord de saaie vragen goed.
  2. Herken direct een gereguleerde vraag.
  3. Reageer in het Nederlands binnen twee seconden.
  4. Krijg binnen 90 seconden een geregistreerde adviseur in het gesprek.
  5. Produceer nooit tekst die lijkt op advies over een gereguleerd onderwerp.

"Nooit" doet veel werk in dat rijtje. Daar komen we op terug.

De classifier staat voor alles

We draaien niet één grote prompt. Vooraan staat een kleine classifier, en de rest van het systeem hangt af van zijn beslissing. Elk inkomend Telegram-bericht gaat er eerst doorheen voordat er iets anders gebeurt.

Vier buckets, met als default doorzetten naar een mens:

  • LOGISTICS: deadlines, openingstijden, documentstatus. De bot antwoordt vanuit een kleine kennisbank.
  • DOCUMENT: klant stuurt een CSV, screenshot of spraakbericht. De bot bevestigt, archiveert het bestand en laat de klant weten wanneer een adviseur er naar kijkt.
  • ADVICE_NEEDED: alles wat raakt aan de fiscale behandeling van een transactie, positie of strategie. Doorzetten.
  • AMBIGUOUS: het model is niet zeker. Doorzetten.

De classifier-prompt is korter dan je denkt. Het structured-output schema doet het meeste werk.

// classifier.ts
import { z } from "zod";

export const Classification = z.object({
  bucket: z.enum(["LOGISTICS", "DOCUMENT", "ADVICE_NEEDED", "AMBIGUOUS"]),
  confidence: z.number().min(0).max(1),
  one_line_reason: z.string().max(140),
  detected_topics: z.array(z.string()).max(5),
});

export const SYSTEM_PROMPT = `
You triage inbound Telegram messages for a Dutch crypto-tax firm.
You do not answer the message. You only assign one of four buckets.

Bucket rules:
- LOGISTICS: deadlines, opening hours, document status, contact info.
- DOCUMENT: client is sending or referencing a file, screenshot, voice note.
- ADVICE_NEEDED: anything about tax treatment, reporting obligations,
  cost basis, gains/losses, specific transactions, or "what should I do".
- AMBIGUOUS: anything else, or when in doubt.

If confidence is below 0.85 for any non-ADVICE bucket, return AMBIGUOUS.
The cost of a false LOGISTICS is high. The cost of a false ADVICE_NEEDED is low.
`;

Die laatste regel is de hele ontwerpfilosofie. We routeren bewust te vaak naar mensen. Het kantoor heeft liever dat hun adviseurs tien extra logistieke vragen per dag zien, dan dat de bot één gereguleerde vraag beantwoordt.

Waarschuwing

Bouw je een chat-agent voor een gereguleerd kantoor? Zet je default bucket op "doorzetten naar mens" en schrijf de prompt zo dat het model zich uit die default moet praten. De meeste teams doen het andersom, en die teams shippen bots die soms advies geven dat ze niet zouden moeten geven.

Binnen twee seconden bevestigen, binnen negentig doorzetten

De handoff is belangrijker dan de classificatie. De classifier is het makkelijke stuk. Snel een mens in het gesprek krijgen, zonder dat de klant het gevoel heeft van het kastje naar de muur gestuurd te worden, is het lastige deel.

Wanneer een bericht in ADVICE_NEEDED of AMBIGUOUS valt, doet de bot vijf dingen achter elkaar:

  1. Binnen twee seconden antwoorden in de Telegram-thread: "Een adviseur kijkt hier nu naar. Een moment."
  2. Een gestructureerd ticket plaatsen in de interne Slack van het kantoor: met het bericht, de naam van de klant, de laatste vijf berichten als context, de redenering van de classifier en een samenvatting in één regel.
  3. De dienstdoende adviseur voor die klant pingen. Elke klant heeft een primaire en een back-up adviseur.
  4. Als er binnen 90 seconden geen mens heeft gereageerd in Slack, wordt de back-up gepingt.
  5. Is er na 180 seconden nog steeds geen mens, dan komt er een zachtere fallback in de Telegram-chat: "Het duurt iets langer dan normaal. Iemand reageert binnen vijftien minuten."

De 90 seconden zijn geen magie. We hebben 60, 90 en 120 getest. Zestig was te krap, adviseurs werden gepingt terwijl ze nog in gesprek waren. Honderdtwintig voelde voor de partner te lang. Negentig bleek goed.

// handoff.ts
async function handoff(msg: TelegramMessage, c: Classification) {
  await telegram.sendMessage(msg.chat_id, ACK_NL);

  const ticket = await slack.postTicket({
    channel: SLACK_TRIAGE,
    client: await lookupClient(msg.from),
    context: await lastNMessages(msg.chat_id, 5),
    classifier: c,
    summary: await summarise(msg.text, { maxChars: 180 }),
  });

  await pingAdviser(ticket.primary, ticket.url);

  const claimed = await waitForClaim(ticket.id, 90_000);
  if (!claimed) {
    await pingAdviser(ticket.backup, ticket.url);
    const claimedBackup = await waitForClaim(ticket.id, 90_000);
    if (!claimedBackup) {
      await telegram.sendMessage(msg.chat_id, SOFT_FALLBACK_NL);
    }
  }
}

"Claim" is een Slack-reactie. Een adviseur reageert met een emoji op het ticket om hem op te pakken. Lichtgewicht, geen nieuwe tool om te leren. Het kantoor leefde toch al in Slack.

Spraakberichten, bewerkingen en screenshots

Drie dingen in Telegram braken onze eerste versie. Stuk voor stuk de moeite waard om te noemen.

Bewerkte berichten

Klanten bewerken berichten op Telegram. Vaak. Een klant stuurt "heb je mijn file ontvangen" en past dat vier minuten later aan naar "heb je mijn file ontvangen en is de bridge van L1 naar Base een belastbaar moment in NL". De bot had de eerste versie al als LOGISTICS geclassificeerd en beantwoord. De classifier zag de bewerking nooit.

Fix: abonneer je op het update-type edited_message in de Telegram Bot API, herclassificeer bij elke bewerking, en als de nieuwe bucket ADVICE_NEEDED is, start direct een handoff met de notitie "klant heeft de vraag aangepast" in het Slack-ticket.

Spraakberichten

Een derde van de klanten van het kantoor stuurt spraakberichten. Sommige duren 90 seconden. We hebben Whisper-transcriptie toegevoegd, maar bewust laten we de classifier niet redeneren over de spraakinhoud. Spraakberichten worden automatisch naar een mens gerouteerd en de transcriptie hangt bij het Slack-ticket voor de adviseur. Het antwoord van de bot op een spraakbericht is altijd hetzelfde: "Bedankt voor je spraakbericht. Een adviseur luistert het terug en reageert."

De reden is klein maar echt. Spraakberichten dragen toon en nuance die we de classifier niet willen laten misverstaan. Het is ook het kanaal waar klanten de meest persoonlijke, gereguleerde vragen stellen. Default naar mens.

Screenshots van exchanges

Klanten sturen screenshots door van Kraken, Bitvavo, Coinbase. Nuttige artefacten voor de adviseur. Het is tegelijk een valkuil voor de bot: een screenshot van een handelsoverzicht lijkt op een logistiek bericht ("hier is mijn data"), maar hangt vrijwel altijd aan een belastingvraag. We OCR'en elke afbeelding, hangen de tekst aan het Slack-ticket en routeren screenshots standaard naar een mens.

De audit log waar niemand om vroeg, totdat dat wel gebeurde

Elke classificatie, elke handoff, elk botantwoord wordt gelogd met de modeloutput, de prompt hash en de timestamp. We bouwden dit niet omdat het kantoor erom vroeg. We bouwden het omdat hun fiscale praktijk onder de Belastingdienst-richtlijnen voor crypto-bezit valt, en "er is geen gereguleerd advies gegeven door een niet-mens" is het soort claim dat bewijsbaar moet zijn, niet alleen waar.

In de derde maand vroeg een auditor om precies dat bewijs. We exporteerden een CSV. Het gesprek duurde twintig minuten.

De cijfers die we mogen delen

Het kantoor is klein genoeg dat we geen percentages over tien berichten geven. Echte cijfers uit de eerste maand in productie, met hun toestemming:

  • Mediane tijd tot het eerste menselijke antwoord op een gereguleerde vraag: van 6 uur 40 naar 1 minuut 12.
  • Adviseurs-uren per week aan Telegram-triage: van ongeveer 22 naar ongeveer 6.
  • Aandeel automatisch afgehandelde (niet doorgezette) berichten: 64%.
  • Foutroutes waar de bot iets beantwoordde dat geëscaleerd had moeten worden: 3 op de ~2.100 berichten. Alle drie werden binnen 24 uur in de dagelijkse review log gevangen en door een adviseur opgepakt. Geen enkele bereikte de auditor.

De foutroute-ratio is het cijfer dat we in de gaten houden. De andere cijfers schuiven wel. Dat ene moet bij nul blijven.

Eén ding dat we niet zouden herhalen

In week één bouwden we een follow-up agent die klanten na 24 uur stilte porde met "Ben je er nog?". De adviseurs haatten hem. Het maakte het kantoor pusherig en onpersoonlijk, en het genereerde meer inkomend werk dan het oploste. In week twee hebben we hem gekild. De les is ouder dan agents: automatiseer niet het deel van de relatie dat de relatie is.

Hoe je morgen je eigen inbox bekijkt

Run je een klein servicekantoor en heb je het vermoeden dat je een agent-vormig probleem hebt? Doe dit voordat je met iemand praat over het bouwen ervan. Open je supportkanaal. Lees de laatste 200 berichten. Tag elk bericht als LOGISTICS, DOCUMENT, ADVICE of AMBIGUOUS. Als de eerste twee samen meer dan de helft zijn, is de bot het bouwen waard. Zo niet, dan heb je een wervings- of trainingsprobleem, geen automatiseringsprobleem.

Toen we deze Telegram-agent bouwden voor het crypto-belastingkantoor, verraste het ons hoeveel van het werk in de handoff zat, niet in de classifier. We losten het op door als default-beslissing "haal een mens erbij" te nemen en de bot te behandelen als een snelle triageverpleegkundige, niet als een arts. Kijk je naar AI-agents voor een gereguleerde praktijk, dan is die omkering de zet die het kopiëren waard is.

Kern

Bij een gereguleerd kantoor is de taak van de bot niet om alles te beantwoorden. Hij moet snel triëren en een mens in de chat krijgen voordat de klant geïrriteerd raakt.

FAQ

Waarom Telegram en niet WhatsApp of e-mail?

De klanten van het kantoor gebruikten Telegram al. We zeggen nooit tegen een klantbestand dat ze van kanaal moeten wisselen voor ons gemak. Hetzelfde triagepatroon werkt ook op WhatsApp Business en op gedeelde inboxes.

Welk model gebruiken jullie voor de classifier?

Een klein, snel model met een structured-output schema. De classifier hoeft niet het slimste model in de stack te zijn. Hij moet snel, goedkoop en geneigd zijn om te escaleren.

Hoe bewijs je dat de bot nooit gereguleerd advies heeft gegeven?

Elke classificatie, prompt hash en reply wordt gelogd met een timestamp en op verzoek geëxporteerd. Het kantoor doet wekelijks een review op elk bericht dat door de bot als LOGISTICS is geclassificeerd.

Hoe lang duurde het bouwen?

Vier weken van kickoff tot productie. Week één was de inbox lezen. Week twee was de classifier. Week drie was de Slack-handoff. Week vier waren de bewerkingen, spraakberichten en screenshots.

Wat gebeurt er als de bot iets verkeerd classificeert?

De dagelijkse review log brengt het aan het licht. Een adviseur neemt contact op met de klant, meestal binnen uren. De verkeerd geclassificeerde prompt wordt de volgende ochtend een testcase in de regressieset.

chat agentsai agentscase studyautomationintegrationsworkflow

Iets bouwen?

Start een project