Embedkit.Meai 0.1.0

dotnet add package Embedkit.Meai --version 0.1.0
                    
NuGet\Install-Package Embedkit.Meai -Version 0.1.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Embedkit.Meai" Version="0.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Embedkit.Meai" Version="0.1.0" />
                    
Directory.Packages.props
<PackageReference Include="Embedkit.Meai" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Embedkit.Meai --version 0.1.0
                    
#r "nuget: Embedkit.Meai, 0.1.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Embedkit.Meai@0.1.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Embedkit.Meai&version=0.1.0
                    
Install as a Cake Addin
#tool nuget:?package=Embedkit.Meai&version=0.1.0
                    
Install as a Cake Tool

Embedkit

What this library is

An embedding turns a piece of text into a vector of floating-point numbers, arranged so that texts with similar meaning end up close together in that vector space. This is the raw material behind semantic search, clustering, and retrieval-augmented generation. Embedkit is a small, disciplined way to produce and carry those vectors in C# so that a whole category of quiet mistakes becomes impossible to make.

The problem it solves

Every embedding model has its own vector space. A vector from one model and a vector from another are just lists of numbers of possibly the same length, but they mean different things, and the geometry that makes "close together" meaningful only holds within a single model. If you compare a vector from one model against a vector from another, you still get a similarity score, because the arithmetic still works. The number is simply meaningless. Nothing throws, nothing warns, and your search results are subtly wrong in a way that is very hard to trace back to its cause.

This property, that vectors are only comparable when they come from the same model, is what we mean by embedding symmetry. Embedkit enforces it structurally. Every vector is stamped with the identity of the model that produced it, and a vector cannot exist without that stamp. A mismatch becomes a failure at construction time, where it is obvious, instead of a silent corruption at query time, where it is not.

Core concepts

There are three types, all in Embedkit.Abstractions.

EmbeddingModelId is the stamp. It records the provider, the model name, and the number of dimensions the model produces. Two ids are equal when the provider and model name match case-insensitively and the dimensions are identical, so ("Ollama", "nomic-embed-text", 768) and ("ollama", "NOMIC-EMBED-TEXT", 768) are treated as the same model.

Embedding is a vector paired with its EmbeddingModelId. It cannot be constructed without an id, and its vector length must equal the id's declared dimensions, so an embedding with the wrong shape or no identity cannot be represented at all.

IEmbeddingModel is the contract that binds a single model identity to the embed operations. It exposes the model's ModelId and two EmbedAsync overloads, one for a single string and one for a batch. Every Embedding it returns carries that same ModelId.

Quick start

Embedkit does not talk to any provider itself. Embedkit.Meai adapts anything that implements IEmbeddingGenerator<string, Embedding<float>> from Microsoft.Extensions.AI, and OllamaSharp is one such implementation.

dotnet add package Embedkit.Meai
dotnet add package OllamaSharp
ollama pull nomic-embed-text
using Embedkit.Abstractions;
using Embedkit.Meai;
using OllamaSharp;

using var generator = new OllamaApiClient(new Uri("http://localhost:11434"), "nomic-embed-text");

// You declare the identity, including the dimensions. See the note below.
var modelId = new EmbeddingModelId("ollama", "nomic-embed-text", 768);
var model = new MeaiEmbeddingModel(generator, modelId);

Embedding single = await model.EmbedAsync("A short sentence to embed.");

IReadOnlyList<Embedding> batch = await model.EmbedAsync(new[]
{
    "Embeddings turn text into vectors.",
    "Similar sentences land near each other.",
    "Different models are not comparable.",
});

The caller declares the dimensions deliberately. Provider metadata about dimensionality is optional and unreliable, so Embedkit does not guess it. The declaration is not a formality: if you get it wrong, the first call fails loudly with an exception rather than handing back a vector of the wrong shape that silently corrupts everything downstream.

What this library deliberately does not do

Embedkit embeds text and nothing else. It has no batching strategy beyond passing your batch through in one call, so splitting oversized batches is yours to decide. It does not retry, back off, or rate limit; wrap the model with a resilience library such as Polly if you need that. It does not cache results. It does not store or index vectors; that is the job of a vector store such as Qdrant, pgvector, or similar. These are scoping decisions, not gaps. Each concern has good dedicated tools, and keeping them out leaves Embedkit small enough to reason about completely.

Integrating with a chunking pipeline

Chunking pipelines, such as Chunkyard, usually define their own embedder interface and expect you to implement it. This is an inverted dependency: the pipeline depends on an abstraction you supply, rather than on Embedkit. Bridging the two is a few lines of adapter that live in your application.

Suppose the pipeline defines an interface roughly like this (check the real shape of whichever pipeline you use and conform to that):

public interface IChunkEmbedder
{
    ValueTask<IReadOnlyList<float[]>> EmbedAsync(IReadOnlyList<string> chunks, CancellationToken ct);
}

You write the adapter yourself, delegating to an IEmbeddingModel:

public sealed class EmbedkitChunkEmbedder(IEmbeddingModel model) : IChunkEmbedder
{
    public async ValueTask<IReadOnlyList<float[]>> EmbedAsync(
        IReadOnlyList<string> chunks, CancellationToken ct)
    {
        var embeddings = await model.EmbedAsync(chunks, ct);
        return embeddings.Select(e => e.Vector.ToArray()).ToList();
    }
}

Embedkit ships no integration packages on purpose. The adapter is small, it belongs in the consumer's code where the pipeline's real interface is known, and writing it there keeps Embedkit and the pipeline entirely free of each other.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.1.0 142 7/8/2026