Sales-software luistert je gesprekken af en zet ze op een server die jij niet beheert. Ik wilde het omgekeerde. Een copilot die tijdens mijn sales-calls meeluistert, mij coacht op het juiste moment, en geen byte de deur uit stuurt.
Dus bouwde ik 'm zelf. Dat werd OnCue, mijn open-source live sales copilot. Een open source sales copilot die volledig lokaal op mijn eigen Mac draait, met de code op GitHub. Dit stuk is geen verkooppraatje. Het is wat ik onderweg heb geleerd over lokaal bouwen, over de modelkeuzes achter de drie jobs, en over de licentie.
Waarom een open source sales copilot, en niet gewoon Gong?
De bestaande tools ken je wel. Gong, Chorus, Fireflies. Ze zijn cloud-first, ze werken achteraf, en ze kosten 75 tot 200 euro per gebruiker per maand. Je gesprekken worden opgenomen op een server van een ander.
Voor privacy, AVG en gereguleerde sectoren is dat een blokkade bij de inkoop. En achteraf is te laat. De call-review een week later verandert niets aan een deal die al beslist is.
Ik wilde twee dingen die geen enkele cloud-tool me gaf. Coaching tijdens het gesprek, niet erna. En mijn klantdata die op mijn machine blijft. Dat kan alleen als je het lokaal bouwt en de code openlegt.
Drie jobs, drie latency-budgets
Dit was het inzicht dat de hele architectuur bepaalde. Een live copilot moet drie dingen doen terwijl de prospect nog aan het praten is. En elk van die drie heeft een eigen tijdsbudget.

Transcriberen loopt doorlopend en moet real-time. Dat is spraak naar tekst, en het draait lokaal met whisper.cpp. Geen audio verlaat de machine.
Detecteren valt in tweeën. Een bekend bezwaar of koopsignaal herkennen moet instant, onder een tiende seconde. Een lokale embedding-router doet dat in ongeveer 5 milliseconden. Het bredere lezen van het gesprek (welk pijnpunt speelt hier, twijfelt iemand?) mag 1 tot 3 seconden kosten en gaat door een taalmodel, lokaal of in de cloud, dat kies je zelf.
Herformuleren (wat zeg je nu?) mag 1 tot 3 seconden duren. Dit is het enige stuk dat een lokaal taalmodel vandaag niet op gesprekssnelheid haalt. Hier leunt de copilot op een cloud-model, of op een sterkere machine op je eigen netwerk.
Er is een vierde job, samenvatten, die op de achtergrond draait en 10 tot 60 seconden mag kosten. Die doet een lokaal model prima.
Het enige voorbehoud is dus die herformulering. Alleen dat stuk kan naar de cloud. Al het andere blijft op de machine.
Twee sporen naast elkaar, niet één classifier
De live-keten mag nooit blijven wachten op een taalmodel. Dus lopen er twee sporen naast elkaar over wat de klant zegt, met een heel verschillende prijs.

