Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,9 @@ namespace BotSharp.Abstraction.Knowledges;

public interface IKnowledgeHook
{
Task<List<KnowledgeChunk>> CollectChunkedKnowledge();
Task<List<KnowledgeChunk>> CollectChunkedKnowledge()
=> Task.FromResult(new List<KnowledgeChunk>());

Task<List<string>> GetRelevantKnowledges()
=> Task.FromResult(new List<string>());
}
12 changes: 12 additions & 0 deletions src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@
<None Remove="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\planner_prompt.naive.liquid" />
<None Remove="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\planner_prompt.sequential.get_remaining_task.liquid" />
<None Remove="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\planner_prompt.sequential.liquid" />
<None Remove="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\planner_prompt.two_stage.1st.plan.liquid" />
<None Remove="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\planner_prompt.two_stage.2nd.plan.liquid" />
<None Remove="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\planner_prompt.two_stage.2nd.task.liquid" />
<None Remove="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\response_with_function.liquid" />
<None Remove="data\agents\dfd9b46d-d00c-40af-8a75-3fbdc2b89869\agent.json" />
<None Remove="data\agents\dfd9b46d-d00c-40af-8a75-3fbdc2b89869\instruction.liquid" />
Expand All @@ -76,6 +79,15 @@
<Content Include="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\instruction.liquid">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\planner_prompt.two_stage.1st.plan.liquid">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\planner_prompt.two_stage.2nd.plan.liquid">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\planner_prompt.two_stage.2nd.task.liquid">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\planner_prompt.sequential.get_remaining_task.liquid">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System.Text.Json.Serialization;

namespace BotSharp.Core.Routing.Planning;

