From d9102053397aee7633686ba8882d5cd084a80405 Mon Sep 17 00:00:00 2001 From: Marco Minerva Date: Fri, 31 Jul 2026 16:38:48 +0200 Subject: [PATCH] Refactor: Replace ContextProvider with DocumentContextProviderService Replaces the ContextProvider class with DocumentContextProviderService, moving vector search logic into its own file. Updates dependency injection and all usages to reference the new service. The service uses embeddings and Entity Framework for vector-based text search, returning relevant document chunks. Removes unused usings and references to ContextProvider. --- SqlDatabaseVectorSearch/Program.cs | 4 +-- .../DocumentContextProviderService.cs | 35 +++++++++++++++++++ .../Services/VectorSearchService.cs | 30 ---------------- 3 files changed, 37 insertions(+), 32 deletions(-) create mode 100644 SqlDatabaseVectorSearch/Services/DocumentContextProviderService.cs diff --git a/SqlDatabaseVectorSearch/Program.cs b/SqlDatabaseVectorSearch/Program.cs index 76177f0..6428050 100644 --- a/SqlDatabaseVectorSearch/Program.cs +++ b/SqlDatabaseVectorSearch/Program.cs @@ -100,7 +100,7 @@ builder.Services.AddSingleton(); builder.Services.AddScoped(); builder.Services.AddScoped(); -builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); @@ -249,7 +249,7 @@ builder.Services.AddAIAgent("RagAgent", (services, key) => && m.GetAgentRequestMessageSourceType() != AgentRequestMessageSourceType.AIContextProvider); } }), - AIContextProviders = [new TextSearchProvider(services.GetRequiredService().SearchAsync, textSearchOptions)] + AIContextProviders = [new TextSearchProvider(services.GetRequiredService().SearchAsync, textSearchOptions)] }, loggerFactory: services.GetRequiredService(), services: services); diff --git a/SqlDatabaseVectorSearch/Services/DocumentContextProviderService.cs b/SqlDatabaseVectorSearch/Services/DocumentContextProviderService.cs new file mode 100644 index 0000000..4b29b5d --- /dev/null +++ b/SqlDatabaseVectorSearch/Services/DocumentContextProviderService.cs @@ -0,0 +1,35 @@ +using System.Data; +using Microsoft.Agents.AI; +using Microsoft.Data.SqlTypes; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.AI; +using Microsoft.Extensions.Options; +using SqlDatabaseVectorSearch.Data; +using SqlDatabaseVectorSearch.Settings; + +namespace SqlDatabaseVectorSearch.Services; + +public class DocumentContextProviderService(ApplicationDbContext dbContext, IEmbeddingGenerator> embeddingGenerator, IOptions appSettingsOptions) +{ + private readonly AppSettings appSettings = appSettingsOptions.Value; + + public async Task> SearchAsync(string query, CancellationToken cancellationToken) + { + // Perform Vector Search on SQL Database. + var questionEmbedding = await embeddingGenerator.GenerateVectorAsync(query, cancellationToken: cancellationToken); + var embeddingVector = new SqlVector(questionEmbedding); + + var chunks = await dbContext.DocumentChunks.Include(c => c.Document) + .OrderBy(c => EF.Functions.VectorDistance("cosine", c.Embedding, embeddingVector)) + .Take(appSettings.MaxRelevantChunks).Select(c => new TextSearchProvider.TextSearchResult + { + SourceLink = c.Id.ToString().ToLowerInvariant(), + SourceName = c.Document.Name, + Text = c.Content, + RawRepresentation = c.PageNumber + }) + .ToListAsync(cancellationToken); + + return chunks; + } +} \ No newline at end of file diff --git a/SqlDatabaseVectorSearch/Services/VectorSearchService.cs b/SqlDatabaseVectorSearch/Services/VectorSearchService.cs index e6edd4e..edcaee8 100644 --- a/SqlDatabaseVectorSearch/Services/VectorSearchService.cs +++ b/SqlDatabaseVectorSearch/Services/VectorSearchService.cs @@ -3,13 +3,8 @@ using System.Runtime.CompilerServices; using Microsoft.Agents.AI; using Microsoft.Agents.AI.Hosting; using Microsoft.Agents.AI.Workflows; -using Microsoft.Data.SqlTypes; -using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.AI; -using Microsoft.Extensions.Options; -using SqlDatabaseVectorSearch.Data; using SqlDatabaseVectorSearch.Models; -using SqlDatabaseVectorSearch.Settings; using SqlDatabaseVectorSearch.Workflows; namespace SqlDatabaseVectorSearch.Services; @@ -87,28 +82,3 @@ public partial class VectorSearchService([FromKeyedServices("EmbeddingWorkflow") yield return new(question.ConversationId, StreamState.End, new TokenUsageResponse(null, response.Usage)); } } - -public class ContextProvider(ApplicationDbContext dbContext, IEmbeddingGenerator> embeddingGenerator, IOptions appSettingsOptions) -{ - private readonly AppSettings appSettings = appSettingsOptions.Value; - - public async Task> SearchAsync(string query, CancellationToken cancellationToken) - { - // Perform Vector Search on SQL Database. - var questionEmbedding = await embeddingGenerator.GenerateVectorAsync(query, cancellationToken: cancellationToken); - var embeddingVector = new SqlVector(questionEmbedding); - - var chunks = await dbContext.DocumentChunks.Include(c => c.Document) - .OrderBy(c => EF.Functions.VectorDistance("cosine", c.Embedding, embeddingVector)) - .Take(appSettings.MaxRelevantChunks).Select(c => new TextSearchProvider.TextSearchResult - { - SourceLink = c.Id.ToString().ToLowerInvariant(), - SourceName = c.Document.Name, - Text = c.Content, - RawRepresentation = c.PageNumber - }) - .ToListAsync(cancellationToken); - - return chunks; - } -} \ No newline at end of file