Introduction
As Artificial Intelligence continues to develop, a major challenge remains - how can we ensure that AI responses are accurate, reliable, and based on real-world data?
In this case, Retrieval-Augmented Generation (RAG) comes into play.
The RAG consists of:
You may use your documents, PDFs, and knowledge base to store your data
Content search (retrieval of relevant content)
Generation of artificial intelligence (LLMs)
You will learn the following in this article:
RAG explained in simple terms
Create your first RAG pipeline using C# 14 and ASP.NET Core
Build a basic API for AI Knowledge Assistants
Become familiar with best practices for production systems
What is RAG?
A RAG pattern consists of:
The user asks a question
Relevant documents are searched by the system
The system sends the context and question to the AI
A grounded answer is generated by AI
In the absence of RAG:
Artificial intelligence guesses (hallucinations❌)
In RAG:
Answers based on your data (accurate✅)
RAG Architecture Overview

Step 1: Create ASP.NET Core Project (.NET 9 / C# 14)
dotnet new webapi -n RAGDemo
cd RAGDemo
Project Structure (Clean & Simple)

Step 2: Define Request Model
namespace RAGDemo.Models;
public class QueryRequest
{
public string Question { get; set; } = string.Empty;
}Step 3: Create Simple Document Store (Mock Retrieval)
Your knowledge base is simulated in this way.
namespace RAGDemo.Contracts;
public interface IDocumentStore
{
List<string> Search(string query);
}using RAGDemo.Contracts;
namespace RAGDemo.Services;
public class InMemoryDocumentStore : IDocumentStore
{
private readonly List<string> _documents =
[
"In C# 14, new modern language features are introduced.",
"Scalable APIs are built with ASP.NET Core.",
"By adding context from documents, RAG improves AI.",
"In order to convert text into vectors, embeddings are used."
];
public List<string> Search(string query)
{
return _documents
.Select(doc => new
{
Document = doc,
Score = CalculateScore(doc, query)
})
.OrderByDescending(x => x.Score)
.Where(x => x.Score > 0) // only relevant docs
.Take(3)
.Select(x => x.Document)
.ToList();
}
private int CalculateScore(string doc, string query)
{
var score = 0;
var queryWords = query
.ToLower()
.Split(' ', StringSplitOptions.RemoveEmptyEntries);
foreach (var word in queryWords)
{
if (doc.ToLower().Contains(word))
{
score++;
}
}
return score;
}
}Step 4: Create RAG Service
It's here that the magic happens.
namespace RAGDemo.Contracts;
public interface IRagService
{
Task<string> AskAsync(string question);
}using RAGDemo.Contracts;
namespace RAGDemo.Services;
public class RagService : IRagService
{
private readonly IDocumentStore _documentStore;
public RagService(IDocumentStore documentStore)
{
_documentStore = documentStore;
}
public async Task<string> AskAsync(string question)
{
var docs = _documentStore.Search(question);
if (docs == null || docs.Count == 0)
{
return "No relevant information found.";
}
var context = string.Join(Environment.NewLine, docs);
var prompt = $"""
Based on the context below, answer the question:
Context:
{context}
Question:
{question}
""";
var answer = docs.First();
return await Task.FromResult(answer);
}
}
Step 4: Create API Controller
using Microsoft.AspNetCore.Mvc;
using RAGDemo.Contracts;
using RAGDemo.Models;
namespace RAGDemo.Controllers;
[ApiController]
[Route("api/[controller]")]
public class RagController : ControllerBase
{
private readonly IRagService _ragService;
public RagController(IRagService ragService)
{
_ragService = ragService;
}
[HttpPost("ask")]
public async Task<IActionResult> Ask([FromBody] QueryRequest request)
{
var answer = await _ragService.AskAsync(request.Question);
return Ok(new { answer });
}
}

Join the conversation! Your thoughts help the community grow.