From 820adcd067d39f2f73f5efbc21f0b2a1e3b67f2c Mon Sep 17 00:00:00 2001 From: Joanna Ren <101223@smsassist.com> Date: Thu, 22 Aug 2024 10:15:05 -0500 Subject: [PATCH 1/3] update two stage planner --- .../Conversations/Models/RoleDialogModel.cs | 5 +- .../BotSharp.Core/BotSharp.Core.csproj | 8 + .../TwoStagePlanner/FirstStagePlan.cs | 2 +- .../templates/database_knowledge.liquid | 17 ++ .../planner_prompt.two_stage.1st.plan.liquid | 19 ++- .../planner_prompt.two_stage.2nd.plan.liquid | 21 ++- .../planner_prompt.two_stage.summarize.liquid | 34 ++++ .../Controllers/TextEmbeddingController.cs | 2 +- .../Embeddings/EmbeddingInputModel.cs | 3 +- .../Embedding/TextEmbeddingProvider.cs | 2 +- .../Functions/KnowledgeRetrievalFn.cs | 4 +- .../Embedding/TextEmbeddingProvider.cs | 4 +- .../Functions/PrimaryStagePlanFn.cs | 151 ++++++++++++++++-- .../Functions/SecondaryStagePlanFn.cs | 91 ++++++++++- .../TwoStaging/Models/FirstStagePlan.cs | 4 +- .../Models/PrimaryRequirementRequest.cs | 3 + .../TwoStaging/Models/SecondStagePlan.cs | 19 +++ .../functions/plan_primary_stage.json | 6 +- .../functions/plan_secondary_stage.json | 36 ++--- .../Functions/AddDatabaseKnowledge.cs | 116 ++++++++++++++ .../Functions/GetTableDefinitionFn.cs | 53 ++++++ .../functions/get_table_definition.json | 24 +++ 22 files changed, 567 insertions(+), 57 deletions(-) create mode 100644 src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/database_knowledge.liquid create mode 100644 src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.two_stage.summarize.liquid create mode 100644 src/Plugins/BotSharp.Plugin.Planner/TwoStaging/Models/SecondStagePlan.cs create mode 100644 src/Plugins/BotSharp.Plugin.SqlDriver/Functions/AddDatabaseKnowledge.cs create mode 100644 src/Plugins/BotSharp.Plugin.SqlDriver/Functions/GetTableDefinitionFn.cs create mode 100644 src/Plugins/BotSharp.Plugin.SqlDriver/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/get_table_definition.json diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs index d48286a4..3d8a25e9 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs @@ -94,7 +94,7 @@ public class RoleDialogModel : ITrackableMessage [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("generated_images")] public List GeneratedImages { get; set; } = new List(); - + public float KnowledgeConfidence { get; set; } = 0.5f; private RoleDialogModel() { } @@ -134,7 +134,8 @@ public class RoleDialogModel : ITrackableMessage Payload = source.Payload, StopCompletion = source.StopCompletion, Instruction = source.Instruction, - Data = source.Data + Data = source.Data, + KnowledgeConfidence = source.KnowledgeConfidence }; } } diff --git a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj index 73bf035c..5787c463 100644 --- a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj +++ b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj @@ -55,6 +55,8 @@ + + @@ -114,6 +116,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest @@ -135,6 +140,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest diff --git a/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/FirstStagePlan.cs b/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/FirstStagePlan.cs index 76e697a5..1ae18e84 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/FirstStagePlan.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/FirstStagePlan.cs @@ -13,7 +13,7 @@ public class FirstStagePlan [JsonPropertyName("step")] public int Step { get; set; } = -1; - [JsonPropertyName("contain_multiple_steps")] + [JsonPropertyName("need_additional_information")] public bool ContainMultipleSteps { get; set; } = false; [JsonPropertyName("related_tables")] diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/database_knowledge.liquid b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/database_knowledge.liquid new file mode 100644 index 00000000..0332af76 --- /dev/null +++ b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/database_knowledge.liquid @@ -0,0 +1,17 @@ +You are a knowledge generator assistant. Based on the provided mysql table structure, including tablename, fieldname,data type and comments, generate the related knowledge for DBA and BA. When user ask the question, they don't know the table name. +the summarized question/answer should: +1. help user to identify the location of tables to find further information +2. identify the table structure and data relationship based on the task description +3. summarize all the table to table relationship information based on the FOREIGN KEY, and include both table in the answer +Go through all the columns and generate multiple question & answer pairs. +The output should be question/answer pair list in JSON: [{"question":"","answer":""}]. And the new line should be replaced with \r\n. + + + +For example, when you have the table structure related to affiliate invoice. You should record the knowledge regarding how to find the invoice, how to insert the new invoice, how to locate the table if user asks for specific information in the invoice. + +===== +Table Structure: +{{ table_structure }} + + diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.two_stage.1st.plan.liquid b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.two_stage.1st.plan.liquid index 1f521517..0a1f6292 100644 --- a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.two_stage.1st.plan.liquid +++ b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.two_stage.1st.plan.liquid @@ -1,19 +1,30 @@ -You are a Task Planner. you will breakdown user business requirements into small executable sub-tasks. +You are a Task Planner. you will breakdown user business requirements into excutable sub-tasks. Thinking process: -1. Reference to "Task Solutions" if there is relevant solutions; -2. Breakdown task into subtasks. The subtask should contains all needed parameters for subsequent steps. +1. Reference to "Task Knowledge" if there is relevant knowledge; +2. Breakdown task into subtasks. + - The subtask should contains all needed parameters for subsequent steps. + - If limited information provided and there are furture information needed, or miss relationship between steps, set the need_additional_information to true. + - If there is extra knowledge or relationship needed between steps, set the need_additional_information to true for both steps. + - If the solution mentioned "related solutions" is needed, set the need_additional_information to true. + - You should find the relationships between data structure based on the task knowledge strictly. If lack of information, set the need_additional_information to true. 3. Input argument must reference to corresponding variable name that retrieved by previous steps, variable name must start with '@'; 4. Output all the subtasks as much detail as possible in JSON: [{{ response_format }}] +5. Don't organize and format the extracted data with any other language rather than sql + +Note:If the task includes repeat steps,e.g.same steps for multiple elements, only generate a single detailed solution without repeating steps for each elements. You can add multiple items in the input and output args. + {% if relevant_knowledges != empty -%} ===== -Task Solutions: +Task Knowledge: {% for k in relevant_knowledges %} {{ k }} {% endfor %} {%- endif %} ===== + Task description: {{ task_description }} + diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.two_stage.2nd.plan.liquid b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.two_stage.2nd.plan.liquid index a87b479f..ccec8033 100644 --- a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.two_stage.2nd.plan.liquid +++ b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.two_stage.2nd.plan.liquid @@ -1,6 +1,17 @@ -Reference to "Task Solutions". Breakdown task into multiple steps. -The step should contains all needed parameters. -The parameters can be extracted from the original task. -Output all the steps as much detail as possible in JSON: [{{ response_format }}] +Reference to "Primary Planning" and the additional knowledge included. Breakdown task into multiple steps. +* the step should contains all needed parameters. +* The parameters can be extracted from the original task. +* You need to list all the steps in detail. Finding relationships should also be a step. +* When generate the steps, you should find the relationships between data structure based on the provided knowledge strictly. +* Output all the steps as much detail as possible in JSON: [{{ response_format }}] -TASK: {{ task_description }} \ No newline at end of file + +Additional Requirements: +* "output_results" is variable name that needed to be used in the next step. + +===== +TASK: {{ task_description }} + +===== +Primary Planning: +{{ primary_plan }} \ No newline at end of file diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.two_stage.summarize.liquid b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.two_stage.summarize.liquid new file mode 100644 index 00000000..5bfb2b6c --- /dev/null +++ b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.two_stage.summarize.liquid @@ -0,0 +1,34 @@ +You are a planning summarizer and sql generator. You will convert the requirement into the excutable MySQL query statement based on the task description and related table structure and relationship. + +Try if you can generate a single query to fulfill the needs. The step should contains all needed parameters. +The parameters can be extracted from the original task. +If not, generate the query step by step based on the planning. + +The query must exactly based on the provided table structure. And carefully review the foreign keys to make sure you include all the accurate information. + + +Note: Output should be only the sql query with sql comments that can be directly run in mysql database with version 8.0. + +Don't use the sql statement that specify target table for update in FROM clause. +For example, you CAN'T write query as below: +INSERT INTO data_Service (Id, Name) +VALUES ((SELECT MAX(Id) + 1 FROM data_Service), 'HVAC'); + +If 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. +For example, you should use SET @id = select max(id) from table; + +Additional Requirements: +* the alias of the table name in the sql query should be identical. +*** the generated sql query MUST be basedd on the provided table structure. *** + +===== +Task description: +{{ task_description }} + +===== +Relevant Knowledges: +{{ relevant_knowledges }} + +===== +Table Structure: +{{ table_structure }} \ No newline at end of file diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/TextEmbeddingController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/TextEmbeddingController.cs index ac53d044..73bfbfcb 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/TextEmbeddingController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/TextEmbeddingController.cs @@ -26,7 +26,7 @@ public class TextEmbeddingController : ControllerBase try { - var completion = CompletionProvider.GetTextEmbedding(_services, provider: input.Provider ?? "openai", model: input.Model ?? "text-embedding-3-small"); + var completion = CompletionProvider.GetTextEmbedding(_services, provider: input.Provider ?? "openai", model: input.Model ?? "text-embedding-3-large"); completion.Dimension = input.Dimension; var embeddings = await completion.GetVectorsAsync(input.Texts?.ToList() ?? []); diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Embeddings/EmbeddingInputModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Embeddings/EmbeddingInputModel.cs index 5d8ec97d..b01840f0 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Embeddings/EmbeddingInputModel.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Embeddings/EmbeddingInputModel.cs @@ -8,5 +8,6 @@ public class EmbeddingInputModel : MessageConfig public IEnumerable Texts { get; set; } = new List(); [JsonPropertyName("dimension")] - public int Dimension { get; set; } = 1536; + public int Dimension { get; set; } = 3072; + } diff --git a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/Embedding/TextEmbeddingProvider.cs b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/Embedding/TextEmbeddingProvider.cs index f6a34072..092d62ec 100644 --- a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/Embedding/TextEmbeddingProvider.cs +++ b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/Embedding/TextEmbeddingProvider.cs @@ -8,7 +8,7 @@ public class TextEmbeddingProvider : ITextEmbedding protected readonly IServiceProvider _services; protected readonly ILogger _logger; - private const int DEFAULT_DIMENSION = 1536; + private const int DEFAULT_DIMENSION = 3072; protected string _model; public virtual string Provider => "azure-openai"; diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Functions/KnowledgeRetrievalFn.cs b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Functions/KnowledgeRetrievalFn.cs index 52e45e7e..dcb4650e 100644 --- a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Functions/KnowledgeRetrievalFn.cs +++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Functions/KnowledgeRetrievalFn.cs @@ -23,11 +23,11 @@ public class KnowledgeRetrievalFn : IFunctionCallback var vector = await embedding.GetVectorAsync(args.Question); var vectorDb = _services.GetServices().FirstOrDefault(x => x.Name == _settings.VectorDb); var collectionName = !string.IsNullOrWhiteSpace(_settings.DefaultCollection) ? _settings.DefaultCollection : KnowledgeCollectionName.BotSharp; - var knowledges = await vectorDb.Search(collectionName, vector, new List { KnowledgePayloadName.Answer }); + var knowledges = await vectorDb.Search(collectionName, vector, new List { KnowledgePayloadName.Text, KnowledgePayloadName.Answer }); if (!knowledges.IsNullOrEmpty()) { - var answers = knowledges.Select(x => x.Data[KnowledgePayloadName.Answer]).ToList(); + var answers = knowledges.Select(x => $"Question: {x.Data[KnowledgePayloadName.Text]}\r\nAnswer: {x.Data[KnowledgePayloadName.Answer]}").ToList(); message.Content = string.Join("\r\n\r\n=====\r\n", answers); } else diff --git a/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Embedding/TextEmbeddingProvider.cs b/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Embedding/TextEmbeddingProvider.cs index 578849bf..b86014a4 100644 --- a/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Embedding/TextEmbeddingProvider.cs +++ b/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Embedding/TextEmbeddingProvider.cs @@ -8,8 +8,8 @@ public class TextEmbeddingProvider : ITextEmbedding protected readonly IServiceProvider _services; protected readonly ILogger _logger; - private const int DEFAULT_DIMENSION = 1536; - protected string _model = "text-embedding-3-small"; + private const int DEFAULT_DIMENSION = 3072; + protected string _model = "text-embedding-3-large"; public virtual string Provider => "openai"; diff --git a/src/Plugins/BotSharp.Plugin.Planner/Functions/PrimaryStagePlanFn.cs b/src/Plugins/BotSharp.Plugin.Planner/Functions/PrimaryStagePlanFn.cs index ffb9b33b..fa6db8c4 100644 --- a/src/Plugins/BotSharp.Plugin.Planner/Functions/PrimaryStagePlanFn.cs +++ b/src/Plugins/BotSharp.Plugin.Planner/Functions/PrimaryStagePlanFn.cs @@ -1,8 +1,14 @@ using BotSharp.Abstraction.Conversations.Models; using BotSharp.Abstraction.Functions; using BotSharp.Abstraction.Templating; -using BotSharp.Plugin.Planner.TwoStaging.Models; using System.Threading.Tasks; +using BotSharp.Abstraction.Routing; +using BotSharp.Abstraction.MLTasks; +using BotSharp.Core.Infrastructures; +using BotSharp.Plugin.Planner.TwoStaging.Models; +using BotSharp.Abstraction.Knowledges; +using Microsoft.Extensions.Logging; +using BotSharp.Abstraction.Knowledges.Models; namespace BotSharp.Plugin.Planner.Functions; @@ -10,32 +16,149 @@ public class PrimaryStagePlanFn : IFunctionCallback { public string Name => "plan_primary_stage"; private readonly IServiceProvider _services; + private readonly ILogger _logger; + private object aiAssistant; - public PrimaryStagePlanFn(IServiceProvider services) + public PrimaryStagePlanFn(IServiceProvider services, ILogger logger) { _services = services; + _logger = logger; } public async Task Execute(RoleDialogModel message) { + //debug + var state = _services.GetRequiredService(); + state.SetState("max_tokens", "4096"); var task = JsonSerializer.Deserialize(message.FunctionArgs); + + //get knowledge from vectordb + var fn = _services.GetRequiredService(); - if (!task.HasKnowledgeReference) + var msg = new ExtractedKnowledge { - message.Content = "Search knowledge base for the solution instructions"; - return false; - } + Question = task.Question, + }; + var retrievalMessage = new RoleDialogModel(AgentRole.User, task.Requirements) + { + FunctionArgs = JsonSerializer.Serialize(msg), + KnowledgeConfidence = 0.1f, + Content = "" + }; + await fn.InvokeFunction("knowledge_retrieval", retrievalMessage); + message.Content = retrievalMessage.Content; var agentService = _services.GetRequiredService(); - var aiAssistant = await agentService.GetAgent(BuiltInAgentId.AIAssistant); - var template = aiAssistant.Templates.First(x => x.Name == "planner_prompt.two_stage.1st.plan").Content; - var render = _services.GetRequiredService(); - render.Render(template, new Dictionary + var currentAgent = await agentService.LoadAgent(message.CurrentAgentId); + + //send knowledge to AI to refine and summarize the primary planning + var firstPlanningPrompt = await GetFirstStagePlanPrompt(task, message); + var plannerAgent = new Agent { - { "relevant_knowledges", message.Content } - }); - //message.Content = task.Requirements; - //message.Content += "\r\n\r\n=====\r\nGet the first primary step, plan the secondary steps."; + Id = "", + Name = "planning_1st", + Instruction = firstPlanningPrompt, + TemplateDict = new Dictionary(), + LlmConfig = currentAgent.LlmConfig + }; + var response = await GetAIResponse(plannerAgent); + message.Content = response.Content; + + await fn.InvokeFunction("plan_secondary_stage", message); + var items = message.Content.JsonArrayContent(); + + //get all the related tables + List allTables = new List(); + foreach (var item in items) + { + allTables.AddRange(item.Tables); + } + message.Data = allTables.Distinct().ToList(); + + //get table DDL and stores in content + var msg2 = RoleDialogModel.From(message); + await fn.InvokeFunction("get_table_definition", msg2); + message.SecondaryContent = msg2.Content; + + //summarize and generate query + var summaryPlanningPrompt = await GetPlanSummaryPrompt(task, message); + _logger.LogInformation(summaryPlanningPrompt); + plannerAgent = new Agent + { + Id = "", + Name = "planner_summary", + Instruction = summaryPlanningPrompt, + TemplateDict = new Dictionary(), + LlmConfig = currentAgent.LlmConfig + }; + var response_summary = await GetAIResponse(plannerAgent); + _logger.LogInformation(response_summary.Content); + + message.Content = response_summary.Content; + message.StopCompletion = true; return true; } + private async Task GetFirstStagePlanPrompt(PrimaryRequirementRequest task, RoleDialogModel message) + { + var agentService = _services.GetRequiredService(); + var aiAssistant = await agentService.GetAgent(BuiltInAgentId.AIAssistant); + var render = _services.GetRequiredService(); + var template = aiAssistant.Templates.First(x => x.Name == "planner_prompt.two_stage.1st.plan").Content; + var responseFormat = JsonSerializer.Serialize(new FirstStagePlan + { + Parameters = new JsonDocument[] { JsonDocument.Parse("{}") }, + Results = new string[] { "" } + }); + + return render.Render(template, new Dictionary + { + { "task_description", task.Requirements }, + { "relevant_knowledges", new[]{ message.Content } }, + { "response_format", responseFormat } + }); + } + private async Task GetPlanSummaryPrompt(PrimaryRequirementRequest task, RoleDialogModel message) + { + // save to knowledge base + var agentService = _services.GetRequiredService(); + var aiAssistant = await agentService.GetAgent(BuiltInAgentId.AIAssistant); + var render = _services.GetRequiredService(); + var template = aiAssistant.Templates.First(x => x.Name == "planner_prompt.two_stage.summarize").Content; + var responseFormat = JsonSerializer.Serialize(new FirstStagePlan + { + Parameters = new JsonDocument[] { JsonDocument.Parse("{}") }, + Results = new string[] { "" } + }); + + return render.Render(template, new Dictionary + { + { "table_structure", message.SecondaryContent }, ////check + { "task_description", task.Requirements}, + { "relevant_knowledges", message.Content }, + { "response_format", responseFormat } + }); + } + private async Task GetAIResponse(Agent plannerAgent) + { + 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."; + } + + var completion = CompletionProvider.GetChatCompletion(_services, + provider: plannerAgent.LlmConfig.Provider, + model: plannerAgent.LlmConfig.Model); + + return await completion.GetChatCompletions(plannerAgent, wholeDialogs); + } } diff --git a/src/Plugins/BotSharp.Plugin.Planner/Functions/SecondaryStagePlanFn.cs b/src/Plugins/BotSharp.Plugin.Planner/Functions/SecondaryStagePlanFn.cs index fd3427b3..dd27c9fa 100644 --- a/src/Plugins/BotSharp.Plugin.Planner/Functions/SecondaryStagePlanFn.cs +++ b/src/Plugins/BotSharp.Plugin.Planner/Functions/SecondaryStagePlanFn.cs @@ -1,19 +1,104 @@ +using Azure; using BotSharp.Abstraction.Conversations.Models; using BotSharp.Abstraction.Functions; +using BotSharp.Abstraction.Knowledges.Models; +using BotSharp.Abstraction.MLTasks; +using BotSharp.Abstraction.Routing; +using BotSharp.Abstraction.Templating; +using BotSharp.Core.Infrastructures; using BotSharp.Plugin.Planner.TwoStaging.Models; +using NetTopologySuite.Index.HPRtree; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; namespace BotSharp.Plugin.Planner.Functions; public class SecondaryStagePlanFn : IFunctionCallback { public string Name => "plan_secondary_stage"; + private readonly IServiceProvider _services; + private readonly ILogger _logger; + public SecondaryStagePlanFn(IServiceProvider services, ILogger logger) + { + _services = services; + _logger = logger; + } public async Task Execute(RoleDialogModel message) { - var task = JsonSerializer.Deserialize(message.FunctionArgs); - message.Content = task.SolutionQuestion; - message.Content += $"\r\n\r\n=====\r\nUse tool of `knowledge_retrieval` for expert instructions."; + var fn = _services.GetRequiredService(); + var msg_secondary = RoleDialogModel.From(message); + var task_primary = JsonSerializer.Deserialize(message.FunctionArgs); + msg_secondary.FunctionArgs = JsonSerializer.Serialize(new SecondaryBreakdownTask + { + TaskDescription = task_primary.Requirements + }); + var task_secondary = JsonSerializer.Deserialize(msg_secondary.FunctionArgs); + var items = msg_secondary.Content.JsonArrayContent(); + + msg_secondary.KnowledgeConfidence = 0.5f; + foreach (var item in items) + { + if (item.NeedAdditionalInformation) + { + msg_secondary.FunctionArgs = JsonSerializer.Serialize(new ExtractedKnowledge + { + Question = item.Task + }); + await fn.InvokeFunction("knowledge_retrieval", msg_secondary); + message.Content += msg_secondary.Content; + } + } + // load agent + var agentService = _services.GetRequiredService(); + var currentAgent = await agentService.LoadAgent(message.CurrentAgentId); + + var secondPlanningPrompt = await GetSecondStagePlanPrompt(task_secondary, message); + _logger.LogInformation(secondPlanningPrompt); + + var plannerAgent = new Agent + { + Id = "", + Name = "test", + Instruction = secondPlanningPrompt, + TemplateDict = new Dictionary(), + LlmConfig = currentAgent.LlmConfig + }; + + var response = await GetAIResponse(plannerAgent); + message.Content = response.Content; + _logger.LogInformation(response.Content); return true; } + private async Task GetSecondStagePlanPrompt(SecondaryBreakdownTask task, RoleDialogModel message) + { + var agentService = _services.GetRequiredService(); + var aiAssistant = await agentService.GetAgent(BuiltInAgentId.AIAssistant); + var render = _services.GetRequiredService(); + var template = aiAssistant.Templates.First(x => x.Name == "planner_prompt.two_stage.2nd.plan").Content; + var responseFormat = JsonSerializer.Serialize(new SecondStagePlan + { + Tool = "tool name if task solution provided", + Parameters = new JsonDocument[] { JsonDocument.Parse("{}") }, + Results = new string[] { "" } + }); + + return render.Render(template, new Dictionary + { + { "task_description", task.TaskDescription }, + { "primary_plan", new[]{ message.Content } }, + { "response_format", responseFormat } + }); + } + private async Task GetAIResponse(Agent plannerAgent) + { + var conv = _services.GetRequiredService(); + var wholeDialogs = conv.GetDialogHistory(); + + var completion = CompletionProvider.GetChatCompletion(_services, + provider: plannerAgent.LlmConfig.Provider, + model: plannerAgent.LlmConfig.Model); + + return await completion.GetChatCompletions(plannerAgent, wholeDialogs); + } } diff --git a/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/Models/FirstStagePlan.cs b/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/Models/FirstStagePlan.cs index 34344596..754e5308 100644 --- a/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/Models/FirstStagePlan.cs +++ b/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/Models/FirstStagePlan.cs @@ -11,8 +11,8 @@ public class FirstStagePlan [JsonPropertyName("step")] public int Step { get; set; } = -1; - [JsonPropertyName("contain_multiple_steps")] - public bool ContainMultipleSteps { get; set; } = false; + [JsonPropertyName("need_additional_information")] + public bool NeedAdditionalInformation { get; set; } = false; [JsonPropertyName("related_tables")] public string[] Tables { get; set; } = []; diff --git a/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/Models/PrimaryRequirementRequest.cs b/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/Models/PrimaryRequirementRequest.cs index 40e8bfca..a19cc984 100644 --- a/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/Models/PrimaryRequirementRequest.cs +++ b/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/Models/PrimaryRequirementRequest.cs @@ -7,4 +7,7 @@ public class PrimaryRequirementRequest [JsonPropertyName("has_knowledge_reference")] public bool HasKnowledgeReference { get; set; } + + [JsonPropertyName("question")] + public string Question { get; set; } = null!; } diff --git a/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/Models/SecondStagePlan.cs b/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/Models/SecondStagePlan.cs new file mode 100644 index 00000000..f1292856 --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/Models/SecondStagePlan.cs @@ -0,0 +1,19 @@ +namespace BotSharp.Plugin.Planner.TwoStaging.Models; + +public class SecondStagePlan +{ + [JsonPropertyName("related_tables")] + public string[] Tables { get; set; } = new string[0]; + + [JsonPropertyName("description")] + public string Description { get; set; } = ""; + + [JsonPropertyName("tool_name")] + public string Tool { get; set; } = ""; + + [JsonPropertyName("input_args")] + public JsonDocument[] Parameters { get; set; } = new JsonDocument[0]; + + [JsonPropertyName("output_results")] + public string[] Results { get; set; } = new string[0]; +} diff --git a/src/Plugins/BotSharp.Plugin.Planner/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/plan_primary_stage.json b/src/Plugins/BotSharp.Plugin.Planner/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/plan_primary_stage.json index 64193ac6..b27ee293 100644 --- a/src/Plugins/BotSharp.Plugin.Planner/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/plan_primary_stage.json +++ b/src/Plugins/BotSharp.Plugin.Planner/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/plan_primary_stage.json @@ -11,8 +11,12 @@ "has_knowledge_reference": { "type": "boolean", "description": "If there is knowledge retrieved from memory" + }, + "question": { + "type": "string", + "description": "Question convert from requirement and reference tables for knowledge search. The question should contain all the detailed information in the requirement" } }, - "required": [ "requirement_detail", "has_knowledge_reference" ] + "required": [ "requirement_detail", "has_knowledge_reference", "question" ] } } \ No newline at end of file diff --git a/src/Plugins/BotSharp.Plugin.Planner/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/plan_secondary_stage.json b/src/Plugins/BotSharp.Plugin.Planner/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/plan_secondary_stage.json index 1ce1d407..26fbd3ae 100644 --- a/src/Plugins/BotSharp.Plugin.Planner/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/plan_secondary_stage.json +++ b/src/Plugins/BotSharp.Plugin.Planner/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/plan_secondary_stage.json @@ -1,18 +1,18 @@ -{ - "name": "plan_secondary_stage", - "description": "Based on the main tasks of the first phase, plan the implementation steps of the second phase.", - "parameters": { - "type": "object", - "properties": { - "task_description": { - "type": "string", - "description": "task description from primary steps" - }, - "solution_search_question": { - "type": "string", - "description": "Provide solution query text" - } - }, - "required": [ "task_description", "solution_search_question" ] - } -} \ No newline at end of file +//{ +// "name": "plan_secondary_stage", +// "description": "Based on the main tasks of the first phase, plan the implementation steps of the second phase.", +// "parameters": { +// "type": "object", +// "properties": { +// "task_description": { +// "type": "string", +// "description": "task description from primary steps" +// }, +// "solution_search_question": { +// "type": "string", +// "description": "Provide solution query text" +// } +// }, +// "required": [ "task_description", "solution_search_question" ] +// } +//} \ No newline at end of file diff --git a/src/Plugins/BotSharp.Plugin.SqlDriver/Functions/AddDatabaseKnowledge.cs b/src/Plugins/BotSharp.Plugin.SqlDriver/Functions/AddDatabaseKnowledge.cs new file mode 100644 index 00000000..b6e3b470 --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.SqlDriver/Functions/AddDatabaseKnowledge.cs @@ -0,0 +1,116 @@ +using BotSharp.Abstraction.Routing; +using BotSharp.Core.Infrastructures; +using MySqlConnector; +using static Dapper.SqlMapper; +using BotSharp.Abstraction.Agents.Enums; + + +namespace BotSharp.Plugin.Planner.Functions; +public class AddDatabaseKnowledgeFn : IFunctionCallback +{ + public string Name => "add_database_knowledge"; + private readonly IServiceProvider _services; + private object aiAssistant; + + public AddDatabaseKnowledgeFn(IServiceProvider services) + { + _services = services; + } + public async Task Execute(RoleDialogModel message) + { + var agentService = _services.GetRequiredService(); + var sqlDriver = _services.GetRequiredService(); + var fn = _services.GetRequiredService(); + var settings = _services.GetRequiredService(); + using var connection = new MySqlConnection(settings.MySqlConnectionString); + var dictionary = new Dictionary(); + + List allTables = new List(); + //var sql = $"select table_name from information_schema.tables where table_schema='GSMPMetaData' and (table_name like 'affiliate_%' or table_name like 'client_%' or table_name like 'data_%' or table_name like 'sms_%') limit 10"; + var sql = $"select * from GSMPMetaData.joanna_knowledgebase where id>1057;"; + //var sql = $"select table_name from information_schema.tables where table_schema='GSMPMetaData' and table_name like 'data_%'"; + //var sql = $"select table_name from information_schema.tables where table_schema='GSMPMetaData' and (table_name like 'client_%Reactive%' or table_name like 'data_%' or table_name like 'sms_%');"; + var result = connection.Query(sql: sql,dictionary); + //var result2 = new string[] { "client_ServiceCategory", "client_ServiceCode", "client_ServiceCodeNTE", "client_ServiceType" }; + foreach (var item in result) + { + allTables.Add(item.TABLE_NAME); + } + message.Data = allTables.Distinct().ToList(); + + var currentAgent = await agentService.LoadAgent(message.CurrentAgentId); + var note = ""; + foreach (var item in allTables) + { + message.Data = new List { item }; + + await fn.InvokeFunction("get_table_definition", message); + var PlanningPrompt = await GetPrompt(message); + var plannerAgent = new Agent + { + Id = "", + Name = "database_knowledge", + Instruction = PlanningPrompt, + TemplateDict = new Dictionary(), + LlmConfig = currentAgent.LlmConfig + }; + var response = await GetAIResponse(plannerAgent); + try + { + var knowledge = response.Content.JsonArrayContent(); + foreach (var k in knowledge) + { + try + { + message.FunctionArgs = JsonSerializer.Serialize(new ExtractedKnowledge + { + Question = k.Question, + Answer = k.Answer + }); + await fn.InvokeFunction("memorize_knowledge", message); + message.SecondaryContent += $"Table: {item}, Question:{k.Question}, {message.Content} \r\n"; + } + catch (Exception e) + { + note += $"Error processing table {item}: {e.Message}\r\n{e.InnerException}"; + } + } + } + catch (Exception e) + { + note += $"Error processing table {item}: {e.Message}\r\n{e.InnerException}"; + } + } + //message.Data = allTables.Distinct().ToList(); + return true; + } + private async Task GetAIResponse(Agent plannerAgent) + { + var conv = _services.GetRequiredService(); + var wholeDialogs = conv.GetDialogHistory(); + var completion = CompletionProvider.GetChatCompletion(_services, + provider: plannerAgent.LlmConfig.Provider, + model: plannerAgent.LlmConfig.Model); + //wholeDialogs.Last().Content += "\n\n=========\n\nthe summarized question/answer should:\n1. help user to identify the location of tables to find further information\n2. identify the table structure and data relationship based on the task description\n3. summarize all the table to table relationship information based on the FOREIGN KEY, and include both table in the answer"; + + return await completion.GetChatCompletions(plannerAgent, wholeDialogs); + } + private async Task GetPrompt(RoleDialogModel message) + { + var agentService = _services.GetRequiredService(); + var aiAssistant = await agentService.GetAgent(BuiltInAgentId.AIAssistant); + var render = _services.GetRequiredService(); + var template = aiAssistant.Templates.First(x => x.Name == "database_knowledge").Content; + //var responseFormat = JsonSerializer.Serialize(new JsonDocument[] { JsonDocument.Parse("{}") }); + var responseFormat = JsonSerializer.Serialize(new ExtractedKnowledge + { + Question = "question", + Answer = "answer" + }); + + return render.Render(template, new Dictionary + { + { "table_structure", message.Content } + }); + } +} diff --git a/src/Plugins/BotSharp.Plugin.SqlDriver/Functions/GetTableDefinitionFn.cs b/src/Plugins/BotSharp.Plugin.SqlDriver/Functions/GetTableDefinitionFn.cs new file mode 100644 index 00000000..74ae8f72 --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.SqlDriver/Functions/GetTableDefinitionFn.cs @@ -0,0 +1,53 @@ +using BotSharp.Plugin.SqlDriver.Models; +using Microsoft.EntityFrameworkCore.Metadata.Internal; +using MySqlConnector; +using static Dapper.SqlMapper; + +namespace BotSharp.Plugin.SqlDriver.Functions; + +public class GetTableDefinitionFn : IFunctionCallback +{ + public string Name => "get_table_definition"; + private readonly IServiceProvider _services; + + public GetTableDefinitionFn(IServiceProvider services) + { + _services = services; + } + + public async Task Execute(RoleDialogModel message) + { + // get agent service + var agentService = _services.GetRequiredService(); + + // var args = JsonSerializer.Deserialize(message.FunctionArgs); + var sqlDriver = _services.GetRequiredService(); + + //get table DDL from database + var settings = _services.GetRequiredService(); + using var connection = new MySqlConnection(settings.MySqlConnectionString); + var dictionary = new Dictionary(); + + var table_ddl = ""; + foreach (var p in (List)message.Data) + { + dictionary["@" + "table_name"] = p; + var escapedTableName = MySqlHelper.EscapeString(p); + dictionary["table_name"] = escapedTableName; + // can you replace this with a parameterized query? + var sql = $"select * from information_schema.tables where table_name ='{dictionary["table_name"]}'"; + + var result = connection.QueryFirstOrDefault(sql: sql, dictionary); + if (result != null) + { + sql = $"SHOW CREATE TABLE `{dictionary["table_name"]}`"; + result = connection.QueryFirstOrDefault(sql: sql, dictionary); + table_ddl += "\r\n" + result; + } + + } + message.Content = table_ddl; + + return true; + } +} diff --git a/src/Plugins/BotSharp.Plugin.SqlDriver/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/get_table_definition.json b/src/Plugins/BotSharp.Plugin.SqlDriver/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/get_table_definition.json new file mode 100644 index 00000000..0848099f --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.SqlDriver/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/get_table_definition.json @@ -0,0 +1,24 @@ +{ + "name": "get_table_definition", + "description": "Get the DDL, including data structure, data field and relationship for table", + "parameters": { + "type": "object", + "properties": { + "table": { + "type": "string", + "description": "table need to check" + }, + "return_field": { + "type": "object", + "description": "the name and alias for the return field", + "properties": { + "ddl": { + "type": "string", + "description": "DDL for the table" + } + } + } + }, + "required": [ "table" ] + } +} \ No newline at end of file From 57a54482dcd7c342f3d99230668d0a59d48905b9 Mon Sep 17 00:00:00 2001 From: Bo Yin Date: Thu, 22 Aug 2024 10:56:10 -0500 Subject: [PATCH 2/3] minor changes --- .../Controllers/TwilioVoiceController.cs | 45 ++++++++++++------- .../Models/AssistantMessage.cs | 1 + .../Services/TwilioMessageQueueService.cs | 3 +- 3 files changed, 31 insertions(+), 18 deletions(-) diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioVoiceController.cs b/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioVoiceController.cs index 859e34ff..8863d64e 100644 --- a/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioVoiceController.cs +++ b/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioVoiceController.cs @@ -54,17 +54,24 @@ public class TwilioVoiceController : TwilioController var twilio = _services.GetRequiredService(); var messageQueue = _services.GetRequiredService(); var sessionManager = _services.GetRequiredService(); - var url = $"twilio/voice/{conversationId}/reply/{seqNum}?states={states}"; var messages = await sessionManager.RetrieveStagedCallerMessagesAsync(conversationId, seqNum); if (!string.IsNullOrWhiteSpace(request.SpeechResult)) { messages.Add(request.SpeechResult); + await sessionManager.StageCallerMessageAsync(conversationId, seqNum, request.SpeechResult); } - var messageContent = string.Join("\r\n", messages); VoiceResponse response; - if (!string.IsNullOrWhiteSpace(messageContent)) + if (messages.Count == 0 && seqNum == 0) + { + response = twilio.ReturnInstructions("twilio/welcome.mp3", $"twilio/voice/{conversationId}/receive/{seqNum}?states={states}", true); + } + else { - + if (messages.Count == 0) + { + messages = await sessionManager.RetrieveStagedCallerMessagesAsync(conversationId, seqNum - 1); + } + var messageContent = string.Join("\r\n", messages); var callerMessage = new CallerMessage() { ConversationId = conversationId, @@ -81,12 +88,7 @@ public class TwilioVoiceController : TwilioController } } await messageQueue.EnqueueAsync(callerMessage); - response = twilio.ReturnInstructions(null, url, true, 1); - } - else - { - var speechPath = seqNum > 0 ? $"twilio/voice/speeches/{conversationId}/{seqNum - 1}.mp3" : "twilio/welcome.mp3"; - response = twilio.ReturnInstructions(speechPath, $"twilio/voice/{conversationId}/receive/{seqNum}?states={states}", true); + response = twilio.ReturnInstructions(null, $"twilio/voice/{conversationId}/reply/{seqNum}?states={states}", true, 1); } return TwiML(response); } @@ -108,12 +110,21 @@ public class TwilioVoiceController : TwilioController var indication = await sessionManager.GetReplyIndicationAsync(conversationId, seqNum); if (indication != null) { - var textToSpeechService = CompletionProvider.GetTextToSpeech(_services, "openai", "tts-1"); - var fileService = _services.GetRequiredService(); - var data = await textToSpeechService.GenerateSpeechFromTextAsync(indication); - var fileName = $"indication_{seqNum}.mp3"; - await fileService.SaveSpeechFileAsync(conversationId, fileName, data); - response = twilio.ReturnInstructions($"twilio/voice/speeches/{conversationId}/{fileName}", $"twilio/voice/{conversationId}/reply/{seqNum}?states={states}", true, 2); + string speechPath; + if (indication.StartsWith('#')) + { + speechPath = $"twilio/{indication.Substring(1)}"; + } + else + { + var textToSpeechService = CompletionProvider.GetTextToSpeech(_services, "openai", "tts-1"); + var fileService = _services.GetRequiredService(); + var data = await textToSpeechService.GenerateSpeechFromTextAsync(indication); + var fileName = $"indication_{seqNum}.mp3"; + await fileService.SaveSpeechFileAsync(conversationId, fileName, data); + speechPath = $"twilio/voice/speeches/{conversationId}/{fileName}"; + } + response = twilio.ReturnInstructions(speechPath, $"twilio/voice/{conversationId}/reply/{seqNum}?states={states}", true, 2); } else { @@ -125,7 +136,7 @@ public class TwilioVoiceController : TwilioController var textToSpeechService = CompletionProvider.GetTextToSpeech(_services, "openai", "tts-1"); var fileService = _services.GetRequiredService(); var data = await textToSpeechService.GenerateSpeechFromTextAsync(reply.Content); - var fileName = $"reply_{seqNum}.mp3"; + var fileName = $"reply_{reply.MessageId ?? seqNum.ToString()}.mp3"; await fileService.SaveSpeechFileAsync(conversationId, fileName, data); if (reply.ConversationEnd) { diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Models/AssistantMessage.cs b/src/Plugins/BotSharp.Plugin.Twilio/Models/AssistantMessage.cs index f9a83613..56065847 100644 --- a/src/Plugins/BotSharp.Plugin.Twilio/Models/AssistantMessage.cs +++ b/src/Plugins/BotSharp.Plugin.Twilio/Models/AssistantMessage.cs @@ -4,5 +4,6 @@ namespace BotSharp.Plugin.Twilio.Models { public bool ConversationEnd { get; set; } public string Content { get; set; } + public string MessageId { get; set; } } } diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioMessageQueueService.cs b/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioMessageQueueService.cs index a84ce5d9..92345bde 100644 --- a/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioMessageQueueService.cs +++ b/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioMessageQueueService.cs @@ -80,7 +80,8 @@ namespace BotSharp.Plugin.Twilio.Services reply = new AssistantMessage() { ConversationEnd = msg.Instruction.ConversationEnd, - Content = msg.Content + Content = msg.Content, + MessageId = msg.MessageId }; }, async msg => From 7f3341a583b127dc91f5dc07afdf229419699b8e Mon Sep 17 00:00:00 2001 From: Joanna Ren <101223@smsassist.com> Date: Thu, 22 Aug 2024 11:25:16 -0500 Subject: [PATCH 3/3] update data knowledge generation --- .../Functions/AddDatabaseKnowledge.cs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/Plugins/BotSharp.Plugin.SqlDriver/Functions/AddDatabaseKnowledge.cs b/src/Plugins/BotSharp.Plugin.SqlDriver/Functions/AddDatabaseKnowledge.cs index b6e3b470..5c2bfa45 100644 --- a/src/Plugins/BotSharp.Plugin.SqlDriver/Functions/AddDatabaseKnowledge.cs +++ b/src/Plugins/BotSharp.Plugin.SqlDriver/Functions/AddDatabaseKnowledge.cs @@ -26,12 +26,8 @@ public class AddDatabaseKnowledgeFn : IFunctionCallback var dictionary = new Dictionary(); List allTables = new List(); - //var sql = $"select table_name from information_schema.tables where table_schema='GSMPMetaData' and (table_name like 'affiliate_%' or table_name like 'client_%' or table_name like 'data_%' or table_name like 'sms_%') limit 10"; - var sql = $"select * from GSMPMetaData.joanna_knowledgebase where id>1057;"; - //var sql = $"select table_name from information_schema.tables where table_schema='GSMPMetaData' and table_name like 'data_%'"; - //var sql = $"select table_name from information_schema.tables where table_schema='GSMPMetaData' and (table_name like 'client_%Reactive%' or table_name like 'data_%' or table_name like 'sms_%');"; + var sql = $"select table_name from information_schema.tables;"; var result = connection.Query(sql: sql,dictionary); - //var result2 = new string[] { "client_ServiceCategory", "client_ServiceCode", "client_ServiceCodeNTE", "client_ServiceType" }; foreach (var item in result) { allTables.Add(item.TABLE_NAME); @@ -81,7 +77,6 @@ public class AddDatabaseKnowledgeFn : IFunctionCallback note += $"Error processing table {item}: {e.Message}\r\n{e.InnerException}"; } } - //message.Data = allTables.Distinct().ToList(); return true; } private async Task GetAIResponse(Agent plannerAgent) @@ -91,7 +86,6 @@ public class AddDatabaseKnowledgeFn : IFunctionCallback var completion = CompletionProvider.GetChatCompletion(_services, provider: plannerAgent.LlmConfig.Provider, model: plannerAgent.LlmConfig.Model); - //wholeDialogs.Last().Content += "\n\n=========\n\nthe summarized question/answer should:\n1. help user to identify the location of tables to find further information\n2. identify the table structure and data relationship based on the task description\n3. summarize all the table to table relationship information based on the FOREIGN KEY, and include both table in the answer"; return await completion.GetChatCompletions(plannerAgent, wholeDialogs); } @@ -101,7 +95,6 @@ public class AddDatabaseKnowledgeFn : IFunctionCallback var aiAssistant = await agentService.GetAgent(BuiltInAgentId.AIAssistant); var render = _services.GetRequiredService(); var template = aiAssistant.Templates.First(x => x.Name == "database_knowledge").Content; - //var responseFormat = JsonSerializer.Serialize(new JsonDocument[] { JsonDocument.Parse("{}") }); var responseFormat = JsonSerializer.Serialize(new ExtractedKnowledge { Question = "question",