Gegevens opnemen in een Vector Store met behulp van Semantische kernel (preview)
Waarschuwing
De Semantische Kernel Vector Store-functionaliteit is in preview en verbeteringen waarvoor wijzigingen die fouten veroorzaken, kunnen nog steeds in beperkte omstandigheden optreden voordat ze worden uitgebracht.
In dit artikel wordt uitgelegd hoe u een toepassing maakt voor
- Tekst ophalen uit elke alinea in een Microsoft Word-document
- Een insluiting voor elke alinea genereren
- De tekst, insluiting en een verwijzing naar de oorspronkelijke locatie in een Redis-exemplaar upsert.
Vereisten
Voor dit voorbeeld hebt u
- Een insluitmodel voor het genereren van inhoud dat wordt gehost in Azure of een andere provider van uw keuze.
- Een exemplaar van Redis of Docker Desktop, zodat u Redis lokaal kunt uitvoeren.
- Een Word-document dat moet worden geparseerd en geladen. Hier volgt een zip met een Word-voorbeelddocument dat u kunt downloaden en gebruiken: vector-store-data-ingestion-input.zip.
Redis instellen
Als u al een Redis-exemplaar hebt, kunt u dat gebruiken. Als u uw project liever lokaal wilt testen, kunt u eenvoudig een Redis-container starten met behulp van docker.
docker run -d --name redis-stack -p 6379:6379 -p 8001:8001 redis/redis-stack:latest
Ga naar http://localhost:8001/redis-stack/browser uw browser om te controleren of deze correct wordt uitgevoerd.
In de rest van deze instructies wordt ervan uitgegaan dat u deze container gebruikt met behulp van de bovenstaande instellingen.
Uw project maken
Maak een nieuw project en voeg nuget-pakketverwijzingen toe voor de Redis-connector van Semantic Kernel, het open XML-pakket waarmee het Word-document wordt gelezen en de OpenAI-connector van Semantische Kernel voor het genereren van insluitingen.
dotnet new console --framework net8.0 --name SKVectorIngest
cd SKVectorIngest
dotnet add package Microsoft.SemanticKernel.Connectors.AzureOpenAI
dotnet add package Microsoft.SemanticKernel.Connectors.Redis --prerelease
dotnet add package DocumentFormat.OpenXml
Een gegevensmodel toevoegen
Als u gegevens wilt uploaden, moeten we eerst beschrijven welke indeling de gegevens in de database moeten hebben. We kunnen dit doen door een gegevensmodel te maken met kenmerken die de functie van elke eigenschap beschrijven.
Voeg een nieuw bestand toe aan het project met de naam TextParagraph.cs
en voeg het volgende model eraan toe.
using Microsoft.Extensions.VectorData;
namespace SKVectorIngest;
internal class TextParagraph
{
/// <summary>A unique key for the text paragraph.</summary>
[VectorStoreRecordKey]
public required string Key { get; init; }
/// <summary>A uri that points at the original location of the document containing the text.</summary>
[VectorStoreRecordData]
public required string DocumentUri { get; init; }
/// <summary>The id of the paragraph from the document containing the text.</summary>
[VectorStoreRecordData]
public required string ParagraphId { get; init; }
/// <summary>The text of the paragraph.</summary>
[VectorStoreRecordData]
public required string Text { get; init; }
/// <summary>The embedding generated from the Text.</summary>
[VectorStoreRecordVector(1536)]
public ReadOnlyMemory<float> TextEmbedding { get; set; }
}
Houd er rekening mee dat we de waarde 1536
doorgeven aan de VectorStoreRecordVectorAttribute
. Dit is de dimensiegrootte van de vector en moet overeenkomen met de grootte van de vector die uw gekozen insluitingsgenerator produceert.
Tip
Raadpleeg het definiëren van uw gegevensmodel voor meer informatie over het maken van aantekeningen bij uw gegevensmodel en welke extra opties beschikbaar zijn voor elk kenmerk.
De alinea's in het document lezen
We hebben code nodig om het word-document te lezen en de tekst van elke alinea erin te zoeken.
Voeg een nieuw bestand toe aan het project met de naam DocumentReader.cs
en voeg de volgende klasse toe om de alinea's uit een document te lezen.
using System.Text;
using System.Xml;
using DocumentFormat.OpenXml.Packaging;
namespace SKVectorIngest;
internal class DocumentReader
{
public static IEnumerable<TextParagraph> ReadParagraphs(Stream documentContents, string documentUri)
{
// Open the document.
using WordprocessingDocument wordDoc = WordprocessingDocument.Open(documentContents, false);
if (wordDoc.MainDocumentPart == null)
{
yield break;
}
// Create an XmlDocument to hold the document contents and load the document contents into the XmlDocument.
XmlDocument xmlDoc = new XmlDocument();
XmlNamespaceManager nsManager = new XmlNamespaceManager(xmlDoc.NameTable);
nsManager.AddNamespace("w", "http://schemas.openxmlformats.org/wordprocessingml/2006/main");
nsManager.AddNamespace("w14", "http://schemas.microsoft.com/office/word/2010/wordml");
xmlDoc.Load(wordDoc.MainDocumentPart.GetStream());
// Select all paragraphs in the document and break if none found.
XmlNodeList? paragraphs = xmlDoc.SelectNodes("//w:p", nsManager);
if (paragraphs == null)
{
yield break;
}
// Iterate over each paragraph.
foreach (XmlNode paragraph in paragraphs)
{
// Select all text nodes in the paragraph and continue if none found.
XmlNodeList? texts = paragraph.SelectNodes(".//w:t", nsManager);
if (texts == null)
{
continue;
}
// Combine all non-empty text nodes into a single string.
var textBuilder = new StringBuilder();
foreach (XmlNode text in texts)
{
if (!string.IsNullOrWhiteSpace(text.InnerText))
{
textBuilder.Append(text.InnerText);
}
}
// Yield a new TextParagraph if the combined text is not empty.
var combinedText = textBuilder.ToString();
if (!string.IsNullOrWhiteSpace(combinedText))
{
Console.WriteLine("Found paragraph:");
Console.WriteLine(combinedText);
Console.WriteLine();
yield return new TextParagraph
{
Key = Guid.NewGuid().ToString(),
DocumentUri = documentUri,
ParagraphId = paragraph.Attributes?["w14:paraId"]?.Value ?? string.Empty,
Text = combinedText
};
}
}
}
}
Insluitingen genereren en de gegevens uploaden
We hebben code nodig om insluitingen te genereren en de alinea's te uploaden naar Redis. Laten we dit doen in een aparte klas.
Voeg een nieuw bestand toe met de naam DataUploader.cs
en voeg de volgende klasse eraan toe.
#pragma warning disable SKEXP0001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
using Microsoft.Extensions.VectorData;
using Microsoft.SemanticKernel.Embeddings;
namespace SKVectorIngest;
internal class DataUploader(IVectorStore vectorStore, ITextEmbeddingGenerationService textEmbeddingGenerationService)
{
/// <summary>
/// Generate an embedding for each text paragraph and upload it to the specified collection.
/// </summary>
/// <param name="collectionName">The name of the collection to upload the text paragraphs to.</param>
/// <param name="textParagraphs">The text paragraphs to upload.</param>
/// <returns>An async task.</returns>
public async Task GenerateEmbeddingsAndUpload(string collectionName, IEnumerable<TextParagraph> textParagraphs)
{
var collection = vectorStore.GetCollection<string, TextParagraph>(collectionName);
await collection.CreateCollectionIfNotExistsAsync();
foreach (var paragraph in textParagraphs)
{
// Generate the text embedding.
Console.WriteLine($"Generating embedding for paragraph: {paragraph.ParagraphId}");
paragraph.TextEmbedding = await textEmbeddingGenerationService.GenerateEmbeddingAsync(paragraph.Text);
// Upload the text paragraph.
Console.WriteLine($"Upserting paragraph: {paragraph.ParagraphId}");
await collection.UpsertAsync(paragraph);
Console.WriteLine();
}
}
}
Alles samenvoegen
Ten slotte moeten we de verschillende onderdelen samenbrengen.
In dit voorbeeld gebruiken we de Semantische container voor afhankelijkheidsinjectie van kernel, maar het is ook mogelijk om een IServiceCollection
op basis van een container te gebruiken.
Voeg de volgende code toe aan uw Program.cs
bestand om de container te maken, het Redis Vector Store te registreren en de insluitservice te registreren.
Zorg ervoor dat u de instellingen voor het genereren van tekst voor het insluiten van tekst vervangt door uw eigen waarden.
#pragma warning disable SKEXP0010 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
#pragma warning disable SKEXP0020 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
using Microsoft.Extensions.DependencyInjection;
using Microsoft.SemanticKernel;
using SKVectorIngest;
// Replace with your values.
var deploymentName = "text-embedding-ada-002";
var endpoint = "https://sksample.openai.azure.com/";
var apiKey = "your-api-key";
// Register Azure Open AI text embedding generation service and Redis vector store.
var builder = Kernel.CreateBuilder()
.AddAzureOpenAITextEmbeddingGeneration(deploymentName, endpoint, apiKey)
.AddRedisVectorStore("localhost:6379");
// Register the data uploader.
builder.Services.AddSingleton<DataUploader>();
// Build the kernel and get the data uploader.
var kernel = builder.Build();
var dataUploader = kernel.Services.GetRequiredService<DataUploader>();
Als laatste stap willen we de alinea's uit ons word-document lezen en de gegevensuploader aanroepen om de insluitingen te genereren en de alinea's te uploaden.
// Load the data.
var textParagraphs = DocumentReader.ReadParagraphs(
new FileStream(
"vector-store-data-ingestion-input.docx",
FileMode.Open),
"file:///c:/vector-store-data-ingestion-input.docx");
await dataUploader.GenerateEmbeddingsAndUpload(
"sk-documentation",
textParagraphs);
Uw gegevens weergeven in Redis
Navigeer naar de Redis-stackbrowser, bijvoorbeeld http://localhost:8001/redis-stack/browser waar u nu de geüploade alinea's kunt zien. Hier volgt een voorbeeld van wat u moet zien voor een van de geüploade alinea's.
{
"DocumentUri" : "file:///c:/vector-store-data-ingestion-input.docx",
"ParagraphId" : "14CA7304",
"Text" : "Version 1.0+ support across C#, Python, and Java means it’s reliable, committed to non breaking changes. Any existing chat-based APIs are easily expanded to support additional modalities like voice and video.",
"TextEmbedding" : [...]
}
Binnenkort beschikbaar
Verdere instructies binnenkort beschikbaar
Binnenkort beschikbaar
Verdere instructies binnenkort beschikbaar