bot-server · productie op api.apibot.nl

Van bronnen naar een chatbot die zijn antwoorden kan bewijzen.

API.Bot is de service die achter het portal draait: je geeft het PDF's, pagina's, databases, API's en wiki-tekst — het maakt daar een doorzoekbare index van en beantwoordt vragen met Groq, met citaten terug naar de brontekst.

Fastify · HTTP BullMQ + Redis · queue Postgres 16 + pgvector · index Xenova/transformers · embeddings (lokaal) Groq · chat-model

Alle endpoints vereisen Authorization: Bearer <BOT_SERVER_KEY>.

01 — Architectuur

Twee gescheiden paden: publiceren (traag, async) en chatten (snel, synchroon).

Het portal praat via één API met de bot-server. Publiceren van een bot start alleen een achtergrondjob — de portal krijgt direct een deployment_id terug en pollt daarna de voortgang. Chat-verzoeken lopen wél synchroon: die moeten binnen enkele seconden een antwoord geven.

Publish
Portal
POST /v1/botsFastify
BullMQRedis-queue
Ingest workerfetch→index
Postgres+ pgvector
Chat
Portal / widget
POST /chatFastify
Retrievercosine top-k
Groqllama-3.3-70b
Antwoord+ citations

02 — De ingest-pipeline

Elke bron doorloopt dezelfde vijf stappen, plus één gezamenlijke healthcheck.

De voortgang van elke stap wordt weggeschreven naar deployment_steps, zodat het portal live kan tonen waar een publish op dat moment staat.

fetch

Ophalen

PDF, URL, database-rows of API-response binnenhalen. Bij een HTML-snapshot: de signed snapshot-URL, niet de originele pagina.

extract

Extraheren

Leesbare tekst uit PDF (pdf-parse), HTML (Readability) of API-response (JSON/XML/HTML) halen.

chunk

Opknippen

Recursief gesplitst op alinea → zin → spatie, ~800 tokens per stuk met 100 tokens overlap.

embed

Embedden

Lokaal ONNX-model (all-MiniLM-L6-v2, 384 dimensies) — geen externe embedding-kosten.

index

Indexeren

Chunks + vectors in chunks, doorzoekbaar via een HNSW-index.

healthcheck

Controleren

Eén keer per deployment: staat er nu daadwerkelijk iets doorzoekbaars klaar?

content_hash overslaan: elke bron stuurt een content_hash mee. Blijft die gelijk aan de laatst succesvol geïndexeerde hash, dan wordt de hele pipeline voor die bron overgeslagen (status skipped). Stuurt het portal null, dan wordt altijd volledig herverwerkt — zo forceer je een reindex na een configuratiewijziging.

03 — Bron-types

Vijf manieren om kennis in de bot te krijgen.

pdf

Bestand via signed URL, tekst geëxtraheerd met pdf-parse. Citaties kunnen naar een paginanummer wijzen.

url

Webpagina, tekst via Readability. Optioneel een source_snapshot: het portal stuurt dan een vooraf gedownloade HTML-snapshot (tegen bot-detectie), maar citaties blijven linken naar de echte origin_url.

database

Rechtstreekse connectie, tabellen als markdown-tabellen weggeschreven (max 500 rijen per tabel, instelbaar via rowLimit in de source-config).

api

GET/POST naar een externe API. Auth: none, bearer, of api_key (in header óf query-param). Response-type (JSON/XML/HTML) bepaalt de extractie.

markdown

Wiki-tekst die het portal zelf meestuurt. Geen fetch, geen chunks — de volledige inhoud gaat als always-on context mee bij élke chatvraag, ongeacht relevantie.

04 — Chat & RAG

Een vraag wordt pas beantwoord als er ook echt iets te citeren valt.

Vraag embedden

Het laatste user-bericht wordt met hetzelfde lokale model omgezet naar een vector.

Top-k ophalen

Cosine-similarity search in pgvector (top_k, standaard 6) — plus, indien aanwezig, de volledige markdown-wiki als vaste context.

Zelfvertrouwen checken

Geen wiki én te weinig chunks boven RAG_MIN_SCORE (standaard 0.72, RAG_MIN_HITS keer)? Dan gaat het antwoord niet naar het taalmodel, maar komt direct de fallback_answer terug — met fallback_used: true en een lege citations-array.

System-prompt samenstellen

Bot-naam/beschrijving + wiki-context + opgehaalde chunks, gevolgd door de system-berichten die het portal meestuurt (system_instructions, antwoordlengte) — die krijgen zo effectief het laatste woord.

Groq aanroepen

Model llama-3.3-70b-versatile, non-stream of als SSE (event:delta / citation / done / error).

Citaten teruggeven

Per citatie: source_id, label, snippet, score, type: "index", optioneel url/page. Geen inline [#1]-markers in de tekst zelf.

05 — Deployments & logs

Elke publish is te volgen als een reeks statussen, niet als een zwarte doos.

Een deployment gaat door queuedrunningdone (of failed). Per bron zie je dezelfde vijf pipeline-stappen afzonderlijk terug, plus de gezamenlijke healthcheck. Logs zijn op te vragen als platte JSON (met since/level) of als live SSE-stream tot de deployment eindigt.

06 — Endpoints

De volledige interface van de bot-server.

MethodePadBeschrijving
GET/v1/botsAlle bots + status en source-stats
POST/v1/botsBot publiceren/updaten — start async ingest
GET/v1/bots/:idStatus en source-stats van één bot
POST/v1/bots/:id/deactivateBot uitzetten, data blijft staan
DELETE/v1/bots/:idBot en alle data verwijderen
GET/v1/bots/:id/deployments/:dep_idDeployment-status + stappen
GET/v1/bots/:id/deployments/:dep_id/logsLogs — JSON of SSE live-tail
POST/v1/bots/:id/chatRAG-chat, optioneel als SSE-stream
GET/healthzLiveness
GET/readyzReadiness — db + redis + llm

07 — Nieuw in deze versie

Wat de bot-server sinds kort erbij kan.

content_hash

Betrouwbaar overslaan

null forceert nu altijd een volledige reindex, in plaats van stil te vertrouwen op een zelfberekende hash.

url-bronnen

HTML-snapshots

Citaties linken naar de echte origin_url, ook als het portal een snapshot liet ophalen.

markdown

Wiki-bronnen

Always-on context die bij elke vraag meegaat, los van de vector-search.

api-bronnen

Auth + content-types

Bearer- en API-key-auth (header of query), plus JSON/XML/HTML-detectie op de response.

fallback

Eerlijk "ik weet het niet"

Onder de relevantie-drempel krijgt de gebruiker een fallback_answer in plaats van een verzonnen antwoord.

citations

Type-veld

Elke citatie draagt nu type: "index", klaar voor toekomstige live_query-resultaten.