Support multi-agent with different profile.
This commit is contained in:
parent
4083e76518
commit
9d3cd6b6e9
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
An agent helps you process user sentences (unstructure data) into structure data that you can use to return an appropriate response.
|
||||
|
||||
Agent is a collection that contains prompt words and function Json Schema definitions, few-shot examples and knowledge base data. You can create multiple different Agents to perform specific operations in specific domains. BotSharp has built-in maintenance for Agents, including creating, updating and deleting, importing and exporting.
|
||||
Agent is a collection that contains prompt words and function Json Schema definitions, few-shot examples and knowledge base data. You can create multiple different Agents to perform specific operations in specific domains. BotSharp has built-in maintenance for Agents, including creating, updating and deleting, importing and exporting. Agents are divided into task agents and routing (non-task) agents. Business domain agents belong to task agents, and routers belong to non-task agents.
|
||||
|
||||
## My Agent
|
||||
After creating the platform account, you can start to enter the steps of creating the Agent.
|
||||
|
|
|
|||
|
|
@ -15,3 +15,7 @@ For simple questions raised by users, the ordinary routing function can already
|
|||

|
||||
|
||||
For more **Routing** related information, please go to [Agent Routing](../agent/router.md).
|
||||
|
||||
## Profile
|
||||
|
||||
There is an array field called `Profile` in the Agent data model, which is used to store the current profiles. When this attribute is set in the `Router`, only matching Task Agents can be included in the routing candidate Agents list, which means that the Task Agent also To set the same profile name. Profiles allows you to enter multiple profiles, and the system will automatically combine them for processing.
|
||||
|
|
@ -60,6 +60,9 @@ public class Agent
|
|||
[JsonIgnore]
|
||||
public bool IsRouter { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public bool IsHost { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public PluginDef Plugin { get; set; }
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ namespace BotSharp.Abstraction.Routing;
|
|||
public interface IRoutingService
|
||||
{
|
||||
Agent Router { get; }
|
||||
RoutingItem[] GetRoutingItems();
|
||||
RoutableAgent[] GetRoutableAgents(List<string> profiles);
|
||||
RoutingRule[] GetRulesByName(string name);
|
||||
RoutingRule[] GetRulesByAgentId(string id);
|
||||
List<RoutingHandlerDef> GetHandlers();
|
||||
|
|
@ -20,5 +20,5 @@ public interface IRoutingService
|
|||
/// <param name="agent"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
Task<RoleDialogModel> ExecuteDirectly(Agent agent, RoleDialogModel message);
|
||||
Task<RoleDialogModel> InstructDirect(Agent agent, RoleDialogModel message);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ using BotSharp.Abstraction.Functions.Models;
|
|||
|
||||
namespace BotSharp.Abstraction.Routing.Models;
|
||||
|
||||
public class RoutingItem
|
||||
public class RoutableAgent
|
||||
{
|
||||
[JsonPropertyName("agent_id")]
|
||||
public string AgentId { get; set; } = string.Empty;
|
||||
|
|
@ -13,6 +13,10 @@ public class RoutingItem
|
|||
[JsonPropertyName("description")]
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("profiles")]
|
||||
public List<string> Profiles { get; set; }
|
||||
= new List<string>();
|
||||
|
||||
[JsonPropertyName("required_fields")]
|
||||
public List<ParameterPropertyDef> RequiredFields { get; set; } = new List<ParameterPropertyDef>();
|
||||
|
||||
|
|
@ -21,6 +21,13 @@ public partial class AgentService
|
|||
agent.Plugin = GetPlugin(agent.Id);
|
||||
}
|
||||
|
||||
// Set IsHost
|
||||
var agentSetting = _services.GetRequiredService<AgentSettings>();
|
||||
foreach (var agent in agents)
|
||||
{
|
||||
agent.IsHost = agentSetting.HostAgentId == agent.Id;
|
||||
}
|
||||
|
||||
agents = agents.Where(x => x.Installed).ToList();
|
||||
var pager = filter?.Pager ?? new Pagination();
|
||||
return new PagedItems<Agent>
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ public partial class ConversationService
|
|||
|
||||
response = settings.AgentIds.Contains(agentId) ?
|
||||
await routing.InstructLoop(message) :
|
||||
await routing.ExecuteDirectly(agent, message);
|
||||
await routing.InstructDirect(agent, message);
|
||||
|
||||
routing.ResetRecursiveCounter();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ public class NaivePlanner : IPlaner
|
|||
var unmatchedAgentId = context.GetCurrentAgentId();
|
||||
|
||||
// Exclude the wrong routed agent
|
||||
var agents = router.TemplateDict["routing_agents"] as RoutingItem[];
|
||||
var agents = router.TemplateDict["routing_agents"] as RoutableAgent[];
|
||||
router.TemplateDict["routing_agents"] = agents.Where(x => x.AgentId != unmatchedAgentId).ToArray();
|
||||
|
||||
// Handover to Router;
|
||||
|
|
|
|||
|
|
@ -24,7 +24,8 @@ public class RoutingAgentHook : AgentHookBase
|
|||
dict["router"] = _agent;
|
||||
|
||||
var routing = _services.GetRequiredService<IRoutingService>();
|
||||
dict["routing_agents"] = routing.GetRoutingItems();
|
||||
var agents = routing.GetRoutableAgents(_agent.Profiles);
|
||||
dict["routing_agents"] = agents;
|
||||
dict["routing_handlers"] = routing.GetHandlers();
|
||||
|
||||
return base.OnInstructionLoaded(template, dict);
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ public partial class RoutingService : IRoutingService
|
|||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<RoleDialogModel> ExecuteDirectly(Agent agent, RoleDialogModel message)
|
||||
public async Task<RoleDialogModel> InstructDirect(Agent agent, RoleDialogModel message)
|
||||
{
|
||||
var handlers = _services.GetServices<IRoutingHandler>();
|
||||
|
||||
|
|
@ -147,22 +147,13 @@ public partial class RoutingService : IRoutingService
|
|||
return x.RoutingRules;
|
||||
}).ToArray();
|
||||
|
||||
// Filter agents by profile
|
||||
var state = _services.GetRequiredService<IConversationStateService>();
|
||||
var channel = state.GetState("channel");
|
||||
var specifiedProfile = agents.FirstOrDefault(x => x.Profiles.Contains(channel));
|
||||
if (specifiedProfile != null)
|
||||
{
|
||||
records = records.Where(x => specifiedProfile.Profiles.Contains(channel)).ToArray();
|
||||
}
|
||||
|
||||
return records;
|
||||
}
|
||||
|
||||
#if !DEBUG
|
||||
[MemoryCache(10 * 60)]
|
||||
#endif
|
||||
public RoutingItem[] GetRoutingItems()
|
||||
public RoutableAgent[] GetRoutableAgents(List<string> profiles)
|
||||
{
|
||||
var db = _services.GetRequiredService<IBotSharpRepository>();
|
||||
|
||||
|
|
@ -171,12 +162,14 @@ public partial class RoutingService : IRoutingService
|
|||
Disabled = false,
|
||||
AllowRouting = true
|
||||
};
|
||||
|
||||
var agents = db.GetAgents(filter);
|
||||
return agents.Select(x => new RoutingItem
|
||||
var routableAgents = agents.Select(x => new RoutableAgent
|
||||
{
|
||||
AgentId = x.Id,
|
||||
Description = x.Description,
|
||||
Name = x.Name,
|
||||
Profiles = x.Profiles,
|
||||
RequiredFields = x.RoutingRules
|
||||
.Where(p => p.Required)
|
||||
.Select(p => new ParameterPropertyDef(p.Field, p.Description, type: p.Type)
|
||||
|
|
@ -190,6 +183,17 @@ public partial class RoutingService : IRoutingService
|
|||
Required = p.Required
|
||||
}).ToList()
|
||||
}).ToArray();
|
||||
|
||||
// Handle profile.
|
||||
// Router profile must match the agent profile
|
||||
if (routableAgents.Length > 0 && profiles.Count > 0)
|
||||
{
|
||||
routableAgents = routableAgents.Where(x => x.Profiles != null &&
|
||||
x.Profiles.Exists(x1 => profiles.Exists(y => x1 == y)))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
return routableAgents;
|
||||
}
|
||||
|
||||
public RoutingRule[] GetRulesByName(string name)
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ public class TemplateRender : ITemplateRender
|
|||
_options.MemberAccessStrategy.Register<ParameterPropertyDef>();
|
||||
_options.MemberAccessStrategy.Register<RoleDialogModel>();
|
||||
_options.MemberAccessStrategy.Register<Agent>();
|
||||
_options.MemberAccessStrategy.Register<RoutingItem>();
|
||||
_options.MemberAccessStrategy.Register<RoutableAgent>();
|
||||
_options.MemberAccessStrategy.Register<RoutingHandlerDef>();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,12 +22,19 @@ public class AgentViewModel
|
|||
[JsonPropertyName("is_router")]
|
||||
public bool IsRouter { get; set; }
|
||||
|
||||
[JsonPropertyName("is_host")]
|
||||
public bool IsHost { get; set; }
|
||||
|
||||
[JsonPropertyName("allow_routing")]
|
||||
public bool AllowRouting { get; set; }
|
||||
|
||||
public bool Disabled { get; set; }
|
||||
|
||||
[JsonPropertyName("icon_url")]
|
||||
public string IconUrl { get; set; }
|
||||
|
||||
public List<string> Profiles { get; set; }
|
||||
= new List<string>();
|
||||
|
||||
[JsonPropertyName("routing_rules")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
|
|
@ -59,10 +66,11 @@ public class AgentViewModel
|
|||
Samples = agent.Samples,
|
||||
IsPublic= agent.IsPublic,
|
||||
IsRouter = agent.IsRouter,
|
||||
IsHost = agent.IsHost,
|
||||
Disabled = agent.Disabled,
|
||||
IconUrl = agent.IconUrl,
|
||||
AllowRouting = agent.AllowRouting,
|
||||
Profiles = agent.Profiles,
|
||||
Profiles = agent.Profiles ?? new List<string>(),
|
||||
RoutingRules = agent.RoutingRules,
|
||||
LlmConfig = agent.LlmConfig,
|
||||
Plugin = agent.Plugin,
|
||||
|
|
|
|||
|
|
@ -210,6 +210,7 @@ public partial class MongoRepository
|
|||
var builder = Builders<ConversationDocument>.Filter;
|
||||
var filters = new List<FilterDefinition<ConversationDocument>>() { builder.Empty };
|
||||
|
||||
if (!string.IsNullOrEmpty(filter.Id)) filters.Add(builder.Eq(x => x.Id, filter.Id));
|
||||
if (!string.IsNullOrEmpty(filter.AgentId)) filters.Add(builder.Eq(x => x.AgentId, filter.AgentId));
|
||||
if (!string.IsNullOrEmpty(filter.Status)) filters.Add(builder.Eq(x => x.Status, filter.Status));
|
||||
if (!string.IsNullOrEmpty(filter.Channel)) filters.Add(builder.Eq(x => x.Channel, filter.Channel));
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
|
|
@ -35,13 +35,9 @@
|
|||
<None Remove="data\agents\fe8c60aa-b114-4ef3-93cb-a8efeac80f75\agent.json" />
|
||||
<None Remove="data\agents\fe8c60aa-b114-4ef3-93cb-a8efeac80f75\functions.json" />
|
||||
<None Remove="data\agents\fe8c60aa-b114-4ef3-93cb-a8efeac80f75\instruction.liquid" />
|
||||
<None Remove="data\users\10d12798-08fb-4aa6-977b-5dd94d82dbfe\agents.json" />
|
||||
<None Remove="data\users\10d12798-08fb-4aa6-977b-5dd94d82dbfe\user.json" />
|
||||
<None Remove="data\users\456e35c5-caf0-4d45-9084-b44a8ca717e4\agents.json" />
|
||||
<None Remove="data\users\456e35c5-caf0-4d45-9084-b44a8ca717e4\user.json" />
|
||||
<None Remove="data\users\d0e6680d-03d5-4ed8-bdcd-aa7d86f2a1bc\agents.json" />
|
||||
<None Remove="data\users\d0e6680d-03d5-4ed8-bdcd-aa7d86f2a1bc\user.json" />
|
||||
<None Remove="data\users\e465af5f-044f-414b-b670-92834929b96c\agents.json" />
|
||||
<None Remove="data\users\e465af5f-044f-414b-b670-92834929b96c\user.json" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
@ -91,27 +87,15 @@
|
|||
<Content Include="data\agents\fe8c60aa-b114-4ef3-93cb-a8efeac80f75\instruction.liquid">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="data\users\10d12798-08fb-4aa6-977b-5dd94d82dbfe\agents.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="data\users\10d12798-08fb-4aa6-977b-5dd94d82dbfe\user.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="data\users\456e35c5-caf0-4d45-9084-b44a8ca717e4\agents.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="data\users\456e35c5-caf0-4d45-9084-b44a8ca717e4\user.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="data\users\d0e6680d-03d5-4ed8-bdcd-aa7d86f2a1bc\agents.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="data\users\d0e6680d-03d5-4ed8-bdcd-aa7d86f2a1bc\user.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="data\users\e465af5f-044f-414b-b670-92834929b96c\agents.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="data\users\e465af5f-044f-414b-b670-92834929b96c\user.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
"id": "b284db86-e9c2-4c25-a59e-4649797dd130",
|
||||
"allowRouting": true,
|
||||
"isPublic": true,
|
||||
"profiles": [ "pizza" ],
|
||||
"routingRules": [
|
||||
{
|
||||
"field": "order_number",
|
||||
|
|
|
|||
|
|
@ -5,5 +5,6 @@
|
|||
"updatedDateTime": "2023-07-26T02:29:25.123274Z",
|
||||
"id": "c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd",
|
||||
"allowRouting": true,
|
||||
"isPublic": true
|
||||
"isPublic": true,
|
||||
"profiles": [ "pizza" ]
|
||||
}
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
[
|
||||
]
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
[
|
||||
{
|
||||
"userId": "456e35c5-caf0-4d45-9084-b44a8ca717e4",
|
||||
"agentId": "01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a",
|
||||
"updatedTime": "2023-08-14T18:14:11.6833783Z",
|
||||
"createdTime": "2023-08-14T18:14:11.6829767Z",
|
||||
"editable": true,
|
||||
"id": "1273379c-4419-460a-b0a2-5695afd097f5"
|
||||
}
|
||||
]
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
[
|
||||
]
|
||||
Loading…
Reference in a new issue