CogniFlow
A retrieval-augmented chatbot that answers from a private, continuously ingested corpus instead of the model's training data — with every answer traceable to its source.
- Next.js 16
- TypeScript
- OpenAI
- Astra DB
- Puppeteer
System schematic
Overview
CogniFlow is a vector RAG chatbot. An ingestion job crawls a defined set of sources, normalises the text, splits it into overlapping chunks, embeds each chunk and writes it to a vector collection alongside its source URL. At query time the application retrieves the nearest chunks and answers from them, so responses stay bounded by the corpus rather than by whatever the base model happens to remember.
Problem
A general-purpose language model has two failure modes that make it unusable as a knowledge interface: it does not know anything specific to your organisation, and when it does not know something it produces a fluent, confident answer anyway.
Fine-tuning does not solve this well. It is expensive to repeat, it bakes knowledge into weights that cannot be updated cheaply when a document changes, and it still gives you no way to point at where an answer came from.
Business context
This is the shape of almost every practical LLM deployment inside a company: a body of knowledge exists — documentation, policies, product data, support history — and people need answers from it in natural language, without a human having to read the source each time.
The constraint that decides whether such a system is adopted is not answer quality in isolation. It is whether a reader can verify an answer. An unverifiable answer transfers risk to the reader, and readers reject it.
Solution
Separate the system into two pipelines that can evolve independently: an offline ingestion pipeline that owns the corpus, and an online query pipeline that owns the conversation.
The ingestion pipeline renders each source with a headless browser rather than fetching raw HTML, so client-rendered content is captured. Extracted text is whitespace-normalised, split into 512-character chunks with 100 characters of overlap so a fact spanning a boundary survives in at least one chunk, then embedded in batches with text-embedding-3-small.
Each chunk is stored as a vector alongside its text and originating URL. Retrieval therefore returns not just the supporting text but its provenance, which is what makes an answer checkable.
Architecture
Sources
Source documents
Web pages, docs, articles
Ingestion
Headless render
Puppeteer · networkidle
Chunker
512 chars · 100 overlap
Embedding
text-embedding-3-small
Store
Astra DB vector collection
1536-dim · cosine · text + source URL
Query
Chat route
Next.js route handler
Retriever
Top-k nearest chunks
Generation
Grounded answer
Retrieved context + question
Citations
Source URLs returned with answer
AI workflow
Ingest — a source is rendered, flattened to text, chunked with overlap, embedded in a single batched call per document, and upserted with its provenance.
Retrieve — the incoming question is embedded with the same model, and the vector collection returns the nearest chunks by cosine similarity. Using one embedding model on both sides is not a detail: mixing models silently destroys retrieval quality because the vectors no longer share a space.
Generate — retrieved chunks become the context for the answer. The model is instructed to answer from context, and the source URLs travel back with the response so the reader can check it.
Implementation
The chunker is hand-written rather than pulled from a library. It advances by chunk size minus overlap and guards the step so a pathological overlap value cannot produce an infinite loop — a real failure mode in naive implementations.
Embeddings are requested per document rather than per chunk, which collapses dozens of round trips into one and is the difference between an ingestion run measured in minutes and one measured in hours.
The browser is launched and closed inside a try/finally around each page, so a page that hangs or throws cannot leak a Chromium process across a long crawl.
Credentials for the vector store and the model provider are read from the environment only. Nothing is embedded in the client bundle, and the collection is created idempotently with an explicit dimension and metric rather than relying on defaults.
Engineering challenges
Chunk boundaries destroy facts
A fixed-size split will eventually cut a sentence, a definition or a number in half, and neither resulting chunk answers the question. Overlapping the windows means any span shorter than the overlap survives whole in at least one chunk. The cost is a larger index; the benefit is that retrieval stops missing facts that are demonstrably in the corpus.
Client-rendered sources return empty text
Fetching HTML directly returns an application shell for a large share of modern pages. Rendering with a headless browser and reading the evaluated document body is slower per page, but it is the difference between ingesting a page and ingesting nothing at all.
Ingestion is the expensive half
Embedding cost and wall-clock time are dominated by ingestion, not by queries. Batching per document, skipping empty chunks and making collection creation idempotent keeps re-runs cheap, which in turn makes it realistic to re-ingest when sources change.
Key decisions
- Retrieval augmentation rather than fine-tuning
- The corpus changes; model weights should not have to. RAG makes an update a re-ingestion rather than a training run, and it is the only one of the two approaches that can cite a source.
- A managed vector database over a self-hosted index
- The interesting problems here are chunking, retrieval quality and grounding. Operating a vector index adds no differentiated value at this scale.
- Store the source URL beside every vector
- Provenance has to be captured at write time. Reconstructing it at read time is guesswork, and guessed citations are worse than none.
- One embedding model on both sides of the pipeline
- Query and document vectors must occupy the same space. This is enforced by construction rather than left as a convention someone can break later.
Results
No production metrics are published for this project yet. I would rather show nothing here than a number I cannot stand behind — the architecture and the decisions above are the part worth reviewing.
Technology
AI
- OpenAI API
- text-embedding-3-small
- RAG pipeline
Data
- DataStax Astra DB
- Vector search (cosine)
- 1536-dim embeddings
Ingestion
- Puppeteer
- Headless scraping
- Overlapping chunker
Application
- Next.js 16
- React 19
- TypeScript
- Tailwind CSS v4
Links
Contact
Have an AI product or workflow worth building?
Send me the problem — not the spec. If it’s a fit I’ll tell you how I’d approach it; if it isn’t, I’ll say so.
Faisalabad, Pakistan · PKT (UTC+5) · Working remotely