How I Built a Multi-Tenant RAG Knowledge Base with Source-Cited Answers — Pipeline, Multi-Tenancy, and Lessons KnowBase AI, a multi-tenant SaaS knowledge base built by a developer, enables businesses to upload documents and receive AI-generated answers grounded in their own content, complete with clickable source citations. The system implements a RAG pipeline with chunking, workspace-scoped retrieval for tenant isolation, and a provider-agnostic design supporting OpenAI, Gemini, and Claude, plus a demo mode for keyless testing. The developer highlights that the key differentiator is source-cited answers, which separates a gimmick from a trusted support tool. Every "build a RAG chatbot" tutorial ends the same way: embed a few paragraphs, call similaritySearch , print the answer. That gets you a demo, not a product. The gap between a RAG demo and a RAG product you'd trust with a company's documents is where all the real engineering lives. I built KnowBase AI , a multi-tenant SaaS knowledge base where businesses upload documents and an AI assistant answers questions grounded in their own content — with source citations you can click. This post covers the RAG pipeline, how multi-tenancy changes the design, and the decisions I'd repeat. Live demo: knowbase-ai.netlify.app https://knowbase-ai.netlify.app — no login needed, fully functional it runs in demo mode with mock responses . RAG sounds simple: retrieve relevant context, feed it to the LLM, get a grounded answer. In production it means: Each step is a small product on its own. Here's the pipeline. Documents arrive as files, URLs, or manual entries. The key decision is chunking — too big and retrieval is fuzzy, too small and you lose context. The pipeline chunks text with overlap so no meaning falls through the gaps: export function chunkText text: string, size = 800, overlap = 200 : string { const chunks: string = ; let i = 0; while i < text.length { chunks.push text.slice i, i + size ; i += size - overlap; } return chunks; } Each chunk becomes a DocumentChunk tied to its source document, so retrieval can always trace back to where the information came from. A single-user RAG app and a multi-tenant SaaS share almost no code after the demo stage. Every query, chunk, and conversation must be scoped to a workspace: // Every AI retrieval is scoped by workspaceId — a tenant can never // retrieve another tenant's chunks, even if the embedding matches. export async function retrieve workspaceId: string, query: string { return prisma.documentChunk.findMany { where: { document: { source: { workspaceId } }, text: { contains: query }, }, take: 5, } ; } The data model enforces isolation at the schema level: Workspace — tenant container WorkspaceMember — roles: Owner / Admin / Member RBAC via NextAuth.js v5 KnowledgeSource + Document + DocumentChunk — the RAG layer, always under a workspace Conversation + Message — chat sessions, scoped per workspace ApiUsage — token tracking per workspaceOne of the best decisions: never hard-code a model. A thin provider interface means the product runs on OpenAI, Google Gemini, or Anthropic Claude by configuration, and it made the demo mode trivial: export interface AIProvider { chat messages: Message : AsyncIterable