I'm always excited to take on new projects and collaborate with innovative minds.
A step-by-step look at BlazorCsvRagChat — a complete, dependency-free RAG pipeline that turns CSV files into a chat interface using .NET 8 and Ollama, entirely on your own machine.
Every dataset often starts the same way: as a spreadsheet someone exported, saved as a CSV, and asked you to analyze. Your typical options are writing custom SQL queries or building pivot tables. Alternatively, you could query your spreadsheet in plain English and receive direct answers.
That is the exact premise of BlazorCsvRagChat, a lightweight Retrieval-Augmented Generation (RAG) application built with Blazor (.NET 8) and Ollama. You upload a CSV file, the application embeds its contents, and you can query the data using natural language.
The solution requires no SQL, no specialized search syntax, and runs entirely locally on your machine with zero API keys or external cloud dependencies.
Many "chat with your data" demonstrations function by sending the entire CSV file to a hosted LLM API inside the prompt window. That approach presents three main challenges:
Privacy: Data leaves your local environment.
Cost: Token costs scale with dataset size on every query.
Scale: Large CSVs quickly exceed context window limits.
RAG resolves these issues by decoupling data ingestion from query generation:
┌─────────────────────────────────────────────────────────────┐
│ 1. Parse & Chunk Data │
│ (Split CSV into small, header-aware text fragments) │
└──────────────────────────────┬──────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 2. Generate Embeddings │
│ (Convert chunks into dense vectors via Ollama) │
└──────────────────────────────┬──────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 3. Query & Vector Search │
│ (Retrieve top-K most relevant chunks using Cosine Similarity)│
└──────────────────────────────┬──────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 4. Grounded LLM Response │
│ (Pass context + user prompt to local LLM for completion) │
└─────────────────────────────────────────────────────────────┘
The model only receives the specific data slices relevant to the active question, keeping prompt sizes small, deterministic, and fully local.
The end-to-end flow follows a standard RAG pipeline optimized for local execution without external vector databases:
CSV Ingestion: Parse raw rows into structured text chunks (~500–700 characters each) while prepending header context.
Local Embedding: Send each chunk to Ollama’s /api/embeddings endpoint using the mxbai-embed-large model.
In-Memory/On-Disk Storage: Store vectors in a simple JSON file on disk.
Similarity Retrieval: Embed incoming user questions and compute cosine similarity against stored vectors to extract the top 4 most relevant chunks.
Grounded Completion: Inject retrieved chunks into the llama3.1:8b-instruct prompt with strict instructions to answer exclusively using the provided context.
Raw CSV rows like 47, 3.2, 88.1 lack semantic context when evaluated independently by an LLM. To resolve this, the ingestion engine builds header-aware chunks: each text block contains group rows prefixed with the original column header line. This ensures the model always understands field mappings.
By embedding chunks with mxbai-embed-large, queries map semantically rather than relying on exact keyword matching. A query like "Who earns the highest salary?" correctly matches chunks containing compensation data, even if the exact words differ.
Instead of introducing external database dependencies, the vector index uses a lightweight List<Chunk> serialized directly to App_Data/index.json. Cosine similarity is computed directly via standard C# loops. For typical operational spreadsheets (a few thousand rows), performance is virtually instantaneous and eliminates external infrastructure setup.
The system prompt enforces strict grounding:
"Answer strictly from the provided CSV context. If the answer is not in the context, state that you do not know."
Combined with a low generation temperature (0.1), the LLM focuses entirely on factual extraction from your data.
| Layer | Component |
|---|---|
| Framework | Blazor Server (Interactive Server Components), .NET 8 |
| Embeddings Model | Ollama + mxbai-embed-large |
| LLM Inference | Ollama + llama3.1:8b-instruct |
| Vector Storage | On-disk JSON file ( index.json ) |
| Dependencies | None (Fully offline, zero cloud APIs) |
The UI is managed within Home.razor, supported by four core services:
EmbeddingClient: Communicates with Ollama's embeddings endpoint.
LlmClient: Manages chat completion generation.
VectorIndex: Handles vector storage and similarity scoring.
KnowledgeService: Orchestrates parsing, indexing, and context retrieval.
Basic Delimiter Parsing: The default string-splitting parser assumes clean CSV structures. Files containing quoted strings with internal commas or newlines may require robust parsing libraries like CsvHelper.
Sequential Embedding Ingestion: Generating embeddings row-by-row via HTTP calls creates initial ingestion overhead during large uploads. Querying remains fast as it only embeds the active user question.
Linear Vector Search: Linear cosine scans scale well for standard spreadsheet sizes, though ultra-large datasets would eventually require dedicated vector indexing engines (e.g., Qdrant or Milvus).
Your email address will not be published. Required fields are marked *