NaivePlanner
This commit is contained in:
parent
58051e2db0
commit
513ad5814e
|
|
@ -16,6 +16,10 @@ public interface IAgentService
|
|||
/// <returns></returns>
|
||||
Task<Agent> LoadAgent(string id);
|
||||
|
||||
string RenderedInstruction(Agent agent);
|
||||
|
||||
string RenderedTemplate(Agent agent, string templateName);
|
||||
|
||||
/// <summary>
|
||||
/// Get agent detail without trigger any hook.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -65,6 +65,12 @@ public class Agent
|
|||
public List<RoutingRule> RoutingRules { get; set; }
|
||||
= new List<RoutingRule>();
|
||||
|
||||
/// <summary>
|
||||
/// For rendering deferral
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public Dictionary<string, object> TemplateDict { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
=> $"{Name} {Id}";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
using BotSharp.Abstraction.Models;
|
||||
|
||||
namespace BotSharp.Abstraction.Functions.Models;
|
||||
|
||||
public class ParameterPropertyDef : NameDesc
|
||||
|
|
@ -10,6 +8,9 @@ public class ParameterPropertyDef : NameDesc
|
|||
Type = type;
|
||||
}
|
||||
|
||||
[JsonPropertyName("required")]
|
||||
public bool Required { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// string, number, object
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -4,5 +4,5 @@ namespace BotSharp.Abstraction.Instructs;
|
|||
|
||||
public interface IInstructService
|
||||
{
|
||||
Task<InstructResult> Execute(Agent agent, RoleDialogModel message);
|
||||
Task<InstructResult> Execute(string agentId, RoleDialogModel message, string? templateName = null);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
using BotSharp.Abstraction.Functions.Models;
|
||||
using BotSharp.Abstraction.Routing;
|
||||
|
||||
namespace BotSharp.Abstraction.Planning;
|
||||
|
||||
public interface IExecutor
|
||||
{
|
||||
Task<bool> Execute(IRoutingService routing,
|
||||
Agent router,
|
||||
FunctionCallFromLlm inst,
|
||||
List<RoleDialogModel> dialogs,
|
||||
RoleDialogModel message);
|
||||
}
|
||||
12
src/Infrastructure/BotSharp.Abstraction/Planning/IPlaner.cs
Normal file
12
src/Infrastructure/BotSharp.Abstraction/Planning/IPlaner.cs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
using BotSharp.Abstraction.Functions.Models;
|
||||
|
||||
namespace BotSharp.Abstraction.Planning;
|
||||
|
||||
/// <summary>
|
||||
/// Task breakdown and execution plan
|
||||
/// </summary>
|
||||
public interface IPlaner
|
||||
{
|
||||
Task<FunctionCallFromLlm> GetNextInstruction(Agent router, string conversation);
|
||||
Task<bool> AgentExecuted(FunctionCallFromLlm inst, RoleDialogModel message);
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
using BotSharp.Abstraction.Functions.Models;
|
||||
using BotSharp.Abstraction.Planning;
|
||||
|
||||
namespace BotSharp.Abstraction.Routing;
|
||||
|
||||
|
|
@ -10,9 +11,9 @@ public interface IRoutingHandler
|
|||
{
|
||||
string Name { get; }
|
||||
string Description { get; }
|
||||
bool IsReasoning => false;
|
||||
List<string> Planers => null;
|
||||
bool Enabled => true;
|
||||
List<NameDesc> Parameters => new List<NameDesc>();
|
||||
List<ParameterPropertyDef> Parameters => new List<ParameterPropertyDef>();
|
||||
|
||||
void SetRouter(Agent router) { }
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
using BotSharp.Abstraction.Functions.Models;
|
||||
|
||||
namespace BotSharp.Abstraction.Routing;
|
||||
|
||||
public interface IRoutingService
|
||||
|
|
@ -7,7 +5,6 @@ public interface IRoutingService
|
|||
List<RoleDialogModel> Dialogs { get; }
|
||||
void ResetRecursiveCounter();
|
||||
void RefreshDialogs();
|
||||
Task<FunctionCallFromLlm> GetNextInstruction();
|
||||
Task<bool> InvokeAgent(string agentId, RoleDialogModel message);
|
||||
Task<bool> InstructLoop(RoleDialogModel message);
|
||||
Task<bool> ExecuteOnce(Agent agent, RoleDialogModel message);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using BotSharp.Abstraction.Models;
|
||||
using BotSharp.Abstraction.Functions.Models;
|
||||
|
||||
namespace BotSharp.Abstraction.Routing.Models;
|
||||
|
||||
|
|
@ -6,7 +6,7 @@ public class RoutingHandlerDef
|
|||
{
|
||||
public string Name { get; set; }
|
||||
public string Description { get; set; }
|
||||
public List<NameDesc> Parameters { get; set; }
|
||||
public List<ParameterPropertyDef> Parameters { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
=> $"{Name}: {Description} ({Parameters.Count} Parameters)";
|
||||
|
|
|
|||
|
|
@ -13,6 +13,6 @@ public class RoutingItem
|
|||
[JsonPropertyName("description")]
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("required_fields")]
|
||||
public List<ParameterPropertyDef> RequiredFields { get; set; } = new List<ParameterPropertyDef>();
|
||||
[JsonPropertyName("fields")]
|
||||
public List<ParameterPropertyDef> Fields { get; set; } = new List<ParameterPropertyDef>();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,9 +7,7 @@ public class RoutingSettings
|
|||
/// </summary>
|
||||
public string RouterId { get; set; } = string.Empty;
|
||||
|
||||
public bool EnableReasoning { get; set; } = false;
|
||||
public bool UseTextCompletion { get; set; } = false;
|
||||
|
||||
public string Planner { get; set; } = string.Empty;
|
||||
public string Provider { get; set; } = string.Empty;
|
||||
|
||||
public string Model { get; set; } = string.Empty;
|
||||
|
|
|
|||
|
|
@ -4,14 +4,16 @@ namespace BotSharp.Core.Agents.Services;
|
|||
|
||||
public partial class AgentService
|
||||
{
|
||||
[MemoryCache(10 * 60, PerInstanceCache = true)]
|
||||
[MemoryCache(10 * 60)]
|
||||
public async Task<List<Agent>> GetAgents(bool? allowRouting = null)
|
||||
{
|
||||
var agents = _db.GetAgents(allowRouting: allowRouting);
|
||||
return await Task.FromResult(agents);
|
||||
}
|
||||
|
||||
[MemoryCache(10 * 60, PerInstanceCache = true)]
|
||||
#if !DEBUG
|
||||
[MemoryCache(10 * 60)]
|
||||
#endif
|
||||
public async Task<Agent> GetAgent(string id)
|
||||
{
|
||||
var profile = _db.GetAgent(id);
|
||||
|
|
|
|||
|
|
@ -27,8 +27,10 @@ public partial class AgentService
|
|||
throw new Exception($"Can't load agent by id: {id}");
|
||||
}
|
||||
|
||||
var templateDict = new Dictionary<string, object>();
|
||||
PopulateState(templateDict);
|
||||
agent.TemplateDict = new Dictionary<string, object>();
|
||||
|
||||
// Populate state into dictionary
|
||||
PopulateState(agent.TemplateDict);
|
||||
|
||||
// After agent is loaded
|
||||
foreach (var hook in hooks)
|
||||
|
|
@ -42,7 +44,7 @@ public partial class AgentService
|
|||
|
||||
if (!string.IsNullOrEmpty(agent.Instruction))
|
||||
{
|
||||
hook.OnInstructionLoaded(agent.Instruction, templateDict);
|
||||
hook.OnInstructionLoaded(agent.Instruction, agent.TemplateDict);
|
||||
}
|
||||
|
||||
if (agent.Functions != null)
|
||||
|
|
@ -58,15 +60,25 @@ public partial class AgentService
|
|||
hook.OnAgentLoaded(agent);
|
||||
}
|
||||
|
||||
// render liquid template
|
||||
var render = _services.GetRequiredService<ITemplateRender>();
|
||||
agent.Instruction = render.Render(agent.Instruction, templateDict);
|
||||
|
||||
_logger.LogInformation($"Loaded agent {agent}.");
|
||||
|
||||
return agent;
|
||||
}
|
||||
|
||||
public string RenderedTemplate(Agent agent, string templateName)
|
||||
{
|
||||
// render liquid template
|
||||
var render = _services.GetRequiredService<ITemplateRender>();
|
||||
var template = agent.Templates.First(x => x.Name == templateName).Content;
|
||||
return render.Render(template, agent.TemplateDict);
|
||||
}
|
||||
|
||||
public string RenderedInstruction(Agent agent)
|
||||
{
|
||||
var render = _services.GetRequiredService<ITemplateRender>();
|
||||
return render.Render(agent.Instruction, agent.TemplateDict);
|
||||
}
|
||||
|
||||
private void PopulateState(Dictionary<string, object> dict)
|
||||
{
|
||||
var conv = _services.GetRequiredService<IConversationService>();
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ using BotSharp.Abstraction.Evaluations;
|
|||
using BotSharp.Core.Evaluatings;
|
||||
using BotSharp.Core.Evaluations;
|
||||
using BotSharp.Abstraction.MLTasks.Settings;
|
||||
using BotSharp.Abstraction.Planning;
|
||||
using BotSharp.Core.Planning;
|
||||
|
||||
namespace BotSharp.Core;
|
||||
|
||||
|
|
@ -68,6 +70,18 @@ public static class BotSharpServiceCollectionExtensions
|
|||
config.Bind("Router", routingSettings);
|
||||
services.AddSingleton((IServiceProvider x) => routingSettings);
|
||||
|
||||
services.AddScoped<NaivePlanner>();
|
||||
services.AddScoped<FeedbackReasoningPlanner>();
|
||||
services.AddScoped<IPlaner>(provider =>
|
||||
{
|
||||
if (routingSettings.Planner == "NaivePlanner")
|
||||
return provider.GetRequiredService<NaivePlanner>();
|
||||
else if (routingSettings.Planner == "FeedbackReasoningPlanner")
|
||||
return provider.GetRequiredService<FeedbackReasoningPlanner>();
|
||||
throw new NotImplementedException();
|
||||
});
|
||||
|
||||
services.AddScoped<IExecutor, InstructExecutor>();
|
||||
services.AddScoped<IRouterInstance, RouterInstance>();
|
||||
services.AddScoped<IRoutingService, RoutingService>();
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ public partial class ConversationService
|
|||
|
||||
var content = $"Received [{agent.Name}] {message.Role}: {message.Content}";
|
||||
#if DEBUG
|
||||
Console.WriteLine(content, Color.OrangeRed);
|
||||
Console.WriteLine(content, Color.GreenYellow);
|
||||
#else
|
||||
_logger.LogInformation(content);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
using BotSharp.Abstraction.Agents.Models;
|
||||
using BotSharp.Abstraction.Instructs;
|
||||
using BotSharp.Abstraction.Instructs.Models;
|
||||
|
||||
namespace BotSharp.Core.Instructs;
|
||||
|
||||
public partial class InstructService : IInstructService
|
||||
|
|
@ -15,13 +14,13 @@ public partial class InstructService : IInstructService
|
|||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<InstructResult> Execute(Agent agent, RoleDialogModel message)
|
||||
public async Task<InstructResult> Execute(string agentId, RoleDialogModel message, string? templateName = null)
|
||||
{
|
||||
// Trigger before completion hooks
|
||||
var hooks = _services.GetServices<IInstructHook>();
|
||||
foreach (var hook in hooks)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != agent.Id)
|
||||
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != agentId)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
@ -39,8 +38,15 @@ public partial class InstructService : IInstructService
|
|||
}
|
||||
}
|
||||
|
||||
// Render prompt
|
||||
var agentService = _services.GetRequiredService<IAgentService>();
|
||||
Agent agent = await agentService.LoadAgent(agentId);
|
||||
var prompt = string.IsNullOrEmpty(templateName) ?
|
||||
agentService.RenderedInstruction(agent) :
|
||||
agentService.RenderedTemplate(agent, templateName);
|
||||
|
||||
var completer = CompletionProvider.GetTextCompletion(_services);
|
||||
var result = await completer.GetCompletion(agent.Instruction);
|
||||
var result = await completer.GetCompletion(prompt);
|
||||
var response = new InstructResult
|
||||
{
|
||||
MessageId = message.MessageId,
|
||||
|
|
@ -49,7 +55,7 @@ public partial class InstructService : IInstructService
|
|||
|
||||
foreach (var hook in hooks)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != agent.Id)
|
||||
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != agentId)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
using BotSharp.Abstraction.Agents.Models;
|
||||
using BotSharp.Abstraction.Functions.Models;
|
||||
using BotSharp.Abstraction.Planning;
|
||||
using BotSharp.Abstraction.Templating;
|
||||
|
||||
namespace BotSharp.Core.Planning;
|
||||
|
||||
public class FeedbackReasoningPlanner : IPlaner
|
||||
{
|
||||
private readonly IServiceProvider _services;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public FeedbackReasoningPlanner(IServiceProvider services, ILogger<FeedbackReasoningPlanner> logger)
|
||||
{
|
||||
_services = services;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<FunctionCallFromLlm> GetNextInstruction(Agent router, string conversation)
|
||||
{
|
||||
var next = GetNextStepPrompt(router);
|
||||
|
||||
RoleDialogModel response = default;
|
||||
var inst = new FunctionCallFromLlm();
|
||||
|
||||
var content = $"{conversation}\r\n###\r\n{next}";
|
||||
|
||||
var completion = CompletionProvider.GetChatCompletion(_services,
|
||||
model: "llm-gpt4");
|
||||
|
||||
int retryCount = 0;
|
||||
while (retryCount < 3)
|
||||
{
|
||||
try
|
||||
{
|
||||
response = completion.GetChatCompletions(router, new List<RoleDialogModel>
|
||||
{
|
||||
new RoleDialogModel(AgentRole.User, content)
|
||||
});
|
||||
|
||||
inst = response.Content.JsonContent<FunctionCallFromLlm>();
|
||||
break;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError($"{ex.Message}: {response.Content}");
|
||||
inst.Function = "response_to_user";
|
||||
inst.Response = ex.Message;
|
||||
inst.AgentName = "Router";
|
||||
}
|
||||
finally
|
||||
{
|
||||
retryCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return inst;
|
||||
}
|
||||
|
||||
public async Task<bool> AgentExecuted(FunctionCallFromLlm inst, RoleDialogModel message)
|
||||
{
|
||||
inst.AgentName = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
private string GetNextStepPrompt(Agent router)
|
||||
{
|
||||
var template = router.Templates.First(x => x.Name == "next_step_prompt").Content;
|
||||
|
||||
var render = _services.GetRequiredService<ITemplateRender>();
|
||||
return render.Render(template, new Dictionary<string, object>
|
||||
{
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
using BotSharp.Abstraction.Agents.Models;
|
||||
using BotSharp.Abstraction.Functions.Models;
|
||||
using BotSharp.Abstraction.Planning;
|
||||
using BotSharp.Abstraction.Routing;
|
||||
|
||||
namespace BotSharp.Core.Planning;
|
||||
|
||||
public class InstructExecutor : IExecutor
|
||||
{
|
||||
private readonly IServiceProvider _services;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public InstructExecutor(IServiceProvider services, ILogger<InstructExecutor> logger)
|
||||
{
|
||||
_services = services;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<bool> Execute(IRoutingService routing,
|
||||
Agent router,
|
||||
FunctionCallFromLlm inst,
|
||||
List<RoleDialogModel> dialogs,
|
||||
RoleDialogModel message)
|
||||
{
|
||||
// Set user content as Planner's question
|
||||
inst.Question = message.Content;
|
||||
message.Instruction = inst;
|
||||
|
||||
var handlers = _services.GetServices<IRoutingHandler>();
|
||||
|
||||
var handler = handlers.FirstOrDefault(x => x.Name == inst.Function);
|
||||
handler.SetRouter(router);
|
||||
handler.SetDialogs(dialogs);
|
||||
|
||||
message.FunctionName = inst.Function;
|
||||
message.Role = AgentRole.Function;
|
||||
message.FunctionArgs = inst.Arguments == null ? "{}" : JsonSerializer.Serialize(inst.Arguments);
|
||||
|
||||
var handled = await handler.Handle(routing, inst, message);
|
||||
|
||||
inst.Response = message.Content;
|
||||
|
||||
return handled;
|
||||
}
|
||||
}
|
||||
76
src/Infrastructure/BotSharp.Core/Planning/NaivePlanner.cs
Normal file
76
src/Infrastructure/BotSharp.Core/Planning/NaivePlanner.cs
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
using BotSharp.Abstraction.Agents.Models;
|
||||
using BotSharp.Abstraction.Functions.Models;
|
||||
using BotSharp.Abstraction.Planning;
|
||||
using BotSharp.Abstraction.Templating;
|
||||
|
||||
namespace BotSharp.Core.Planning;
|
||||
|
||||
public class NaivePlanner : IPlaner
|
||||
{
|
||||
private readonly IServiceProvider _services;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public NaivePlanner(IServiceProvider services, ILogger<NaivePlanner> logger)
|
||||
{
|
||||
_services = services;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<FunctionCallFromLlm> GetNextInstruction(Agent router, string conversation)
|
||||
{
|
||||
var next = GetNextStepPrompt(router);
|
||||
|
||||
RoleDialogModel response = default;
|
||||
var inst = new FunctionCallFromLlm();
|
||||
|
||||
var agentService = _services.GetRequiredService<IAgentService>();
|
||||
var instruction = agentService.RenderedInstruction(router);
|
||||
var content = $"{instruction}\r\n{conversation}\r\n###\r\n{next}";
|
||||
|
||||
// text completion
|
||||
content = content + "\r\nResponse: ";
|
||||
|
||||
var completion = CompletionProvider.GetTextCompletion(_services);
|
||||
|
||||
int retryCount = 0;
|
||||
while (retryCount < 3)
|
||||
{
|
||||
try
|
||||
{
|
||||
var text = await completion.GetCompletion(content);
|
||||
response = new RoleDialogModel(AgentRole.Assistant, text);
|
||||
inst = response.Content.JsonContent<FunctionCallFromLlm>();
|
||||
break;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError($"{ex.Message}: {response.Content}");
|
||||
inst.Function = "response_to_user";
|
||||
inst.Response = ex.Message;
|
||||
inst.AgentName = "Router";
|
||||
}
|
||||
finally
|
||||
{
|
||||
retryCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return inst;
|
||||
}
|
||||
|
||||
public async Task<bool> AgentExecuted(FunctionCallFromLlm inst, RoleDialogModel message)
|
||||
{
|
||||
inst.AgentName = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
private string GetNextStepPrompt(Agent router)
|
||||
{
|
||||
var template = router.Templates.First(x => x.Name == "next_step_prompt").Content;
|
||||
|
||||
var render = _services.GetRequiredService<ITemplateRender>();
|
||||
return render.Render(template, new Dictionary<string, object>
|
||||
{
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -12,14 +12,20 @@ public class ContinueExecuteTaskRoutingHandler : RoutingHandlerBase, IRoutingHan
|
|||
|
||||
public string Description => "Continue to execute user's request without further information retrival.";
|
||||
|
||||
public List<NameDesc> Parameters => new List<NameDesc>
|
||||
public List<ParameterPropertyDef> Parameters => new List<ParameterPropertyDef>
|
||||
{
|
||||
new NameDesc("agent", "the name of the agent"),
|
||||
new NameDesc("args", "required parameters extracted from question"),
|
||||
new NameDesc("reason", "why continue to execute current task")
|
||||
new ParameterPropertyDef("agent", "the name of the agent"),
|
||||
new ParameterPropertyDef("reason", "why continue to execute current task"),
|
||||
new ParameterPropertyDef("args", "required parameters extracted from question")
|
||||
{
|
||||
Type = "object"
|
||||
}
|
||||
};
|
||||
|
||||
public bool IsReasoning => true;
|
||||
public List<string> Planers => new List<string>
|
||||
{
|
||||
"FeedbackReasoningPlanner"
|
||||
};
|
||||
|
||||
public ContinueExecuteTaskRoutingHandler(IServiceProvider services, ILogger<ContinueExecuteTaskRoutingHandler> logger, RoutingSettings settings)
|
||||
: base(services, logger, settings)
|
||||
|
|
|
|||
|
|
@ -11,12 +11,10 @@ public class ConversationEndRoutingHandler : RoutingHandlerBase, IRoutingHandler
|
|||
|
||||
public string Description => "User completed his task and wants to end the conversation.";
|
||||
|
||||
public bool IsReasoning => false;
|
||||
|
||||
public List<NameDesc> Parameters => new List<NameDesc>
|
||||
public List<ParameterPropertyDef> Parameters => new List<ParameterPropertyDef>
|
||||
{
|
||||
new NameDesc("reason", "why end conversation"),
|
||||
new NameDesc("response", "response content to user")
|
||||
new ParameterPropertyDef("reason", "why end conversation"),
|
||||
new ParameterPropertyDef("response", "response content to user")
|
||||
};
|
||||
|
||||
public ConversationEndRoutingHandler(IServiceProvider services, ILogger<ConversationEndRoutingHandler> logger, RoutingSettings settings)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using BotSharp.Abstraction.Functions.Models;
|
||||
using BotSharp.Abstraction.Models;
|
||||
using BotSharp.Abstraction.Routing;
|
||||
using BotSharp.Abstraction.Routing.Settings;
|
||||
|
||||
|
|
@ -11,10 +10,10 @@ public class HumanInterventionNeededHandler : RoutingHandlerBase, IRoutingHandle
|
|||
|
||||
public string Description => "Reach out to human being, customer service or customer representative.";
|
||||
|
||||
public List<NameDesc> Parameters => new List<NameDesc>
|
||||
public List<ParameterPropertyDef> Parameters => new List<ParameterPropertyDef>
|
||||
{
|
||||
new NameDesc("reason", "why need customer service"),
|
||||
new NameDesc("response", "response content to user")
|
||||
new ParameterPropertyDef("reason", "why need customer service"),
|
||||
new ParameterPropertyDef("response", "response content to user")
|
||||
};
|
||||
|
||||
public HumanInterventionNeededHandler(IServiceProvider services, ILogger<HumanInterventionNeededHandler> logger, RoutingSettings settings)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using BotSharp.Abstraction.Functions.Models;
|
||||
using BotSharp.Abstraction.Models;
|
||||
using BotSharp.Abstraction.Routing;
|
||||
using BotSharp.Abstraction.Routing.Settings;
|
||||
|
||||
|
|
@ -11,13 +10,16 @@ public class InterruptTaskExecutionRoutingHandler : RoutingHandlerBase, IRouting
|
|||
|
||||
public string Description => "Can't continue user's request becauase the requirements are not met.";
|
||||
|
||||
public List<NameDesc> Parameters => new List<NameDesc>
|
||||
public List<ParameterPropertyDef> Parameters => new List<ParameterPropertyDef>
|
||||
{
|
||||
new NameDesc("reason", "the reason why the request is interrupted"),
|
||||
new NameDesc("answer", "the content response to user")
|
||||
new ParameterPropertyDef("reason", "the reason why the request is interrupted"),
|
||||
new ParameterPropertyDef("answer", "the content response to user")
|
||||
};
|
||||
|
||||
public bool IsReasoning => true;
|
||||
public List<string> Planers => new List<string>
|
||||
{
|
||||
"FeedbackReasoningPlanner"
|
||||
};
|
||||
|
||||
public InterruptTaskExecutionRoutingHandler(IServiceProvider services, ILogger<InterruptTaskExecutionRoutingHandler> logger, RoutingSettings settings)
|
||||
: base(services, logger, settings)
|
||||
|
|
|
|||
|
|
@ -11,12 +11,10 @@ public class ResponseToUserRoutingHandler : RoutingHandlerBase, IRoutingHandler
|
|||
|
||||
public string Description => "Response according to the context without asking specific agent.";
|
||||
|
||||
public bool IsReasoning => false;
|
||||
|
||||
public List<NameDesc> Parameters => new List<NameDesc>
|
||||
public List<ParameterPropertyDef> Parameters => new List<ParameterPropertyDef>
|
||||
{
|
||||
new NameDesc("reason", "why response to user"),
|
||||
new NameDesc("response", "response content")
|
||||
new ParameterPropertyDef("reason", "why response to user"),
|
||||
new ParameterPropertyDef("response", "response content")
|
||||
};
|
||||
|
||||
public ResponseToUserRoutingHandler(IServiceProvider services, ILogger<ResponseToUserRoutingHandler> logger, RoutingSettings settings)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using BotSharp.Abstraction.Functions.Models;
|
||||
using BotSharp.Abstraction.Models;
|
||||
using BotSharp.Abstraction.Repositories;
|
||||
using BotSharp.Abstraction.Routing;
|
||||
using BotSharp.Abstraction.Routing.Settings;
|
||||
|
|
@ -12,15 +11,21 @@ public class RetrieveDataFromAgentRoutingHandler : RoutingHandlerBase, IRoutingH
|
|||
|
||||
public string Description => "Retrieve data from appropriate agent.";
|
||||
|
||||
public List<NameDesc> Parameters => new List<NameDesc>
|
||||
public List<ParameterPropertyDef> Parameters => new List<ParameterPropertyDef>
|
||||
{
|
||||
new NameDesc("agent", "the name of the agent"),
|
||||
new NameDesc("question", "the question you will ask the agent to get the necessary data"),
|
||||
new NameDesc("reason", "why retrieve data"),
|
||||
new NameDesc("args", "required parameters extracted from question and hand over to the next agent")
|
||||
new ParameterPropertyDef("agent", "the name of the agent"),
|
||||
new ParameterPropertyDef("question", "the question you will ask the agent to get the necessary data"),
|
||||
new ParameterPropertyDef("reason", "why retrieve data"),
|
||||
new ParameterPropertyDef("args", "required parameters extracted from question and hand over to the next agent")
|
||||
{
|
||||
Type = "object"
|
||||
}
|
||||
};
|
||||
|
||||
public bool IsReasoning => true;
|
||||
public List<string> Planers => new List<string>
|
||||
{
|
||||
"FeedbackReasoningPlanner"
|
||||
};
|
||||
|
||||
public RetrieveDataFromAgentRoutingHandler(IServiceProvider services, ILogger<RetrieveDataFromAgentRoutingHandler> logger, RoutingSettings settings)
|
||||
: base(services, logger, settings)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
using BotSharp.Abstraction.Functions;
|
||||
using BotSharp.Abstraction.Functions.Models;
|
||||
using BotSharp.Abstraction.Models;
|
||||
using BotSharp.Abstraction.Routing;
|
||||
using BotSharp.Abstraction.Routing.Models;
|
||||
using BotSharp.Abstraction.Routing.Settings;
|
||||
|
|
@ -13,16 +12,17 @@ public class RouteToAgentRoutingHandler : RoutingHandlerBase, IRoutingHandler
|
|||
|
||||
public string Description => "Route request to appropriate agent.";
|
||||
|
||||
public List<NameDesc> Parameters => new List<NameDesc>
|
||||
public List<ParameterPropertyDef> Parameters => new List<ParameterPropertyDef>
|
||||
{
|
||||
new NameDesc("reason", "why route to agent"),
|
||||
new NameDesc("next_action_agent", "agent for next action based on user latest response"),
|
||||
new NameDesc("user_goal_agent", "agent who can achieve user original goal"),
|
||||
new NameDesc("args", "useful parameters of next action agent")
|
||||
new ParameterPropertyDef("reason", "why route to agent"),
|
||||
new ParameterPropertyDef("next_action_agent", "agent for next action based on user latest response"),
|
||||
new ParameterPropertyDef("user_goal_agent", "agent who can achieve user original goal"),
|
||||
new ParameterPropertyDef("args", "useful parameters of next action agent, format: { }")
|
||||
{
|
||||
Type = "object"
|
||||
}
|
||||
};
|
||||
|
||||
public bool IsReasoning => false;
|
||||
|
||||
public RouteToAgentRoutingHandler(IServiceProvider services, ILogger<RouteToAgentRoutingHandler> logger, RoutingSettings settings)
|
||||
: base(services, logger, settings)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using BotSharp.Abstraction.Functions.Models;
|
||||
using BotSharp.Abstraction.Models;
|
||||
using BotSharp.Abstraction.Routing;
|
||||
using BotSharp.Abstraction.Routing.Settings;
|
||||
|
||||
|
|
@ -11,12 +10,15 @@ public class TaskEndRoutingHandler : RoutingHandlerBase, IRoutingHandler
|
|||
|
||||
public string Description => "Call this function when current task is completed.";
|
||||
|
||||
public List<NameDesc> Parameters => new List<NameDesc>
|
||||
public List<ParameterPropertyDef> Parameters => new List<ParameterPropertyDef>
|
||||
{
|
||||
new NameDesc("abandoned_arguments", "the arguments next task can't reuse")
|
||||
new ParameterPropertyDef("abandoned_arguments", "the arguments next task can't reuse")
|
||||
};
|
||||
|
||||
public bool IsReasoning => true;
|
||||
public List<string> Planers => new List<string>
|
||||
{
|
||||
"FeedbackReasoningPlanner"
|
||||
};
|
||||
|
||||
public TaskEndRoutingHandler(IServiceProvider services, ILogger<TaskEndRoutingHandler> logger, RoutingSettings settings)
|
||||
: base(services, logger, settings)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
using BotSharp.Abstraction.Agents.Models;
|
||||
using BotSharp.Abstraction.Functions.Models;
|
||||
using BotSharp.Abstraction.Models;
|
||||
using BotSharp.Abstraction.Planning;
|
||||
using BotSharp.Abstraction.Repositories;
|
||||
using BotSharp.Abstraction.Routing;
|
||||
using BotSharp.Abstraction.Routing.Models;
|
||||
|
|
@ -36,8 +36,10 @@ public class RouterInstance : IRouterInstance
|
|||
|
||||
public List<RoutingHandlerDef> GetHandlers()
|
||||
{
|
||||
var planer = _services.GetRequiredService<IPlaner>();
|
||||
|
||||
return _services.GetServices<IRoutingHandler>()
|
||||
.Where(x => x.IsReasoning == _settings.EnableReasoning)
|
||||
.Where(x => x.Planers == null || x.Planers.Contains(planer.GetType().Name))
|
||||
.Where(x => !string.IsNullOrEmpty(x.Description))
|
||||
.Select((x, i) => new RoutingHandlerDef
|
||||
{
|
||||
|
|
@ -90,10 +92,11 @@ public class RouterInstance : IRouterInstance
|
|||
AgentId = x.Id,
|
||||
Description = x.Description,
|
||||
Name = x.Name,
|
||||
RequiredFields = x.RoutingRules
|
||||
.Where(x => x.Required)
|
||||
.Select(p => new ParameterPropertyDef(p.Field, p.Description, type: p.Type))
|
||||
.ToList()
|
||||
Fields = x.RoutingRules
|
||||
.Select(p => new ParameterPropertyDef(p.Field, p.Description, type: p.Type)
|
||||
{
|
||||
Required = p.Required
|
||||
}).ToList()
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
using BotSharp.Abstraction.Functions.Models;
|
||||
|
||||
namespace BotSharp.Core.Routing;
|
||||
|
||||
public partial class RoutingService
|
||||
{
|
||||
/// <summary>
|
||||
/// Sometimes LLM hallucinates and fails to set function names correctly.
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
private void FixMalformedResponse(FunctionCallFromLlm args)
|
||||
{
|
||||
var agentService = _services.GetRequiredService<IAgentService>();
|
||||
var agents = agentService.GetAgents(allowRouting: true).Result;
|
||||
var malformed = false;
|
||||
|
||||
// Sometimes it populate malformed Function in Agent name
|
||||
if (!string.IsNullOrEmpty(args.Function) &&
|
||||
args.Function == args.AgentName)
|
||||
{
|
||||
args.Function = "route_to_agent";
|
||||
malformed = true;
|
||||
}
|
||||
|
||||
// Another case of malformed response
|
||||
if (string.IsNullOrEmpty(args.AgentName) &&
|
||||
agents.Select(x => x.Name).Contains(args.Function))
|
||||
{
|
||||
args.AgentName = args.Function;
|
||||
args.Function = "route_to_agent";
|
||||
malformed = true;
|
||||
}
|
||||
|
||||
// It should be Route to agent, but it is used as Response to user.
|
||||
if (!string.IsNullOrEmpty(args.AgentName) &&
|
||||
agents.Select(x => x.Name).Contains(args.AgentName) &&
|
||||
args.Function != "route_to_agent")
|
||||
{
|
||||
args.Function = "route_to_agent";
|
||||
malformed = true;
|
||||
}
|
||||
|
||||
// Function name shouldn't contain dot symbol
|
||||
if (!string.IsNullOrEmpty(args.Function) &&
|
||||
args.Function.Contains('.'))
|
||||
{
|
||||
args.Function = args.Function.Split('.').Last();
|
||||
malformed = true;
|
||||
}
|
||||
|
||||
if (malformed)
|
||||
{
|
||||
_logger.LogWarning($"Captured LLM malformed response");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
namespace BotSharp.Core.Routing;
|
||||
|
||||
public partial class RoutingService
|
||||
{
|
||||
public async Task<string> GetConversationContent(List<RoleDialogModel> dialogs, int maxDialogCount = 50)
|
||||
{
|
||||
var agentService = _services.GetRequiredService<IAgentService>();
|
||||
var conversation = "";
|
||||
|
||||
foreach (var dialog in dialogs.TakeLast(maxDialogCount))
|
||||
{
|
||||
var role = dialog.Role;
|
||||
if (role != AgentRole.User)
|
||||
{
|
||||
var agent = await agentService.GetAgent(dialog.CurrentAgentId);
|
||||
role = agent.Name;
|
||||
}
|
||||
|
||||
conversation += $"{role}: {dialog.Content}\r\n";
|
||||
}
|
||||
|
||||
return conversation;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,187 +0,0 @@
|
|||
using BotSharp.Abstraction.Functions.Models;
|
||||
using BotSharp.Abstraction.Templating;
|
||||
using System.Drawing;
|
||||
using System.Text.RegularExpressions;
|
||||
namespace BotSharp.Core.Routing;
|
||||
|
||||
public partial class RoutingService
|
||||
{
|
||||
public async Task<FunctionCallFromLlm> GetNextInstruction()
|
||||
{
|
||||
var content = GetNextStepPrompt();
|
||||
|
||||
RoleDialogModel response = default;
|
||||
var args = new FunctionCallFromLlm();
|
||||
|
||||
if (_settings.UseTextCompletion)
|
||||
{
|
||||
var completion = CompletionProvider.GetTextCompletion(_services,
|
||||
provider: _settings.Provider,
|
||||
model: _settings.Model);
|
||||
|
||||
content = _routerInstance.Router.Instruction + "\r\n\r\n" + content + "\r\nResponse: ";
|
||||
|
||||
int retryCount = 0;
|
||||
|
||||
while (retryCount < 3)
|
||||
{
|
||||
try
|
||||
{
|
||||
var text = await completion.GetCompletion(content);
|
||||
response = new RoleDialogModel(AgentRole.Assistant, text);
|
||||
|
||||
var pattern = @"\{(?:[^{}]|(?<open>\{)|(?<-open>\}))+(?(open)(?!))\}";
|
||||
response.Content = Regex.Match(response.Content, pattern).Value;
|
||||
args = JsonSerializer.Deserialize<FunctionCallFromLlm>(response.Content);
|
||||
break;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError($"{ex.Message}: {response.Content}");
|
||||
args.Function = "response_to_user";
|
||||
args.Response = ex.Message;
|
||||
args.AgentName = "Router";
|
||||
content += "\r\nPlease response in JSON format.";
|
||||
}
|
||||
finally
|
||||
{
|
||||
retryCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var completion = CompletionProvider.GetChatCompletion(_services,
|
||||
provider: _settings.Provider,
|
||||
model: _settings.Model);
|
||||
|
||||
int retryCount = 0;
|
||||
var agentService = _services.GetRequiredService<IAgentService>();
|
||||
var dialogs = Dialogs;
|
||||
|
||||
while (retryCount < 3)
|
||||
{
|
||||
try
|
||||
{
|
||||
var conversation = "";
|
||||
|
||||
foreach (var dialog in dialogs.TakeLast(50))
|
||||
{
|
||||
var role = dialog.Role;
|
||||
if (role != AgentRole.User)
|
||||
{
|
||||
var agent = await agentService.GetAgent(dialog.CurrentAgentId);
|
||||
role = agent.Name;
|
||||
}
|
||||
|
||||
conversation += $"{role}: {dialog.Content}\r\n";
|
||||
}
|
||||
content = $"{conversation}\r\n###\r\n{content}";
|
||||
|
||||
response = completion.GetChatCompletions(_routerInstance.Router, new List<RoleDialogModel>
|
||||
{
|
||||
new RoleDialogModel(AgentRole.User, content)
|
||||
});
|
||||
|
||||
args = response.Content.JsonContent<FunctionCallFromLlm>();
|
||||
break;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError($"{ex.Message}: {response.Content}");
|
||||
args.Function = "response_to_user";
|
||||
args.Response = ex.Message;
|
||||
args.AgentName = "Router";
|
||||
content += "\r\nPlease response in JSON format.";
|
||||
}
|
||||
finally
|
||||
{
|
||||
retryCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
Console.WriteLine(response.Content, Color.Green);
|
||||
#else
|
||||
_logger.LogInformation(response.Content);
|
||||
#endif
|
||||
|
||||
// Fix LLM malformed response
|
||||
FixMalformedResponse(args);
|
||||
|
||||
SaveStateByArgs(args.Arguments);
|
||||
|
||||
#if DEBUG
|
||||
Console.WriteLine($"*** Next Instruction *** {args}", Color.Green);
|
||||
#else
|
||||
_logger.LogInformation($"*** Next Instruction *** {args}");
|
||||
#endif
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
private string GetNextStepPrompt()
|
||||
{
|
||||
var template = _routerInstance.Router.Templates.First(x => x.Name == "next_step_prompt").Content;
|
||||
|
||||
// If enabled reasoning
|
||||
// JsonSerializer.Serialize(new FunctionCallFromLlm());
|
||||
|
||||
var render = _services.GetRequiredService<ITemplateRender>();
|
||||
return render.Render(template, new Dictionary<string, object>
|
||||
{
|
||||
{ "enabled_reasoning", _settings.EnableReasoning }
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sometimes LLM hallucinates and fails to set function names correctly.
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
private void FixMalformedResponse(FunctionCallFromLlm args)
|
||||
{
|
||||
var agentService = _services.GetRequiredService<IAgentService>();
|
||||
var agents = agentService.GetAgents(allowRouting: true).Result;
|
||||
var malformed = false;
|
||||
|
||||
// Sometimes it populate malformed Function in Agent name
|
||||
if (!string.IsNullOrEmpty(args.Function) &&
|
||||
args.Function == args.AgentName)
|
||||
{
|
||||
args.Function = "route_to_agent";
|
||||
malformed = true;
|
||||
}
|
||||
|
||||
// Another case of malformed response
|
||||
if (string.IsNullOrEmpty(args.AgentName) &&
|
||||
agents.Select(x => x.Name).Contains(args.Function))
|
||||
{
|
||||
args.AgentName = args.Function;
|
||||
args.Function = "route_to_agent";
|
||||
malformed = true;
|
||||
}
|
||||
|
||||
// It should be Route to agent, but it is used as Response to user.
|
||||
if (!string.IsNullOrEmpty(args.AgentName) &&
|
||||
agents.Select(x => x.Name).Contains(args.AgentName) &&
|
||||
args.Function != "route_to_agent")
|
||||
{
|
||||
args.Function = "route_to_agent";
|
||||
malformed = true;
|
||||
}
|
||||
|
||||
// Function name shouldn't contain dot symbol
|
||||
if (!string.IsNullOrEmpty(args.Function) &&
|
||||
args.Function.Contains('.'))
|
||||
{
|
||||
args.Function = args.Function.Split('.').Last();
|
||||
malformed = true;
|
||||
}
|
||||
|
||||
if (malformed)
|
||||
{
|
||||
_logger.LogWarning($"Captured LLM malformed response");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
using BotSharp.Abstraction.Agents.Models;
|
||||
using BotSharp.Abstraction.Functions.Models;
|
||||
using BotSharp.Abstraction.Planning;
|
||||
using BotSharp.Abstraction.Routing;
|
||||
using BotSharp.Abstraction.Routing.Settings;
|
||||
using System.Drawing;
|
||||
|
||||
namespace BotSharp.Core.Routing;
|
||||
|
||||
|
|
@ -69,7 +71,8 @@ public partial class RoutingService : IRoutingService
|
|||
_routerInstance.Load();
|
||||
var router = _routerInstance.Router;
|
||||
|
||||
var handlers = _services.GetServices<IRoutingHandler>();
|
||||
var planner = _services.GetRequiredService<IPlaner>();
|
||||
var executor = _services.GetRequiredService<IExecutor>();
|
||||
|
||||
int loopCount = 0;
|
||||
var stop = false;
|
||||
|
|
@ -77,28 +80,33 @@ public partial class RoutingService : IRoutingService
|
|||
{
|
||||
loopCount++;
|
||||
|
||||
var inst = await GetNextInstruction();
|
||||
message.Instruction = inst;
|
||||
inst.Question = message.Content;
|
||||
var conversation = await GetConversationContent(Dialogs);
|
||||
|
||||
var handler = handlers.FirstOrDefault(x => x.Name == inst.Function);
|
||||
if (handler == null)
|
||||
// Get instruction from Planner
|
||||
var inst = await planner.GetNextInstruction(router, conversation);
|
||||
|
||||
// Fix LLM malformed response
|
||||
FixMalformedResponse(inst);
|
||||
|
||||
// Save states
|
||||
SaveStateByArgs(inst.Arguments);
|
||||
|
||||
#if DEBUG
|
||||
Console.WriteLine($"*** Next Instruction *** {inst}", Color.GreenYellow);
|
||||
#else
|
||||
_logger.LogInformation($"*** Next Instruction *** {inst}");
|
||||
#endif
|
||||
|
||||
// Handle instruction by Executor
|
||||
var executed = await executor.Execute(this, router, inst, Dialogs, message);
|
||||
|
||||
await planner.AgentExecuted(inst, message);
|
||||
|
||||
// There is no need for the agent to continue processing, indicating that the task has been completed.
|
||||
if (inst.AgentName == null)
|
||||
{
|
||||
handler = handlers.FirstOrDefault(x => x.Name == "get_next_instruction");
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
handler.SetRouter(router);
|
||||
handler.SetDialogs(Dialogs);
|
||||
|
||||
message.FunctionName = inst.Function;
|
||||
message.Role = AgentRole.Function;
|
||||
message.FunctionArgs = inst.Arguments == null ? "{}" : JsonSerializer.Serialize(inst.Arguments);
|
||||
|
||||
await handler.Handle(this, inst, message);
|
||||
|
||||
inst.Response = message.Content;
|
||||
|
||||
stop = !_settings.EnableReasoning;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ public class TemplateRender : ITemplateRender
|
|||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning(error);
|
||||
return template;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,23 +31,10 @@ public class InstructModeController : ControllerBase, IApiAdapter
|
|||
.SetState("model", input.Model)
|
||||
.SetState("input_text", input.Text);
|
||||
|
||||
var agentService = _services.GetRequiredService<IAgentService>();
|
||||
Agent agent = await agentService.LoadAgent(agentId);
|
||||
|
||||
// switch to different instruction template
|
||||
if (!string.IsNullOrEmpty(input.Template))
|
||||
{
|
||||
var template = agent.Templates.First(x => x.Name == input.Template).Content;
|
||||
var render = _services.GetRequiredService<ITemplateRender>();
|
||||
var dict = new Dictionary<string, object>();
|
||||
state.GetStates().Select(x => dict[x.Key] = x.Value).ToArray();
|
||||
var prompt = render.Render(template, dict);
|
||||
agent.Instruction = prompt;
|
||||
}
|
||||
|
||||
var instructor = _services.GetRequiredService<IInstructService>();
|
||||
var result = await instructor.Execute(agent,
|
||||
new RoleDialogModel(AgentRole.User, input.Text));
|
||||
var result = await instructor.Execute(agentId,
|
||||
new RoleDialogModel(AgentRole.User, input.Text),
|
||||
templateName: input.Template);
|
||||
|
||||
result.States = state.GetStates();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using Azure;
|
||||
using Azure.AI.OpenAI;
|
||||
using BotSharp.Abstraction.Agents;
|
||||
using BotSharp.Abstraction.Agents.Enums;
|
||||
using BotSharp.Abstraction.Agents.Models;
|
||||
using BotSharp.Abstraction.Conversations;
|
||||
|
|
@ -73,6 +74,12 @@ public class ChatCompletionProvider : IChatCompletion
|
|||
}
|
||||
}
|
||||
|
||||
var setting = _services.GetRequiredService<ConversationSetting>();
|
||||
if (setting.ShowVerboseLog)
|
||||
{
|
||||
_logger.LogInformation(msg.Content);
|
||||
}
|
||||
|
||||
// After chat completion hook
|
||||
Task.WaitAll(hooks.Select(hook =>
|
||||
hook.AfterGenerated(msg, new TokenStatsModel
|
||||
|
|
@ -193,11 +200,14 @@ public class ChatCompletionProvider : IChatCompletion
|
|||
|
||||
protected ChatCompletionsOptions PrepareOptions(Agent agent, List<RoleDialogModel> conversations)
|
||||
{
|
||||
var agentService = _services.GetRequiredService<IAgentService>();
|
||||
|
||||
var chatCompletionsOptions = new ChatCompletionsOptions();
|
||||
|
||||
if (!string.IsNullOrEmpty(agent.Instruction))
|
||||
{
|
||||
chatCompletionsOptions.Messages.Add(new ChatMessage(ChatRole.System, agent.Instruction));
|
||||
var instruction = agentService.RenderedInstruction(agent);
|
||||
chatCompletionsOptions.Messages.Add(new ChatMessage(ChatRole.System, instruction));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(agent.Knowledges))
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ public class ProviderHelper
|
|||
{
|
||||
public static OpenAIClient GetClient(string model, AzureOpenAiSettings settings)
|
||||
{
|
||||
if (model == "gpt-4")
|
||||
if (model == "gpt-4" || model == "llm-gpt4")
|
||||
{
|
||||
var client = new OpenAIClient(new Uri(settings.GPT4.Endpoint), new AzureKeyCredential(settings.GPT4.ApiKey));
|
||||
return client;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using BotSharp.Abstraction.Agents;
|
||||
using BotSharp.Abstraction.Agents.Enums;
|
||||
using BotSharp.Abstraction.Conversations;
|
||||
using BotSharp.Plugin.GoogleAI.Settings;
|
||||
|
|
@ -35,7 +36,9 @@ public class ChatCompletionProvider : IChatCompletion
|
|||
var messages = conversations.Select(c => new PalmChatMessage(c.Content, c.Role == AgentRole.User ? "user" : "AI"))
|
||||
.ToList();
|
||||
|
||||
var response = client.ChatAsync(messages, agent.Instruction, null).Result;
|
||||
var agentService = _services.GetRequiredService<IAgentService>();
|
||||
var instruction = agentService.RenderedInstruction(agent);
|
||||
var response = client.ChatAsync(messages, instruction, null).Result;
|
||||
|
||||
var message = response.Candidates.First();
|
||||
var msg = new RoleDialogModel(AgentRole.Assistant, message.Content)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using BotSharp.Abstraction.Agents;
|
||||
using BotSharp.Abstraction.Agents.Enums;
|
||||
using BotSharp.Abstraction.Conversations.Settings;
|
||||
using BotSharp.Plugin.HuggingFace.Services;
|
||||
|
|
@ -97,7 +98,9 @@ public class ChatCompletionProvider : IChatCompletion
|
|||
var content = string.Join("\r\n", conversations.Select(x => $"{AgentRole.System}: {x.Content}")).Trim();
|
||||
content += $"\r\n{AgentRole.Assistant}: ";
|
||||
|
||||
var prompt = agent.Instruction + "\r\n" + content;
|
||||
var agentService = _services.GetRequiredService<IAgentService>();
|
||||
var instruction = agentService.RenderedInstruction(agent);
|
||||
var prompt = instruction + "\r\n" + content;
|
||||
|
||||
var convSetting = _services.GetRequiredService<ConversationSetting>();
|
||||
if (convSetting.ShowVerboseLog)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
using BotSharp.Abstraction.Agents;
|
||||
|
||||
namespace BotSharp.Plugin.LLamaSharp.Providers;
|
||||
|
||||
public class ChatCompletionProvider : IChatCompletion
|
||||
|
|
@ -42,7 +44,9 @@ public class ChatCompletionProvider : IChatCompletion
|
|||
|
||||
string totalResponse = "";
|
||||
|
||||
var prompt = agent.Instruction + "\r\n" + content;
|
||||
var agentService = _services.GetRequiredService<IAgentService>();
|
||||
var instruction = agentService.RenderedInstruction(agent);
|
||||
var prompt = instruction + "\r\n" + content;
|
||||
|
||||
var convSetting = _services.GetRequiredService<ConversationSetting>();
|
||||
if (convSetting.ShowVerboseLog)
|
||||
|
|
|
|||
|
|
@ -15,8 +15,7 @@
|
|||
|
||||
"Router": {
|
||||
"RouterId": "01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a",
|
||||
"UseTextCompletion": false,
|
||||
"EnableReasoning": false,
|
||||
"Planner": "NaivePlanner",
|
||||
"Provider": "azure-openai",
|
||||
"Model": "gpt-3.5-turbo"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -9,23 +9,24 @@ You're {{router.name}} ({{router.description}}). Follow these steps to handle us
|
|||
{% for handler in routing_handlers %}
|
||||
# {{ handler.description}}
|
||||
{% if handler.parameters and handler.parameters != empty -%}
|
||||
Response: { "function": "{{ handler.name }}",
|
||||
Parameters:
|
||||
- function: {{ handler.name }}
|
||||
{% for p in handler.parameters -%}
|
||||
"{{ p.name }}": "{{ p.description }}"{{ ",\r\n " }}
|
||||
{%- endfor %}}
|
||||
- {{ p.name }}: {{ p.description }}{{ "\r\n " }}
|
||||
{%- endfor %}
|
||||
{%- endif %}
|
||||
{% endfor %}
|
||||
|
||||
[AGENTS]
|
||||
{% for agent in routing_agents %}
|
||||
* Agent: {{ agent.name }}
|
||||
{{ agent.description}}
|
||||
{% if agent.required_fields and agent.required_fields != empty -%}
|
||||
Required args:
|
||||
{% for f in agent.required_fields -%}
|
||||
- {{ f.name }} ({{ f.type }}): {{ f.description }}{{ "\r\n " }}
|
||||
* {{ agent.description}}
|
||||
Agent: {{ agent.name }}
|
||||
{% if agent.fields and agent.fields != empty -%}
|
||||
Arguments:
|
||||
{% for f in agent.fields -%}
|
||||
- {{ f.name }}: {{ f.description }} (type: {{ f.type }}, required: {{f.required}}){{ "\r\n " }}
|
||||
{%- endfor %}
|
||||
{%- endif %}
|
||||
{% endfor %}
|
||||
|
||||
[CONVERSATION]
|
||||
[CONVERSATION]
|
||||
|
|
@ -5,5 +5,13 @@
|
|||
"updatedDateTime": "2023-08-18T14:39:32.2349686Z",
|
||||
"id": "b284db86-e9c2-4c25-a59e-4649797dd130",
|
||||
"allowRouting": true,
|
||||
"isPublic": true
|
||||
"isPublic": true,
|
||||
"routingRules": [
|
||||
{
|
||||
"field": "order_number",
|
||||
"description": "order number",
|
||||
"type": "string",
|
||||
"redirectTo": "c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd"
|
||||
}
|
||||
]
|
||||
}
|
||||
Loading…
Reference in a new issue