April 15th, 2025

Customer Case Study: Announcing the Neon Serverless Postgres Connector for Microsoft Semantic Kernel

Announcing the Neon Serverless Postgres Connector for Microsoft Semantic Kernel

We’re excited to introduce the Neon Serverless Postgres Connector for Microsoft Semantic Kernel, enabling developers to seamlessly integrate Neon’s serverless Postgres capabilities with AI-driven vector search and retrieval workflows. By leveraging the pgvector extension in Neon and the existing Postgres Vector Store connector, this integration provides a high-performance, scalable solution for vector embeddings and performing vector similarity search in Postgres.

Why Use Neon for Semantic Kernel?

Neon is a fully managed Serverless Postgres built for the cloud and has a native integration for Microsoft Azure. Neon’s architecture separates compute from storage, which enables serverless features like instant provisioning, autoscaling, scale to zero, and more. Three things to remember about Neon:

  1. Postgres – 100% Postgres compatible, use the same extensions, drivers, and SQL.
  2. Serverless – the database is just a URL. Neon automatically scales up and down to zero based on your workload. No more overprovisioning.
  3. Branching – Just like with code, you can instantly create isolated copies of your data for development, testing, and more.

Neon offers pgvector support for efficient vector data storing and bringing Elasticsearch-grade features inside Postgres. By combining Neon’s scalable Postgres with Semantic Kernel, developers can power Retrieval-Augmented Generation (RAG) workflows, search large datasets, and build intelligent AI-powered applications with minimal setup.

Getting Started

Prerequisites

To start using Neon with Semantic Kernel, ensure you have:

Setting Up Your Neon Database

Create a new Neon project:

  • Navigate to the Neon Console.
  • Click New Project.
  • Select Azure as the cloud provider.
  • Choose a region.
  • Name your project (e.g., sample-rag).
  • Click Create Project.
  • Once the project is created successfully, copy the Neon connection string. You can find the connection details in the Connection Details widget on the Neon

Enable pgvector extension

Open the SQL editor in Neon Console and execute the following script to enable vector store:

CREATE EXTENSION IF NOT EXISTS vector;

Implementing Vector Store Retrieval-Augmented Generation (RAG)

This GitHub repository provides examples of how to use Neon Serverless Postgres, in combination with a .NET console app and the Semantic Kernel. It includes a RAG workflow, demonstrating how to search the arXiv API for specific papers based on a topic and category. Sample project embeds the paper abstracts using OpenAI’s embedding service and stores these embeddings in a Neon vector store for efficient searching. It includes commands for loading data, searching data, and querying the model.

You can initialize Neon Postgres Vector Store with Semantic Kernel in .NET using Microsoft.SemanticKernel.Connectors.Postgres NuGet package. Follow the ReadMe file instructions to run the project.

Loading Data into Neon

Run the following command to fetch, create a database schema (arxiv_records) in Neon, and embed 100 arXiv papers related to RAG:

dotnet run --project PGSKExamples.csproj load --topic RAG --total 100

This command:

  1. Retrieves papers from arXiv based on the specified topic.
  2. Embeds abstracts using Azure OpenAI.
  3. Stores embeddings in the Neon Postgres vector store.

Here is an example of how you can initiate Neon data source and store vector embeddings:

// Program.cs using Microsoft.Extensions.Configuration; using Microsoft.SemanticKernel; using Microsoft.SemanticKernel.Connectors.AzureOpenAI; using Microsoft.SemanticKernel.Connectors.Postgres; using Microsoft.SemanticKernel.Data; using Npgsql; using CommandLine; namespace SemanticKernelWithPostgres; class Program { ... private static NpgsqlDataSource GetDataSource() { var postgresConfig = Configuration!.GetSection("Postgres"); var connectionString = postgresConfig["ConnectionString"] ?? throw new InvalidOperationException("Postgres connection string is missing."); var dataSourceBuilder = new NpgsqlDataSourceBuilder(connectionString); dataSourceBuilder.UseVector(); return dataSourceBuilder.Build(); } private static async Task Load(int totalResults = 1000, string topic = "RAG") { try { Console.WriteLine($"Loading ArXiv records for topic '{topic}'..."); var records = await ArxivQuery.QueryArxivAsync(topic, totalResults: totalResults); Console.WriteLine($"Found {records.Count} results"); var azureOpenAIConfig = Configuration!.GetSection("AzureOpenAI"); if (azureOpenAIConfig is null) { throw new InvalidOperationException("AzureOpenAI configuration is missing."); } var textEmbeddingDeploymentName = azureOpenAIConfig["TextEmbeddingDeploymentName"] ?? throw new InvalidOperationException("TextEmbeddingDeploymentName is missing."); var endpoint = azureOpenAIConfig["Endpoint"] ?? throw new InvalidOperationException("Endpoint is missing."); var apiKey = azureOpenAIConfig["ApiKey"] ?? throw new InvalidOperationException("ApiKey is missing."); var textEmbeddingGenerationService = new AzureOpenAITextEmbeddingGenerationService( deploymentName: textEmbeddingDeploymentName, endpoint: endpoint, apiKey: apiKey); await using var dataSource = GetDataSource(); var vectorStore = new PostgresVectorStore(dataSource); var recordCollection = vectorStore.GetCollection<string, ArxivRecord>("arxiv_records"); await recordCollection.CreateCollectionIfNotExistsAsync().ConfigureAwait(false); // Group arxiv records into batches, generate embeddings for each batch, and upsert the records int i = 1; foreach (var batch in records.Batch(20)) { Console.WriteLine($"Processing batch {i++} ({batch.Count()} records)..."); var embeddings = await textEmbeddingGenerationService.GenerateEmbeddingsAsync(batch.Select(r => r.Abstract).ToList()); Console.WriteLine(" ...embeddings generated"); foreach (var zipped in batch.Zip(embeddings, (record, embedding) => (record, embedding))) { zipped.record.Embedding = zipped.embedding; } await recordCollection.UpsertBatchAsync(batch).ToListAsync(); Console.WriteLine(" ...batch upserted"); } } catch (Exception ex) { Console.WriteLine($"An error occurred: {ex.Message}"); throw; } } } 

