Merge branch 'SciSharp:master' into master
This commit is contained in:
commit
90932fa2dc
|
|
@ -55,8 +55,6 @@ public class ConversationPlugin : IBotSharpPlugin
|
|||
services.AddScoped<IExecutor, InstructExecutor>();
|
||||
services.AddScoped<IInstructService, InstructService>();
|
||||
services.AddScoped<ITokenStatistics, TokenStatistics>();
|
||||
|
||||
services.AddScoped<IKnowledgeService, KnowledgeService>();
|
||||
}
|
||||
|
||||
public bool AttachMenu(List<PluginMenuDef> menu)
|
||||
|
|
|
|||
|
|
@ -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<IPdf2TextConverter, PigPdf2TextConverter>();
|
||||
services.AddScoped<IAgentUtilityHook, KnowledgeBaseUtilityHook>();
|
||||
services.AddScoped<IAgentHook, KnowledgeBaseAgentHook>();
|
||||
|
||||
services.AddScoped<IKnowledgeService, KnowledgeService>();
|
||||
}
|
||||
|
||||
public bool AttachMenu(List<PluginMenuDef> menu)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,3 @@
|
|||
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 +17,6 @@ public class PrimaryStagePlanFn : IFunctionCallback
|
|||
|
||||
public async Task<bool> Execute(RoleDialogModel message)
|
||||
{
|
||||
// Debug
|
||||
var agentService = _services.GetRequiredService<IAgentService>();
|
||||
var state = _services.GetRequiredService<IConversationStateService>();
|
||||
var knowledgeService = _services.GetRequiredService<IKnowledgeService>();
|
||||
|
|
@ -31,26 +25,23 @@ public class PrimaryStagePlanFn : IFunctionCallback
|
|||
|
||||
state.SetState("max_tokens", "4096");
|
||||
var task = JsonSerializer.Deserialize<PrimaryRequirementRequest>(message.FunctionArgs);
|
||||
var collectionName = knowledgeSettings.Default.CollectionName ?? KnowledgeCollectionName.BotSharp;
|
||||
|
||||
//get knowledge from vectordb
|
||||
// Get knowledge from vectordb
|
||||
var knowledges = new List<string>();
|
||||
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())));
|
||||
}
|
||||
|
||||
// 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 +56,22 @@ public class PrimaryStagePlanFn : IFunctionCallback
|
|||
return true;
|
||||
}
|
||||
|
||||
private async Task<string> GetFirstStagePlanPrompt(PrimaryRequirementRequest task, List<string> relevantKnowledges)
|
||||
private async Task<string> GetFirstStagePlanPrompt(string taskDescription, List<string> relevantKnowledges)
|
||||
{
|
||||
var agentService = _services.GetRequiredService<IAgentService>();
|
||||
var render = _services.GetRequiredService<ITemplateRender>();
|
||||
var knowledgeHooks = _services.GetServices<IKnowledgeHook>();
|
||||
|
||||
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("{}")],
|
||||
Results = [""]
|
||||
Parameters = [ JsonDocument.Parse("{}") ],
|
||||
Results = [ string.Empty ]
|
||||
});
|
||||
|
||||
// Get global knowledges
|
||||
var globalKnowledges = new List<string>();
|
||||
var knowledgeHooks = _services.GetServices<IKnowledgeHook>();
|
||||
foreach (var hook in knowledgeHooks)
|
||||
{
|
||||
var k = await hook.GetGlobalKnowledges();
|
||||
|
|
@ -88,7 +80,7 @@ public class PrimaryStagePlanFn : IFunctionCallback
|
|||
|
||||
return render.Render(template, new Dictionary<string, object>
|
||||
{
|
||||
{ "task_description", task.Requirements },
|
||||
{ "task_description", taskDescription },
|
||||
{ "global_knowledges", globalKnowledges },
|
||||
{ "relevant_knowledges", relevantKnowledges },
|
||||
{ "response_format", responseFormat }
|
||||
|
|
@ -100,19 +92,8 @@ public class PrimaryStagePlanFn : IFunctionCallback
|
|||
var conv = _services.GetRequiredService<IConversationService>();
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -18,12 +18,13 @@ public class SecondaryStagePlanFn : IFunctionCallback
|
|||
public async Task<bool> Execute(RoleDialogModel message)
|
||||
{
|
||||
var fn = _services.GetRequiredService<IRoutingService>();
|
||||
var agentService = _services.GetRequiredService<IAgentService>();
|
||||
var knowledgeService = _services.GetRequiredService<IKnowledgeService>();
|
||||
var knowledgeSettings = _services.GetRequiredService<KnowledgeBaseSettings>();
|
||||
var collectionName = knowledgeSettings.Default.CollectionName ?? KnowledgeCollectionName.BotSharp;
|
||||
|
||||
|
||||
var msgSecondary = RoleDialogModel.From(message);
|
||||
var taskPrimary = JsonSerializer.Deserialize<PrimaryRequirementRequest>(message.FunctionArgs);
|
||||
var collectionName = knowledgeSettings.Default.CollectionName ?? KnowledgeCollectionName.BotSharp;
|
||||
|
||||
msgSecondary.FunctionArgs = JsonSerializer.Serialize(new SecondaryBreakdownTask
|
||||
{
|
||||
|
|
@ -33,6 +34,7 @@ public class SecondaryStagePlanFn : IFunctionCallback
|
|||
var taskSecondary = JsonSerializer.Deserialize<SecondaryBreakdownTask>(msgSecondary.FunctionArgs);
|
||||
var items = msgSecondary.Content.JsonArrayContent<FirstStagePlan>();
|
||||
|
||||
// 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<IAgentService>();
|
||||
// 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<string, object>(),
|
||||
LlmConfig = currentAgent.LlmConfig
|
||||
|
|
@ -65,27 +65,29 @@ public class SecondaryStagePlanFn : IFunctionCallback
|
|||
_logger.LogInformation(response.Content);
|
||||
return true;
|
||||
}
|
||||
private async Task<string> GetSecondStagePlanPrompt(SecondaryBreakdownTask task, RoleDialogModel message)
|
||||
|
||||
private async Task<string> GetSecondStagePlanPrompt(string taskDescription, RoleDialogModel message)
|
||||
{
|
||||
var agentService = _services.GetRequiredService<IAgentService>();
|
||||
var render = _services.GetRequiredService<ITemplateRender>();
|
||||
|
||||
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",
|
||||
Parameters = new JsonDocument[] { JsonDocument.Parse("{}") },
|
||||
Results = new string[] { "" }
|
||||
Parameters = [ JsonDocument.Parse("{}") ],
|
||||
Results = [ string.Empty ]
|
||||
});
|
||||
|
||||
return render.Render(template, new Dictionary<string, object>
|
||||
{
|
||||
{ "task_description", task.TaskDescription },
|
||||
{ "task_description", taskDescription },
|
||||
{ "primary_plan", new[]{ message.Content } },
|
||||
{ "response_format", responseFormat }
|
||||
});
|
||||
}
|
||||
|
||||
private async Task<RoleDialogModel> GetAiResponse(Agent plannerAgent)
|
||||
{
|
||||
var conv = _services.GetRequiredService<IConversationService>();
|
||||
|
|
|
|||
|
|
@ -23,15 +23,12 @@ public class SummaryPlanFn : IFunctionCallback
|
|||
var agentService = _services.GetRequiredService<IAgentService>();
|
||||
var state = _services.GetRequiredService<IConversationStateService>();
|
||||
|
||||
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");
|
||||
|
||||
var task = state.GetState("requirement_detail");
|
||||
|
||||
// Get DDL
|
||||
// Get table names
|
||||
var steps = message.Content.JsonArrayContent<SecondStagePlan>();
|
||||
|
||||
// Get all the related tables
|
||||
var allTables = new List<string>();
|
||||
foreach (var step in steps)
|
||||
{
|
||||
|
|
@ -39,14 +36,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 GetSummaryPlanPrompt(taskRequirement, relevantKnowledge, ddlStatements);
|
||||
_logger.LogInformation($"Summary plan prompt:\r\n{summaryPlanPrompt}");
|
||||
|
||||
var plannerAgent = new Agent
|
||||
|
|
@ -64,14 +62,13 @@ public class SummaryPlanFn : IFunctionCallback
|
|||
return true;
|
||||
}
|
||||
|
||||
private async Task<string> GetPlanSummaryPrompt(string task, string knowledge, string ddlStatement)
|
||||
private async Task<string> GetSummaryPlanPrompt(string taskDescription, string relevantKnowledge, string ddlStatement)
|
||||
{
|
||||
// save to knowledge base
|
||||
var agentService = _services.GetRequiredService<IAgentService>();
|
||||
var render = _services.GetRequiredService<ITemplateRender>();
|
||||
|
||||
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("{}")],
|
||||
|
|
@ -81,8 +78,8 @@ public class SummaryPlanFn : IFunctionCallback
|
|||
return render.Render(template, new Dictionary<string, object>
|
||||
{
|
||||
{ "table_structure", ddlStatement },
|
||||
{ "task_description", task },
|
||||
{ "relevant_knowledges", knowledge },
|
||||
{ "task_description", taskDescription },
|
||||
{ "relevant_knowledges", relevantKnowledge },
|
||||
{ "response_format", responseFormat }
|
||||
});
|
||||
}
|
||||
|
|
@ -91,19 +88,9 @@ public class SummaryPlanFn : IFunctionCallback
|
|||
var conv = _services.GetRequiredService<IConversationService>();
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ public class GetTableDefinitionFn : IFunctionCallback
|
|||
var settings = _services.GetRequiredService<SqlDriverSetting>();
|
||||
|
||||
// Get table DDL from database
|
||||
var tables = message.Data as List<string>;
|
||||
var tables = message.Data as IEnumerable<string>;
|
||||
if (tables.IsNullOrEmpty()) return false;
|
||||
|
||||
var tableDdls = new List<string>();
|
||||
|
|
@ -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}");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue