Support to change Host Agent and used model.

This commit is contained in:
Haiping Chen 2024-01-16 11:38:45 -06:00
parent a6761fc90c
commit bcf56767be
23 changed files with 139 additions and 61 deletions

View file

@ -4,6 +4,7 @@ public class AgentSettings
{
public string DataDir { get; set; } = string.Empty;
public string TemplateFormat { get; set; } = "liquid";
public string HostAgentId { get; set; } = string.Empty;
/// <summary>
/// This is the default LLM config for agent

View file

@ -2,7 +2,9 @@ using BotSharp.Abstraction.MLTasks.Settings;
namespace BotSharp.Abstraction.MLTasks;
public interface ILlmProviderSettingService
public interface ILlmProviderService
{
LlmModelSetting GetSetting(string provider, string model);
List<string> GetProviders();
List<LlmModelSetting> GetProviderModels(string provider);
}

View file

@ -1,9 +1,11 @@
using System.Threading;
namespace BotSharp.Abstraction.MLTasks;
public interface ITextEmbedding
{
/// <summary>
/// The Embedding provider like Microsoft Azure, OpenAI, ClaudAI
/// </summary>
string Provider { get; }
int Dimension { get; }
Task<float[]> GetVectorAsync(string text);
Task<List<float[]>> GetVectorsAsync(List<string> texts);

View file

@ -18,7 +18,7 @@ public class AgentPlugin : IBotSharpPlugin
public void RegisterDI(IServiceCollection services, IConfiguration config)
{
services.AddScoped<ILlmProviderSettingService, LlmProviderSettingService>();
services.AddScoped<ILlmProviderService, LlmProviderService>();
services.AddScoped<IAgentService, AgentService>();
services.AddScoped(provider =>

View file

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
@ -45,6 +45,8 @@
</PropertyGroup>
<ItemGroup>
<None Remove="data\agents\01e2fc5c-2c89-4ec7-8470-7688608b496c\agent.json" />
<None Remove="data\agents\01e2fc5c-2c89-4ec7-8470-7688608b496c\instruction.liquid" />
<None Remove="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\agent.json" />
<None Remove="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\instruction.liquid" />
<None Remove="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\next_step_prompt.hf_planner.liquid" />
@ -55,6 +57,12 @@
</ItemGroup>
<ItemGroup>
<Content Include="data\agents\01e2fc5c-2c89-4ec7-8470-7688608b496c\agent.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="data\agents\01e2fc5c-2c89-4ec7-8470-7688608b496c\instruction.liquid">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\agent.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>

View file

@ -38,7 +38,7 @@ public class TokenStatistics : ITokenStatistics
_promptTokenCount += stats.PromptCount;
_completionTokenCount += stats.CompletionCount;
var settingsService = _services.GetRequiredService<ILlmProviderSettingService>();
var settingsService = _services.GetRequiredService<ILlmProviderService>();
var settings = settingsService.GetSetting(stats.Provider, _model);
_promptCost += stats.PromptCount / 1000f * settings.PromptCost;

View file

@ -26,7 +26,7 @@ public class CompletionProvider
model = state.GetState("model", model ?? "gpt-35-turbo-4k");
}
var settingsService = services.GetRequiredService<ILlmProviderSettingService>();
var settingsService = services.GetRequiredService<ILlmProviderService>();
var settings = settingsService.GetSetting(provider, model);
if (settings.Type == LlmModelType.Text)

View file

@ -1,19 +1,43 @@
using BotSharp.Abstraction.MLTasks;
using BotSharp.Abstraction.MLTasks.Settings;
using BotSharp.Abstraction.Settings;
namespace BotSharp.Core.Infrastructures;
public class LlmProviderSettingService : ILlmProviderSettingService
public class LlmProviderService : ILlmProviderService
{
private readonly IServiceProvider _services;
private readonly ILogger _logger;
public LlmProviderSettingService(IServiceProvider services, ILogger<LlmProviderSettingService> logger)
public LlmProviderService(IServiceProvider services, ILogger<LlmProviderService> logger)
{
_services = services;
_logger = logger;
}
public List<string> GetProviders()
{
var providers = new List<string>();
var services1 = _services.GetServices<ITextCompletion>();
providers.AddRange(services1.Select(x => x.Provider));
var services2 = _services.GetServices<IChatCompletion>();
providers.AddRange(services2.Select(x => x.Provider));
var services3 = _services.GetServices<ITextEmbedding>();
providers.AddRange(services3.Select(x => x.Provider));
return providers.Distinct().ToList();
}
public List<LlmModelSetting> GetProviderModels(string provider)
{
var settingService = _services.GetRequiredService<ISettingService>();
return settingService.Bind<List<LlmProviderSetting>>($"LlmProviders")
.FirstOrDefault(x => x.Provider.Equals(provider))
?.Models ?? new List<LlmModelSetting>();
}
public LlmModelSetting? GetSetting(string provider, string model)
{
var settings = _services.GetRequiredService<List<LlmProviderSetting>>();

View file

@ -41,9 +41,9 @@ public class SettingService : ISettingService
public static string Mask(string value)
{
if (value == null)
if (string.IsNullOrEmpty(value))
{
return null;
return string.Empty;
}
value = value.Substring(0, value.Length / 2 - 1)
+ string.Join("", Enumerable.Repeat("*", value.Length / 2));

View file

@ -0,0 +1,10 @@
{
"name": "Chatbot",
"description": "AI chatbot that can do variaty of tasks",
"createdDateTime": "2024-01-15T10:39:32Z",
"updatedDateTime": "2024-01-15T14:39:32Z",
"id": "01e2fc5c-2c89-4ec7-8470-7688608b496c",
"iconUrl": "/images/users/bot.png",
"disabled": false,
"isPublic": true
}

View file

@ -0,0 +1 @@
You are a AI Assistant. You can answer user's question.

View file

@ -1,5 +1,3 @@
using BotSharp.Abstraction.Routing.Settings;
namespace BotSharp.OpenAPI.Controllers;
[Authorize]

View file

@ -0,0 +1,29 @@
using BotSharp.Abstraction.MLTasks;
using BotSharp.Abstraction.MLTasks.Settings;
namespace BotSharp.OpenAPI.Controllers;
[Authorize]
[ApiController]
public class LlmProviderController : ControllerBase
{
private readonly IServiceProvider _services;
private readonly ILlmProviderService _llmProvider;
public LlmProviderController(IServiceProvider services, ILlmProviderService llmProvider)
{
_services = services;
_llmProvider = llmProvider;
}
[HttpGet("/llm-providers")]
public IEnumerable<string> GetLlmProviders()
{
return _llmProvider.GetProviders();
}
[HttpGet("/llm-provider/{provider}/models")]
public IEnumerable<LlmModelSetting> GetLlmProviderModels([FromRoute] string provider)
{
return _llmProvider.GetProviderModels(provider);
}
}

View file

@ -12,7 +12,7 @@ public class ProviderHelper
{
public static OpenAIClient GetClient(string model, IServiceProvider services)
{
var settingsService = services.GetRequiredService<ILlmProviderSettingService>();
var settingsService = services.GetRequiredService<ILlmProviderService>();
var settings = settingsService.GetSetting("azure-openai", model);
var client = new OpenAIClient(new Uri(settings.Endpoint), new AzureKeyCredential(settings.ApiKey));
return client;

View file

@ -6,5 +6,5 @@ public class InferenceInputOptions
public bool UseCache { get; set; } = true;
[JsonPropertyName("wait_for_model")]
public bool WaitForModel { get; set; } = false;
public bool WaitForModel { get; set; } = true;
}

View file

@ -3,10 +3,10 @@ namespace BotSharp.Plugin.HuggingFace.DataModels;
public class InferenceInputParameters
{
[JsonPropertyName("temperature")]
public float Temperature { get; set; } = 1.0f;
public float Temperature { get; set; } = 0.7f;
[JsonPropertyName("max_new_tokens")]
public int MaxNewTokens { get; set; } = 250;
public int MaxNewTokens { get; set; } = 128;
[JsonPropertyName("return_full_text")]
public bool ReturnFullText { get; set; } = false;

View file

@ -1,6 +1,6 @@
namespace BotSharp.Plugin.HuggingFace.DataModels;
public class FalconLlmResponse
public class TextGenResponse
{
[JsonPropertyName("generated_text")]
public string GeneratedText { get; set; }

View file

@ -31,34 +31,27 @@ public class ChatCompletionProvider : IChatCompletion
var hooks = _services.GetServices<IContentGeneratingHook>().ToList();
// Before chat completion hook
Task.WaitAll(hooks.Select(hook =>
hook.BeforeGenerating(agent, conversations)).ToArray());
foreach (var hook in hooks)
{
await hook.BeforeGenerating(agent, conversations);
}
var content = string.Join("\r\n", conversations.Select(x => $"{AgentRole.System}: {x.Content}")).Trim();
var content = string.Join("\r\n", conversations.Select(x => $"{x.Role}: {x.Content}")).Trim();
content += $"\r\n{AgentRole.Assistant}: ";
var prompt = agent.Instruction + "\r\n" + content;
var convSetting = _services.GetRequiredService<ConversationSetting>();
if (convSetting.ShowVerboseLog)
{
_logger.LogInformation(prompt);
}
var api = _services.GetRequiredService<IInferenceApi>();
var space = _model.Split('/')[0];
var model = _model.Split("/")[1];
var response = await api.Post(space, model, new InferenceInput
var response = await api.TextGenerate(space, model, new InferenceInput
{
Inputs = prompt
});
var falcon = JsonSerializer.Deserialize<List<FalconLlmResponse>>(response);
var message = falcon[0].GeneratedText.Trim();
_logger.LogInformation($"[{agent.Name}] {AgentRole.Assistant}: {message}");
var message = response[0].GeneratedText.Trim();
var msg = new RoleDialogModel(AgentRole.Assistant, message)
{
@ -66,11 +59,15 @@ public class ChatCompletionProvider : IChatCompletion
};
// After chat completion hook
Task.WaitAll(hooks.Select(hook =>
hook.AfterGenerated(msg, new TokenStatsModel
foreach (var hook in hooks)
{
await hook.AfterGenerated(msg, new TokenStatsModel
{
Prompt = prompt,
Provider = Provider,
Model = _model
})).ToArray());
});
}
// Text response received
await onMessageReceived(msg);
@ -93,36 +90,37 @@ public class ChatCompletionProvider : IChatCompletion
var hooks = _services.GetServices<IContentGeneratingHook>().ToList();
// Before chat completion hook
Task.WaitAll(hooks.Select(hook =>
hook.BeforeGenerating(agent, conversations)).ToArray());
foreach (var hook in hooks)
{
await hook.BeforeGenerating(agent, conversations);
}
var content = string.Join("\r\n", conversations.Select(x => $"{AgentRole.System}: {x.Content}")).Trim();
var content = string.Join("\r\n", conversations.Select(x => $"{x.Role}: {x.Content}")).Trim();
content += $"\r\n{AgentRole.Assistant}: ";
var agentService = _services.GetRequiredService<IAgentService>();
var instruction = agentService.RenderedInstruction(agent);
var prompt = instruction + "\r\n" + content;
var convSetting = _services.GetRequiredService<ConversationSetting>();
if (convSetting.ShowVerboseLog)
{
_logger.LogInformation(prompt);
}
var api = _services.GetRequiredService<IInferenceApi>();
var space = _model.Split('/')[0];
var model = _model.Split("/")[1];
var response = api.Post(space, model, new InferenceInput
var response = await api.TextGenerate(space, model, new InferenceInput
{
Inputs = prompt
}).Result;
Inputs = prompt,
Parameters = new InferenceInputParameters
{
MaxNewTokens = 64,
Temperature = 0.7f
}
});
var falcon = JsonSerializer.Deserialize<List<FalconLlmResponse>>(response);
var message = falcon[0].GeneratedText.Trim();
_logger.LogInformation($"[{agent.Name}] {AgentRole.Assistant}: {message}");
var message = response[0].GeneratedText
.Split($"{AgentRole.User}:")[0]
.Split($"{AgentRole.Assistant}:")[0]
.Trim();
var msg = new RoleDialogModel(AgentRole.Assistant, message)
{
@ -130,11 +128,15 @@ public class ChatCompletionProvider : IChatCompletion
};
// After chat completion hook
Task.WaitAll(hooks.Select(hook =>
hook.AfterGenerated(msg, new TokenStatsModel
foreach(var hook in hooks)
{
await hook.AfterGenerated(msg, new TokenStatsModel
{
Prompt = prompt,
Provider = Provider,
Model = _model
})).ToArray());
});
}
return msg;
}

View file

@ -8,5 +8,5 @@ namespace BotSharp.Plugin.HuggingFace.Services;
public interface IInferenceApi
{
[Post("/models/{space}/{model}")]
Task<JsonDocument> Post(string space, string model, [Body] InferenceInput input);
Task<List<TextGenResponse>> TextGenerate(string space, string model, [Body] InferenceInput input);
}

View file

@ -9,6 +9,8 @@ public class TextEmbeddingProvider : ITextEmbedding
private readonly IServiceProvider _services;
public int Dimension => 4096;
public string Provider => "llama-sharp";
public TextEmbeddingProvider(IServiceProvider services, LlamaSharpSettings settings)
{
_services = services;

View file

@ -23,6 +23,8 @@ public class fastTextEmbeddingProvider : ITextEmbedding
}
}
public string Provider => "meta-ai";
public fastTextEmbeddingProvider(IServiceProvider services)
{
_services = services;

View file

@ -6,7 +6,7 @@
<LangVersion>$(LangVersion)</LangVersion>
<VersionPrefix>$(BotSharpVersion)</VersionPrefix>
<GeneratePackageOnBuild>$(GeneratePackageOnBuild)</GeneratePackageOnBuild>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<GenerateDocumentationFile>$(GeneratePackageOnBuild)</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>

View file

@ -1,13 +1,8 @@
using BotSharp.Abstraction.MLTasks;
using Microsoft.Extensions.Configuration;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.AI.Embeddings;
using Microsoft.SemanticKernel.Memory;
using Microsoft.SemanticKernel.Plugins.Memory;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BotSharp.Plugin.SemanticKernel
@ -33,6 +28,8 @@ namespace BotSharp.Plugin.SemanticKernel
/// <inheritdoc/>
public int Dimension { get; set; }
public string Provider => "semantic-kernel";
/// <inheritdoc/>
public async Task<float[]> GetVectorAsync(string text)
{