Querying Data from Neon

Once data is loaded, you can search for relevant papers:

dotnet run --project PGSKExamples.csproj query "What are good chunking strategies for RAG applications?"

This command:

  1. Embeds the query using OpenAI.
  2. Searches for relevant embeddings in Neon’s vector store.
  3. Returns the most relevant arXiv papers.

Example output:

> dotnet run query "What are good chunking strategies to use for unstructured text in RAG applications?" 1. Paper: "Chunking Techniques for RAG Efficiency" 2. Paper: "Text Segmentation in Large Language Models" 3. Paper: "Embedding Optimization for Context Retrieval"

Below code how you can query and search for relevant research papers on arXiv using semantic search (vector embeddings):

// Program.cs ... private static async Task Query(string query) { // Load the configuration var azureOpenAIConfig = Configuration!.GetSection("AzureOpenAI"); if (azureOpenAIConfig is null) { throw new InvalidOperationException("AzureOpenAI configuration is missing."); } var textEmbeddingDeploymentName = azureOpenAIConfig["TextEmbeddingDeploymentName"] ?? throw new InvalidOperationException("TextEmbeddingDeploymentName is missing."); var endpoint = azureOpenAIConfig["Endpoint"] ?? throw new InvalidOperationException("Endpoint is missing."); var apiKey = azureOpenAIConfig["ApiKey"] ?? throw new InvalidOperationException("ApiKey is missing."); var chatCompletionDeploymentName = azureOpenAIConfig["ChatCompletionDeploymentName"] ?? throw new InvalidOperationException("ChatCompletionDeploymentName is missing."); // Create a text embedding service var textEmbeddingGenerationService = new AzureOpenAITextEmbeddingGenerationService( deploymentName: textEmbeddingDeploymentName, endpoint: endpoint, apiKey: apiKey); // Create a vector store and text search service await using var dataSource = GetDataSource(); var vectorStore = new PostgresVectorStore(dataSource); var recordCollection = vectorStore.GetCollection<string, ArxivRecord>("arxiv_records"); var textSearch = new VectorStoreTextSearch<ArxivRecord>(recordCollection, textEmbeddingGenerationService); // Create a kernel with OpenAI chat completion IKernelBuilder kernelBuilder = Kernel.CreateBuilder(); kernelBuilder.AddAzureOpenAIChatCompletion( deploymentName: chatCompletionDeploymentName, endpoint: endpoint, apiKey: apiKey); Kernel kernel = kernelBuilder.Build(); // Build a text search plugin with vector store search and add to the kernel var options = new KernelFunctionFromMethodOptions() { FunctionName = "ArXivSearch", Description = "Search for ArXiv abstracts for latest research in computer science topics.", Parameters = [ new KernelParameterMetadata("query") { Description = "What to search for", IsRequired = true }, new KernelParameterMetadata("count") { Description = "Number of results", IsRequired = true, DefaultValue = 3, ParameterType = typeof(int) }, new KernelParameterMetadata("skip") { Description = "Number of results to skip", IsRequired = false, DefaultValue = 0 }, ], ReturnParameter = new() { ParameterType = typeof(KernelSearchResults<string>) }, }; var searchPlugin = KernelPluginFactory.CreateFromFunctions("ArXiV", "Functions for working with research papers", [ textSearch.CreateGetSearchResultsCustom(options) ]); kernel.Plugins.Add(searchPlugin); AzureOpenAIPromptExecutionSettings settings = new() { FunctionChoiceBehavior = FunctionChoiceBehavior.Auto(), MaxTokens = 1000 }; KernelArguments arguments = new(settings); Console.WriteLine(await kernel.InvokePromptAsync(query, arguments)); } 

Next Steps

  1. Try theexample project and experiment with Neon-powered AI search.
  2. Explorepg_search: Get 1,000x faster full-text search in Postgres.
  3. Scale Your AI Workflows with serverless database solutions.

Microsoft Semantic Kernel Neon Connector is ideally suited to AI Agentic use cases where Agents can create new databases programmatically with one-second provisioning time. In Neon, databases automatically scale to zero when idle and wake up instantly. You don’t pay for a database unless it’s being used or has data on it. Join us in transforming AI Agents workflows with Neon Serverless Postgres and Microsoft Semantic Kernel!

0 comments