public class FirstStagePlan
{
[JsonPropertyName("task_detail")]
public string Task { get; set; } = "";

[JsonPropertyName("reason")]
public string Reason { get; set; } = "";

[JsonPropertyName("step")]
public int Step { get; set; } = -1;

[JsonPropertyName("contain_multiple_steps")]
public bool ContainMultipleSteps { get; set; } = false;

[JsonPropertyName("related_tables")]
public string[] Tables { get; set; } = new string[0];

[JsonPropertyName("input_args")]
public JsonDocument[] Parameters { get; set; } = new JsonDocument[0];

[JsonPropertyName("output_results")]
public string[] Results { get; set; } = new string[0];

public override string ToString()
{
return $"STEP {Step}: {Task}";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System.Text.Json.Serialization;

public class FirstStagePlanParameter
{
[JsonPropertyName("input_args")]
public JsonDocument[] Parameters { get; set; } = new JsonDocument[0];

[JsonPropertyName("output_results")]
public string[] Results { get; set; } = new string[0];

public override string ToString()
{
return $"INPUTS:\r\n{JsonSerializer.Serialize(Parameters)}\r\n\r\nOUTPUTS:\r\n{JsonSerializer.Serialize(Results)}";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System.Text.Json.Serialization;

namespace BotSharp.Core.Routing.Planning;

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];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
public class SecondStagePlanParameter : FirstStagePlanParameter
{

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using BotSharp.Abstraction.Agents.Models;
using BotSharp.Abstraction.MLTasks;
using BotSharp.Abstraction.Templating;

namespace BotSharp.Core.Routing.Planning;

public partial class TwoStagePlanner
{
private async Task<FirstStagePlan[]> GetFirstStagePlanAsync(Agent router, string messageId, List<RoleDialogModel> dialogs)
{
var firstStagePlanPrompt = await GetFirstStagePlanPrompt(router);

var plan = new FirstStagePlan[0];

var llmProviderService = _services.GetRequiredService<ILlmProviderService>();
var model = llmProviderService.GetProviderModel("azure-openai", "gpt-4");

// chat completion
var completion = CompletionProvider.GetChatCompletion(_services,
provider: "azure-openai",
model: model.Name);

string text = string.Empty;

try
{
var response = await completion.GetChatCompletions(new Agent
{
Id = router.Id,
Name = nameof(TwoStagePlanner),
Instruction = firstStagePlanPrompt
}, dialogs);

text = response.Content;
plan = response.Content.JsonArrayContent<FirstStagePlan>();
}
catch (Exception ex)
{
_logger.LogError($"{ex.Message}: {text}");
}

return plan;
}

private async Task<string> GetFirstStagePlanPrompt(Agent router)
{
var template = router.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[] { "" }
});

var relevantKnowledges = new List<string>();
var hooks = _services.GetServices<IKnowledgeHook>();
foreach (var hook in hooks)
{
var k = await hook.GetRelevantKnowledges();
relevantKnowledges.AddRange(k);
}

var render = _services.GetRequiredService<ITemplateRender>();
return render.Render(template, new Dictionary<string, object>
{
{ "response_format", responseFormat },
{ "relevant_knowledges", relevantKnowledges.ToArray() }
});
}

private string GetFirstStageNextPrompt(Agent router)
{
var template = router.Templates.First(x => x.Name == "planner_prompt.first_stage.next").Content;
var responseFormat = JsonSerializer.Serialize(new FirstStagePlan
{
});
var render = _services.GetRequiredService<ITemplateRender>();
return render.Render(template, new Dictionary<string, object>
{
{ "response_format", responseFormat },
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace BotSharp.Core.Routing.Planning;

public partial class TwoStagePlanner
{
public string GetContext()
{
var content = "";
foreach (var c in _executionContext)
{
content += $"* {c}\r\n";
}
return content;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using BotSharp.Abstraction.Agents.Models;
using BotSharp.Abstraction.MLTasks;
using BotSharp.Abstraction.Templating;

namespace BotSharp.Core.Routing.Planning;

public partial class TwoStagePlanner
{
private async Task<SecondStagePlan[]> GetSecondStagePlanAsync(Agent router, string messageId, FirstStagePlan plan1st, List<RoleDialogModel> dialogs)
{
var secondStagePrompt = GetSecondStagePlanPrompt(router, plan1st);
var firstStageSystemPrompt = await GetFirstStagePlanPrompt(router);

var plan = new SecondStagePlan[0];

var llmProviderService = _services.GetRequiredService<ILlmProviderService>();
var model = llmProviderService.GetProviderModel("azure-openai", "gpt-4");

// chat completion
var completion = CompletionProvider.GetChatCompletion(_services,
provider: "azure-openai",
model: model.Name);

string text = string.Empty;

var conversations = dialogs.Where(x => x.Role != AgentRole.Function).ToList();
conversations.Add(new RoleDialogModel(AgentRole.User, secondStagePrompt)
{
CurrentAgentId = router.Id,
MessageId = messageId,
});

try
{
var response = await completion.GetChatCompletions(new Agent
{
Id = router.Id,
Name = nameof(TwoStagePlanner),
Instruction = firstStageSystemPrompt
}, conversations);

text = response.Content;
plan = response.Content.JsonArrayContent<SecondStagePlan>();
}
catch (Exception ex)
{
_logger.LogError($"{ex.Message}: {text}");
}

return plan;
}

private string GetSecondStageTaskPrompt(Agent router, SecondStagePlan plan)
{
var template = router.Templates.First(x => x.Name == "planner_prompt.two_stage.2nd.task").Content;
var render = _services.GetRequiredService<ITemplateRender>();
return render.Render(template, new Dictionary<string, object>
{
{ "task_description", plan.Description },
{ "related_tables", plan.Tables },
{ "input_arguments", JsonSerializer.Serialize(plan.Parameters) },
{ "output_results", JsonSerializer.Serialize(plan.Results) },
});
}

private string GetSecondStagePlanPrompt(Agent router, FirstStagePlan plan)
{
var template = router.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[] { "" }
});
var context = GetContext();
var render = _services.GetRequiredService<ITemplateRender>();
return render.Render(template, new Dictionary<string, object>
{
{ "task_description", plan.Task },
{ "response_format", responseFormat }
});
}
}
Loading