A pragmatic .NET 10 stack for embedded LLM inference, embeddings, vector search, RAG, and document processing — built local-first, cloud-optional, and free of any single-provider lock-in.
The .NET AI ecosystem in 2026 has filled in a lot of gaps, but two specific shapes remain under-served.
One: embedded AI inside a .NET application. A desktop app, a worker service, an MCP server, a game on the .NET runtime. Where you want an LLM, embeddings, RAG, and document conversion to all run in the same process — without a Python sidecar, without a Postgres+pgvector deployment, and (optionally) without a cloud LLM dependency.
Two: one coherent stack rather than five libraries to assemble. The pieces exist — Microsoft.ML.OnnxRuntimeGenAI, LLamaSharp, pgvector, LangChain.NET (or hand-rolled chunkers), Microsoft's Python markitdown, somebody else's HuggingFace downloader. You can stitch them together. Many people do. Foundation.AI is what the result looks like when one developer needed exactly this shape for two products and got tired of re-stitching.
This project is not trying to be the universal answer. It exists because the maintainer was building two products — a healthcare scheduling system and a Steam game — that needed exactly this shape, and there was nothing off-the-shelf that fit.
You will probably benefit if:
- You build .NET applications and want to add AI features without operating a separate Python service.
- You ship desktop / single-binary / worker-service / game / regulated-industry workloads where "talk to OpenAI from production" is not on the menu.
- You want embedded vector search — no Postgres, no Pinecone, no separate process.
- You want RAG that works in 50 lines of code rather than 500, and document conversion in the same package.
- You want one
IInferenceProviderinterface fronting OpenAI, Azure OpenAI, Ollama, ONNX GenAI, LLamaSharp/GGUF, and BitNet — so you can swap backends without touching application code.
You should probably look elsewhere if:
- You are starting fresh on
Microsoft.Extensions.AIand it's covering your needs — there is no compelling reason to switch. - You need cloud-native vector search at scale (>100 QPS over millions of vectors). Pinecone, Weaviate, Qdrant, or pgvector are better tools for that job.
- You need the polish and SLAs of a managed product. This is a one-maintainer project shipping in evenings.
- You are building production agentic systems with strict observability/telemetry requirements — those are not yet in this stack.
Microsoft.Extensions.AI is the obvious-default for provider-neutral abstractions in new .NET AI work. It does that job well. What it does not ship is concrete implementations of everything below the abstraction — the embedded vector database, the chunker, the document-conversion pipeline, the model downloader, the RAG orchestrator. You assemble those yourself.
Foundation.AI is more opinionated and more bundled. The IInferenceProvider interface is smaller (chat, completion, streaming, tool-calling — that's it). The vector store is shipped in-process and ready. RAG is a one-method-call away. Document conversion is in the same package. The trade-off is exactly what you'd expect: less ceremony, less flexibility.
The two stacks are not in opposition. They target different sweet spots.
| Module | Purpose |
|---|---|
Foundation.AI |
Umbrella facade — AddFoundationAI() + the builder pattern |
Foundation.AI.Inference |
Unified IInferenceProvider interface — chat, completion, streaming, tool-calling |
Foundation.AI.Inference.Onnx |
ONNX GenAI runtime — Phi-4-mini, Phi-3, etc. (DirectML on Windows, CPU elsewhere). Includes a HuggingFace model downloader. |
Foundation.AI.Inference.LlamaSharp |
GGUF inference via LLamaSharp. Pluggable CPU / CUDA / Vulkan backend. |
Foundation.AI.Inference.BitNet |
1-bit quantised inference via Microsoft Research's BitNet llama.cpp fork |
Foundation.AI.Embed |
Embedding pipeline with ONNX models + batching, plus an OpenAI-compatible (works against Ollama too) provider |
Foundation.AI.VectorStore |
IVectorStore abstraction |
Foundation.AI.VectorStore.Zvec |
Zvec — .NET port of alibaba/zvec; in-process embedded vector database, no external service required |
Foundation.AI.Rag |
RAG: chunking, retrieval, synthesis, streaming, optional RepetitionPenalty for small models |
Foundation.AI.Vision |
Vision/image abstractions |
Foundation.AI.MarkItDown[.Pdf / .Office / .Media] |
Convert PDF, Office (DOCX/PPTX/XLSX), HTML, ZIP, EPUB, plain text, audio metadata, and ~50 other formats to clean Markdown |
Foundation.AI.Experiment |
Autonomous LLM experiment runner — C# port and generalisation of karpathy/autoresearch |
Three runnable console samples under examples/, in increasing order of stack depth. Each one is one folder, one dotnet run from a clean clone, and one focused thing it proves.
| Sample | What it shows | Cost |
|---|---|---|
| SemanticFinder | Semantic search over a folder of text files. No LLM required. Index 16 sample files and ask "what's a South American pack animal?" — it returns llamas and alpacas without those words appearing in the query. | ~80 MB embedder download |
| DocsQ | Full RAG over PDFs / Office / Markdown / HTML. Three swappable inference backends — Phi-4-mini ONNX (small, mediocre answers), Qwen3-8B GGUF via LLamaSharp (good), Qwen3:8b via Ollama (best). Side-by-side answer-quality comparison documented in its README. | ~80 MB + 4.7-5 GB depending on backend |
| AgentLoop | Multi-hop tool-calling research agent. Five tools (browse, read, search, compare, finalize), 8-hop budget. Demonstrates exactly where small-model multi-hop reasoning falls down — Phi-4-mini will visibly fail, Qwen3-8B will succeed. | ~80 MB + LLM (any of the three backends) |
The samples are deliberately small — SemanticFinder is one 100-line Program.cs, DocsQ is ~250 lines, AgentLoop is ~140 lines of agent loop + ~340 lines of tool definitions. Copy them into your own project, swap ProjectReference for PackageReference, and you have a working starting point.
dotnet add package Foundation.AI
dotnet add package Foundation.AI.Embed
dotnet add package Foundation.AI.VectorStore.Zvec
dotnet add package Foundation.AI.Inference.Onnx # or LLamaSharp, or use OpenAI-compat against Ollama
dotnet add package Foundation.AI.Rag
dotnet add package Foundation.AI.MarkItDown
dotnet add package Foundation.AI.MarkItDown.Pdf # add format-specific converters as neededusing Foundation.AI;
using Foundation.AI.Embed;
using Foundation.AI.Inference;
using Foundation.AI.Inference.Onnx;
using Foundation.AI.MarkItDown;
using Foundation.AI.Rag;
using Foundation.AI.VectorStore;
using Foundation.AI.VectorStore.Zvec;
using Microsoft.Extensions.DependencyInjection;
// 1. Compose the stack via DI.
var services = new ServiceCollection().AddFoundationAI(ai =>
{
ai.Services.AddOnnxEmbedding(c =>
{
c.ModelPath = "./models/all-MiniLM-L6-v2/model.onnx";
c.ModelName = "all-MiniLM-L6-v2";
});
ai.Services.AddVectorStore(_ => new ZvecVectorStore(new ZvecVectorStoreConfig
{
BasePath = "./vectors"
}));
ai.Services.AddSingleton<IInferenceProvider>(_ =>
new OnnxInferenceProvider("./models/phi-4-mini-instruct-onnx", "phi-4-mini"));
ai.Services.AddRag();
ai.Services.AddMarkItDown();
});
await using var sp = services.BuildServiceProvider();
var rag = sp.GetRequiredService<IRagService>();
var markItDown = sp.GetRequiredService<IMarkItDown>();
// 2. Index a folder of documents. MarkItDown handles the format conversion;
// IndexFileAsync chunks the result, embeds the chunks, and stores them.
foreach (string file in Directory.EnumerateFiles("./docs"))
{
await rag.IndexFileAsync(markItDown, "default", Path.GetFileName(file), file);
}
// 3. Ask questions. Sources are attached to every response.
RagResponse response = await rag.QueryAsync(
"What does the deployment guide say about Vulkan backends?",
new RagOptions { Collection = "default", TopK = 4 });
Console.WriteLine(response.Answer);
foreach (RagSource s in response.Sources)
Console.WriteLine($" [{s.Score:F2}] {s.DocId}: {s.Excerpt[..Math.Min(100, s.Excerpt.Length)]}...");For runnable end-to-end code with sample data, model auto-download, and the three-backend toggle, see examples/DocsQ.
LLamaSharp ships native backends as separate NuGet packages. Pick exactly one in your application project:
LLamaSharp.Backend.Cpu— works everywhereLLamaSharp.Backend.Cuda12— NVIDIA up through Ada Lovelace (sm_89)LLamaSharp.Backend.Vulkan— required for RTX 50-series (Blackwell, sm_120) and works well on AMD/Intel GPUs too
The Cuda12 backend at version 0.26.0 silently falls back to CPU on Blackwell because no sm_120 kernel ships in that build. If you have a 50-series card and your tokens-per-second look CPU-shaped, that's why — switch to Vulkan.
The most important thing this project teaches, perhaps slightly inadvertently: the model dictates answer quality far more than any framework choice. DocsQ's README documents this concretely — the same RAG pipeline produces a clean coherent answer on Qwen3-8B and a repetition loop on Phi-4-mini-cpu-int4 for the same question over the same documents. If your demo isn't impressing people, the answer is almost always "use a bigger model", not "tune the framework".
This is honest data, not a sales pitch. Foundation.AI gives you a uniform interface across many backends precisely so you can make this trade-off explicit and reversible.
This project stands on the shoulders of work done by other people. Where Foundation.AI is a port or close adaptation of an upstream project, the upstream is named here and reproduced in NOTICE:
Foundation.AI.VectorStore.Zvec— .NET port ofalibaba/zvec, an in-process embedded vector database originally written in C++ by Alibaba Group. Apache-2.0.Foundation.AI.Experiment— C# port and generalisation of Andrej Karpathy'sautoresearch. The original is a 5-minute-budget train-and-evaluate loop for ML research; this version replaces the runner, agent, and metric parser with interfaces so you can drive any iterative-improvement task that has a measurable outcome. MIT.Foundation.AI.MarkItDown— conceptually inspired by Microsoft'smarkitdown(Python). Independent .NET implementation, not a direct port. MIT.Foundation.AI.Inference.BitNet— built on Microsoft Research's BitNet llama.cpp fork (which itself forksggerganov/llama.cppand uses lookup-table kernels pioneered in Microsoft Research's T-MAC). MIT.
See NOTICE for full attribution and third-party license text.
Pre-1.0. APIs may shift. Used in two unreleased products by the maintainer: a healthcare scheduling system (server-side, Linux) and a Steam-bound game (Windows desktop, BMC.Studio). Battle-tested for those two shapes; coverage of less-trodden paths (ARM64, macOS, large-scale distributed) is best-effort.
What's stable enough to depend on: IEmbeddingProvider, IVectorStore, IInferenceProvider, IRagService, IMarkItDown. Concrete provider implementations behind those interfaces are stable too.
What's most likely to change: Foundation.AI.Experiment (still settling), Foundation.AI.Vision (placeholder shape — current implementations are minimal), the chunker configuration surface, additions to RagOptions.
Issues and PRs welcome. For larger changes please open an issue first to discuss. See CONTRIBUTING.md for setup, scope guidelines, and the small list of conventions the codebase follows.
Apache License 2.0 — Copyright 2026 Demetree Kallergis.