Nexttag.Rag 1.1.0

dotnet add package Nexttag.Rag --version 1.1.0
                    
NuGet\Install-Package Nexttag.Rag -Version 1.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="Nexttag.Rag" Version="1.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Nexttag.Rag" Version="1.1.0" />
                    
Directory.Packages.props
<PackageReference Include="Nexttag.Rag" />
                    
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 Nexttag.Rag --version 1.1.0
                    
#r "nuget: Nexttag.Rag, 1.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 Nexttag.Rag@1.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=Nexttag.Rag&version=1.1.0
                    
Install as a Cake Addin
#tool nuget:?package=Nexttag.Rag&version=1.1.0
                    
Install as a Cake Tool

Nexttag.Rag

Camada de retrieval para RAG em .NET: recupera trechos relevantes de um banco vetorial com reranking, multi-query e hybrid search — composto por decoradores sobre IRetriever.

Instalar

dotnet add package Nexttag.Rag

Requer .NET 10. Depende de: Nexttag.VectorStore, Microsoft.Extensions.AI 10.6.0.

Registrar (Program.cs)

Sem método de extensão de DI. Componha os decoradores manualmente:

using Microsoft.Extensions.AI;
using Nexttag.Rag;
using Nexttag.VectorStore;

// Retriever base (singleton — IEmbeddingGenerator e IVectorStore são thread-safe)
services.AddSingleton<IRetriever>(sp => new VectorRetriever(
    sp.GetRequiredService<IEmbeddingGenerator<string, Embedding<float>>>(),
    sp.GetRequiredService<IVectorStore>(),
    collections: ["documentos"],   // coleções a buscar
    textPayloadKey: "chunk_text"   // chave do texto no payload (padrão: "chunk_text")
));

// Com reranking LLM (opcional — adiciona 1 chamada extra ao LLM)
services.AddSingleton<IRetriever>(sp =>
    new RerankingRetriever(
        sp.GetRequiredService<IRetriever>(),   // inner
        new LlmReranker(sp.GetRequiredService<IChatClient>()),
        fetchK: 20));

Configurar

Sem seção de appsettings obrigatória. Os parâmetros são passados nos construtores:

Classe Parâmetro relevante Descrição
VectorRetriever collections Lista de coleções a buscar
VectorRetriever textPayloadKey Chave do texto no payload (padrão "chunk_text")
MultiQueryRetriever variations Nº de reformulações geradas pelo LLM (padrão 3)
RerankingRetriever fetchK Candidatos buscados antes do rerank (padrão 20)
LlmReranker maxCharsPorTrecho Trunca cada trecho no prompt de rerank (padrão 500)
FusionRetriever rrfK Parâmetro k do RRF (padrão 60, valor clássico do paper)

Usar

Retriever base (vetorial puro)

IRetriever retriever = new VectorRetriever(embeddings, store, ["documentos"]);

IReadOnlyList<RetrievedChunk> trechos = await retriever.RetrieveAsync(
    "como solicitar reembolso?",
    topK: 5,
    filter: VectorFilter.Eq("kb_id", kbId));

foreach (var t in trechos)
    Console.WriteLine($"[{t.Score:F3}] {t.Text}  (doc: {t.Meta("doc_id")})");

Com multi-query + reranking

IRetriever vetor = new VectorRetriever(embeddings, store, ["documentos"]);

IRetriever retriever =
    new RerankingRetriever(
        new MultiQueryRetriever(vetor, chatClient, variations: 3),
        new LlmReranker(chatClient),
        fetchK: 20);

var trechos = await retriever.RetrieveAsync("prazo para contestação", topK: 5,
    filter: VectorFilter.And(
        VectorFilter.Eq("kb_id", kbId),
        VectorFilter.In("setor", usuario.Setores.Cast<object>().ToList())));

Hybrid search (vetor + keyword/BM25)

IRetriever vetorRetriever = new VectorRetriever(embeddings, store, ["documentos"]);
IRetriever bm25Retriever  = /* sua implementação de IRetriever para busca por keyword */;

IRetriever hybrid = new FusionRetriever([vetorRetriever, bm25Retriever], rrfK: 60);
var trechos = await hybrid.RetrieveAsync(query, topK: 5, filter: acl);

Loaders — ingerir páginas web

using Nexttag.Rag;

// Uma página
var fonte = new WebPageSource(httpClient, "https://docs.minha-empresa.com/faq");
await foreach (var doc in fonte.LoadAsync())
{
    // doc.Content  = Stream com HTML
    // doc.Mime     = "text/html"
    // doc.Name     = nome derivado da URL
    // doc.SourceUri = URL original
    await pipeline.IngestAsync(doc);
}

// Sitemap inteiro (até max páginas)
var sitemap = new SitemapSource(httpClient, "https://docs.minha-empresa.com/sitemap.xml", max: 200);
await foreach (var doc in sitemap.LoadAsync())
    await pipeline.IngestAsync(doc);

Receitas

Pipeline de ingestão web ponta a ponta

// 1) Carregar páginas via sitemap
var fonte = new SitemapSource(httpClient, "https://site.com/sitemap.xml", max: 100);

// 2) Para cada documento: parsear HTML → fatiar → embedar → indexar no VectorStore
await foreach (var doc in fonte.LoadAsync())
{
    var html  = await new StreamReader(doc.Content).ReadToEndAsync();
    var texto = ExtractText(html);                                  // parser HTML do host
    var chunks = chunker.Split(texto);

    var embeddings = await embedder.GenerateAsync(chunks);
    var pontos = chunks.Zip(embeddings).Select((p, i) => new VectorPoint(
        Id:      VectorIds.ChunkId(doc.SourceUri!, i),
        Vector:  p.Second,
        Payload: new Dictionary<string, object?> { ["chunk_text"] = p.First, ["source"] = doc.SourceUri }
    )).ToList();

    await store.UpsertAsync("documentos", pontos);
}

Contexto para prompt de RAG

var trechos = await retriever.RetrieveAsync(pergunta, topK: 5, filter: acl);
var contexto = string.Join("\n---\n", trechos.Select(t => t.Text));

var systemPrompt = $"Use os trechos abaixo para responder:\n\n{contexto}";

Só reranking sem multi-query

IRetriever retriever = new RerankingRetriever(
    new VectorRetriever(embeddings, store, ["documentos"]),
    new LlmReranker(chatClient),
    fetchK: 15);

Notas

  • MultiQueryRetriever e LlmReranker fazem chamadas extras ao LLM — conte o custo de tokens.
  • Ambos degradam com graça: se o modelo não retornar JSON válido, caem para a consulta/ordem original.
  • RetrievedChunk.Meta("campo") é atalho para ler uma string do payload; retorna null se ausente.
  • SitemapSource tolera sitemaps sem namespace XML e pula páginas que retornam erro HTTP.
  • Os loaders devolvem Stream bruto — o parsing (HTML→texto, PDF→texto) é responsabilidade do host.
  • RankFusion.ReciprocalRankFusion e RankFusion.DedupById são públicos e podem ser usados diretamente pelo host.
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
1.1.0 114 6/17/2026

1.1.0: loaders (IDocumentSource) — WebPageSource e SitemapSource para ingerir paginas/sites. 1.0.0: retrieval (IRetriever, rerank, multi-query, RRF).