Gosoft Connect - AI-chatt förankrad i kundens dokument

Ett multi-tenant widget-SaaS vars AI-chatt svarar utifrån varje kunds egen kunskapsbas - hela sökstacken självhostad på en enda CPU-nod.

Viktor Sundberg · viktorsundberg.me/sv/work/connect/

Vad det är

Gosoft Connect är ett multi-tenant SaaS som jag har designat och byggt på egen hand på GoSoft, mitt bolag: inbäddnings­bara webbwidgetar - AI-chatt, livechatt, formulär, popuper - och en adminportal.

Varje kund­arbetsyta har en kunskapsbas som fylls på fyra sätt: klistra in text, hämta en URL, ladda upp filer eller crawla en hel sitemap. AI-chatten på kundens webbplats svarar på besökarnas frågor utifrån kunskapsbasen och strömmar svaren token för token.

Assistenten arbetar genom interna verktygsanrop: sökverktyg, en räknare och verktyg för att slå upp företags­uppgifter, fånga leads och lämna över till en människa. Vid varje meddelande med verkligt innehåll tvingas modellen anropa ett verktyg i den första rundan, så att svaren bygger på kundens data och inte på modellens antaganden.

Runt chatten finns samman­fattnings­mejl, AI-samman­fattningar av formulär­svar, kategorisering av konversationer, nattliga rapporter över frågor boten inte kunde svara på, och moderering av både input och output.

Sökpipelinen

Svaren förankras genom hybrid­sökning: täta vektorer i pgvector och fulltext­rankning sammanvägda med reciprocal rank fusion, därefter omrankade av en cross-encoder, med ett mångfaldstak per dokument och språk­medveten sökning över finskt, svenskt och engelskt innehåll. Chunkningen är styckes­medveten med kontextuella rubriker, och innehålls­hashning gör att oförändrade dokument aldrig bäddas in på nytt.

besökarens frågaen Linux-nod, enbart CPUtät sökningbge-m3 → pgvector HNSWlexikal sökningtsvector, BM25-stilPostgreSQLen databas för alltreciprocal rank fusionomrankning, cross-encoderbge-reranker-v2-m3, q8mångfaldstakhögst 2 stycken per dokumentLLMdet enda externa anropetsvar, strömmat token för tokenbesökarens frågaen Linux-nod, enbart CPUtät sökningbge-m3 → pgvector HNSWlexikal sökningtsvector, BM25-stilPostgreSQLen databas för alltreciprocal rank fusionomrankning, cross-encoderbge-reranker-v2-m3, q8mångfaldstakhögst 2 stycken per dokumentLLMdet enda externa anropetsvar, strömmat token för token
Förenklad sökpipeline.

Stack & infrastruktur

Medvetet litet: allt körs på en enda Linux-nod, enbart CPU. Embedding­modellen (bge-m3) och omrankaren (bge-reranker-v2-m3) körs lokalt via ONNX - ingen GPU, inget embedding-API. Kund­dokumenten lämnar maskinen för exakt en sak: själva LLM-anropet (OpenAI, modell valbar per arbetsyta), som omfattas av ett personuppgifts­biträdes­avtal med leverantören. Vektorlagret är vanlig PostgreSQL med pgvector - en databas för allt. Bun och Hono i backend, en Solid.js-portal, nginx framför.

Ingenjörsarbetet

De siffror jag kan publicera är ingenjörs­siffror. Kvantisering av omrankaren tog sökningen från 14 sekunder till 4,1 på CPU, själva omranknings­steget från 5,6 till 1,1. Ett tidigt belastnings­test tappade 2 av 10 samtidiga chattar och dödade processen vid 10,4 GB minne; efter en inferens­semafor och batch­indelning klarade samma test 10 av 10 med 6,8 GB som topp och noll omstarter. I produktion sedan juni 2026.

Modellerna väljs med en automatiserad utvärderings­svit. Den körs genom det verkliga chattflödet, samma kod som en besökares fråga passerar, och ligger kvar i kodbasen som regressions­test. På GoSoft använder vi också AI-agenter internt, i mjukvaru­utvecklingen och i det dagliga arbetet.