Merge pull request #159 from hchen2020/master
print functions in verbose.
This commit is contained in:
commit
8dbceb9245
|
|
@ -1,4 +1,5 @@
|
|||
using BotSharp.Abstraction.Agents.Settings;
|
||||
using BotSharp.Abstraction.Functions.Models;
|
||||
|
||||
namespace BotSharp.Abstraction.Agents;
|
||||
|
||||
|
|
@ -34,7 +35,7 @@ public abstract class AgentHookBase : IAgentHook
|
|||
return true;
|
||||
}
|
||||
|
||||
public virtual bool OnFunctionsLoaded(ref List<string> functions)
|
||||
public virtual bool OnFunctionsLoaded(ref List<FunctionDef> functions)
|
||||
{
|
||||
_agent.Functions = functions;
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
using BotSharp.Abstraction.Functions.Models;
|
||||
|
||||
namespace BotSharp.Abstraction.Agents;
|
||||
|
||||
public interface IAgentHook
|
||||
|
|
@ -15,7 +17,7 @@ public interface IAgentHook
|
|||
|
||||
bool OnInstructionLoaded(string template, Dictionary<string, object> dict);
|
||||
|
||||
bool OnFunctionsLoaded(ref List<string> functions);
|
||||
bool OnFunctionsLoaded(ref List<FunctionDef> functions);
|
||||
|
||||
bool OnSamplesLoaded(ref string samples);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using BotSharp.Abstraction.Functions.Models;
|
||||
using BotSharp.Abstraction.Routing.Models;
|
||||
|
||||
namespace BotSharp.Abstraction.Agents.Models;
|
||||
|
|
@ -32,7 +33,7 @@ public class Agent
|
|||
/// Functions
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public List<string> Functions { get; set; }
|
||||
public List<FunctionDef> Functions { get; set; } = new List<FunctionDef>();
|
||||
|
||||
/// <summary>
|
||||
/// Responses
|
||||
|
|
@ -102,9 +103,9 @@ public class Agent
|
|||
return this;
|
||||
}
|
||||
|
||||
public Agent SetFunctions(List<string> functions)
|
||||
public Agent SetFunctions(List<FunctionDef> functions)
|
||||
{
|
||||
Functions = functions ?? new List<string>();
|
||||
Functions = functions ?? new List<FunctionDef>();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
using System.Text.Json;
|
||||
|
||||
namespace BotSharp.Abstraction.Functions.Models;
|
||||
|
||||
public class FunctionDef
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Description { get; set; }
|
||||
public JsonDocument Parameters { get; set; }
|
||||
public FunctionParametersDef Parameters { get; set; } = new FunctionParametersDef();
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
using System.Text.Json;
|
||||
|
||||
namespace BotSharp.Abstraction.Functions.Models;
|
||||
|
||||
public class FunctionParametersDef
|
||||
{
|
||||
[JsonPropertyName("type")]
|
||||
public string Type { get; set; } = "object";
|
||||
|
||||
/// <summary>
|
||||
/// ParameterPropertyDef
|
||||
/// {
|
||||
/// "field_name": {}
|
||||
/// }
|
||||
/// </summary>
|
||||
[JsonPropertyName("properties")]
|
||||
public JsonDocument Properties { get; set; } = JsonSerializer.Deserialize<JsonDocument>("{}");
|
||||
|
||||
[JsonPropertyName("required")]
|
||||
public List<string> Required { get; set; } = new List<string>();
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
namespace BotSharp.Abstraction.Functions.Models;
|
||||
|
||||
public class ParameterPropertyDef
|
||||
{
|
||||
public string Type { get; set; } = "string";
|
||||
public string Description { get; set; }
|
||||
}
|
||||
|
|
@ -3,6 +3,10 @@ using BotSharp.Abstraction.Models;
|
|||
|
||||
namespace BotSharp.Abstraction.Routing;
|
||||
|
||||
/// <summary>
|
||||
/// The routing handler will be injected to Router's FUNCTIONS section of the system prompt
|
||||
/// So the handler will be invoked by LLM autonomously.
|
||||
/// </summary>
|
||||
public interface IRoutingHandler
|
||||
{
|
||||
string Name { get; }
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using BotSharp.Abstraction.Agents.Models;
|
||||
using BotSharp.Abstraction.Functions.Models;
|
||||
using BotSharp.Abstraction.Repositories;
|
||||
using System.IO;
|
||||
|
||||
|
|
@ -114,14 +115,13 @@ public partial class AgentService
|
|||
return templates;
|
||||
}
|
||||
|
||||
private List<string> FetchFunctionsFromFile(string fileDir)
|
||||
private List<FunctionDef> FetchFunctionsFromFile(string fileDir)
|
||||
{
|
||||
var file = Path.Combine(fileDir, "functions.json");
|
||||
if (!File.Exists(file)) return new List<string>();
|
||||
if (!File.Exists(file)) return new List<FunctionDef>();
|
||||
|
||||
var functionsJson = File.ReadAllText(file);
|
||||
var functionDefs = JsonSerializer.Deserialize<List<Abstraction.Functions.Models.FunctionDef>>(functionsJson, _options);
|
||||
var functions = functionDefs.Select(x => JsonSerializer.Serialize(x, _options)).ToList();
|
||||
var functions = JsonSerializer.Deserialize<List<FunctionDef>>(functionsJson, _options);
|
||||
return functions;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
using BotSharp.Abstraction.Agents.Models;
|
||||
using BotSharp.Abstraction.Routing;
|
||||
using BotSharp.Abstraction.Routing.Settings;
|
||||
using BotSharp.Abstraction.Templating;
|
||||
|
||||
namespace BotSharp.Core.Agents.Services;
|
||||
|
|
@ -34,7 +32,7 @@ public partial class AgentService
|
|||
hook.OnInstructionLoaded(agent.Instruction, templateDict);
|
||||
}
|
||||
|
||||
if (!agent.Functions.IsNullOrEmpty())
|
||||
if (agent.Functions != null)
|
||||
{
|
||||
var functions = agent.Functions;
|
||||
hook.OnFunctionsLoaded(ref functions);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using BotSharp.Abstraction.Agents.Models;
|
||||
using BotSharp.Abstraction.Functions.Models;
|
||||
using BotSharp.Abstraction.Repositories;
|
||||
using BotSharp.Abstraction.Routing.Models;
|
||||
using System.IO;
|
||||
|
|
@ -22,7 +23,7 @@ public partial class AgentService
|
|||
record.Profiles = agent.Profiles ?? new List<string>();
|
||||
record.RoutingRules = agent.RoutingRules ?? new List<RoutingRule>();
|
||||
record.Instruction = agent.Instruction ?? string.Empty;
|
||||
record.Functions = agent.Functions ?? new List<string>();
|
||||
record.Functions = agent.Functions ?? new List<FunctionDef>();
|
||||
record.Templates = agent.Templates ?? new List<AgentTemplate>();
|
||||
record.Responses = agent.Responses ?? new List<AgentResponse>();
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,8 @@ public partial class AgentService : IAgentService
|
|||
{
|
||||
PropertyNameCaseInsensitive = true,
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||
WriteIndented = true
|
||||
WriteIndented = true,
|
||||
AllowTrailingCommas = true
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ using BotSharp.Abstraction.Templating;
|
|||
using BotSharp.Core.Instructs;
|
||||
using BotSharp.Abstraction.Instructs;
|
||||
using BotSharp.Abstraction.Routing;
|
||||
using System.Reflection;
|
||||
using BotSharp.Core.Routing.Hooks;
|
||||
|
||||
namespace BotSharp.Core;
|
||||
|
||||
|
|
@ -63,6 +63,8 @@ public static class BotSharpServiceCollectionExtensions
|
|||
services.AddScoped<IInstructService, InstructService>();
|
||||
services.AddScoped<ITokenStatistics, TokenStatistics>();
|
||||
|
||||
services.AddScoped<IAgentHook, RoutingAgentHook>();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ public class TokenStatistics : ITokenStatistics
|
|||
|
||||
public void PrintStatistics()
|
||||
{
|
||||
var stats = $"Token Usage: {_promptTokenCount} prompt + {_completionTokenCount} completion = {Total} total tokens. One-Way cost: ${Cost:C4}, accumulated cost: ${AccumulatedCost:C4}. Model: {_model}";
|
||||
var stats = $"Token Usage: {_promptTokenCount} prompt + {_completionTokenCount} completion = {Total} total tokens. One-Way cost: {Cost:C4}, accumulated cost: {AccumulatedCost:C4}. [{_model}]";
|
||||
#if DEBUG
|
||||
Console.WriteLine(stats, Color.DarkGray);
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -372,7 +372,7 @@ public class FileRepository : IBotSharpRepository
|
|||
File.WriteAllText(instructionFile, instruction);
|
||||
}
|
||||
|
||||
private void UpdateAgentFunctions(string agentId, List<string> inputFunctions)
|
||||
private void UpdateAgentFunctions(string agentId, List<FunctionDef> inputFunctions)
|
||||
{
|
||||
if (inputFunctions.IsNullOrEmpty()) return;
|
||||
|
||||
|
|
@ -385,8 +385,7 @@ public class FileRepository : IBotSharpRepository
|
|||
var functions = new List<string>();
|
||||
foreach (var function in inputFunctions)
|
||||
{
|
||||
var functionDef = JsonSerializer.Deserialize<FunctionDef>(function, _options);
|
||||
functions.Add(JsonSerializer.Serialize(functionDef, _options));
|
||||
functions.Add(JsonSerializer.Serialize(function, _options));
|
||||
}
|
||||
|
||||
var functionText = JsonSerializer.Serialize(functions, _options);
|
||||
|
|
@ -730,14 +729,13 @@ public class FileRepository : IBotSharpRepository
|
|||
return instruction;
|
||||
}
|
||||
|
||||
private List<string> FetchFunctions(string fileDir)
|
||||
private List<FunctionDef> FetchFunctions(string fileDir)
|
||||
{
|
||||
var file = Path.Combine(fileDir, "functions.json");
|
||||
if (!File.Exists(file)) return new List<string>();
|
||||
if (!File.Exists(file)) return new List<FunctionDef>();
|
||||
|
||||
var functionsJson = File.ReadAllText(file);
|
||||
var functionDefs = JsonSerializer.Deserialize<List<FunctionDef>>(functionsJson, _options);
|
||||
var functions = functionDefs.Select(x => JsonSerializer.Serialize(x, _options)).ToList();
|
||||
var functions = JsonSerializer.Deserialize<List<FunctionDef>>(functionsJson, _options);
|
||||
return functions;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
using BotSharp.Abstraction.Functions.Models;
|
||||
|
||||
namespace BotSharp.Core.Routing.Hooks;
|
||||
|
||||
public class RoutingAgentHook : AgentHookBase
|
||||
{
|
||||
public RoutingAgentHook(IServiceProvider services, AgentSettings settings)
|
||||
: base(services, settings)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool OnFunctionsLoaded(ref List<FunctionDef> functions)
|
||||
{
|
||||
functions.Add(new FunctionDef
|
||||
{
|
||||
Name = "fallback_to_router",
|
||||
Description = "If the user's request is beyond your capabilities, you can call this function for help."
|
||||
});
|
||||
return base.OnFunctionsLoaded(ref functions);
|
||||
}
|
||||
}
|
||||
|
|
@ -18,51 +18,48 @@ public partial class RoutingService
|
|||
var agent = await agentService.LoadAgent(agentId);
|
||||
|
||||
var chatCompletion = CompletionProvider.GetChatCompletion(_services);
|
||||
RoleDialogModel response = chatCompletion.GetChatCompletions(agent, Dialogs);
|
||||
|
||||
RoleDialogModel response = null;
|
||||
await chatCompletion.GetChatCompletionsAsync(agent, Dialogs,
|
||||
async msg =>
|
||||
if (response.Role == AgentRole.Function)
|
||||
{
|
||||
var fn = response;
|
||||
// execute function
|
||||
// Save states
|
||||
SaveStateByArgs(JsonSerializer.Deserialize<JsonDocument>(fn.FunctionArgs));
|
||||
|
||||
var conversationService = _services.GetRequiredService<IConversationService>();
|
||||
// Call functions
|
||||
await conversationService.CallFunctions(fn);
|
||||
|
||||
if (string.IsNullOrEmpty(fn.Content))
|
||||
{
|
||||
response = msg;
|
||||
}, async fn =>
|
||||
fn.Content = fn.ExecutionResult;
|
||||
}
|
||||
|
||||
Dialogs.Add(fn);
|
||||
|
||||
if (!fn.StopCompletion)
|
||||
{
|
||||
// execute function
|
||||
// Save states
|
||||
SaveStateByArgs(JsonSerializer.Deserialize<JsonDocument>(fn.FunctionArgs));
|
||||
|
||||
var conversationService = _services.GetRequiredService<IConversationService>();
|
||||
// Call functions
|
||||
await conversationService.CallFunctions(fn);
|
||||
|
||||
if (string.IsNullOrEmpty(fn.Content))
|
||||
// Find response template
|
||||
var templateService = _services.GetRequiredService<IResponseTemplateService>();
|
||||
var quickResponse = await templateService.RenderFunctionResponse(agent.Id, fn);
|
||||
if (!string.IsNullOrEmpty(quickResponse))
|
||||
{
|
||||
fn.Content = fn.ExecutionResult;
|
||||
}
|
||||
|
||||
Dialogs.Add(fn);
|
||||
|
||||
if (!fn.StopCompletion)
|
||||
{
|
||||
// Find response template
|
||||
var templateService = _services.GetRequiredService<IResponseTemplateService>();
|
||||
var quickResponse = await templateService.RenderFunctionResponse(agent.Id, fn);
|
||||
if (!string.IsNullOrEmpty(quickResponse))
|
||||
response = new RoleDialogModel(AgentRole.Assistant, quickResponse)
|
||||
{
|
||||
response = new RoleDialogModel(AgentRole.Assistant, quickResponse)
|
||||
{
|
||||
CurrentAgentId = agent.Id
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
response = await InvokeAgent(fn.CurrentAgentId);
|
||||
}
|
||||
CurrentAgentId = agent.Id
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
response = fn;
|
||||
response = await InvokeAgent(fn.CurrentAgentId);
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
response = fn;
|
||||
}
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using BotSharp.Abstraction.Agents.Models;
|
||||
using BotSharp.Abstraction.Functions.Models;
|
||||
using BotSharp.Abstraction.Routing.Models;
|
||||
|
||||
namespace BotSharp.OpenAPI.ViewModels.Agents;
|
||||
|
|
@ -9,7 +10,7 @@ public class AgentCreationModel
|
|||
public string Description { get; set; }
|
||||
public string Instruction { get; set; }
|
||||
public List<AgentTemplate> Templates { get; set; }
|
||||
public List<string> Functions { get; set; }
|
||||
public List<FunctionDef> Functions { get; set; }
|
||||
public List<AgentResponse> Responses { get; set; }
|
||||
public bool IsPublic { get; set; }
|
||||
public bool AllowRouting { get; set; }
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using BotSharp.Abstraction.Agents.Models;
|
||||
using BotSharp.Abstraction.Functions.Models;
|
||||
using BotSharp.Abstraction.Routing.Models;
|
||||
|
||||
namespace BotSharp.OpenAPI.ViewModels.Agents;
|
||||
|
|
@ -26,7 +27,7 @@ public class AgentUpdateModel
|
|||
/// <summary>
|
||||
/// Functions
|
||||
/// </summary>
|
||||
public List<string>? Functions { get; set; }
|
||||
public List<FunctionDef>? Functions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Routes
|
||||
|
|
@ -61,7 +62,7 @@ public class AgentUpdateModel
|
|||
.ToList() ?? new List<RoutingRule>(),
|
||||
Instruction = Instruction ?? string.Empty,
|
||||
Templates = Templates ?? new List<AgentTemplate>(),
|
||||
Functions = Functions ?? new List<string>(),
|
||||
Functions = Functions ?? new List<FunctionDef>(),
|
||||
Responses = Responses ?? new List<AgentResponse>()
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using BotSharp.Abstraction.Agents.Models;
|
||||
using BotSharp.Abstraction.Functions.Models;
|
||||
using BotSharp.Abstraction.Routing.Models;
|
||||
|
||||
namespace BotSharp.OpenAPI.ViewModels.Agents;
|
||||
|
|
@ -10,7 +11,7 @@ public class AgentViewModel
|
|||
public string Description { get; set; }
|
||||
public string Instruction { get; set; }
|
||||
public List<AgentTemplate> Templates { get; set; }
|
||||
public List<string> Functions { get; set; }
|
||||
public List<FunctionDef> Functions { get; set; }
|
||||
public List<AgentResponse> Responses { get; set; }
|
||||
public bool IsPublic { get; set; }
|
||||
public bool AllowRouting { get; set; }
|
||||
|
|
|
|||
|
|
@ -84,17 +84,6 @@ public class ChatCompletionProvider : IChatCompletion
|
|||
return samples;
|
||||
}
|
||||
|
||||
public List<FunctionDef> GetFunctions(List<string> functionsJson)
|
||||
{
|
||||
var functions = functionsJson?.Select(x => JsonSerializer.Deserialize<FunctionDef>(x, new JsonSerializerOptions
|
||||
{
|
||||
PropertyNameCaseInsensitive = true,
|
||||
AllowTrailingCommas = true
|
||||
}))?.ToList() ?? new List<FunctionDef>();
|
||||
|
||||
return functions;
|
||||
}
|
||||
|
||||
public RoleDialogModel GetChatCompletions(Agent agent, List<RoleDialogModel> conversations)
|
||||
{
|
||||
var (client, deploymentModel) = GetClient();
|
||||
|
|
@ -263,8 +252,7 @@ public class ChatCompletionProvider : IChatCompletion
|
|||
chatCompletionsOptions.Messages.Add(new ChatMessage(message.Role, message.Content));
|
||||
}
|
||||
|
||||
var functions = GetFunctions(agent.Functions);
|
||||
foreach (var function in functions)
|
||||
foreach (var function in agent.Functions)
|
||||
{
|
||||
chatCompletionsOptions.Functions.Add(new FunctionDefinition
|
||||
{
|
||||
|
|
@ -301,14 +289,23 @@ public class ChatCompletionProvider : IChatCompletion
|
|||
var convSetting = _services.GetRequiredService<ConversationSetting>();
|
||||
if (convSetting.ShowVerboseLog)
|
||||
{
|
||||
var verbose = string.Join("\n", chatCompletionsOptions.Messages.Select(x =>
|
||||
_logger.LogInformation("VERBOSE COMPLETION MESSAGES");
|
||||
var verbose = string.Join("\r\n", chatCompletionsOptions.Messages.Select(x =>
|
||||
{
|
||||
return x.Role == ChatRole.Function ?
|
||||
$"{x.Role}: {x.Name} {x.Content}" :
|
||||
$"{x.Role}: {x.Name} => {x.Content}" :
|
||||
$"{x.Role}: {x.Content}";
|
||||
}));
|
||||
|
||||
_logger.LogInformation(verbose);
|
||||
|
||||
_logger.LogInformation("VERBOSE FUNCTIONS");
|
||||
verbose = string.Join("\r\n", chatCompletionsOptions.Functions.Select(x =>
|
||||
{
|
||||
return $"{x.Name}: {x.Description}\r\n{x.Parameters}";
|
||||
}));
|
||||
|
||||
_logger.LogInformation(verbose);
|
||||
}
|
||||
|
||||
return chatCompletionsOptions;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using BotSharp.Abstraction.Agents.Models;
|
||||
using BotSharp.Abstraction.Functions.Models;
|
||||
using BotSharp.Plugin.MongoStorage.Models;
|
||||
|
||||
namespace BotSharp.Plugin.MongoStorage.Collections;
|
||||
|
|
@ -9,7 +10,7 @@ public class AgentCollection : MongoBase
|
|||
public string Description { get; set; }
|
||||
public string Instruction { get; set; }
|
||||
public List<AgentTemplate> Templates { get; set; }
|
||||
public List<string> Functions { get; set; }
|
||||
public List<FunctionDef> Functions { get; set; }
|
||||
public List<AgentResponse> Responses { get; set; }
|
||||
public bool IsPublic { get; set; }
|
||||
public bool AllowRouting { get; set; }
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using BotSharp.Abstraction.Agents.Models;
|
||||
using BotSharp.Abstraction.Conversations.Models;
|
||||
using BotSharp.Abstraction.Functions.Models;
|
||||
using BotSharp.Abstraction.Routing.Models;
|
||||
using BotSharp.Abstraction.Users.Models;
|
||||
using BotSharp.Plugin.MongoStorage.Collections;
|
||||
|
|
@ -441,7 +442,7 @@ public class MongoRepository : IBotSharpRepository
|
|||
_dc.Agents.UpdateOne(filter, update);
|
||||
}
|
||||
|
||||
private void UpdateAgentFunctions(string agentId, List<string> functions)
|
||||
private void UpdateAgentFunctions(string agentId, List<FunctionDef> functions)
|
||||
{
|
||||
if (functions.IsNullOrEmpty()) return;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue