Fix route to agent.
This commit is contained in:
parent
30c809ed37
commit
ed35da1928
|
|
@ -6,4 +6,5 @@ public class BuiltInAgentId
|
|||
public const string Chatbot = "01e2fc5c-2c89-4ec7-8470-7688608b496c";
|
||||
public const string HumanSupport = "01dcc3e5-0af7-49e6-ad7a-a760bd12dc4b";
|
||||
public const string UtilityAssistant = "6745151e-6d46-4a02-8de4-1c4f21c7da95";
|
||||
public const string Fallback = "01fcc3e5-0af7-49e6-ad7a-a760bd12dc4d";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ public partial class ConversationService
|
|||
// Enqueue receiving agent first in case it stop completion by OnMessageReceived
|
||||
var routing = _services.GetRequiredService<IRoutingService>();
|
||||
routing.Context.SetMessageId(_conversationId, message.MessageId);
|
||||
routing.Context.Push(agent.Id);
|
||||
routing.Context.Push(agent.Id, reason: "request started");
|
||||
|
||||
// Save payload
|
||||
if (replyMessage != null && !string.IsNullOrEmpty(replyMessage.Payload))
|
||||
|
|
|
|||
|
|
@ -88,6 +88,8 @@ public partial class RouteToAgentFn : IFunctionCallback
|
|||
{
|
||||
// Stack redirection agent
|
||||
_context.Push(agentId, reason: $"REDIRECTION {reason}");
|
||||
message.Content = reason;
|
||||
message.Role = AgentRole.Function;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ namespace BotSharp.Core.Routing.Handlers;
|
|||
/// <summary>
|
||||
/// Retrieve information from specific agent
|
||||
/// </summary>
|
||||
public class RetrieveDataFromAgentRoutingHandler : RoutingHandlerBase, IRoutingHandler
|
||||
public class RetrieveDataFromAgentRoutingHandler : RoutingHandlerBase//, IRoutingHandler
|
||||
{
|
||||
public string Name => "retrieve_data_from_agent";
|
||||
|
||||
|
|
|
|||
|
|
@ -59,7 +59,9 @@ public class RouteToAgentRoutingHandler : RoutingHandlerBase, IRoutingHandler
|
|||
message.FunctionArgs = JsonSerializer.Serialize(inst);
|
||||
if (message.FunctionName != null)
|
||||
{
|
||||
var ret = await routing.InvokeFunction(message.FunctionName, message);
|
||||
var msg = RoleDialogModel.From(message);
|
||||
var ret = await routing.InvokeFunction(message.FunctionName, msg);
|
||||
_dialogs.Add(msg);
|
||||
}
|
||||
|
||||
var agentId = routing.Context.GetCurrentAgentId();
|
||||
|
|
|
|||
|
|
@ -59,6 +59,9 @@ public class HFPlanner : IPlaner
|
|||
}
|
||||
}
|
||||
|
||||
// Fix LLM malformed response
|
||||
PlannerHelper.FixMalformedResponse(_services, inst);
|
||||
|
||||
return inst;
|
||||
}
|
||||
|
||||
|
|
@ -71,7 +74,11 @@ public class HFPlanner : IPlaner
|
|||
var agent = db.GetAgents(filter).FirstOrDefault();
|
||||
|
||||
var context = _services.GetRequiredService<IRoutingContext>();
|
||||
context.Push(agent.Id);
|
||||
context.Push(agent.Id, reason: inst.NextActionReason);
|
||||
|
||||
// Set user content as Planner's question
|
||||
message.FunctionName = inst.Function;
|
||||
message.FunctionArgs = inst.Arguments == null ? "{}" : JsonSerializer.Serialize(inst.Arguments);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ public class NaivePlanner : IPlaner
|
|||
}
|
||||
|
||||
// Fix LLM malformed response
|
||||
FixMalformedResponse(inst);
|
||||
PlannerHelper.FixMalformedResponse(_services, inst);
|
||||
|
||||
return inst;
|
||||
}
|
||||
|
|
@ -117,73 +117,4 @@ public class NaivePlanner : IPlaner
|
|||
{ StateConst.EXPECTED_GOAL_AGENT, states.GetState(StateConst.EXPECTED_GOAL_AGENT) }
|
||||
});
|
||||
}
|
||||
|
||||
/// <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(new AgentFilter
|
||||
{
|
||||
Type = AgentType.Task
|
||||
}).Result.Items.ToList();
|
||||
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;
|
||||
}
|
||||
|
||||
// Agent Name is contaminated.
|
||||
if (args.Function == "route_to_agent")
|
||||
{
|
||||
// Action agent name
|
||||
if (!agents.Any(x => x.Name == args.AgentName) && !string.IsNullOrEmpty(args.AgentName))
|
||||
{
|
||||
args.AgentName = agents.FirstOrDefault(x => args.AgentName.Contains(x.Name))?.Name ?? args.AgentName;
|
||||
}
|
||||
|
||||
// Goal agent name
|
||||
if (!agents.Any(x => x.Name == args.OriginalAgent) && !string.IsNullOrEmpty(args.OriginalAgent))
|
||||
{
|
||||
args.OriginalAgent = agents.FirstOrDefault(x => args.OriginalAgent.Contains(x.Name))?.Name ?? args.OriginalAgent;
|
||||
}
|
||||
}
|
||||
|
||||
if (malformed)
|
||||
{
|
||||
_logger.LogWarning($"Captured LLM malformed response");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,73 @@
|
|||
namespace BotSharp.Core.Routing.Planning;
|
||||
|
||||
public static class PlannerHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Sometimes LLM hallucinates and fails to set function names correctly.
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
public static void FixMalformedResponse(IServiceProvider services, FunctionCallFromLlm args)
|
||||
{
|
||||
var agentService = services.GetRequiredService<IAgentService>();
|
||||
var agents = agentService.GetAgents(new AgentFilter
|
||||
{
|
||||
Type = AgentType.Task
|
||||
}).Result.Items.ToList();
|
||||
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;
|
||||
}
|
||||
|
||||
// Agent Name is contaminated.
|
||||
if (args.Function == "route_to_agent")
|
||||
{
|
||||
// Action agent name
|
||||
if (!agents.Any(x => x.Name == args.AgentName) && !string.IsNullOrEmpty(args.AgentName))
|
||||
{
|
||||
args.AgentName = agents.FirstOrDefault(x => args.AgentName.Contains(x.Name))?.Name ?? args.AgentName;
|
||||
}
|
||||
|
||||
// Goal agent name
|
||||
if (!agents.Any(x => x.Name == args.OriginalAgent) && !string.IsNullOrEmpty(args.OriginalAgent))
|
||||
{
|
||||
args.OriginalAgent = agents.FirstOrDefault(x => args.OriginalAgent.Contains(x.Name))?.Name ?? args.OriginalAgent;
|
||||
}
|
||||
}
|
||||
|
||||
if (malformed)
|
||||
{
|
||||
Console.WriteLine($"Captured LLM malformed response");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
using BotSharp.Abstraction.Agents.Models;
|
||||
using BotSharp.Abstraction.MLTasks;
|
||||
using BotSharp.Abstraction.Templating;
|
||||
|
||||
|
|
@ -13,11 +12,12 @@ public partial class TwoStagePlanner
|
|||
var plan = new FirstStagePlan[0];
|
||||
|
||||
var llmProviderService = _services.GetRequiredService<ILlmProviderService>();
|
||||
var model = llmProviderService.GetProviderModel("azure-openai", "gpt-4");
|
||||
var provider = router.LlmConfig.Provider ?? "openai";
|
||||
var model = llmProviderService.GetProviderModel(provider, router.LlmConfig.Model ?? "gpt-4o");
|
||||
|
||||
// chat completion
|
||||
var completion = CompletionProvider.GetChatCompletion(_services,
|
||||
provider: "azure-openai",
|
||||
provider: provider,
|
||||
model: model.Name);
|
||||
|
||||
string text = string.Empty;
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ public partial class RoutingService
|
|||
}
|
||||
|
||||
// Set result to original message
|
||||
message.Role = clonedMessage.Role;
|
||||
message.PostbackFunctionName = clonedMessage.PostbackFunctionName;
|
||||
message.CurrentAgentId = clonedMessage.CurrentAgentId;
|
||||
message.Content = clonedMessage.Content;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
You're {{router.name}} ({{router.description}}).
|
||||
You can understand messages sent by users in different languages.
|
||||
You can understand messages sent by users in different languages, and route the request to appropriate agent.
|
||||
Follow these steps to handle user request:
|
||||
1. Read the [CONVERSATION] content.
|
||||
2. Determine which agent is suitable to handle this conversation.
|
||||
3. For agent required arguments, think carefully, leave it as blank object if user didn't provide the specific arguments.
|
||||
2. Determine which agent is suitable to handle this conversation. Try to minimize the routing of human service.
|
||||
3. Extract and populate agent required arguments, think carefully, leave it as blank object if user didn't provide the specific arguments.
|
||||
4. You must include all required args for the selected agent, but you must not make up any parameters when there is no exact value provided, those parameters must set value as null if not declared.
|
||||
5. Response must be in JSON format.
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Break down the user’s most recent needs and figure out the next steps.
|
||||
Break down the user’s most recent needs and figure out the instruction of next step.
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
},
|
||||
"request_content": {
|
||||
"type": "string",
|
||||
"description": "The http request content. It must be in json format.."
|
||||
"description": "The http request content. It must be in serialized json string."
|
||||
}
|
||||
},
|
||||
"required": [ "request_url", "http_method" ]
|
||||
|
|
|
|||
Loading…
Reference in a new issue