Use Redis for memory storage with the Semantic Kernel SDK
This article demonstrates how to integrate a Redis database with the RediSearch module into the Semantic Kernel SDK and use it for memory storage and retrieval.
Memories represent text information that has been stored alongside a precomputed embedding vector for the whole text. When an LLM is prompted to recall a memory, it uses these precomputed embeddings to efficiently evaluate whether a memory is relevant to the prompt. After the LLM finds a matching memory, it uses the memory's text information as context for the next steps in the prompt completion.
Memory storage that's added to the Semantic Kernel SDK provides a broader context for your requests. It also enables you to store data in the same manner as you store a traditional database, but query it by using natural language.
Prerequisites
- An Azure account that has an active subscription. Create an account for free.
- .NET SDK
Microsoft.SemanticKernel
NuGet packageMicrosoft.SemanticKernel.Connectors.Redis
NuGet packageMicrosoft.SemanticKernel.Plugins.Memory
NuGet packageStackExchange.Redis
NuGet package- A Redis database that has the RediSearch module, deployed and accessible to your .NET application
Implement memory storage using a Redis database
Before you integrate your Redis database to the Semantic Kernel SDK, make sure that you have the RediSearch module enabled. For module information for Azure Cache for Redis, see Use Redis modules with Azure Cache for Redis.
Initialize a connection to your Redis database. For example:
// Retrieve the Redis connection config. IConfigurationRoot config = new ConfigurationBuilder().AddUserSecrets<Program>().Build(); string redisConfig = config["REDIS_CONFIG"]!; // Initialize a connection to the Redis database. ConnectionMultiplexer connectionMultiplexer = await ConnectionMultiplexer.ConnectAsync( redisConfig ); IDatabase database = connectionMultiplexer.GetDatabase();
Build the
Kernel
by includingITextEmbeddingGenerationService
. For example:// Retrieve the Azure OpenAI config and secrets saved during deployment. string endpoint = config["AZURE_OPENAI_ENDPOINT"]!; string embeddingModel = config["AZURE_OPENAI_EMBEDDING_NAME"]!; string completionModel = config["AZURE_OPENAI_GPT_NAME"]!; string key = config["AZURE_OPENAI_KEY"]!; // Build the Kernel; must add an embedding generation service. Kernel kernel = Kernel .CreateBuilder() .AddAzureOpenAITextEmbeddingGeneration(embeddingModel, endpoint, key) .AddAzureOpenAIChatCompletion(completionModel, endpoint, key) .Build();
Wrap the Redis database in a
RedisMemoryStore
instance, and then initialize aSemanticTextMemory
object by using the memory store and embedding generation service. For example:// Retrieve the desired vector size for the memory store. // If unspecified, the default vector size is 1536. int vectorSize = int.Parse(config["REDIS_MEMORY_VECTOR_SIZE"]!); // Initialize a memory store using the redis database IMemoryStore memoryStore = new RedisMemoryStore(database, vectorSize); // Retrieve the embedding service from the Kernel. ITextEmbeddingGenerationService embeddingService = kernel.Services.GetRequiredService<ITextEmbeddingGenerationService>(); // Initialize a SemanticTextMemory using the memory store and embedding generation service. SemanticTextMemory textMemory = new(memoryStore, embeddingService);
Add the semantic text memory to the
Kernel
by using theTextMemoryPlugin
class. For example:// Initialize a TextMemoryPlugin using the text memory. TextMemoryPlugin memoryPlugin = new(textMemory); // Import the text memory plugin into the Kernel. KernelPlugin memory = kernel.ImportPluginFromObject(memoryPlugin);
Use the
Kernel
and plug-in to save, retrieve, and recall memories. For example:// Retrieve the desired memory collection name. string memoryCollectionName = config["REDIS_MEMORY_COLLECTION_NAME"]!; // Save a memory with the Kernel. await kernel.InvokeAsync( memory["Save"], new() { [TextMemoryPlugin.InputParam] = "My family is from New York", [TextMemoryPlugin.CollectionParam] = memoryCollectionName, [TextMemoryPlugin.KeyParam] = "info1", } ); // Retrieve a memory with the Kernel. FunctionResult result = await kernel.InvokeAsync( memory["Retrieve"], new() { [TextMemoryPlugin.CollectionParam] = memoryCollectionName, [TextMemoryPlugin.KeyParam] = "info1", } ); // Get the memory string from the function result; returns a null value if no memory is found. Console.WriteLine( $"Retrieved memory: {result.GetValue<string>() ?? "ERROR: memory not found"}" ); // Alternatively, recall similar memories with the Kernel. // Can configure the memory collection, number of memories to recall, and relevance score. result = await kernel.InvokeAsync( memory["Recall"], new() { [TextMemoryPlugin.InputParam] = "Ask: where do I live?", [TextMemoryPlugin.CollectionParam] = memoryCollectionName, [TextMemoryPlugin.LimitParam] = "2", [TextMemoryPlugin.RelevanceParam] = "0.79", } ); // If memories are recalled, the function result can be deserialized as a string[]. string? resultStr = result.GetValue<string>(); string[]? parsedResult = string.IsNullOrEmpty(resultStr) ? null : JsonSerializer.Deserialize<string[]>(resultStr); Console.WriteLine( $"Recalled memories: {(parsedResult?.Length > 0 ? resultStr : "ERROR: memory not found")}" );
Use memory recall as part of a prompt by using the prompt template syntax
{{...}}
. For example:// Create a prompt that includes memory recall. // The {{...}} syntax represents an expression to Semantic Kernel. // For more information on this syntax see: // https://learn.microsoft.com/semantic-kernel/prompts/prompt-template-syntax string memoryRecallPrompt = """ Consider only the facts below when answering questions: BEGIN FACTS About me: {{recall 'where did I grow up?'}} END FACTS Question: What are some fun facts about my home state? """; // Invoke the prompt with the Kernel. // Must configure the memory collection, number of memories to recall, and relevance score. resultStr = await kernel.InvokePromptAsync<string>( memoryRecallPrompt, new() { [TextMemoryPlugin.CollectionParam] = memoryCollectionName, [TextMemoryPlugin.LimitParam] = "2", [TextMemoryPlugin.RelevanceParam] = "0.79", } ); // If the memory recall fails, the model will indicate it has missing information in its output. // Otherwise the output will incorporate your memory as context. Console.WriteLine($"Output: {resultStr}");
Related content
- [Use RAG with SQL]
- [Data ingestion from SharePoint]
- [Working with vector databases]
Feedback
https://aka.ms/ContentUserFeedback.
Coming soon: Throughout 2024 we will be phasing out GitHub Issues as the feedback mechanism for content and replacing it with a new feedback system. For more information see:Submit and view feedback for