From 61cd6cc686d7c8aeca0b9baf125e1530d018d7ad Mon Sep 17 00:00:00 2001 From: Jicheng Lu Date: Wed, 4 Sep 2024 19:27:19 -0500 Subject: [PATCH 1/4] minor change --- .../Functions/PrimaryStagePlanFn.cs | 35 ++++++------------- .../Functions/SecondaryStagePlanFn.cs | 20 ++++++----- .../Functions/SummaryPlanFn.cs | 34 ++++++------------ 3 files changed, 32 insertions(+), 57 deletions(-) diff --git a/src/Plugins/BotSharp.Plugin.Planner/Functions/PrimaryStagePlanFn.cs b/src/Plugins/BotSharp.Plugin.Planner/Functions/PrimaryStagePlanFn.cs index d6347641..92d3401f 100644 --- a/src/Plugins/BotSharp.Plugin.Planner/Functions/PrimaryStagePlanFn.cs +++ b/src/Plugins/BotSharp.Plugin.Planner/Functions/PrimaryStagePlanFn.cs @@ -1,8 +1,4 @@ -using BotSharp.Abstraction.Conversations.Models; -using BotSharp.Abstraction.Functions; -using BotSharp.Abstraction.Knowledges; using BotSharp.Abstraction.Knowledges.Models; -using BotSharp.Abstraction.Routing; using BotSharp.Plugin.Planner.TwoStaging.Models; namespace BotSharp.Plugin.Planner.Functions; @@ -22,7 +18,6 @@ public class PrimaryStagePlanFn : IFunctionCallback public async Task Execute(RoleDialogModel message) { - // Debug var agentService = _services.GetRequiredService(); var state = _services.GetRequiredService(); var knowledgeService = _services.GetRequiredService(); @@ -48,9 +43,9 @@ public class PrimaryStagePlanFn : IFunctionCallback knowledges.Add(retrievalMessage.Content); } - // Send knowledge to AI to refine and summarize the primary planning + // Get first stage planning prompt var currentAgent = await agentService.LoadAgent(message.CurrentAgentId); - var firstPlanningPrompt = await GetFirstStagePlanPrompt(task, knowledges); + var firstPlanningPrompt = await GetFirstStagePlanPrompt(task.Requirements, knowledges); var plannerAgent = new Agent { Id = BuiltInAgentId.Planner, @@ -65,21 +60,22 @@ public class PrimaryStagePlanFn : IFunctionCallback return true; } - private async Task GetFirstStagePlanPrompt(PrimaryRequirementRequest task, List relevantKnowledges) + private async Task GetFirstStagePlanPrompt(string taskDescription, List relevantKnowledges) { var agentService = _services.GetRequiredService(); var render = _services.GetRequiredService(); + var knowledgeHooks = _services.GetServices(); var aiAssistant = await agentService.GetAgent(BuiltInAgentId.Planner); var template = aiAssistant.Templates.FirstOrDefault(x => x.Name == "two_stage.1st.plan")?.Content ?? string.Empty; var responseFormat = JsonSerializer.Serialize(new FirstStagePlan { - Parameters = [JsonDocument.Parse("{}")], - Results = [""] + Parameters = [ JsonDocument.Parse("{}") ], + Results = [ string.Empty ] }); + // Get global knowledges var globalKnowledges = new List(); - var knowledgeHooks = _services.GetServices(); foreach (var hook in knowledgeHooks) { var k = await hook.GetGlobalKnowledges(); @@ -88,7 +84,7 @@ public class PrimaryStagePlanFn : IFunctionCallback return render.Render(template, new Dictionary { - { "task_description", task.Requirements }, + { "task_description", taskDescription }, { "global_knowledges", globalKnowledges }, { "relevant_knowledges", relevantKnowledges }, { "response_format", responseFormat } @@ -100,19 +96,8 @@ public class PrimaryStagePlanFn : IFunctionCallback var conv = _services.GetRequiredService(); var wholeDialogs = conv.GetDialogHistory(); - //add "test" to wholeDialogs' last element - if(plannerAgent.Name == "planner_summary") - { - //add "test" to wholeDialogs' last element in a new paragraph - wholeDialogs.Last().Content += "\n\nIf the table structure didn't mention auto incremental, the data field id needs to insert id manually and you need to use max(id) instead of LAST_INSERT_ID function.\nFor example, you should use SET @id = select max(id) from table;"; - wholeDialogs.Last().Content += "\n\nTry if you can generate a single query to fulfill the needs"; - } - - if (plannerAgent.Name == "planning_1st") - { - //add "test" to wholeDialogs' last element in a new paragraph - wholeDialogs.Last().Content += "\n\nYou must analyze the table description to infer the table relations."; - } + // Append text + wholeDialogs.Last().Content += "\n\nYou must analyze the table description to infer the table relations."; var completion = CompletionProvider.GetChatCompletion(_services, provider: plannerAgent.LlmConfig.Provider, diff --git a/src/Plugins/BotSharp.Plugin.Planner/Functions/SecondaryStagePlanFn.cs b/src/Plugins/BotSharp.Plugin.Planner/Functions/SecondaryStagePlanFn.cs index 211eea53..d3bdca68 100644 --- a/src/Plugins/BotSharp.Plugin.Planner/Functions/SecondaryStagePlanFn.cs +++ b/src/Plugins/BotSharp.Plugin.Planner/Functions/SecondaryStagePlanFn.cs @@ -18,6 +18,7 @@ public class SecondaryStagePlanFn : IFunctionCallback public async Task Execute(RoleDialogModel message) { var fn = _services.GetRequiredService(); + var agentService = _services.GetRequiredService(); var knowledgeService = _services.GetRequiredService(); var knowledgeSettings = _services.GetRequiredService(); var collectionName = knowledgeSettings.Default.CollectionName ?? KnowledgeCollectionName.BotSharp; @@ -33,6 +34,7 @@ public class SecondaryStagePlanFn : IFunctionCallback var taskSecondary = JsonSerializer.Deserialize(msgSecondary.FunctionArgs); var items = msgSecondary.Content.JsonArrayContent(); + // Search knowledgebase foreach (var item in items) { if (!item.NeedAdditionalInformation) continue; @@ -44,17 +46,15 @@ public class SecondaryStagePlanFn : IFunctionCallback message.Content += string.Join("\r\n\r\n=====\r\n", knowledges.Select(x => x.ToQuestionAnswer())); } - // load agent - var agentService = _services.GetRequiredService(); + // Get second stage planning prompt var currentAgent = await agentService.LoadAgent(message.CurrentAgentId); - - var secondPlanningPrompt = await GetSecondStagePlanPrompt(taskSecondary, message); + var secondPlanningPrompt = await GetSecondStagePlanPrompt(taskSecondary.TaskDescription, message); _logger.LogInformation(secondPlanningPrompt); var plannerAgent = new Agent { Id = string.Empty, - Name = "test", + Name = "planning_2nd", Instruction = secondPlanningPrompt, TemplateDict = new Dictionary(), LlmConfig = currentAgent.LlmConfig @@ -65,7 +65,8 @@ public class SecondaryStagePlanFn : IFunctionCallback _logger.LogInformation(response.Content); return true; } - private async Task GetSecondStagePlanPrompt(SecondaryBreakdownTask task, RoleDialogModel message) + + private async Task GetSecondStagePlanPrompt(string taskDescription, RoleDialogModel message) { var agentService = _services.GetRequiredService(); var render = _services.GetRequiredService(); @@ -75,17 +76,18 @@ public class SecondaryStagePlanFn : IFunctionCallback var responseFormat = JsonSerializer.Serialize(new SecondStagePlan { Tool = "tool name if task solution provided", - Parameters = new JsonDocument[] { JsonDocument.Parse("{}") }, - Results = new string[] { "" } + Parameters = [ JsonDocument.Parse("{}") ], + Results = [ string.Empty ] }); return render.Render(template, new Dictionary { - { "task_description", task.TaskDescription }, + { "task_description", taskDescription }, { "primary_plan", new[]{ message.Content } }, { "response_format", responseFormat } }); } + private async Task GetAiResponse(Agent plannerAgent) { var conv = _services.GetRequiredService(); diff --git a/src/Plugins/BotSharp.Plugin.Planner/Functions/SummaryPlanFn.cs b/src/Plugins/BotSharp.Plugin.Planner/Functions/SummaryPlanFn.cs index dd55ae7e..55e99de9 100644 --- a/src/Plugins/BotSharp.Plugin.Planner/Functions/SummaryPlanFn.cs +++ b/src/Plugins/BotSharp.Plugin.Planner/Functions/SummaryPlanFn.cs @@ -26,12 +26,10 @@ public class SummaryPlanFn : IFunctionCallback var currentAgent = await agentService.LoadAgent(message.CurrentAgentId); state.SetState("max_tokens", "4096"); - var task = state.GetState("requirement_detail"); + var taskRequirement = state.GetState("requirement_detail"); - // Get DDL + // Get table names var steps = message.Content.JsonArrayContent(); - - // Get all the related tables var allTables = new List(); foreach (var step in steps) { @@ -39,14 +37,15 @@ public class SummaryPlanFn : IFunctionCallback } message.Data = allTables.Distinct().ToList(); - // Get table DDL and stores in content + // Get table DDL statements var msgCopy = RoleDialogModel.From(message); await fn.InvokeFunction("get_table_definition", msgCopy); var ddlStatements = msgCopy.Content; + var relevantKnowledge = message.Content; message.Data = null; // Summarize and generate query - var summaryPlanPrompt = await GetPlanSummaryPrompt(task, message.Content, ddlStatements); + var summaryPlanPrompt = await GetPlanSummaryPrompt(taskRequirement, relevantKnowledge, ddlStatements); _logger.LogInformation($"Summary plan prompt:\r\n{summaryPlanPrompt}"); var plannerAgent = new Agent @@ -64,9 +63,8 @@ public class SummaryPlanFn : IFunctionCallback return true; } - private async Task GetPlanSummaryPrompt(string task, string knowledge, string ddlStatement) + private async Task GetPlanSummaryPrompt(string taskDescription, string relevantKnowledge, string ddlStatement) { - // save to knowledge base var agentService = _services.GetRequiredService(); var render = _services.GetRequiredService(); @@ -81,8 +79,8 @@ public class SummaryPlanFn : IFunctionCallback return render.Render(template, new Dictionary { { "table_structure", ddlStatement }, - { "task_description", task }, - { "relevant_knowledges", knowledge }, + { "task_description", taskDescription }, + { "relevant_knowledges", relevantKnowledge }, { "response_format", responseFormat } }); } @@ -91,19 +89,9 @@ public class SummaryPlanFn : IFunctionCallback var conv = _services.GetRequiredService(); var wholeDialogs = conv.GetDialogHistory(); - // Add "test" to wholeDialogs' last element - if (plannerAgent.Name == "planner_summary") - { - // Add "test" to wholeDialogs' last element in a new paragraph - wholeDialogs.Last().Content += "\n\nIf the table structure didn't mention auto incremental, the data field id needs to insert id manually and you need to use max(id) instead of LAST_INSERT_ID function.\nFor example, you should use SET @id = select max(id) from table;"; - wholeDialogs.Last().Content += "\n\nTry if you can generate a single query to fulfill the needs"; - } - - if (plannerAgent.Name == "planning_1st") - { - // Add "test" to wholeDialogs' last element in a new paragraph - wholeDialogs.Last().Content += "\n\nYou must analyze the table description to infer the table relations."; - } + // Append text + wholeDialogs.Last().Content += "\n\nIf the table structure didn't mention auto incremental, the data field id needs to insert id manually and you need to use max(id) instead of LAST_INSERT_ID function.\nFor example, you should use SET @id = select max(id) from table;"; + wholeDialogs.Last().Content += "\n\nTry if you can generate a single query to fulfill the needs"; var completion = CompletionProvider.GetChatCompletion(_services, provider: plannerAgent.LlmConfig.Provider, From 797b8abebab2b1e81f16217942fdcf9ebb19e466 Mon Sep 17 00:00:00 2001 From: Jicheng Lu Date: Wed, 4 Sep 2024 20:11:25 -0500 Subject: [PATCH 2/4] minor change --- .../Functions/PrimaryStagePlanFn.cs | 22 ++++++++----------- .../Functions/SecondaryStagePlanFn.cs | 4 ++-- .../Functions/SummaryPlanFn.cs | 7 +++--- .../Functions/GetTableDefinitionFn.cs | 6 ++--- 4 files changed, 17 insertions(+), 22 deletions(-) diff --git a/src/Plugins/BotSharp.Plugin.Planner/Functions/PrimaryStagePlanFn.cs b/src/Plugins/BotSharp.Plugin.Planner/Functions/PrimaryStagePlanFn.cs index 92d3401f..593e8053 100644 --- a/src/Plugins/BotSharp.Plugin.Planner/Functions/PrimaryStagePlanFn.cs +++ b/src/Plugins/BotSharp.Plugin.Planner/Functions/PrimaryStagePlanFn.cs @@ -1,4 +1,3 @@ -using BotSharp.Abstraction.Knowledges.Models; using BotSharp.Plugin.Planner.TwoStaging.Models; namespace BotSharp.Plugin.Planner.Functions; @@ -26,21 +25,18 @@ public class PrimaryStagePlanFn : IFunctionCallback state.SetState("max_tokens", "4096"); var task = JsonSerializer.Deserialize(message.FunctionArgs); + var collectionName = knowledgeSettings.Default.CollectionName ?? KnowledgeCollectionName.BotSharp; - //get knowledge from vectordb + // Get knowledge from vectordb var knowledges = new List(); foreach (var question in task.Questions) { - var retrievalMessage = new RoleDialogModel(AgentRole.User, question) + var list = await knowledgeService.SearchVectorKnowledge(question, collectionName, new VectorSearchOptions { - FunctionArgs = JsonSerializer.Serialize(new ExtractedKnowledge - { - Question = question - }), - Content = "" - }; - await fn.InvokeFunction("knowledge_retrieval", retrievalMessage); - knowledges.Add(retrievalMessage.Content); + Confidence = 0.2f + }); + + knowledges.Add(string.Join("\r\n\r\n=====\r\n", list.Select(x => x.ToQuestionAnswer()))); } // Get first stage planning prompt @@ -66,8 +62,8 @@ public class PrimaryStagePlanFn : IFunctionCallback var render = _services.GetRequiredService(); var knowledgeHooks = _services.GetServices(); - var aiAssistant = await agentService.GetAgent(BuiltInAgentId.Planner); - var template = aiAssistant.Templates.FirstOrDefault(x => x.Name == "two_stage.1st.plan")?.Content ?? string.Empty; + var agent = await agentService.GetAgent(BuiltInAgentId.Planner); + var template = agent.Templates.FirstOrDefault(x => x.Name == "two_stage.1st.plan")?.Content ?? string.Empty; var responseFormat = JsonSerializer.Serialize(new FirstStagePlan { Parameters = [ JsonDocument.Parse("{}") ], diff --git a/src/Plugins/BotSharp.Plugin.Planner/Functions/SecondaryStagePlanFn.cs b/src/Plugins/BotSharp.Plugin.Planner/Functions/SecondaryStagePlanFn.cs index d3bdca68..cc5aaa9b 100644 --- a/src/Plugins/BotSharp.Plugin.Planner/Functions/SecondaryStagePlanFn.cs +++ b/src/Plugins/BotSharp.Plugin.Planner/Functions/SecondaryStagePlanFn.cs @@ -21,10 +21,10 @@ public class SecondaryStagePlanFn : IFunctionCallback var agentService = _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); + var collectionName = knowledgeSettings.Default.CollectionName ?? KnowledgeCollectionName.BotSharp; msgSecondary.FunctionArgs = JsonSerializer.Serialize(new SecondaryBreakdownTask { diff --git a/src/Plugins/BotSharp.Plugin.Planner/Functions/SummaryPlanFn.cs b/src/Plugins/BotSharp.Plugin.Planner/Functions/SummaryPlanFn.cs index 55e99de9..8320713c 100644 --- a/src/Plugins/BotSharp.Plugin.Planner/Functions/SummaryPlanFn.cs +++ b/src/Plugins/BotSharp.Plugin.Planner/Functions/SummaryPlanFn.cs @@ -23,9 +23,8 @@ public class SummaryPlanFn : IFunctionCallback var agentService = _services.GetRequiredService(); var state = _services.GetRequiredService(); - var currentAgent = await agentService.LoadAgent(message.CurrentAgentId); state.SetState("max_tokens", "4096"); - + var currentAgent = await agentService.LoadAgent(message.CurrentAgentId); var taskRequirement = state.GetState("requirement_detail"); // Get table names @@ -45,7 +44,7 @@ public class SummaryPlanFn : IFunctionCallback message.Data = null; // Summarize and generate query - var summaryPlanPrompt = await GetPlanSummaryPrompt(taskRequirement, relevantKnowledge, ddlStatements); + var summaryPlanPrompt = await GetSummaryPlanPrompt(taskRequirement, relevantKnowledge, ddlStatements); _logger.LogInformation($"Summary plan prompt:\r\n{summaryPlanPrompt}"); var plannerAgent = new Agent @@ -63,7 +62,7 @@ public class SummaryPlanFn : IFunctionCallback return true; } - private async Task GetPlanSummaryPrompt(string taskDescription, string relevantKnowledge, string ddlStatement) + private async Task GetSummaryPlanPrompt(string taskDescription, string relevantKnowledge, string ddlStatement) { var agentService = _services.GetRequiredService(); var render = _services.GetRequiredService(); diff --git a/src/Plugins/BotSharp.Plugin.SqlDriver/Functions/GetTableDefinitionFn.cs b/src/Plugins/BotSharp.Plugin.SqlDriver/Functions/GetTableDefinitionFn.cs index 14314a8f..31c3a31e 100644 --- a/src/Plugins/BotSharp.Plugin.SqlDriver/Functions/GetTableDefinitionFn.cs +++ b/src/Plugins/BotSharp.Plugin.SqlDriver/Functions/GetTableDefinitionFn.cs @@ -25,7 +25,7 @@ public class GetTableDefinitionFn : IFunctionCallback var settings = _services.GetRequiredService(); // Get table DDL from database - var tables = message.Data as List; + var tables = message.Data as IEnumerable; if (tables.IsNullOrEmpty()) return false; var tableDdls = new List(); @@ -36,9 +36,9 @@ public class GetTableDefinitionFn : IFunctionCallback { try { + var sql = $"select * from information_schema.tables where table_name = @tableName"; var escapedTableName = MySqlHelper.EscapeString(table); - var sql = $"select * from information_schema.tables where table_name = @tableName"; var result = connection.QueryFirstOrDefault(sql, new { tableName = escapedTableName @@ -60,7 +60,7 @@ public class GetTableDefinitionFn : IFunctionCallback } catch (Exception ex) { - _logger.LogWarning($"Error when getting ddl statement of table {table}."); + _logger.LogWarning($"Error when getting ddl statement of table {table}. {ex.Message}\r\n{ex.InnerException}"); } } From bb49b39e82562f21866c46cd320b762c5738bf95 Mon Sep 17 00:00:00 2001 From: Jicheng Lu Date: Wed, 4 Sep 2024 20:12:55 -0500 Subject: [PATCH 3/4] minor change --- .../BotSharp.Plugin.Planner/Functions/SecondaryStagePlanFn.cs | 4 ++-- .../BotSharp.Plugin.Planner/Functions/SummaryPlanFn.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Plugins/BotSharp.Plugin.Planner/Functions/SecondaryStagePlanFn.cs b/src/Plugins/BotSharp.Plugin.Planner/Functions/SecondaryStagePlanFn.cs index cc5aaa9b..9ff3a002 100644 --- a/src/Plugins/BotSharp.Plugin.Planner/Functions/SecondaryStagePlanFn.cs +++ b/src/Plugins/BotSharp.Plugin.Planner/Functions/SecondaryStagePlanFn.cs @@ -71,8 +71,8 @@ public class SecondaryStagePlanFn : IFunctionCallback var agentService = _services.GetRequiredService(); var render = _services.GetRequiredService(); - var planner = await agentService.GetAgent(message.CurrentAgentId); - var template = planner.Templates.FirstOrDefault(x => x.Name == "two_stage.2nd.plan")?.Content ?? string.Empty; + var agent = await agentService.GetAgent(message.CurrentAgentId); + var template = agent.Templates.FirstOrDefault(x => x.Name == "two_stage.2nd.plan")?.Content ?? string.Empty; var responseFormat = JsonSerializer.Serialize(new SecondStagePlan { Tool = "tool name if task solution provided", diff --git a/src/Plugins/BotSharp.Plugin.Planner/Functions/SummaryPlanFn.cs b/src/Plugins/BotSharp.Plugin.Planner/Functions/SummaryPlanFn.cs index 8320713c..bba623b9 100644 --- a/src/Plugins/BotSharp.Plugin.Planner/Functions/SummaryPlanFn.cs +++ b/src/Plugins/BotSharp.Plugin.Planner/Functions/SummaryPlanFn.cs @@ -67,8 +67,8 @@ public class SummaryPlanFn : IFunctionCallback var agentService = _services.GetRequiredService(); var render = _services.GetRequiredService(); - var aiAssistant = await agentService.GetAgent(BuiltInAgentId.Planner); - var template = aiAssistant.Templates.FirstOrDefault(x => x.Name == "two_stage.summarize")?.Content ?? string.Empty; + var agent = await agentService.GetAgent(BuiltInAgentId.Planner); + var template = agent.Templates.FirstOrDefault(x => x.Name == "two_stage.summarize")?.Content ?? string.Empty; var responseFormat = JsonSerializer.Serialize(new FirstStagePlan { Parameters = [JsonDocument.Parse("{}")], From afdd9d74832b3a2bfb861d28f762e2939884002f Mon Sep 17 00:00:00 2001 From: Haiping Chen Date: Thu, 5 Sep 2024 06:39:26 -0500 Subject: [PATCH 4/4] Move KnowledgeService register to KnowledgebasePlugin --- .../BotSharp.Core/Conversations/ConversationPlugin.cs | 2 -- .../BotSharp.Plugin.KnowledgeBase/KnowledgeBasePlugin.cs | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Infrastructure/BotSharp.Core/Conversations/ConversationPlugin.cs b/src/Infrastructure/BotSharp.Core/Conversations/ConversationPlugin.cs index 05653d9c..70c91d9f 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/ConversationPlugin.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/ConversationPlugin.cs @@ -55,8 +55,6 @@ public class ConversationPlugin : IBotSharpPlugin services.AddScoped(); services.AddScoped(); services.AddScoped(); - - services.AddScoped(); } public bool AttachMenu(List menu) diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/KnowledgeBasePlugin.cs b/src/Plugins/BotSharp.Plugin.KnowledgeBase/KnowledgeBasePlugin.cs index ffe4d8f1..0e7bcc63 100644 --- a/src/Plugins/BotSharp.Plugin.KnowledgeBase/KnowledgeBasePlugin.cs +++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/KnowledgeBasePlugin.cs @@ -1,5 +1,6 @@ using BotSharp.Abstraction.Plugins.Models; using BotSharp.Abstraction.Settings; +using BotSharp.Core.Knowledges.Services; using BotSharp.Plugin.KnowledgeBase.Converters; using BotSharp.Plugin.KnowledgeBase.Hooks; using Microsoft.Extensions.Configuration; @@ -24,6 +25,8 @@ public class KnowledgeBasePlugin : IBotSharpPlugin services.AddSingleton(); services.AddScoped(); services.AddScoped(); + + services.AddScoped(); } public bool AttachMenu(List menu)