Spoor 1: kaarten achter een embedding-router. Klanten zeggen zelden letterlijk "dat is te duur". Ze zeggen "we moeten even naar het budget kijken". Een embedding herkent dat op betekenis in plaats van op exacte woorden, in ongeveer 5 milliseconden. Is het raak, dan staat de vooraf geschreven kaart er meteen: het bezwaar met de sterkste tegenreactie. Geen model, geen wachttijd, volledig voorspelbaar. Bezwaren en koopsignalen komen alleen uit dit spoor, zodat de gecureerde tegenreactie op precies één plek wordt bepaald.
Spoor 2: het gespreksvenster. Eén gestructureerde model-call leest de laatste vijf stukjes klanttekst als geheel, en haalt daar pijnpunten en twijfel uit. Dat gebeurt pas bij minstens drie stukjes en hoogstens eens per vijf seconden, en alleen over wat de klant zegt. Nooit over mijn eigen spraak.
Wat dit betaalbaar houdt is niet een slimme drempel, maar het venster, de wachttijd ertussen, en het filter op alleen de klant. Dat maakt de privacy-grens ook eerlijk: spoor 2 is een model-call, dus welk niveau je voor dat gesprek koos, is het niveau dat die vensters leest. Kies je Ollama, dan gaat er niets weg. Kies je een cloud-model, dan gaan er korte stukjes klanttekst naartoe.
Het aardige gevolg: spoor 1 verbeteren is een datavraagstuk, geen modelvraagstuk. Elke kaart en elk bezwaar dat ik toevoeg haalt werk weg bij spoor 2, en dat scheelt tijd en geld.
De modelkeuzes, met de cijfers erbij
Ik heb dit niet op gevoel gekozen. Ik heb het gemeten.
Voor de detectievergeleek ik**lokale modellen** tegen een cloud-referentie. Mijn lokale free-tier model (gemma-3n-e4b) haalde 58% categorie-match met nul fails. De cloud-referentie (gemini-2.5-flash) zat op 87% in 1,4 seconde. Lokaal is dus goed genoeg voor het snelle pad, de cloud scherpt bij waar het moet.
De grootste vondst zat in het denk-budget van het herformuleer-model. Dezelfde gestructureerde call met vol redeneren duurde ongeveer 11 seconden. Met een denk-budget van 128 tokens zakte dat naar ongeveer 2,3 seconden, met schonere output. Van elf seconden naar instant plus een paar tellen, met één knop.
Over de hele keten gemeten (audio, transcriptie, detectie, model, scherm) zit de p95 op ongeveer 2,9 seconden. Geen enkel gemeten fragment ging boven de 5 seconden.
Een voller geheugen telt meer dan een beter model
De les die me het meest verraste zat in de embeddings, het model dat bezwaren herkent op betekenis in plaats van op exacte woorden.
Ik testte vier meertalige modellen op 16 canonieke bezwaren en 18 achtergehouden formuleringen. Het beste model (multilingual-e5-large) pakte 13 van de 18 in één keer goed, 72%. Het oude, kleine model dat er al in zat (MiniLM, 384 dimensies, uit 2020) haalde 12 van de 18 en versloeg twee grotere modellen. Het verloor met precies één query verschil.
De conclusie was ontnuchterend. Een voller geheugen telt meer dan een beter model. Ik kon beter mijn bibliotheek met bezwaren en tegenreacties vullen dan een groter embedding-model najagen. Dat scheelt schijf, geheugen en laadtijd, en het levert meer op.
Waar ik nu vastloop: de hardware
Hier zit mijn grootste openstaande probleem, en ik wil er niet omheen draaien.
De transcriptie is de zwaarste vaste kost in de keten. Zwaarder dan het genereren. Lokaal draait whisper large-v3-turbo op p50 990 milliseconden. Ik gooide er meer CPU-threads tegenaan, van 4 naar 8, en kwam uit op 986 milliseconden. Vrijwel geen verschil. De kost zit niet in de threads, maar in rauwe rekenkracht.
Toen testte ik dezelfde audio via Groq. Hetzelfde model, 209 milliseconden, ongeveer vijf keer sneller, voor een halve cent per run. Dat is precies het gat dat de hele live-ervaring soepel zou maken.
Alleen: dan verlaat je audio je machine. Dat is exact wat ik met OnCue wilde voorkomen. Dus is dat een opt-in, geen standaard.
Die 209 milliseconden laten wel zien wat er mogelijk is zodra je genoeg rekenkracht hebt. Het is geen modelprobleem, het is een hardwareprobleem. Met een sterke lokale GPU zou dezelfde transcriptie richting die 200 milliseconden moeten kunnen, met de audio gewoon op je eigen machine.
Dat kan ik niet in mijn eentje uitzoeken. Ik heb een Mac, en dat is één datapunt. Draai je een dikke lokale GPU, een DGX-achtige bak of een stevige Strix Halo? Dan is jouw meting waardevoller dan wat ik hier kan produceren. Draai de benchmark, open een issue met je hardware en je cijfers. Daar zoek ik contributors voor.
Waarom AGPL-3.0-only plus een commerciële licentie
De code is open. De moat zit niet in de code. Die zit in de gecureerde kaart-data, de gehoste dienst eromheen, en de implementatie-expertise. Die drie houd ik apart.
Dat maakt de licentiekeuze scherp. Ik koos AGPL-3.0, en wel om een specifieke reden. De netwerk-clausule van AGPL sluit het gat dat gewone GPL laat liggen. Wie een aangepaste versie als netwerkdienst aanbiedt, moet zijn wijzigingen ook publiceren. Een SaaS-fork die mijn werk sluit is daarmee van tafel.
Ik koos bewust de -only variant, niet -or-later. Bij dual-licensing wil je grip houden op welke licentieversie geldt. -or-later laat gebruikers eenzijdig een toekomstige AGPL-versie kiezen. -only houdt die keuze bij mij.
Daaronder ligt een CLA in de stijl van Apache. Elke bijdrager houdt zijn eigen copyright en verleent mij een brede licentie, geen overdracht. Dat is wat dual-licensing mogelijk maakt: dezelfde code kan onder AGPL en onder een commerciële licentie de deur uit.
BSL en FSL heb ik overwogen en afgewezen. Dat is source-available, geen open source. Ik mag het geen open source noemen, en het jaagt bijdragers en vroege gebruikers weg. Gratis tot ik besluit dat je moet betalen leest niemand als open. De bescherming tegen concurrenten heb ik al via AGPL plus die gescheiden moat.
Wat ik hiervan meeneem
Vier dingen die ik bij een volgend real-time systeem meteen weer zo doe. Het is precies hoe ik AI-productiesystemen ontwerp: eerst de architectuur, dan het model.
Splits het werk eerst op latency-budget, dan pas op model. Laat de kaarten en de embeddings het instant-spoor dragen, en geef het taalmodel een eigen tempo naast de live-keten in plaats van erin.
Vul de bibliotheek voordat je een groter model pakt. Data verslaat modelgrootte vaker dan je denkt.
Meet waar je tijd echt heen gaat. Ik ging er lang van uit dat het genereren de bottleneck was. Het was de transcriptie, en daarmee de hardware.
En kies de licentie op dag één, bewust. Een licentie is tegelijk je distributiekanaal en je moat-beslissing. Niet iets om achteraf op te plakken.
Lees ook: AI en AVG: wat mag wel en niet met klantdata: waarom lokaal draaien het privacy-probleem bij de bron oplost.
Veelgestelde vragen
Bouw mee
De code staat op GitHub: github.com/Vinix24/OnCue, onder AGPL-3.0. Sloop het, stel vragen, of bouw mee via een pull request (er hoort een CLA bij).
Twee dingen waar ik concreet hulp bij zoek. Heb je snelle lokale hardware, draai dan de transcriptie-benchmark en post je cijfers in een issue. Ik wil weten hoe dicht je lokaal bij die 209 milliseconden komt. En ik zoek een paar beta-testers die OnCue in echte gesprekken gebruiken, geen demo-scenario's.
Wat de tool verder allemaal doet, en voor welke gesprekken hij bedoeld is, staat op vincentvandeth.nl/oncue.