Qdrant with Aspire times out #915
-
Context / ScenarioIf you spin up Qdrant using .net Aspire like this:
Ensuring that your project has a WithReference, and then spin up Kernel Memory by creating a qdrantConfig from the connection string (which is verified to have valid http and apikey) and then passing .WithQdrantMemoryDb(qdrantConfig) What happened?When you try and import a document you get a timeout within the qdrant memory db code. A qdrant client works just fine. It should just work. It would be really nice if Kernel Memory wrapped a proper QdrantClient instead of using direct Http requests because then we could use the service provider to get a qdrant client and pass it into WithQdrantMemoryDb and know it works and everything would integrate nicely with Aspire. Failing that, it would be nice if there were samples on how to integrate with Aspire with Kernel Memory for everything. ImportanceI cannot use Kernel Memory Platform, Language, VersionsWindows, C#, .NET 9.0 RTM with Aspire 9.0.0 Relevant log outputat System.Net.Http.HttpConnection.<SendAsync>d__56.MoveNext()
at System.Net.Http.HttpConnectionPool.<SendWithVersionDetectionAndRetryAsync>d__50.MoveNext()
at System.Net.Http.Metrics.MetricsHandler.<SendAsyncWithMetrics>d__5.MoveNext()
at System.Net.Http.DiagnosticsHandler.<SendAsyncCore>d__10.MoveNext()
at System.Net.Http.RedirectHandler.<SendAsync>d__4.MoveNext()
at System.Net.Http.HttpClient.<<SendAsync>g__Core|83_0>d.MoveNext()
at Microsoft.KernelMemory.MemoryDb.Qdrant.Client.QdrantClient`1.<ExecuteHttpRequestAsync>d__14.MoveNext()
at Microsoft.KernelMemory.MemoryDb.Qdrant.Client.QdrantClient`1.<CreateCollectionAsync>d__3.MoveNext()
at Microsoft.KernelMemory.Handlers.SaveRecordsHandler.<CreateIndexOnceAsync>d__19.MoveNext()
at Microsoft.KernelMemory.Handlers.SaveRecordsHandler.<InvokeAsync>d__13.MoveNext()
at Microsoft.KernelMemory.Pipeline.InProcessPipelineOrchestrator.<RunPipelineAsync>d__11.MoveNext()
at Microsoft.KernelMemory.Pipeline.BaseOrchestrator.<ImportDocumentAsync>d__23.MoveNext()
at Microsoft.KernelMemory.MemoryServerless.<ImportTextAsync>d__11.MoveNext()
at Microsoft.KernelMemory.MemoryServerless.<ImportTextAsync>d__11.MoveNext() |
Beta Was this translation helpful? Give feedback.
Replies: 16 comments 5 replies
-
PS: I suspect this is because of how the http client is being created inside of the Qdrant client. It's breaking on the proxy stuff in aspire. |
Beta Was this translation helpful? Give feedback.
-
could you provide the full aspire builder code? it might be about the hostname to be set in the env var |
Beta Was this translation helpful? Give feedback.
-
I assume this is what you're referring to? And the endpoint that is passed in is: http://localhost:16334 which is the grpc port set by aspire. |
Beta Was this translation helpful? Give feedback.
-
are you loading KM as a docker image or as a project? KM also needs Qdrant config, how are you passing those settings? The env var for Qdrant endpoint is |
Beta Was this translation helpful? Give feedback.
-
I'm using it as a project, not a docker image. I'm using the nuget packages. |
Beta Was this translation helpful? Give feedback.
-
Update: If i hard code the http URL it works. The problem is that because it isn't using the qdrant client (GRPC) and is httping everything (slower), it can never work with what is passed by Aspire without hacking. (of which you have no way in production versus dev to know what the ports are) |
Beta Was this translation helpful? Give feedback.
-
Without access to code it's too hard to say, my guess is that some required configuration is not being passed to KM, so KM doesn't know which port to use when connecting to Qdrant, or simply might be using the default settings |
Beta Was this translation helpful? Give feedback.
-
See my comment that we posted at the same time. |
Beta Was this translation helpful? Give feedback.
-
in prod it's probably easier because aspire proxy is not present. You could try disabling the proxy locally too, and just using the default ports, ie 6333 for qdrant |
Beta Was this translation helpful? Give feedback.
-
You can't do that without creating duplicate mappings because the default ones will also be created and then the connection string will still be the ones automatically created by aspire in the connection string information. The connection string info from aspire correctly only has the GRPC endpoint, not the http endpoint since Qdrant prefers GRPC and that's the default for the qdrantClient which KM isn't using. So basically the only way right now to use KM with Aspire is to just defeat Aspire entirely and pretend it doesn't exist and hard code everything. KM Qdrant should be using the QdrantClient under the hood. (and yes, Aspire is a HUGE use case for KM and should be heavily tested for all KM connectors) |
Beta Was this translation helpful? Give feedback.
-
Aspire like Kubernetes and others is an orchestrator, and shouldn't require changes to the code being hosted specifically for it. Otherwise, we'd have to change the code for 10 different orchestration engines :-) I believe the issue here is simpler, e.g. what Aspire assumes about connection strings is not how every app works. For instance, KM doesn't use a "Connection String". Anyway, I'll publish an Aspire example as soon as I find the time. |
Beta Was this translation helpful? Give feedback.
-
Here's my KM setup:
.WithQdrantMemoryDb("http://localhost:16333", qdrantConfig.APIKey) should be able to take a qdrantClient from sp.GetRequiredService() which was previously injected with builder.AddQdrantClient("aspireresourceid") Then this would be aspire friendly and work. Any other clients that KM uses that uses 3rd party clients should work the same way. |
Beta Was this translation helpful? Give feedback.
-
The real issue is that even though I split the connection string into the endpoint and apikey and provide KM with that, the endpoint provided by aspire is the GRPC endpoint which KM doesn't use because KM is using a custom http qdrant client instead of the Qdrant provided client. Here's the code that parses the connection string that the Aspire.Hosting.Qdrant library injects:
But I shouldn't have to do this, because KM should be using QdrantClient from their nuget package, not a custom rolled http client. |
Beta Was this translation helpful? Give feedback.
-
by the way, the qdrant client didn't exist when we started 3 years ago :-) We'll take a look, thanks |
Beta Was this translation helpful? Give feedback.
-
Makes sense! Thanks! I appreciate it! |
Beta Was this translation helpful? Give feedback.
-
Here's a working example: var builder = DistributedApplication.CreateBuilder(args);
var qdrant = builder.AddContainer("qdrant", "qdrant/qdrant")
.WithHttpEndpoint(targetPort: 6333)
.PublishAsContainer();
var qdrantEndpoint = qdrant.GetEndpoint("http");
builder.AddProject<Projects.Service>("kernel-memory")
.WaitFor(qdrant)
.WithEnvironment("KernelMemory__TextGeneratorType", "AzureOpenAIText")
.WithEnvironment("KernelMemory__DataIngestion__EmbeddingGeneratorTypes__0", "AzureOpenAIEmbedding")
.WithEnvironment("KernelMemory__DataIngestion__MemoryDbTypes__0", "Qdrant")
.WithEnvironment("KernelMemory__Retrieval__EmbeddingGeneratorType", "AzureOpenAIEmbedding")
.WithEnvironment("KernelMemory__Retrieval__MemoryDbType", "Qdrant")
.WithEnvironment("KernelMemory__Services__Qdrant__Endpoint", qdrantEndpoint)
.WithEnvironment("KernelMemory__Services__Qdrant__APIKey", "")
.WithEnvironment("KernelMemory__Services__AzureOpenAIText__Endpoint", "https://....openai.azure.com/")
.WithEnvironment("KernelMemory__Services__AzureOpenAIText__Deployment", "gpt-4o")
.WithEnvironment("KernelMemory__Services__AzureOpenAIEmbedding__Endpoint", "https://....openai.azure.com/")
.WithEnvironment("KernelMemory__Services__AzureOpenAIEmbedding__Deployment", "text-embedding-ada-002");
builder.Build().Run(); |
Beta Was this translation helpful? Give feedback.
Here's a working example: