Support more data type in Qdrant payload.

This commit is contained in:
Haiping Chen 2024-09-28 20:00:35 -05:00
parent 08d1a40916
commit af484579f5
13 changed files with 76 additions and 22 deletions

View file

@ -12,7 +12,7 @@ public interface IVectorDb
Task<IEnumerable<VectorCollectionData>> GetCollectionData(string collectionName, IEnumerable<Guid> ids, bool withPayload = false, bool withVector = false); Task<IEnumerable<VectorCollectionData>> GetCollectionData(string collectionName, IEnumerable<Guid> ids, bool withPayload = false, bool withVector = false);
Task<bool> CreateCollection(string collectionName, int dimension); Task<bool> CreateCollection(string collectionName, int dimension);
Task<bool> DeleteCollection(string collectionName); Task<bool> DeleteCollection(string collectionName);
Task<bool> Upsert(string collectionName, Guid id, float[] vector, string text, Dictionary<string, string>? payload = null); Task<bool> Upsert(string collectionName, Guid id, float[] vector, string text, Dictionary<string, object>? payload = null);
Task<IEnumerable<VectorCollectionData>> Search(string collectionName, float[] vector, IEnumerable<string>? fields, int limit = 5, float confidence = 0.5f, bool withVector = false); Task<IEnumerable<VectorCollectionData>> Search(string collectionName, float[] vector, IEnumerable<string>? fields, int limit = 5, float confidence = 0.5f, bool withVector = false);
Task<bool> DeleteCollectionData(string collectionName, List<Guid> ids); Task<bool> DeleteCollectionData(string collectionName, List<Guid> ids);
Task<bool> DeleteCollectionAllData(string collectionName); Task<bool> DeleteCollectionAllData(string collectionName);

View file

@ -3,7 +3,7 @@ namespace BotSharp.Abstraction.VectorStorage.Models;
public class VectorCollectionData public class VectorCollectionData
{ {
public string Id { get; set; } public string Id { get; set; }
public Dictionary<string, string> Data { get; set; } = new(); public Dictionary<string, object> Data { get; set; } = new();
public double? Score { get; set; } public double? Score { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]

View file

@ -6,5 +6,5 @@ public class VectorCreateModel
{ {
public string Text { get; set; } public string Text { get; set; }
public string DataSource { get; set; } = VectorDataSource.Api; public string DataSource { get; set; } = VectorDataSource.Api;
public Dictionary<string, string>? Payload { get; set; } public Dictionary<string, object>? Payload { get; set; }
} }

View file

@ -11,5 +11,5 @@ public class VectorKnowledgeCreateRequest
public string DataSource { get; set; } = VectorDataSource.Api; public string DataSource { get; set; } = VectorDataSource.Api;
[JsonPropertyName("payload")] [JsonPropertyName("payload")]
public Dictionary<string, string>? Payload { get; set; } public Dictionary<string, object>? Payload { get; set; }
} }

View file

@ -9,7 +9,7 @@ public class VectorKnowledgeViewModel
public string Id { get; set; } public string Id { get; set; }
[JsonPropertyName("data")] [JsonPropertyName("data")]
public IDictionary<string, string> Data { get; set; } public IDictionary<string, object> Data { get; set; }
[JsonPropertyName("score")] [JsonPropertyName("score")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]

View file

@ -24,7 +24,7 @@ public class MemorizeKnowledgeFn : IFunctionCallback
var result = await knowledgeService.CreateVectorCollectionData(collectionName, new VectorCreateModel var result = await knowledgeService.CreateVectorCollectionData(collectionName, new VectorCreateModel
{ {
Text = args.Question, Text = args.Question,
Payload = new Dictionary<string, string> Payload = new Dictionary<string, object>
{ {
{ KnowledgePayloadName.Answer, args.Answer } { KnowledgePayloadName.Answer, args.Answer }
} }

View file

@ -59,7 +59,7 @@ public class MemoryVectorDb : IVectorDb
.Take(limit) .Take(limit)
.Select(i => new VectorCollectionData .Select(i => new VectorCollectionData
{ {
Data = new Dictionary<string, string> { { "text", _vectors[collectionName][i].Text } }, Data = new Dictionary<string, object> { { "text", _vectors[collectionName][i].Text } },
Score = similarities[i], Score = similarities[i],
Vector = withVector ? _vectors[collectionName][i].Vector : null, Vector = withVector ? _vectors[collectionName][i].Vector : null,
}) })
@ -68,7 +68,7 @@ public class MemoryVectorDb : IVectorDb
return await Task.FromResult(results); return await Task.FromResult(results);
} }
public async Task<bool> Upsert(string collectionName, Guid id, float[] vector, string text, Dictionary<string, string>? payload = null) public async Task<bool> Upsert(string collectionName, Guid id, float[] vector, string text, Dictionary<string, object>? payload = null)
{ {
_vectors[collectionName].Add(new VecRecord _vectors[collectionName].Add(new VecRecord
{ {

View file

@ -398,7 +398,7 @@ public partial class KnowledgeService
var vectorDb = GetVectorDb(); var vectorDb = GetVectorDb();
var textEmbedding = GetTextEmbedding(collectionName); var textEmbedding = GetTextEmbedding(collectionName);
var payload = new Dictionary<string, string> var payload = new Dictionary<string, object>
{ {
{ KnowledgePayloadName.DataSource, vectorDataSource }, { KnowledgePayloadName.DataSource, vectorDataSource },
{ KnowledgePayloadName.FileId, fileId.ToString() }, { KnowledgePayloadName.FileId, fileId.ToString() },

View file

@ -196,7 +196,7 @@ public partial class KnowledgeService
withPayload: true); withPayload: true);
if (!found.IsNullOrEmpty()) if (!found.IsNullOrEmpty())
{ {
if (found.First().Data["text"] == update.Text) if (found.First().Data["text"].ToString() == update.Text)
{ {
// Only update payload // Only update payload
return await db.Upsert(collectionName, guid, found.First().Vector, update.Text, update.Payload); return await db.Upsert(collectionName, guid, found.First().Vector, update.Text, update.Payload);

View file

@ -19,23 +19,23 @@ public class PrimaryStagePlanFn : IFunctionCallback
{ {
var agentService = _services.GetRequiredService<IAgentService>(); var agentService = _services.GetRequiredService<IAgentService>();
var state = _services.GetRequiredService<IConversationStateService>(); var state = _services.GetRequiredService<IConversationStateService>();
var knowledgeService = _services.GetRequiredService<IKnowledgeService>(); // var knowledgeService = _services.GetRequiredService<IKnowledgeService>();
var knowledgeSettings = _services.GetRequiredService<KnowledgeBaseSettings>(); // var knowledgeSettings = _services.GetRequiredService<KnowledgeBaseSettings>();
state.SetState("max_tokens", "4096"); state.SetState("max_tokens", "4096");
var task = JsonSerializer.Deserialize<PrimaryRequirementRequest>(message.FunctionArgs); var task = JsonSerializer.Deserialize<PrimaryRequirementRequest>(message.FunctionArgs);
var collectionName = knowledgeSettings.Default.CollectionName ?? KnowledgeCollectionName.BotSharp; // var collectionName = knowledgeSettings.Default.CollectionName ?? KnowledgeCollectionName.BotSharp;
// Get knowledge from vectordb // Get knowledge from vectordb
var hooks = _services.GetServices<IKnowledgeHook>(); var hooks = _services.GetServices<IKnowledgeHook>();
var knowledges = new List<string>(); var knowledges = new List<string>();
foreach (var question in task.Questions) foreach (var question in task.Questions)
{ {
var list = await knowledgeService.SearchVectorKnowledge(question, collectionName, new VectorSearchOptions /*var list = await knowledgeService.SearchVectorKnowledge(question, collectionName, new VectorSearchOptions
{ {
Confidence = 0.4f Confidence = 0.4f
}); });
knowledges.Add(string.Join("\r\n\r\n=====\r\n", list.Select(x => x.ToQuestionAnswer()))); knowledges.Add(string.Join("\r\n\r\n=====\r\n", list.Select(x => x.ToQuestionAnswer())));*/
foreach (var hook in hooks) foreach (var hook in hooks)
{ {
@ -43,6 +43,7 @@ public class PrimaryStagePlanFn : IFunctionCallback
knowledges.AddRange(k); knowledges.AddRange(k);
} }
} }
knowledges = knowledges.Distinct().ToList();
// Get first stage planning prompt // Get first stage planning prompt
var currentAgent = await agentService.LoadAgent(message.CurrentAgentId); var currentAgent = await agentService.LoadAgent(message.CurrentAgentId);

View file

@ -11,7 +11,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Qdrant.Client" Version="1.10.0" /> <PackageReference Include="Qdrant.Client" Version="1.11.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -142,7 +142,13 @@ public class QdrantDb : IVectorDb
var points = response?.Result?.Select(x => new VectorCollectionData var points = response?.Result?.Select(x => new VectorCollectionData
{ {
Id = x.Id?.Uuid ?? string.Empty, Id = x.Id?.Uuid ?? string.Empty,
Data = x.Payload.ToDictionary(x => x.Key, x => x.Value.StringValue), Data = x.Payload.ToDictionary(p => p.Key, p => p.Value.KindCase switch
{
Value.KindOneofCase.StringValue => p.Value.StringValue,
Value.KindOneofCase.BoolValue => p.Value.BoolValue,
Value.KindOneofCase.IntegerValue => p.Value.IntegerValue,
_ => new object()
}),
Vector = filter.WithVector ? x.Vectors?.Vector?.Data?.ToArray() : null Vector = filter.WithVector ? x.Vectors?.Vector?.Data?.ToArray() : null
})?.ToList() ?? new List<VectorCollectionData>(); })?.ToList() ?? new List<VectorCollectionData>();
@ -175,12 +181,18 @@ public class QdrantDb : IVectorDb
return points.Select(x => new VectorCollectionData return points.Select(x => new VectorCollectionData
{ {
Id = x.Id?.Uuid ?? string.Empty, Id = x.Id?.Uuid ?? string.Empty,
Data = x.Payload?.ToDictionary(x => x.Key, x => x.Value.StringValue) ?? new(), Data = x.Payload?.ToDictionary(p => p.Key, p => p.Value.KindCase switch
{
Value.KindOneofCase.StringValue => p.Value.StringValue,
Value.KindOneofCase.BoolValue => p.Value.BoolValue,
Value.KindOneofCase.IntegerValue => p.Value.IntegerValue,
_ => new object()
}) ?? new(),
Vector = x.Vectors?.Vector?.Data?.ToArray() Vector = x.Vectors?.Vector?.Data?.ToArray()
}); });
} }
public async Task<bool> Upsert(string collectionName, Guid id, float[] vector, string text, Dictionary<string, string>? payload = null) public async Task<bool> Upsert(string collectionName, Guid id, float[] vector, string text, Dictionary<string, object>? payload = null)
{ {
// Insert vectors // Insert vectors
var point = new PointStruct() var point = new PointStruct()
@ -200,7 +212,42 @@ public class QdrantDb : IVectorDb
{ {
foreach (var item in payload) foreach (var item in payload)
{ {
point.Payload[item.Key] = item.Value; if (item.Value is string str)
{
point.Payload[item.Key] = str;
}
else if (item.Value is bool b)
{
point.Payload[item.Key] = b;
}
else if (item.Value is byte int8)
{
point.Payload[item.Key] = int8;
}
else if (item.Value is short int16)
{
point.Payload[item.Key] = int16;
}
else if (item.Value is int int32)
{
point.Payload[item.Key] = int32;
}
else if (item.Value is long int64)
{
point.Payload[item.Key] = int64;
}
else if (item.Value is float f32)
{
point.Payload[item.Key] = f32;
}
else if (item.Value is double f64)
{
point.Payload[item.Key] = f64;
}
else if (item.Value is DateTime dt)
{
point.Payload[item.Key] = dt.ToUniversalTime().ToString("o");
}
} }
} }
@ -241,7 +288,13 @@ public class QdrantDb : IVectorDb
results = points.Select(x => new VectorCollectionData results = points.Select(x => new VectorCollectionData
{ {
Id = x.Id.Uuid, Id = x.Id.Uuid,
Data = x.Payload.ToDictionary(x => x.Key, x => x.Value.StringValue), Data = x.Payload.ToDictionary(p => p.Key, p => p.Value.KindCase switch
{
Value.KindOneofCase.StringValue => p.Value.StringValue,
Value.KindOneofCase.BoolValue => p.Value.BoolValue,
Value.KindOneofCase.IntegerValue => p.Value.IntegerValue,
_ => new object()
}),
Score = x.Score, Score = x.Score,
Vector = x.Vectors?.Vector?.Data?.ToArray() Vector = x.Vectors?.Vector?.Data?.ToArray()
}).ToList(); }).ToList();

View file

@ -69,7 +69,7 @@ public class DbKnowledgeService
await knowledgeService.CreateVectorCollectionData(collectionName, new VectorCreateModel await knowledgeService.CreateVectorCollectionData(collectionName, new VectorCreateModel
{ {
Text = item.Question, Text = item.Question,
Payload = new Dictionary<string, string> Payload = new Dictionary<string, object>
{ {
{ KnowledgePayloadName.Answer, item.Answer } { KnowledgePayloadName.Answer, item.Answer }
} }