Semantic Kernel XPO Fork – Added MySQL support

The goal of this fork is to create a DevExpress XPO-compatible memory store, and in this case add MySQL support. Let’s see it in action:

Extending Semantic Kernel Memory with XPO

Semantic Kernel supports a variety of databases for memory extension through its connectors. Here is a list of supported databases:

  • Connectors.Memory.AzureAISearch
  • Connectors.Memory.AzureCosmosDBMongoDB
  • Connectors.Memory.AzureCosmosDBNoSQL
  • Connectors.Memory.Chroma
  • Connectors.Memory.DuckDB
  • Connectors.Memory.Kusto
  • Connectors.Memory.Milvus
  • Connectors.Memory.MongoDB
  • Connectors.Memory.Pinecone
  • Connectors.Memory.Postgres
  • Connectors.Memory.Qdrant
  • Connectors.Memory.Redis
  • Connectors.Memory.Sqlite
  • Connectors.Memory.SqlServer
  • Connectors.Memory.Weaviate

Now, with the custom XPO memory provider created by Joche, we can connect to several additional databases:

  • Connectors.Memory.Xpo
    • Db2
    • Db2i
    • Firebird
    • MySQL
    • SapHanna
    • Oracle
    • Postgres
    • SQLite

Battle Testing the XPO Memory Provider

We will begin by making a copy of the TextMemoryPlugin_MultipleMemoryStore.cs file in the Concept project under Memory and renaming it to TextMemoryPlugin_XpoMemoryStoreMySql.cs.

Below is the implementation of the RunAsync method. In this example, we are using MySQL, but feel free to use any other connection string or any of the supported XPO connection strings. For more information, check out this link.

    [Fact]
    public async Task RunAsync() 
    {
        // Firebird
        // var cnx = "XpoProvider=Firebird;DataSource=localhost;User=SYSDBA;Password=masterkey;Database=MyDatabase.fdb;ServerType=0;Charset=NONE";

        // Xpo Memory Store - using InMemoryDataStore, an in-memory store that is not persisted
        // var cnx = DevExpress.Xpo.DB.InMemoryDataStore.GetConnectionStringInMemory(true);

        // Xpo MySQL
        var cnx = "XpoProvider=MySql;Server=127.0.0.1;User ID=root;Password=1234567890;Database=XpoKernelMemory;Persist Security Info=true;Charset=utf8";
        XpoMemoryStore store = await XpoMemoryStore.ConnectAsync(cnx);

        await RunWithStoreAsync(store);
    }
    

Using Embedding Generator and Chat Completion Services

Now let’s integrate the embedding generator and chat completion services with the XpoMemoryStore:

    private async Task RunWithStoreAsync(IMemoryStore memoryStore)
    {
        var EmbeddingModelId = "text-embedding-3-small";
        var ChatModelId = "gpt-4o";

        var GetKey = () => Environment.GetEnvironmentVariable("OpenAiTestKey", EnvironmentVariableTarget.Machine);
        var kernel = Kernel.CreateBuilder()
           .AddOpenAIChatCompletion(ChatModelId, GetKey.Invoke())
           .AddOpenAITextEmbeddingGeneration(EmbeddingModelId, GetKey.Invoke())
           .Build();

        // Create an embedding generator to use for semantic memory.
        var embeddingGenerator = new OpenAITextEmbeddingGenerationService(EmbeddingModelId, GetKey.Invoke());

        // The combination of the text embedding generator and the memory store makes up the 'SemanticTextMemory' object used to
        // store and retrieve memories.
        SemanticTextMemory textMemory = new(memoryStore, embeddingGenerator);
    }
    

As you can see, the textMemory object (SemanticTextMemory) now uses XpoMemoryStore to save collections in a MySQL database. Changing the database is as easy as modifying the connection string.

Adding NuGet References

Finally, let’s add NuGet references for databases like Firebird and MySQL, which are not natively supported by Semantic Kernel:

    <PackageReference Include="FirebirdSql.Data.FirebirdClient" />
    <PackageReference Include="MySql.Data" />
    

You can see the full implementation in this link.

Stay tuned for more implementations of XPO with Semantic Kernel!

Leave a Reply

Your email address will not be published.