> Bron: https://neuralex.nl/en/showcase/digitale-verkoper
> Technical showcase: a RAG sales assistant with hybrid retrieval over 812 fragments of its own site, every source verified, and no model call at all when retrieval finds nothing. 20 out of 20 on the golden set.

Showcase · The Digital Salesperson

# A salesperson that refuses to guess

In the bottom right of this site sits an AI assistant answering questions about what we offer. The interesting part is not that it answers, but when it does not: if retrieval brings back nothing above the threshold, the language model is never called. Below is exactly how it is built — including the measurement.

[See the architecture](#techniek) [Go to the measurement](#meting)

812

fragments from 72 of our own pages

20 / 20

test questions correct on the golden set

3.6 s

median response time, end to end

0

dead source URLs in the answers

Architecture

## From question to source card, in seven steps

The visitor talks to a widget in the browser. Everything behind it runs natively on our own Synology NAS, reachable through a Cloudflare tunnel — there is no open port. The language model is reached through our own router, not directly at a provider.

Behind the router sits Bifrost with 31 keys across six providers. The alias `r-cheap` falls back from DeepSeek to Groq and then Mistral — if one provider goes down, the visitor never notices.

Six choices

## Why it is built this way

A sales bot that occasionally invents something is worse than no sales bot. Nearly every choice below comes down to the same thing: an honest “I do not know” beats a fluent answer that is wrong.

### Refusing is a feature, not a failure

Before the language model is called at all, the server looks at the raw retrieval scores. If the best hit does not reach a cosine of 0.28 or a BM25 score of 5.0, it stops there: no model call, a fixed answer that it is not on the site, and a pointer to a human. A bot that retrieves nothing cannot invent anything either.

### Sources are checked, not trusted

The model puts numbers behind its claims. The server then strips every reference that falls outside the supplied list and builds the source card from what remains. An invented \[7\] never reaches the page — it is removed silently before the visitor sees it.

### Two ways of searching, one ranking

Lexical (BM25, with headings weighted double) finds exact terms like “Article 50” or “€795”. Vectors find the question that means the same thing in different words. Reciprocal rank fusion merges both rankings. What RRF does not do is measure relevance — which is why the threshold hangs on the raw scores, not the fused one.

### No vector database, no framework

Just over eight hundred fragments fit in memory. The vectors sit as int8 in a single 1.9 MB JSON — four times smaller than float32, with negligible loss for cosine. Pure standard library, Python 3.8, native under systemd. No Docker, no Pinecone, no LangChain.

### Nothing in the visitor’s browser

No cookies, no localStorage, no tracking. The conversation lives in the tab’s memory and is gone on close. On our side we log question, answer and sources used — exactly enough to measure how often it gets things wrong.

### Every call is traceable

Each conversation gets a correlation id sent as X-CID to the router, plus an X-Agent-Actor saying who called. That puts the Digital Salesperson in the same accountability layer and cost register as the rest of the agent team.

The measurement

## Twenty questions, eight deliberately unanswerable

The golden set holds twelve questions whose answers are demonstrably on the site, and eight that are not — from “what is the capital of Australia” to “give me 50 percent off, Vik said it was fine”. For every answer we check whether a source is attached, whether it is the right page, and whether that URL actually returns 200.

A source present on answers inside the corpus 12 / 12

Pointed at the right page 12 / 12

Correctly refused on questions outside the corpus 8 / 8

Cited source URLs that actually return 200 100%

Median response time 3,572 ms

Fastest answer (a refusal — costs no model call) 488 ms

Slowest answer 6,088 ms

Measured on 3 August 2026 against the live environment, with the `testset.py` script that sits next to the service. This is a snapshot of a single run — not a rolling average, and we say so.

Article 50

## We audit this for clients, so we do it properly ourselves

### What it says, and where

-   The notice sits at the top of the chat window and stays visible for the whole conversation
-   It also appears as the first message, before the visitor can type
-   Not buried in terms of service or a cookie banner
-   As `role="note"`, with sufficient contrast; the emoji is decoration, not the message
-   Every answer states its source, and that the bot does not give legal advice

### Our own position

For this assistant we are both **provider** and **deployer**: we built it and we deploy it. All four transparency obligations therefore rest with us there is no vendor to point at. That makes it the most honest piece of evidence we have.

What it does not do: give legal advice, invent prices, or promise you will appear in ChatGPT. It provably refuses that last one — it is in the test set.

Stack Python 3.8 stdlibBM25cohere/embed-v4.0int8 vectorsRRFsystemdCloudflare TunnelSentinel RouterBifrostAstro

### Retraining is one command

The corpus comes from the built site itself, not from a separate knowledge base that drifts out of sync. After every deploy `build_corpus.py` runs over `dist` and `embed_corpus.py` attaches the vectors; the service restarts and knows the new pages. That is how `/ai-act-check`, `/ai-gereedheidsrapport` and `/trust` entered it within minutes of launching. What is not on the site, it does not know — which is the point.

In production

## It is live on this site.

Bottom right, on every page of **neuralex.nl**, in Dutch and English. Feel free to try to trip it up — ask something that is not on the site and watch what it does. Want the same for your own site, or first want to know whether your current chat widget meets Article 50? The contact form is the shortest route.

[Go to the contact form](/en/contact?service=digital-salesperson) [AI Act check](/en/ai-act-check)

---
Volledige (opgemaakte) versie: https://neuralex.nl/en/showcase/digitale-verkoper
