diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs index f93ef96f..84f194c4 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs @@ -1,7 +1,6 @@ using BotSharp.Abstraction.Functions.Models; using BotSharp.Abstraction.Messaging; using BotSharp.Abstraction.Messaging.Models.RichContent; -using BotSharp.Abstraction.MLTasks; namespace BotSharp.Abstraction.Conversations.Models; diff --git a/src/Infrastructure/BotSharp.Abstraction/VectorStorage/Helpers/VectorStorageHelper.cs b/src/Infrastructure/BotSharp.Abstraction/VectorStorage/Helpers/VectorStorageHelper.cs new file mode 100644 index 00000000..f1f0ebde --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/VectorStorage/Helpers/VectorStorageHelper.cs @@ -0,0 +1,29 @@ +using BotSharp.Abstraction.Knowledges.Enums; +using BotSharp.Abstraction.VectorStorage.Models; + +namespace BotSharp.Abstraction.VectorStorage.Helpers; + +public static class VectorStorageHelper +{ + public static string ToQuestionAnswer(this VectorSearchResult data) + { + if (data?.Data == null) return string.Empty; + + return $"Question: {data.Data[KnowledgePayloadName.Text]}\r\nAnswer: {data.Data[KnowledgePayloadName.Answer]}"; + } + + public static string ToPayloadPair(this VectorSearchResult data, IList payloads) + { + if (data?.Data == null || payloads.IsNullOrEmpty()) return string.Empty; + + var results = data.Data.Where(x => payloads.Contains(x.Key)) + .OrderBy(x => payloads.IndexOf(x.Key)) + .Select(x => + { + return $"{x.Key}: {x.Value}"; + }) + .ToList(); + + return string.Join("\r\n", results.Where(x => !string.IsNullOrWhiteSpace(x))); + } +} diff --git a/src/Infrastructure/BotSharp.Abstraction/VectorStorage/Models/VectorSearchResult.cs b/src/Infrastructure/BotSharp.Abstraction/VectorStorage/Models/VectorSearchResult.cs index ce39edbf..f2c582ce 100644 --- a/src/Infrastructure/BotSharp.Abstraction/VectorStorage/Models/VectorSearchResult.cs +++ b/src/Infrastructure/BotSharp.Abstraction/VectorStorage/Models/VectorSearchResult.cs @@ -1,3 +1,5 @@ +using BotSharp.Abstraction.Knowledges.Enums; + namespace BotSharp.Abstraction.VectorStorage.Models; public class VectorSearchResult : VectorCollectionData diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Functions/KnowledgeRetrievalFn.cs b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Functions/KnowledgeRetrievalFn.cs index d6d719d7..a9337419 100644 --- a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Functions/KnowledgeRetrievalFn.cs +++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Functions/KnowledgeRetrievalFn.cs @@ -1,9 +1,13 @@ +using BotSharp.Abstraction.VectorStorage.Helpers; + namespace BotSharp.Plugin.KnowledgeBase.Functions; public class KnowledgeRetrievalFn : IFunctionCallback { public string Name => "knowledge_retrieval"; + public string Indication => "searching my brain"; + private readonly IServiceProvider _services; private readonly KnowledgeBaseSettings _settings; @@ -18,15 +22,16 @@ public class KnowledgeRetrievalFn : IFunctionCallback var args = JsonSerializer.Deserialize(message.FunctionArgs ?? "{}"); var collectionName = _settings.Default.CollectionName ?? KnowledgeCollectionName.BotSharp; - var embedding = KnowledgeSettingHelper.GetTextEmbeddingSetting(_services, collectionName); - - var vector = await embedding.GetVectorAsync(args.Question); - var vectorDb = _services.GetServices().FirstOrDefault(x => x.Provider == _settings.VectorDb.Provider); - var knowledges = await vectorDb.Search(collectionName, vector, new List { KnowledgePayloadName.Text, KnowledgePayloadName.Answer }); + var knowledgeService = _services.GetRequiredService(); + var knowledges = await knowledgeService.SearchVectorKnowledge(args.Question, collectionName, new VectorSearchOptions + { + Fields = new List { KnowledgePayloadName.Text, KnowledgePayloadName.Answer }, + Confidence = 0.2f + }); if (!knowledges.IsNullOrEmpty()) { - var answers = knowledges.Select(x => $"Question: {x.Data[KnowledgePayloadName.Text]}\r\nAnswer: {x.Data[KnowledgePayloadName.Answer]}").ToList(); + var answers = knowledges.Select(x => x.ToQuestionAnswer()).ToList(); message.Content = string.Join("\r\n\r\n=====\r\n", answers); } else diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Functions/MemorizeKnowledgeFn.cs b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Functions/MemorizeKnowledgeFn.cs index ca545c65..62388f19 100644 --- a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Functions/MemorizeKnowledgeFn.cs +++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Functions/MemorizeKnowledgeFn.cs @@ -4,6 +4,8 @@ public class MemorizeKnowledgeFn : IFunctionCallback { public string Name => "memorize_knowledge"; + public string Indication => "remembering knowledge"; + private readonly IServiceProvider _services; private readonly KnowledgeBaseSettings _settings; @@ -18,23 +20,16 @@ public class MemorizeKnowledgeFn : IFunctionCallback var args = JsonSerializer.Deserialize(message.FunctionArgs ?? "{}"); var collectionName = _settings.Default.CollectionName ?? KnowledgeCollectionName.BotSharp; - var embedding = KnowledgeSettingHelper.GetTextEmbeddingSetting(_services, collectionName); - - var vector = await embedding.GetVectorsAsync(new List + var knowledgeService = _services.GetRequiredService(); + var result = await knowledgeService.CreateVectorCollectionData(collectionName, new VectorCreateModel { - args.Question + Text = args.Question, + Payload = new Dictionary + { + { KnowledgePayloadName.Answer, args.Answer } + } }); - var vectorDb = _services.GetServices().FirstOrDefault(x => x.Provider == _settings.VectorDb.Provider); - await vectorDb.CreateCollection(collectionName, vector[0].Length); - - var result = await vectorDb.Upsert(collectionName, Guid.NewGuid(), vector[0], - args.Question, - new Dictionary - { - { KnowledgePayloadName.Answer, args.Answer } - }); - message.Content = result ? "Saved to my brain" : "I forgot it"; return true; } diff --git a/src/Plugins/BotSharp.Plugin.Planner/Functions/PrimaryStagePlanFn.cs b/src/Plugins/BotSharp.Plugin.Planner/Functions/PrimaryStagePlanFn.cs index 2842397b..01d2bfdf 100644 --- a/src/Plugins/BotSharp.Plugin.Planner/Functions/PrimaryStagePlanFn.cs +++ b/src/Plugins/BotSharp.Plugin.Planner/Functions/PrimaryStagePlanFn.cs @@ -1,12 +1,4 @@ -using BotSharp.Abstraction.Conversations.Models; -using BotSharp.Abstraction.Functions; -using BotSharp.Abstraction.Templating; -using System.Threading.Tasks; -using BotSharp.Abstraction.Routing; -using BotSharp.Core.Infrastructures; using BotSharp.Plugin.Planner.TwoStaging.Models; -using Microsoft.Extensions.Logging; -using BotSharp.Abstraction.Knowledges.Models; namespace BotSharp.Plugin.Planner.Functions; @@ -27,26 +19,20 @@ public class PrimaryStagePlanFn : IFunctionCallback { // Debug var state = _services.GetRequiredService(); + var knowledgeService = _services.GetRequiredService(); + var knowledgeSettings = _services.GetRequiredService(); + var fn = _services.GetRequiredService(); + state.SetState("max_tokens", "4096"); var task = JsonSerializer.Deserialize(message.FunctionArgs); - // Get knowledge from vectordb - var fn = _services.GetRequiredService(); - - var msg = new ExtractedKnowledge + // Get knowledge from vectordb + var collectionName = knowledgeSettings.Default.CollectionName ?? KnowledgeCollectionName.BotSharp; ; + var knowledges = await knowledgeService.SearchVectorKnowledge(task.Question, collectionName, new VectorSearchOptions { - Question = task.Question, - }; - - var retrievalMessage = new RoleDialogModel(AgentRole.User, task.Requirements) - { - FunctionArgs = JsonSerializer.Serialize(msg), - KnowledgeConfidence = 0.1f, - Content = string.Empty - }; - - await fn.InvokeFunction("knowledge_retrieval", retrievalMessage); - message.Content = retrievalMessage.Content; + Confidence = 0.1f + }); + message.Content = string.Join("\r\n\r\n=====\r\n", knowledges.Select(x => x.ToQuestionAnswer())); var agentService = _services.GetRequiredService(); var currentAgent = await agentService.LoadAgent(message.CurrentAgentId); diff --git a/src/Plugins/BotSharp.Plugin.Planner/Functions/SecondaryStagePlanFn.cs b/src/Plugins/BotSharp.Plugin.Planner/Functions/SecondaryStagePlanFn.cs index 2723d070..211eea53 100644 --- a/src/Plugins/BotSharp.Plugin.Planner/Functions/SecondaryStagePlanFn.cs +++ b/src/Plugins/BotSharp.Plugin.Planner/Functions/SecondaryStagePlanFn.cs @@ -1,12 +1,4 @@ -using BotSharp.Abstraction.Conversations.Models; -using BotSharp.Abstraction.Functions; -using BotSharp.Abstraction.Knowledges.Models; -using BotSharp.Abstraction.Routing; -using BotSharp.Abstraction.Templating; -using BotSharp.Core.Infrastructures; using BotSharp.Plugin.Planner.TwoStaging.Models; -using System.Threading.Tasks; -using Microsoft.Extensions.Logging; namespace BotSharp.Plugin.Planner.Functions; @@ -26,6 +18,9 @@ public class SecondaryStagePlanFn : IFunctionCallback public async Task Execute(RoleDialogModel message) { var fn = _services.GetRequiredService(); + var knowledgeService = _services.GetRequiredService(); + var knowledgeSettings = _services.GetRequiredService(); + var collectionName = knowledgeSettings.Default.CollectionName ?? KnowledgeCollectionName.BotSharp; var msgSecondary = RoleDialogModel.From(message); var taskPrimary = JsonSerializer.Deserialize(message.FunctionArgs); @@ -38,18 +33,15 @@ public class SecondaryStagePlanFn : IFunctionCallback var taskSecondary = JsonSerializer.Deserialize(msgSecondary.FunctionArgs); var items = msgSecondary.Content.JsonArrayContent(); - msgSecondary.KnowledgeConfidence = 0.5f; foreach (var item in items) { - if (item.NeedAdditionalInformation) + if (!item.NeedAdditionalInformation) continue; + + var knowledges = await knowledgeService.SearchVectorKnowledge(item.Task, collectionName, new VectorSearchOptions { - msgSecondary.FunctionArgs = JsonSerializer.Serialize(new ExtractedKnowledge - { - Question = item.Task - }); - await fn.InvokeFunction("knowledge_retrieval", msgSecondary); - message.Content += msgSecondary.Content; - } + Confidence = 0.5f + }); + message.Content += string.Join("\r\n\r\n=====\r\n", knowledges.Select(x => x.ToQuestionAnswer())); } // load agent diff --git a/src/Plugins/BotSharp.Plugin.Planner/Functions/SummaryPlanFn.cs b/src/Plugins/BotSharp.Plugin.Planner/Functions/SummaryPlanFn.cs index 5fd9fe94..0f9da4aa 100644 --- a/src/Plugins/BotSharp.Plugin.Planner/Functions/SummaryPlanFn.cs +++ b/src/Plugins/BotSharp.Plugin.Planner/Functions/SummaryPlanFn.cs @@ -1,10 +1,4 @@ -using BotSharp.Abstraction.Conversations.Models; -using BotSharp.Abstraction.Functions; -using BotSharp.Abstraction.Templating; -using System.Threading.Tasks; -using BotSharp.Core.Infrastructures; using BotSharp.Plugin.Planner.TwoStaging.Models; -using Microsoft.Extensions.Logging; namespace BotSharp.Plugin.Planner.Functions; diff --git a/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/TwoStageTaskPlanner.cs b/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/TwoStageTaskPlanner.cs index be627c75..c6f819e5 100644 --- a/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/TwoStageTaskPlanner.cs +++ b/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/TwoStageTaskPlanner.cs @@ -1,13 +1,6 @@ -using BotSharp.Abstraction.Conversations.Models; -using BotSharp.Abstraction.Knowledges; using BotSharp.Abstraction.MLTasks; -using BotSharp.Abstraction.Routing; using BotSharp.Abstraction.Routing.Planning; -using BotSharp.Abstraction.Templating; -using BotSharp.Core.Infrastructures; using BotSharp.Core.Routing.Planning; -using Microsoft.Extensions.Logging; -using System.Threading.Tasks; namespace BotSharp.Plugin.Planner.TwoStaging; diff --git a/src/Plugins/BotSharp.Plugin.Planner/Using.cs b/src/Plugins/BotSharp.Plugin.Planner/Using.cs index 20880e81..fa59ee23 100644 --- a/src/Plugins/BotSharp.Plugin.Planner/Using.cs +++ b/src/Plugins/BotSharp.Plugin.Planner/Using.cs @@ -3,12 +3,13 @@ global using System.Text.Json; global using System.Text.Json.Serialization; global using System.Collections.Generic; global using System.Linq; +global using System.Threading.Tasks; global using Microsoft.Extensions.Configuration; global using Microsoft.Extensions.DependencyInjection; +global using Microsoft.Extensions.Logging; global using BotSharp.Abstraction.Plugins; -global using BotSharp.Abstraction.Planning; global using BotSharp.Abstraction.Agents; global using BotSharp.Abstraction.Agents.Enums; global using BotSharp.Abstraction.Agents.Models; @@ -18,5 +19,18 @@ global using BotSharp.Abstraction.Functions.Models; global using BotSharp.Abstraction.Repositories; global using BotSharp.Abstraction.Utilities; +global using BotSharp.Abstraction.Conversations.Models; +global using BotSharp.Abstraction.Functions; +global using BotSharp.Abstraction.Routing; +global using BotSharp.Abstraction.Templating; + +global using BotSharp.Abstraction.Knowledges; +global using BotSharp.Abstraction.Knowledges.Settings; +global using BotSharp.Abstraction.Knowledges.Enums; +global using BotSharp.Abstraction.VectorStorage.Models; +global using BotSharp.Abstraction.VectorStorage.Helpers; + global using BotSharp.Plugin.Planner.Hooks; -global using BotSharp.Plugin.Planner.Enums; \ No newline at end of file +global using BotSharp.Plugin.Planner.Enums; + +global using BotSharp.Core.Infrastructures; \ No newline at end of file