Add EvaluatingService.
This commit is contained in:
parent
a69cb49044
commit
2f3e71ef09
|
|
@ -10,13 +10,19 @@ public interface IAgentService
|
|||
Task<List<Agent>> GetAgents();
|
||||
|
||||
/// <summary>
|
||||
/// Load agent configurations and triggher hooks
|
||||
/// Load agent configurations and trigghe hooks
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
Task<Agent> LoadAgent(string id);
|
||||
|
||||
/// <summary>
|
||||
/// Get agent detail without trigger any hook.
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns>Original agent information</returns>
|
||||
Task<Agent> GetAgent(string id);
|
||||
|
||||
Task<bool> DeleteAgent(string id);
|
||||
Task UpdateAgent(Agent agent, AgentField updateField);
|
||||
Task UpdateAgentFromFile(string id);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
using BotSharp.Abstraction.Routing.Models;
|
||||
|
||||
namespace BotSharp.Abstraction.Conversations.Models;
|
||||
|
||||
public class RoleDialogModel
|
||||
|
|
@ -10,29 +8,36 @@ public class RoleDialogModel
|
|||
public string Role { get; set; }
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
public string Content { get; set; }
|
||||
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public string CurrentAgentId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Function name if LLM response function call
|
||||
/// </summary>
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public string? FunctionName { get; set; }
|
||||
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public string? FunctionArgs { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Function execution result, this result will be seen by LLM.
|
||||
/// </summary>
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public string? ExecutionResult { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Function execution structured data, this data won't pass to LLM.
|
||||
/// It's ideal to render in rich content in UI.
|
||||
/// </summary>
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public object ExecutionData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Stop conversation completion
|
||||
/// </summary>
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.Always)]
|
||||
public bool StopCompletion { get; set; }
|
||||
|
||||
public RoleDialogModel(string role, string text)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
using BotSharp.Abstraction.Evaluations.Models;
|
||||
|
||||
namespace BotSharp.Abstraction.Evaluations;
|
||||
|
||||
public interface IEvaluatingService
|
||||
{
|
||||
Task<EvaluationResult> Evaluate(EvaluationRequest request);
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
namespace BotSharp.Abstraction.Evaluations.Models;
|
||||
|
||||
public class EvaluationRequest
|
||||
{
|
||||
public string AgentId { get; set; }
|
||||
public string Task { get; set; }
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
namespace BotSharp.Abstraction.Evaluations.Models;
|
||||
|
||||
public class EvaluationResult
|
||||
{
|
||||
public List<RoleDialogModel> Dialogs { get; set; }
|
||||
public string TaskInstruction { get; set; }
|
||||
public string SystemPrompt { get; set; }
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
namespace BotSharp.Abstraction.Evaluations.Settings;
|
||||
|
||||
public class EvaluatorSetting
|
||||
{
|
||||
public string EvaluatorId { get; set; }
|
||||
public string Provider { get; set; }
|
||||
public string Model { get; set; }
|
||||
}
|
||||
|
|
@ -12,6 +12,9 @@ using BotSharp.Abstraction.Routing;
|
|||
using BotSharp.Core.Routing.Hooks;
|
||||
using BotSharp.Abstraction.Routing.Models;
|
||||
using BotSharp.Core.Plugins;
|
||||
using BotSharp.Abstraction.Evaluations.Settings;
|
||||
using BotSharp.Abstraction.Evaluations;
|
||||
using BotSharp.Core.Evaluatings;
|
||||
|
||||
namespace BotSharp.Core;
|
||||
|
||||
|
|
@ -68,6 +71,13 @@ public static class BotSharpServiceCollectionExtensions
|
|||
|
||||
services.AddScoped<IAgentHook, RoutingAgentHook>();
|
||||
|
||||
// Evaluation
|
||||
var evalSetting = new EvaluatorSetting();
|
||||
config.Bind("Evaluator", evalSetting);
|
||||
services.AddSingleton((IServiceProvider x) => evalSetting);
|
||||
|
||||
services.AddScoped<IEvaluatingService, EvaluatingService>();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace BotSharp.Core.Evaluatings;
|
||||
|
||||
public class Evaluater
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
using BotSharp.Abstraction.Conversations.Models;
|
||||
using BotSharp.Abstraction.Evaluations;
|
||||
using BotSharp.Abstraction.Evaluations.Models;
|
||||
using BotSharp.Abstraction.Evaluations.Settings;
|
||||
using BotSharp.Abstraction.Templating;
|
||||
using System.Drawing;
|
||||
|
||||
namespace BotSharp.Core.Evaluatings;
|
||||
|
||||
public class EvaluatingService : IEvaluatingService
|
||||
{
|
||||
private readonly IServiceProvider _services;
|
||||
private readonly EvaluatorSetting _settings;
|
||||
public EvaluatingService(IServiceProvider services, EvaluatorSetting settings)
|
||||
{
|
||||
_services = services;
|
||||
_settings = settings;
|
||||
}
|
||||
|
||||
public async Task<EvaluationResult> Evaluate(EvaluationRequest request)
|
||||
{
|
||||
var agentService = _services.GetRequiredService<IAgentService>();
|
||||
var evaluator = await agentService.GetAgent(_settings.EvaluatorId);
|
||||
var taskPrompt = evaluator.Templates.First(x => x.Name == $"task.{request.Task}").Content;
|
||||
|
||||
var render = _services.GetRequiredService<ITemplateRender>();
|
||||
var prompt = render.Render(evaluator.Instruction, new Dictionary<string, object>
|
||||
{
|
||||
{ "task_prompt", taskPrompt}
|
||||
});
|
||||
|
||||
var service = _services.GetRequiredService<IConversationService>();
|
||||
var conv = await service.NewConversation(new Conversation
|
||||
{
|
||||
AgentId = request.AgentId
|
||||
});
|
||||
|
||||
var result = new EvaluationResult
|
||||
{
|
||||
TaskInstruction = taskPrompt,
|
||||
SystemPrompt = evaluator.Instruction
|
||||
};
|
||||
|
||||
var textCompletion = CompletionProvider.GetTextCompletion(_services);
|
||||
RoleDialogModel response = default;
|
||||
var dialogs = new List<RoleDialogModel>();
|
||||
int roundCount = 0;
|
||||
while (true)
|
||||
{
|
||||
// var text = string.Join("\r\n", dialogs.Select(x => $"{x.Role}: {x.Content}"));
|
||||
// text = instruction + $"\r\n###\r\n{text}\r\n{AgentRole.User}: ";
|
||||
var question = await textCompletion.GetCompletion(prompt);
|
||||
dialogs.Add(new RoleDialogModel(AgentRole.User, question));
|
||||
prompt += question.Trim();
|
||||
|
||||
response = await SendMessage(request.AgentId, conv.Id, question);
|
||||
dialogs.Add(new RoleDialogModel(AgentRole.Assistant, response.Content));
|
||||
prompt += $"\r\n{AgentRole.Assistant}: {response.Content.Trim()}";
|
||||
prompt += $"\r\n{AgentRole.User}: ";
|
||||
|
||||
roundCount++;
|
||||
|
||||
if (response.FunctionName == "conversation_end" ||
|
||||
response.FunctionName == "human_intervention_needed" ||
|
||||
roundCount > 5)
|
||||
{
|
||||
Console.WriteLine($"Conversation ended by function {response.FunctionName}", Color.Green);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
result.Dialogs = dialogs;
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<RoleDialogModel> SendMessage(string agentId, string conversationId, string text)
|
||||
{
|
||||
var conv = _services.GetRequiredService<IConversationService>();
|
||||
conv.SetConversationId(conversationId, new List<string>());
|
||||
|
||||
RoleDialogModel response = default;
|
||||
|
||||
await conv.SendMessage(agentId,
|
||||
new RoleDialogModel("user", text),
|
||||
async msg => response = msg,
|
||||
fnExecuting => Task.CompletedTask,
|
||||
fnExecuted => Task.CompletedTask);
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
|
@ -489,6 +489,9 @@ public class FileRepository : IBotSharpRepository
|
|||
return responses;
|
||||
}
|
||||
|
||||
#if !DEBUG
|
||||
[MemoryCache(10 * 60)]
|
||||
#endif
|
||||
public Agent? GetAgent(string agentId)
|
||||
{
|
||||
var agentDir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir);
|
||||
|
|
@ -766,8 +769,8 @@ public class FileRepository : IBotSharpRepository
|
|||
{
|
||||
var fileName = file.Split(Path.DirectorySeparatorChar).Last();
|
||||
var splits = fileName.ToLower().Split('.');
|
||||
var name = splits[0];
|
||||
var extension = splits[1];
|
||||
var name = string.Join('.', splits.Take(splits.Length - 1));
|
||||
var extension = splits.Last();
|
||||
if (extension.Equals(_agentSettings.TemplateFormat, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var content = File.ReadAllText(file);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
using BotSharp.Abstraction.ApiAdapters;
|
||||
using BotSharp.Abstraction.Evaluations;
|
||||
using BotSharp.Abstraction.Evaluations.Models;
|
||||
|
||||
namespace BotSharp.OpenAPI.Controllers;
|
||||
|
||||
[Authorize]
|
||||
[ApiController]
|
||||
public class EvaluationController : ControllerBase, IApiAdapter
|
||||
{
|
||||
private readonly IServiceProvider _services;
|
||||
public EvaluationController(IServiceProvider services)
|
||||
{
|
||||
_services = services;
|
||||
}
|
||||
|
||||
[HttpPost("/evaluation")]
|
||||
public async Task<EvaluationResult> RunTask([FromBody] EvaluationRequest request)
|
||||
{
|
||||
var eval = _services.GetRequiredService<IEvaluatingService>();
|
||||
return await eval.Evaluate(request);
|
||||
}
|
||||
}
|
||||
|
|
@ -15,14 +15,18 @@
|
|||
|
||||
"Router": {
|
||||
"RouterId": "01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a",
|
||||
"RouterName": "PizzaBot",
|
||||
"Description": "Pizza restaurant AI Bot",
|
||||
"UseTextCompletion": false,
|
||||
"EnableReasoning": false,
|
||||
"Provider": "azure-openai",
|
||||
"Model": "gpt-3.5-turbo"
|
||||
},
|
||||
|
||||
"Evaluator": {
|
||||
"EvaluatorId": "dfd9b46d-d00c-40af-8a75-3fbdc2b89869",
|
||||
"Provider": "azure-openai",
|
||||
"Model": "gpt-3.5-turbo"
|
||||
},
|
||||
|
||||
"Agent": {
|
||||
"DataDir": "agents",
|
||||
"TemplateFormat": "liquid",
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
What is the next step based on the CONVERSATION? Or you can handle without asking specific agent.
|
||||
|
||||
Response must be in JSON format
|
||||
{% if enabled_reasoning -%}
|
||||
{% if enabled_reasoning %}
|
||||
{
|
||||
"function":"route_to_agent"
|
||||
}
|
||||
{%- else -%}
|
||||
{% else %}
|
||||
{
|
||||
"function":"route_to_agent",
|
||||
"reason":"the reason why you select this function or agent",
|
||||
|
|
@ -14,7 +14,7 @@ Response must be in JSON format
|
|||
"user_goal_agent":"agent who can achieve user original goal",
|
||||
"args": {}
|
||||
}
|
||||
{%- endif %}
|
||||
{% endif %}
|
||||
|
||||
If the user has no other tasks need help with, set function as conversation_end with reason and reply user courteously.
|
||||
If the user wants to reach out to real human being, set function as human_intervention_needed with reason and reply user courteously.
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"name": "EvaluationAgent",
|
||||
"description": "Evaluate the performance of the LLM agents",
|
||||
"createdDateTime": "2023-08-18T00:00:00Z",
|
||||
"updatedDateTime": "2023-08-18T00:00:00Z",
|
||||
"id": "dfd9b46d-d00c-40af-8a75-3fbdc2b89869"
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
This is a model evaluation program, which interactive with model to complete a certain task based on the background information given to you.
|
||||
|
||||
{{ task_prompt }}
|
||||
|
||||
user: Hi!
|
||||
assistant: Hello, How can I help you?
|
||||
user:
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
Role: You're a customer who is going to buy a pizza.
|
||||
* You like pepperoni flavor.
|
||||
* You will pay the order in cash.
|
||||
* Your address is 347 S Gladstone Ave, Aurora, IL 60506.
|
||||
* Your phone number is +16308926431
|
||||
|
||||
Requirments:
|
||||
* You want to know what kind of pizza do they have.
|
||||
* You want to buy three piece of pizza.
|
||||
* Say Bye if the order is placed and payment is completed.
|
||||
Loading…
Reference in a new issue