Merge remote-tracking branch 'origin/master' into jason_dev

This commit is contained in:
jason.wang 2024-09-24 15:09:18 +08:00
commit 515783e21d
17 changed files with 81 additions and 52 deletions

View file

@ -5,7 +5,7 @@ public interface IKnowledgeHook
Task<List<KnowledgeChunk>> CollectChunkedKnowledge()
=> Task.FromResult(new List<KnowledgeChunk>());
Task<List<string>> GetRelevantKnowledges()
Task<List<string>> GetRelevantKnowledges(string text)
=> Task.FromResult(new List<string>());
Task<List<string>> GetGlobalKnowledges()

View file

@ -15,6 +15,7 @@ public interface IKnowledgeService
Task<bool> DeleteVectorCollectionAllData(string collectionName);
Task<bool> CreateVectorCollectionData(string collectionName, VectorCreateModel create);
Task<bool> UpdateVectorCollectionData(string collectionName, VectorUpdateModel update);
Task<bool> UpsertVectorCollectionData(string collectionName, VectorUpdateModel update);
#endregion
#region Graph

View file

@ -5,6 +5,9 @@ public class GenericTemplateMessage<T> : IRichMessage, ITemplateMessage
[JsonPropertyName("rich_type")]
public string RichType => RichTypeEnum.GenericTemplate;
/// <summary>
/// Use model refined content if leaving blank
/// </summary>
[JsonPropertyName("text")]
[Translate]
public string Text { get; set; } = string.Empty;

View file

@ -4,6 +4,7 @@ public interface IPlanningHook
{
Task<string> GetSummaryAdditionalRequirements(string planner)
=> Task.FromResult(string.Empty);
Task OnPlanningCompleted(string planner, RoleDialogModel msg)
=> Task.CompletedTask;
}

View file

@ -5,5 +5,7 @@ public class VectorCollectionData
public string Id { get; set; }
public Dictionary<string, string> Data { get; set; } = new();
public double? Score { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public float[]? Vector { get; set; }
}

View file

@ -1,5 +1,3 @@
using BotSharp.Abstraction.Knowledges.Enums;
namespace BotSharp.Abstraction.VectorStorage.Models;
public class VectorSearchResult : VectorCollectionData

View file

@ -123,6 +123,12 @@ public partial class ConversationService
Message = new TextMessage(response.SecondaryContent ?? response.Content)
};
// Use model refined response
if (string.IsNullOrEmpty(response.RichContent.Message.Text))
{
response.RichContent.Message.Text = response.Content;
}
// Patch return function name
if (response.PostbackFunctionName != null)
{

View file

@ -10,6 +10,12 @@
<OutputPath>$(SolutionDir)packages</OutputPath>
</PropertyGroup>
<ItemGroup>
<Compile Remove="packages\**" />
<EmbeddedResource Remove="packages\**" />
<None Remove="packages\**" />
</ItemGroup>
<ItemGroup>
<None Include="..\..\..\arts\Icon.png">
<Pack>True</Pack>

View file

@ -31,8 +31,12 @@ namespace BotSharp.OpenAPI.Filters
return;
}
if (token.ValidTo.ToLongTimeString() != GetUserExpires().ToLongTimeString())
var validTo = token.ValidTo.ToLongTimeString();
var currentExpires = GetUserExpires().ToLongTimeString();
if (validTo != currentExpires)
{
Serilog.Log.Warning($"Token expired. Token expires at {validTo}, current expires at {currentExpires}");
context.Result = new UnauthorizedResult();
}
}

View file

