From 381deaa143d5b4a344d143e779b58b2922299877 Mon Sep 17 00:00:00 2001 From: Haiping Chen Date: Wed, 17 Jul 2024 16:03:46 -0500 Subject: [PATCH] knowledge learner --- .../Agents/Enums/BuiltInAgentId.cs | 24 +++++++ .../Infrastructures/Enums/StateConst.cs | 1 + .../Knowledges/Models/ExtractedKnowledge.cs | 10 +++ .../VectorStorage/IVectorDb.cs | 4 +- .../ConversationService.SendMessage.cs | 4 -- .../Routing/Functions/RouteToAgentFn.cs | 1 + .../instruction.liquid | 5 +- .../templates/planner_prompt.hf.liquid | 2 +- .../BotSharp.Plugin.AnthropicAI.csproj | 2 +- .../Providers/ChatCompletionProvider.cs | 11 +++- .../BotSharp.Plugin.KnowledgeBase.csproj | 26 ++++++++ .../Enum/UtilityName.cs | 6 ++ .../Functions/KnowledgeRetrievalFn.cs | 40 +++++++++++ .../Functions/MemorizeKnowledgeFn.cs | 47 +++++++++++++ .../Hooks/KnowledgeBaseAgentHook.cs | 66 +++++++++++++++++++ .../Hooks/KnowledgeBaseUtilityHook.cs | 11 ++++ .../KnowledgeBasePlugin.cs | 3 + .../MemVecDb/MemVectorDatabase.cs | 6 +- .../Services/KnowledgeService.cs | 2 +- .../agent.json | 16 +++++ .../functions/memorize_knowledge.json | 18 +++++ .../instruction.liquid | 2 + .../functions/knowledge_retrieval.json | 14 ++++ .../templates/knowledge_retrieval.fn.liquid | 3 + .../Providers/FaissDb.cs | 4 +- .../Embedding/TextEmbeddingProvider.cs | 2 +- .../BotSharp.Plugin.Qdrant/QdrantDb.cs | 34 ++++++---- .../templates/sql_executor.fn.liquid | 3 +- 28 files changed, 335 insertions(+), 32 deletions(-) create mode 100644 src/Infrastructure/BotSharp.Abstraction/Knowledges/Models/ExtractedKnowledge.cs create mode 100644 src/Plugins/BotSharp.Plugin.KnowledgeBase/Enum/UtilityName.cs create mode 100644 src/Plugins/BotSharp.Plugin.KnowledgeBase/Functions/KnowledgeRetrievalFn.cs create mode 100644 src/Plugins/BotSharp.Plugin.KnowledgeBase/Functions/MemorizeKnowledgeFn.cs create mode 100644 src/Plugins/BotSharp.Plugin.KnowledgeBase/Hooks/KnowledgeBaseAgentHook.cs create mode 100644 src/Plugins/BotSharp.Plugin.KnowledgeBase/Hooks/KnowledgeBaseUtilityHook.cs create mode 100644 src/Plugins/BotSharp.Plugin.KnowledgeBase/data/agents/01acc3e5-0af7-49e6-ad7a-a760bd12dc40/agent.json create mode 100644 src/Plugins/BotSharp.Plugin.KnowledgeBase/data/agents/01acc3e5-0af7-49e6-ad7a-a760bd12dc40/functions/memorize_knowledge.json create mode 100644 src/Plugins/BotSharp.Plugin.KnowledgeBase/data/agents/01acc3e5-0af7-49e6-ad7a-a760bd12dc40/instruction.liquid create mode 100644 src/Plugins/BotSharp.Plugin.KnowledgeBase/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/knowledge_retrieval.json create mode 100644 src/Plugins/BotSharp.Plugin.KnowledgeBase/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/knowledge_retrieval.fn.liquid diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/BuiltInAgentId.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/BuiltInAgentId.cs index dc1fb3123..58da1fd42 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/BuiltInAgentId.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/BuiltInAgentId.cs @@ -2,9 +2,33 @@ namespace BotSharp.Abstraction.Agents.Enums; public class BuiltInAgentId { + /// + /// A routing agent can be used as a base router. + /// public const string AIAssistant = "01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a"; + + /// + /// A demo agent used for open domain chatting + /// public const string Chatbot = "01e2fc5c-2c89-4ec7-8470-7688608b496c"; + + /// + /// Human customer service + /// public const string HumanSupport = "01dcc3e5-0af7-49e6-ad7a-a760bd12dc4b"; + + /// + /// Used as a container to host the shared tools/ utilities built in different plugins. + /// public const string UtilityAssistant = "6745151e-6d46-4a02-8de4-1c4f21c7da95"; + + /// + /// Used when router can't route to any existing task agent + /// public const string Fallback = "01fcc3e5-0af7-49e6-ad7a-a760bd12dc4d"; + + /// + /// Used by knowledgebase plugin to acquire domain knowledge + /// + public const string Learner = "01acc3e5-0af7-49e6-ad7a-a760bd12dc40"; } diff --git a/src/Infrastructure/BotSharp.Abstraction/Infrastructures/Enums/StateConst.cs b/src/Infrastructure/BotSharp.Abstraction/Infrastructures/Enums/StateConst.cs index 442c8ef81..c452b7abb 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Infrastructures/Enums/StateConst.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Infrastructures/Enums/StateConst.cs @@ -7,6 +7,7 @@ public class StateConst public const string NEXT_ACTION_AGENT = "next_action_agent"; public const string NEXT_ACTION_REASON = "next_action_reason"; public const string USER_GOAL_AGENT = "user_goal_agent"; + public const string AGENT_REDIRECTION_REASON = "agent_redirection_reason"; public const string LANGUAGE = "language"; } diff --git a/src/Infrastructure/BotSharp.Abstraction/Knowledges/Models/ExtractedKnowledge.cs b/src/Infrastructure/BotSharp.Abstraction/Knowledges/Models/ExtractedKnowledge.cs new file mode 100644 index 000000000..0043c437a --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Knowledges/Models/ExtractedKnowledge.cs @@ -0,0 +1,10 @@ +namespace BotSharp.Abstraction.Knowledges.Models; + +public class ExtractedKnowledge +{ + [JsonPropertyName("question")] + public string Question { get; set; } = string.Empty; + + [JsonPropertyName("answer")] + public string Answer { get; set; } = string.Empty; +} diff --git a/src/Infrastructure/BotSharp.Abstraction/VectorStorage/IVectorDb.cs b/src/Infrastructure/BotSharp.Abstraction/VectorStorage/IVectorDb.cs index c385153a9..68aaaa785 100644 --- a/src/Infrastructure/BotSharp.Abstraction/VectorStorage/IVectorDb.cs +++ b/src/Infrastructure/BotSharp.Abstraction/VectorStorage/IVectorDb.cs @@ -4,6 +4,6 @@ public interface IVectorDb { Task> GetCollections(); Task CreateCollection(string collectionName, int dim); - Task Upsert(string collectionName, string id, float[] vector, string text, Dictionary? payload = null); - Task> Search(string collectionName, float[] vector, int limit = 5); + Task Upsert(string collectionName, string id, float[] vector, string text, Dictionary? payload = null); + Task> Search(string collectionName, float[] vector, string returnFieldName, int limit = 5, float confidence = 0.5f); } diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs index 753a34491..790c64e2d 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs @@ -19,11 +19,7 @@ public async Task SendMessage(string agentId, Agent agent = await agentService.LoadAgent(agentId); var content = $"Received [{agent.Name}] {message.Role}: {message.Content}"; -#if DEBUG - Console.WriteLine(content); -#else _logger.LogInformation(content); -#endif message.CurrentAgentId = agent.Id; if (string.IsNullOrEmpty(message.SenderId)) diff --git a/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs b/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs index c9abf5511..7bf3171bd 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs @@ -89,6 +89,7 @@ public async Task Execute(RoleDialogModel message) // Stack redirection agent _context.Push(agentId, reason: $"REDIRECTION {reason}"); message.Content = reason; + states.SetState(StateConst.AGENT_REDIRECTION_REASON, reason, isNeedVersion: false); } } diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-0af7-49e6-ad7a-a760bd12dc4d/instruction.liquid b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-0af7-49e6-ad7a-a760bd12dc4d/instruction.liquid index ced0264cd..7e170f72c 100644 --- a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-0af7-49e6-ad7a-a760bd12dc4d/instruction.liquid +++ b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-0af7-49e6-ad7a-a760bd12dc4d/instruction.liquid @@ -1 +1,4 @@ -You are a smart AI Assistant. \ No newline at end of file +You are a smart AI Assistant. +{% if agent_redirection_reason %} +You've been reached out because: {{ agent_redirection_reason }} +{% endif %} \ No newline at end of file diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.hf.liquid b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.hf.liquid index 2404a04c3..740ed1341 100644 --- a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.hf.liquid +++ b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.hf.liquid @@ -1 +1 @@ -Break down the user’s most recent needs and figure out the instruction of next step. \ No newline at end of file +Break down the user’s most recent needs and figure out the instruction of next step without explanation. \ No newline at end of file diff --git a/src/Plugins/BotSharp.Plugin.AnthropicAI/BotSharp.Plugin.AnthropicAI.csproj b/src/Plugins/BotSharp.Plugin.AnthropicAI/BotSharp.Plugin.AnthropicAI.csproj index 708917195..5574afe56 100644 --- a/src/Plugins/BotSharp.Plugin.AnthropicAI/BotSharp.Plugin.AnthropicAI.csproj +++ b/src/Plugins/BotSharp.Plugin.AnthropicAI/BotSharp.Plugin.AnthropicAI.csproj @@ -11,7 +11,7 @@ - + diff --git a/src/Plugins/BotSharp.Plugin.AnthropicAI/Providers/ChatCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.AnthropicAI/Providers/ChatCompletionProvider.cs index 872021098..1a3a829b3 100644 --- a/src/Plugins/BotSharp.Plugin.AnthropicAI/Providers/ChatCompletionProvider.cs +++ b/src/Plugins/BotSharp.Plugin.AnthropicAI/Providers/ChatCompletionProvider.cs @@ -1,4 +1,5 @@ using Anthropic.SDK.Common; +using BotSharp.Abstraction.Conversations; using BotSharp.Abstraction.MLTasks.Settings; using System.Text.Json; using System.Text.Json.Nodes; @@ -160,13 +161,17 @@ public Task GetChatCompletionsStreamingAsync(Agent agent, List(); + var temperature = decimal.Parse(state.GetState("temperature", "0.0")); + var maxToken = int.Parse(state.GetState("max_tokens", "512")); + var parameters = new MessageParameters() { Messages = messages, - MaxTokens = 256, - Model = settings.Version, // AnthropicModels.Claude3Haiku + MaxTokens = maxToken, + Model = settings.Name, Stream = false, - Temperature = 0m, + Temperature = temperature, SystemMessage = instruction, Tools = new List() { } }; diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/BotSharp.Plugin.KnowledgeBase.csproj b/src/Plugins/BotSharp.Plugin.KnowledgeBase/BotSharp.Plugin.KnowledgeBase.csproj index bdb0c2304..27cd4c788 100644 --- a/src/Plugins/BotSharp.Plugin.KnowledgeBase/BotSharp.Plugin.KnowledgeBase.csproj +++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/BotSharp.Plugin.KnowledgeBase.csproj @@ -16,6 +16,31 @@ + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + @@ -23,6 +48,7 @@ + diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Enum/UtilityName.cs b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Enum/UtilityName.cs new file mode 100644 index 000000000..18a28c91f --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Enum/UtilityName.cs @@ -0,0 +1,6 @@ +namespace BotSharp.Plugin.KnowledgeBase.Enum; + +public class UtilityName +{ + public const string KnowledgeRetrieval = "knowledge-retrieval"; +} diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Functions/KnowledgeRetrievalFn.cs b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Functions/KnowledgeRetrievalFn.cs new file mode 100644 index 000000000..19a0c97f4 --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Functions/KnowledgeRetrievalFn.cs @@ -0,0 +1,40 @@ +using BotSharp.Abstraction.Functions; +using BotSharp.Core.Infrastructures; + +namespace BotSharp.Plugin.KnowledgeBase.Functions; + +public class KnowledgeRetrievalFn : IFunctionCallback +{ + public string Name => "knowledge_retrieval"; + + private readonly IServiceProvider _services; + private readonly KnowledgeBaseSettings _settings; + + public KnowledgeRetrievalFn(IServiceProvider services, KnowledgeBaseSettings settings) + { + _services = services; + _settings = settings; + } + + public async Task Execute(RoleDialogModel message) + { + var args = JsonSerializer.Deserialize(message.FunctionArgs ?? "{}"); + + var embedding = _services.GetServices() + .FirstOrDefault(x => x.GetType().FullName.EndsWith(_settings.TextEmbedding)); + + var vector = await embedding.GetVectorsAsync(new List + { + args.Question + }); + + var vectorDb = _services.GetRequiredService(); + + var id = Utilities.HashTextMd5(args.Question); + var knowledges = await vectorDb.Search("lessen", vector[0], "answer"); + + message.Content = string.Join("\r\n\r\n=====\r\n", knowledges); + + return true; + } +} diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Functions/MemorizeKnowledgeFn.cs b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Functions/MemorizeKnowledgeFn.cs new file mode 100644 index 000000000..2a20f0f02 --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Functions/MemorizeKnowledgeFn.cs @@ -0,0 +1,47 @@ +using BotSharp.Abstraction.Functions; +using BotSharp.Core.Infrastructures; + +namespace BotSharp.Plugin.KnowledgeBase.Functions; + +public class MemorizeKnowledgeFn : IFunctionCallback +{ + public string Name => "memorize_knowledge"; + + private readonly IServiceProvider _services; + private readonly KnowledgeBaseSettings _settings; + + public MemorizeKnowledgeFn(IServiceProvider services, KnowledgeBaseSettings settings) + { + _services = services; + _settings = settings; + } + + public async Task Execute(RoleDialogModel message) + { + var args = JsonSerializer.Deserialize(message.FunctionArgs ?? "{}"); + + var embedding = _services.GetServices() + .First(x => x.GetType().FullName.EndsWith(_settings.TextEmbedding)); + + var vector = await embedding.GetVectorsAsync(new List + { + args.Question + }); + + var vectorDb = _services.GetRequiredService(); + + await vectorDb.CreateCollection("lessen", vector[0].Length); + + var id = Utilities.HashTextMd5(args.Question); + var result = await vectorDb.Upsert("lessen", id, vector[0], + args.Question, + new Dictionary + { + { "answer", args.Answer } + }); + + message.Content = $"Save result: {(result ? "success" : "failed")}"; + + return true; + } +} diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Hooks/KnowledgeBaseAgentHook.cs b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Hooks/KnowledgeBaseAgentHook.cs new file mode 100644 index 000000000..2eebf75c5 --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Hooks/KnowledgeBaseAgentHook.cs @@ -0,0 +1,66 @@ +using BotSharp.Abstraction.Agents.Enums; +using BotSharp.Abstraction.Agents.Models; +using BotSharp.Abstraction.Functions.Models; +using BotSharp.Abstraction.Repositories; +using BotSharp.Plugin.KnowledgeBase.Enum; + +namespace BotSharp.Plugin.KnowledgeBase.Hooks; + +public class KnowledgeBaseAgentHook : AgentHookBase, IAgentHook +{ + public override string SelfId => string.Empty; + public KnowledgeBaseAgentHook(IServiceProvider services, AgentSettings settings) : base(services, settings) + { + + } + + public override void OnAgentLoaded(Agent agent) + { + var conv = _services.GetRequiredService(); + var isConvMode = conv.IsConversationMode(); + + if (isConvMode) + { + AddUtility(agent, UtilityName.KnowledgeRetrieval, "knowledge_retrieval"); + } + + base.OnAgentLoaded(agent); + } + + private void AddUtility(Agent agent, string utility, string functionName) + { + if (!IsEnableUtility(agent, utility)) return; + + var (prompt, fn) = GetPromptAndFunction(functionName); + if (fn != null) + { + if (!string.IsNullOrWhiteSpace(prompt)) + { + agent.Instruction += $"\r\n\r\n{prompt}\r\n\r\n"; + } + + if (agent.Functions == null) + { + agent.Functions = new List { fn }; + } + else + { + agent.Functions.Add(fn); + } + } + } + + private bool IsEnableUtility(Agent agent, string utility) + { + return !agent.Utilities.IsNullOrEmpty() && agent.Utilities.Contains(utility); + } + + private (string, FunctionDef?) GetPromptAndFunction(string functionName) + { + var db = _services.GetRequiredService(); + var agent = db.GetAgent(BuiltInAgentId.UtilityAssistant); + var prompt = agent?.Templates?.FirstOrDefault(x => x.Name.IsEqualTo($"{functionName}.fn"))?.Content ?? string.Empty; + var fn = agent?.Functions?.FirstOrDefault(x => x.Name.IsEqualTo(functionName)); + return (prompt, fn); + } +} diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Hooks/KnowledgeBaseUtilityHook.cs b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Hooks/KnowledgeBaseUtilityHook.cs new file mode 100644 index 000000000..fd163cbf2 --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Hooks/KnowledgeBaseUtilityHook.cs @@ -0,0 +1,11 @@ +using BotSharp.Plugin.KnowledgeBase.Enum; + +namespace BotSharp.Plugin.KnowledgeBase.Hooks; + +public class KnowledgeBaseUtilityHook : IAgentUtilityHook +{ + public void AddUtilities(List utilities) + { + utilities.Add(UtilityName.KnowledgeRetrieval); + } +} diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/KnowledgeBasePlugin.cs b/src/Plugins/BotSharp.Plugin.KnowledgeBase/KnowledgeBasePlugin.cs index 60fb0e8a8..51c390bf5 100644 --- a/src/Plugins/BotSharp.Plugin.KnowledgeBase/KnowledgeBasePlugin.cs +++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/KnowledgeBasePlugin.cs @@ -1,5 +1,6 @@ using BotSharp.Abstraction.Plugins.Models; using BotSharp.Abstraction.Settings; +using BotSharp.Plugin.KnowledgeBase.Hooks; using Microsoft.Extensions.Configuration; namespace BotSharp.Plugin.KnowledgeBase; @@ -24,6 +25,8 @@ public void RegisterDI(IServiceCollection services, IConfiguration config) services.AddScoped(); services.AddScoped(); services.AddSingleton(); + services.AddScoped(); + services.AddScoped(); } public bool AttachMenu(List menu) diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/MemVecDb/MemVectorDatabase.cs b/src/Plugins/BotSharp.Plugin.KnowledgeBase/MemVecDb/MemVectorDatabase.cs index a595c5da3..c46ccdf5a 100644 --- a/src/Plugins/BotSharp.Plugin.KnowledgeBase/MemVecDb/MemVectorDatabase.cs +++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/MemVecDb/MemVectorDatabase.cs @@ -18,7 +18,7 @@ public async Task> GetCollections() return _collections.Select(x => x.Key).ToList(); } - public async Task> Search(string collectionName, float[] vector, int limit = 5) + public async Task> Search(string collectionName, float[] vector, string returnFieldName, int limit = 5, float confidence = 0.5f) { if (!_vectors.ContainsKey(collectionName)) { @@ -37,7 +37,7 @@ public async Task> Search(string collectionName, float[] vector, in return texts; } - public async Task Upsert(string collectionName, string id, float[] vector, string text, Dictionary? payload = null) + public async Task Upsert(string collectionName, string id, float[] vector, string text, Dictionary? payload = null) { _vectors[collectionName].Add(new VecRecord { @@ -45,6 +45,8 @@ public async Task Upsert(string collectionName, string id, float[] vector, strin Vector = vector, Text = text }); + + return true; } private float[] CalEuclideanDistance(float[] vec, List records) diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.cs b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.cs index bd4cf6f47..7ac5cf4c1 100644 --- a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.cs +++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.cs @@ -68,7 +68,7 @@ public async Task GetKnowledges(KnowledgeRetrievalModel retrievalModel) // Vector search var db = GetVectorDb(); - var result = await db.Search("shared", vector, limit: 10); + var result = await db.Search("shared", vector, "answer", limit: 10); // Restore return string.Join("\n\n", result.Select((x, i) => $"### Paragraph {i + 1} ###\n{x.Trim()}")); diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/data/agents/01acc3e5-0af7-49e6-ad7a-a760bd12dc40/agent.json b/src/Plugins/BotSharp.Plugin.KnowledgeBase/data/agents/01acc3e5-0af7-49e6-ad7a-a760bd12dc40/agent.json new file mode 100644 index 000000000..79310ecc7 --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/data/agents/01acc3e5-0af7-49e6-ad7a-a760bd12dc40/agent.json @@ -0,0 +1,16 @@ +{ + "id": "01acc3e5-0af7-49e6-ad7a-a760bd12dc40", + "name": "Learner", + "description": "An avid learner who is eager to learn and acquire knowledge", + "iconUrl": "https://cdn-icons-png.flaticon.com/512/4578/4578413.png", + "type": "task", + "createdDateTime": "2024-07-17T00:00:00Z", + "updatedDateTime": "2024-07-17T00:00:00Z", + "disabled": false, + "isPublic": true, + "profiles": [ "tool" ], + "llmConfig": { + "provider": "anthropic", + "model": "claude-3-5-sonnet-20240620" + } +} \ No newline at end of file diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/data/agents/01acc3e5-0af7-49e6-ad7a-a760bd12dc40/functions/memorize_knowledge.json b/src/Plugins/BotSharp.Plugin.KnowledgeBase/data/agents/01acc3e5-0af7-49e6-ad7a-a760bd12dc40/functions/memorize_knowledge.json new file mode 100644 index 000000000..7ecaa37aa --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/data/agents/01acc3e5-0af7-49e6-ad7a-a760bd12dc40/functions/memorize_knowledge.json @@ -0,0 +1,18 @@ +{ + "name": "memorize_knowledge", + "description": "Retrieve related domain knowledge to handle user request", + "parameters": { + "type": "object", + "properties": { + "question": { + "type": "string", + "description": "User question with scenario detail" + }, + "answer": { + "type": "string", + "description": "The answer to handle user question" + } + }, + "required": [ "question", "answer" ] + } +} \ No newline at end of file diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/data/agents/01acc3e5-0af7-49e6-ad7a-a760bd12dc40/instruction.liquid b/src/Plugins/BotSharp.Plugin.KnowledgeBase/data/agents/01acc3e5-0af7-49e6-ad7a-a760bd12dc40/instruction.liquid new file mode 100644 index 000000000..7f6efa95e --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/data/agents/01acc3e5-0af7-49e6-ad7a-a760bd12dc40/instruction.liquid @@ -0,0 +1,2 @@ +You an avid learner who is eager to learn and acquire knowledge from the conversation. +You're good at learning useful domain knowledge and experience by interacting with user. \ No newline at end of file diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/knowledge_retrieval.json b/src/Plugins/BotSharp.Plugin.KnowledgeBase/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/knowledge_retrieval.json new file mode 100644 index 000000000..b292d7d97 --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/knowledge_retrieval.json @@ -0,0 +1,14 @@ +{ + "name": "knowledge_retrieval", + "description": "Retrieve related domain knowledge to handle user request", + "parameters": { + "type": "object", + "properties": { + "question": { + "type": "string", + "description": "Knowledge topic with scenario detail" + } + }, + "required": [ "question" ] + } +} \ No newline at end of file diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/knowledge_retrieval.fn.liquid b/src/Plugins/BotSharp.Plugin.KnowledgeBase/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/knowledge_retrieval.fn.liquid new file mode 100644 index 000000000..da5e157b3 --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/knowledge_retrieval.fn.liquid @@ -0,0 +1,3 @@ +Call function knowledge_retrieval to retrieve related domain knowledge to handle user request. +You must retrieve existing KnowledgeBase to get prerequisite informations before you writing SQL query; +You must retrieve existing API specification from KnowledgeBase before calling a Web API; diff --git a/src/Plugins/BotSharp.Plugin.MetaAI/Providers/FaissDb.cs b/src/Plugins/BotSharp.Plugin.MetaAI/Providers/FaissDb.cs index c74c86bbf..48e2be170 100644 --- a/src/Plugins/BotSharp.Plugin.MetaAI/Providers/FaissDb.cs +++ b/src/Plugins/BotSharp.Plugin.MetaAI/Providers/FaissDb.cs @@ -17,12 +17,12 @@ public Task> GetCollections() throw new NotImplementedException(); } - public Task> Search(string collectionName, float[] vector, int limit = 10) + public Task> Search(string collectionName, float[] vector, string returnFieldName, int limit = 10, float confidence = 0.5f) { throw new NotImplementedException(); } - public Task Upsert(string collectionName, string id, float[] vector, string text, Dictionary? payload = null) + public Task Upsert(string collectionName, string id, float[] vector, string text, Dictionary? payload = null) { throw new NotImplementedException(); } diff --git a/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Embedding/TextEmbeddingProvider.cs b/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Embedding/TextEmbeddingProvider.cs index 2a84b61a3..578849bfa 100644 --- a/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Embedding/TextEmbeddingProvider.cs +++ b/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Embedding/TextEmbeddingProvider.cs @@ -9,7 +9,7 @@ public class TextEmbeddingProvider : ITextEmbedding protected readonly ILogger _logger; private const int DEFAULT_DIMENSION = 1536; - protected string _model; + protected string _model = "text-embedding-3-small"; public virtual string Provider => "openai"; diff --git a/src/Plugins/BotSharp.Plugin.Qdrant/QdrantDb.cs b/src/Plugins/BotSharp.Plugin.Qdrant/QdrantDb.cs index c571fba10..e698d5e3f 100644 --- a/src/Plugins/BotSharp.Plugin.Qdrant/QdrantDb.cs +++ b/src/Plugins/BotSharp.Plugin.Qdrant/QdrantDb.cs @@ -67,7 +67,7 @@ public async Task CreateCollection(string collectionName, int dim) } } - public async Task Upsert(string collectionName, string id, float[] vector, string text, Dictionary? payload = null) + public async Task Upsert(string collectionName, string id, float[] vector, string text, Dictionary? payload = null) { // Insert vectors var point = new PointStruct() @@ -78,29 +78,37 @@ public async Task Upsert(string collectionName, string id, float[] vector, strin }, Vectors = vector, - Payload = { } + Payload = + { + { "text", text } + } }; - foreach (var item in payload) + if (payload != null) { - point.Payload.Add(item.Key, item.Value); + foreach (var item in payload) + { + point.Payload.Add(item.Key, item.Value); + } } - var result = await GetClient().UpsertAsync(collectionName, points: new List + var client = GetClient(); + + var result = await client.UpsertAsync(collectionName, points: new List { point }); + + return result.Status == UpdateStatus.Completed; } - public async Task> Search(string collectionName, float[] vector, int limit = 5) + public async Task> Search(string collectionName, float[] vector, string returnFieldName, int limit = 5, float confidence = 0.5f) { - var result = await GetClient().SearchAsync(collectionName, vector, limit: (ulong)limit); - - var agentService = _services.GetRequiredService(); - var agentDataDir = agentService.GetAgentDataDir(collectionName); - var knowledgePath = Path.Combine(agentDataDir, "knowledge.txt"); - var texts = File.ReadAllLines(knowledgePath); + var client = GetClient(); + var points = await client.SearchAsync(collectionName, vector, + limit: (ulong)limit, + scoreThreshold: confidence); - return result.Select(x => texts[x.Id.Num]).ToList(); + return points.Select(x => x.Payload[returnFieldName].StringValue).ToList(); } } diff --git a/src/Plugins/BotSharp.Plugin.SqlDriver/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/sql_executor.fn.liquid b/src/Plugins/BotSharp.Plugin.SqlDriver/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/sql_executor.fn.liquid index e8ac2a14e..30fa8124a 100644 --- a/src/Plugins/BotSharp.Plugin.SqlDriver/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/sql_executor.fn.liquid +++ b/src/Plugins/BotSharp.Plugin.SqlDriver/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/sql_executor.fn.liquid @@ -2,4 +2,5 @@ You are connecting to {{ db_type }} database. Please generate SQL statements fol Please call function sql_select if user wants to get or retrieve data from data tables. If there are any parameters, please add them in the WHERE clause, each of which starts with "@". -For example, SELECT * FROM table WHERE Id=@Id AND Name=@Name +Avoid returning the entire record and only return the fields you need. +For example, SELECT Id FROM table WHERE Id=@Id AND Name=@Name