@ -164,6 +164,42 @@ public partial class KnowledgeService
}
}
public async Task<bool> UpsertVectorCollectionData(string collectionName, VectorUpdateModel update)
{
try
{
if (string.IsNullOrWhiteSpace(collectionName) || string.IsNullOrWhiteSpace(update.Text) || !Guid.TryParse(update.Id, out var guid))
{
return false;
}
var db = GetVectorDb();
var found = await db.GetCollectionData(collectionName, new List<Guid> { guid },
withVector: true,
withPayload: true);
if (!found.IsNullOrEmpty())
{
if (found.First().Data["text"] == update.Text)
{
// Only update payload
return await db.Upsert(collectionName, guid, found.First().Vector, update.Text, update.Payload);
}
}
var textEmbedding = GetTextEmbedding(collectionName);
var vector = await textEmbedding.GetVectorAsync(update.Text);
var payload = update.Payload ?? new();
payload[KnowledgePayloadName.DataSource] = !string.IsNullOrWhiteSpace(update.DataSource) ? update.DataSource : VectorDataSource.Api;
return await db.Upsert(collectionName, guid, vector, update.Text, payload);
}
catch (Exception ex)
{
_logger.LogWarning($"Error when updating vector collection data. {ex.Message}\r\n{ex.InnerException}");
return false;
}
}
public async Task<bool> DeleteVectorCollectionData(string collectionName, string id)
{
try

View file

@ -27,6 +27,7 @@ public class PrimaryStagePlanFn : IFunctionCallback
var collectionName = knowledgeSettings.Default.CollectionName ?? KnowledgeCollectionName.BotSharp;
// Get knowledge from vectordb
var hooks = _services.GetServices<IKnowledgeHook>();
var knowledges = new List<string>();
foreach (var question in task.Questions)
{
@ -34,8 +35,13 @@ public class PrimaryStagePlanFn : IFunctionCallback
{
Confidence = 0.2f
});
knowledges.Add(string.Join("\r\n\r\n=====\r\n", list.Select(x => x.ToQuestionAnswer())));
foreach (var hook in hooks)
{
var k = await hook.GetRelevantKnowledges(question);
knowledges.AddRange(k);
}
}
// Get first stage planning prompt
@ -92,7 +98,7 @@ public class PrimaryStagePlanFn : IFunctionCallback
var wholeDialogs = conv.GetDialogHistory();
// Append text
wholeDialogs.Last().Content += "\n\nYou must analyze the table description to infer the table relations.";
wholeDialogs.Last().Content += "\n\nYou must analyze the table description to infer the table relations. Only output the JSON result.";
var completion = CompletionProvider.GetChatCompletion(_services,
provider: plannerAgent.LlmConfig.Provider,

View file

@ -75,7 +75,6 @@ public class SecondaryStagePlanFn : IFunctionCallback
var template = agent.Templates.FirstOrDefault(x => x.Name == "two_stage.2nd.plan")?.Content ?? string.Empty;
var responseFormat = JsonSerializer.Serialize(new SecondStagePlan
{
Tool = "tool name if task solution provided",
Parameters = [ JsonDocument.Parse("{}") ],
Results = [ string.Empty ]
});

View file

@ -8,9 +8,6 @@ public class SecondStagePlan
[JsonPropertyName("description")]
public string Description { get; set; } = "";
[JsonPropertyName("tool_name")]
public string Tool { get; set; } = "";
[JsonPropertyName("input_args")]
public JsonDocument[] Parameters { get; set; } = [];

View file

@ -96,31 +96,6 @@ public partial class TwoStageTaskPlanner : IRoutingPlaner
return true;
}
private async Task<string> GetFirstStagePlanPrompt(Agent router)
{
var template = router.Templates.First(x => x.Name == "two_stage.1st.plan").Content;
var responseFormat = JsonSerializer.Serialize(new FirstStagePlan
{
Parameters = new JsonDocument[] { JsonDocument.Parse("{}") },
Results = new string[] { "" }
});
var relevantKnowledges = new List<string>();
var hooks = _services.GetServices<IKnowledgeHook>();
foreach (var hook in hooks)
{
var k = await hook.GetRelevantKnowledges();
relevantKnowledges.AddRange(k);
}
var render = _services.GetRequiredService<ITemplateRender>();
return render.Render(template, new Dictionary<string, object>
{
{ "response_format", responseFormat },
{ "relevant_knowledges", relevantKnowledges.ToArray() }
});
}
private async Task<string> GetNextStepPrompt(Agent router)
{
var agentService = _services.GetRequiredService<IAgentService>();
@ -134,17 +109,4 @@ public partial class TwoStageTaskPlanner : IRoutingPlaner
{ StateConst.EXPECTED_GOAL_AGENT, states.GetState(StateConst.EXPECTED_GOAL_AGENT) }
});
}
private string GetSecondStageTaskPrompt(Agent router, SecondStagePlan plan)
{
var template = router.Templates.First(x => x.Name == "planner_prompt.two_stage.2nd.task").Content;
var render = _services.GetRequiredService<ITemplateRender>();
return render.Render(template, new Dictionary<string, object>
{
{ "task_description", plan.Description },
{ "related_tables", plan.Tables },
{ "input_arguments", JsonSerializer.Serialize(plan.Parameters) },
{ "output_results", JsonSerializer.Serialize(plan.Results) },
});
}
}

View file

@ -1,7 +1,8 @@
Use the TwoStagePlanner approach to plan the overall implementation steps, follow the below steps strictly.
1. call plan_primary_stage to generate the primary plan.
1. Call plan_primary_stage to generate the primary plan.
2. If need_additional_information is true, call plan_secondary_stage for the specific primary stage.
3. You must call plan_summary for you final planned output.
3. You must call plan_summary to generate final planned steps.
4. If you can't generate the final accurate planning steps due to missing some specific informations, please ask user for more information.
*** IMPORTANT ***
Don't run the planning process repeatedly if you have already got the result of user's request.

View file

@ -10,4 +10,3 @@ Expected user goal agent is {{ expected_user_goal_agent }}.
{%- else -%}
User goal agent is inferred based on user initial request.
{%- endif %}
Always route to planner first.

View file

@ -29,7 +29,15 @@ public class ExecuteQueryFn : IFunctionCallback
_ => throw new NotImplementedException($"Database type {settings.DatabaseType} is not supported.")
};
message.Content = JsonSerializer.Serialize(results);
if (results.Count() == 0)
{
message.Content = "No record found";
}
else
{
message.Content = JsonSerializer.Serialize(results);
}
return true;
}