Skip to content

Commit 2b6b92c

Browse files
authored
Merge pull request #656 from Joannall/master
Add sql dictionary lookup utility
2 parents 0e2a457 + 4c561eb commit 2b6b92c

File tree

21 files changed

+185
-141
lines changed

21 files changed

+185
-141
lines changed

src/Plugins/BotSharp.Plugin.Planner/Functions/PrimaryStagePlanFn.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public async Task<bool> Execute(RoleDialogModel message)
3333
{
3434
var list = await knowledgeService.SearchVectorKnowledge(question, collectionName, new VectorSearchOptions
3535
{
36-
Confidence = 0.2f
36+
Confidence = 0.4f
3737
});
3838
knowledges.Add(string.Join("\r\n\r\n=====\r\n", list.Select(x => x.ToQuestionAnswer())));
3939

@@ -56,7 +56,10 @@ public async Task<bool> Execute(RoleDialogModel message)
5656
LlmConfig = currentAgent.LlmConfig
5757
};
5858
var response = await GetAiResponse(plannerAgent);
59-
message.Content = response.Content;
59+
message.Content = response.Content;
60+
61+
var states = _services.GetRequiredService<IConversationStateService>();
62+
states.SetState("planning_result", response.Content);
6063

6164
return true;
6265
}

src/Plugins/BotSharp.Plugin.Planner/Functions/SecondaryStagePlanFn.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public async Task<bool> Execute(RoleDialogModel message)
4141

4242
var knowledges = await knowledgeService.SearchVectorKnowledge(item.Task, collectionName, new VectorSearchOptions
4343
{
44-
Confidence = 0.5f
44+
Confidence = 0.6f
4545
});
4646
message.Content += string.Join("\r\n\r\n=====\r\n", knowledges.Select(x => x.ToQuestionAnswer()));
4747
}
@@ -63,6 +63,9 @@ public async Task<bool> Execute(RoleDialogModel message)
6363
var response = await GetAiResponse(plannerAgent);
6464
message.Content = response.Content;
6565
_logger.LogInformation(response.Content);
66+
67+
var states = _services.GetRequiredService<IConversationStateService>();
68+
states.SetState("planning_result", response.Content);
6669
return true;
6770
}
6871

src/Plugins/BotSharp.Plugin.Planner/Functions/SummaryPlanFn.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,13 @@ public async Task<bool> Execute(RoleDialogModel message)
3030
var taskRequirement = state.GetState("requirement_detail");
3131

3232
// Get table names
33-
var steps = message.Content.JsonArrayContent<SecondStagePlan>();
33+
var states = _services.GetRequiredService<IConversationStateService>();
34+
var steps = states.GetState("planning_result").JsonArrayContent<SecondStagePlan>();
3435
var allTables = new List<string>();
3536
var ddlStatements = "";
36-
var relevantKnowledge = message.Content;
37+
var relevantKnowledge = states.GetState("planning_result");
38+
relevantKnowledge += states.GetState("dictionary_items");
39+
3740
foreach (var step in steps)
3841
{
3942
allTables.AddRange(step.Tables);

src/Plugins/BotSharp.Plugin.Planner/TwoStaging/Models/SecondaryBreakdownTask.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,7 @@ public class SecondaryBreakdownTask
77

88
[JsonPropertyName("solution_search_question")]
99
public string SolutionQuestion { get; set; } = null!;
10+
11+
[JsonPropertyName("need_lookup_dictionary")]
12+
public bool NeedLookupDictionary { get; set; }
1013
}

src/Plugins/BotSharp.Plugin.Planner/data/agents/282a7128-69a1-44b0-878c-a9159b88f3b9/functions/plan_summary.json

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,15 @@
44
"parameters": {
55
"type": "object",
66
"properties": {
7+
"related_tables": {
8+
"type": "array",
9+
"description": "table name in planning steps",
10+
"items": {
11+
"type": "string",
12+
"description": "table name"
13+
}
14+
}
715
},
8-
"required": []
16+
"required": [ "related_tables" ]
917
}
1018
}

src/Plugins/BotSharp.Plugin.Planner/data/agents/282a7128-69a1-44b0-878c-a9159b88f3b9/instructions/instruction.liquid

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
Use the TwoStagePlanner approach to plan the overall implementation steps, follow the below steps strictly.
22
1. Call plan_primary_stage to generate the primary plan.
33
2. If need_additional_information is true, call plan_secondary_stage for the specific primary stage.
4-
3. You must call plan_summary to generate final planned steps.
5-
4. If you can't generate the final accurate planning steps due to missing some specific informations, please ask user for more information.
4+
3. Repeat step 2 until you processed all the primary stages.
5+
4. If need_lookup_dictionary is true, call sql_dictionary_lookup to verify or get the enum/term/dictionary value. Pull id and name.
6+
If you no items retured, you can pull all the list and find the match.
7+
5. You must call plan_summary for you final planned output.
68

79
*** IMPORTANT ***
810
Don't run the planning process repeatedly if you have already got the result of user's request.

src/Plugins/BotSharp.Plugin.Planner/data/agents/282a7128-69a1-44b0-878c-a9159b88f3b9/templates/two_stage.1st.plan.liquid

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ Thinking process:
88
- If there is extra knowledge or relationship needed between steps, set the need_additional_information to true for both steps.
99
- If the solution mentioned "related solutions" is needed, set the need_additional_information to true.
1010
- You should find the relationships between data structure based on the task knowledge strictly. If lack of information, set the need_additional_information to true.
11+
- If you need to verify or get the enum/term/dictionary value, set the need_additional_information to true.
1112
3. Input argument must reference to corresponding variable name that retrieved by previous steps, variable name must start with '@';
1213
4. Output all the subtasks as much detail as possible in JSON: [{{ response_format }}]
1314
5. You can NOT generate the final query before calling function plan_summary.

src/Plugins/BotSharp.Plugin.Planner/data/agents/282a7128-69a1-44b0-878c-a9159b88f3b9/templates/two_stage.2nd.plan.liquid

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ Reference to "Primary Planning" and the additional knowledge included. Breakdown
33
* The parameters can be extracted from the original task.
44
* You need to list all the steps in detail. Finding relationships should also be a step.
55
* When generate the steps, you should find the relationships between data structure based on the provided knowledge strictly.
6+
* If need_lookup_dictionary is true, call sql_dictionary_lookup to verify or get the enum/term/dictionary value. Pull id and name/code.
67
* Output all the steps as much detail as possible in JSON: [{{ response_format }}]
78

89

Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
For every primary step, if need_additional_information is true, you have to call plan_secondary_stage to plan the detail steps to complete the primary step.
1+
For every primary step, if need_additional_information is true, you have to call plan_secondary_stage to plan the detail steps to complete the primary step.
2+
if need_lookup_dictionary is true, you have to call sql_dictionary_lookup to verify or get the enum/term/dictionary value. Pull id and name/code.

src/Plugins/BotSharp.Plugin.SqlDriver/BotSharp.Plugin.SqlDriver.csproj

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,27 @@
1818

1919
<ItemGroup>
2020
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\functions\get_table_definition.json" />
21+
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\functions\sql_dictionary_lookup.json" />
2122
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\functions\sql_select.json" />
2223
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\get_table_definition.fn.liquid" />
24+
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\sql_dictionary_lookup.fn.liquid" />
2325
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\sql_executor.fn.liquid" />
2426
<None Remove="data\agents\beda4c12-e1ec-4b4b-b328-3df4a6687c4f\agent.json" />
2527
<None Remove="data\agents\beda4c12-e1ec-4b4b-b328-3df4a6687c4f\functions\execute_sql.json" />
2628
<None Remove="data\agents\beda4c12-e1ec-4b4b-b328-3df4a6687c4f\functions\lookup_dictionary.json" />
2729
<None Remove="data\agents\beda4c12-e1ec-4b4b-b328-3df4a6687c4f\functions\sql_insert.json" />
2830
<None Remove="data\agents\beda4c12-e1ec-4b4b-b328-3df4a6687c4f\functions\sql_select.json" />
2931
<None Remove="data\agents\beda4c12-e1ec-4b4b-b328-3df4a6687c4f\instructions\instruction.liquid" />
30-
<None Remove="data\agents\beda4c12-e1ec-4b4b-b328-3df4a6687c4f\templates\lookup_dictionary.liquid" />
32+
<None Remove="data\agents\beda4c12-e1ec-4b4b-b328-3df4a6687c4f\templates\sql_dictionary_lookup.liquid" />
3133
</ItemGroup>
3234

3335
<ItemGroup>
36+
<Content Include="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\functions\sql_dictionary_lookup.json">
37+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
38+
</Content>
39+
<Content Include="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\sql_dictionary_lookup.fn.liquid">
40+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
41+
</Content>
3442
<Content Include="data\agents\beda4c12-e1ec-4b4b-b328-3df4a6687c4f\functions\get_table_definition.json">
3543
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
3644
</Content>
@@ -46,10 +54,7 @@
4654
<Content Include="data\agents\beda4c12-e1ec-4b4b-b328-3df4a6687c4f\instructions\instruction.liquid">
4755
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
4856
</Content>
49-
<Content Include="data\agents\beda4c12-e1ec-4b4b-b328-3df4a6687c4f\templates\lookup_dictionary.liquid">
50-
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
51-
</Content>
52-
<Content Include="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\lookup_dictionary.json">
57+
<Content Include="data\agents\beda4c12-e1ec-4b4b-b328-3df4a6687c4f\templates\sql_dictionary_lookup.liquid">
5358
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
5459
</Content>
5560
<Content Include="data\agents\beda4c12-e1ec-4b4b-b328-3df4a6687c4f\functions\sql_insert.json">

src/Plugins/BotSharp.Plugin.SqlDriver/Enum/Utility.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ namespace BotSharp.Plugin.SqlDriver.Enum;
33
public class Utility
44
{
55
public const string SqlExecutor = "sql-executor";
6+
public const string SqlDictionaryLookup = "sql-dictionary-lookup";
67
}
Lines changed: 15 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using Azure;
12
using BotSharp.Abstraction.Agents.Enums;
23
using BotSharp.Abstraction.MLTasks;
34
using BotSharp.Core.Infrastructures;
@@ -9,7 +10,7 @@ namespace BotSharp.Plugin.SqlDriver.Functions;
910

1011
public class LookupDictionaryFn : IFunctionCallback
1112
{
12-
public string Name => "lookup_dictionary";
13+
public string Name => "sql_dictionary_lookup";
1314
private readonly IServiceProvider _services;
1415

1516
public LookupDictionaryFn(IServiceProvider services)
@@ -21,58 +22,24 @@ public async Task<bool> Execute(RoleDialogModel message)
2122
{
2223
var args = JsonSerializer.Deserialize<LookupDictionary>(message.FunctionArgs);
2324

25+
// check if need to instantely
2426
var settings = _services.GetRequiredService<SqlDriverSetting>();
25-
using var connection = new MySqlConnection(settings.MySqlConnectionString);
26-
var dictionary = new Dictionary<string, object>();
27-
var results = connection.Query($"SELECT * FROM {args.Table} LIMIT 10");
28-
var items = new List<string>();
29-
foreach(var item in results)
30-
{
31-
items.Add(JsonSerializer.Serialize(item));
32-
}
33-
34-
var agentService = _services.GetRequiredService<IAgentService>();
35-
var agent = await agentService.LoadAgent(message.CurrentAgentId);
36-
var prompt = GetPrompt(agent, items, args.Keyword);
37-
38-
// Ask LLM which one is the best
39-
var llmProviderService = _services.GetRequiredService<ILlmProviderService>();
40-
var model = llmProviderService.GetProviderModel("azure-openai", "gpt-35-turbo");
27+
using var connection = new MySqlConnection(settings.MySqlExecutionConnectionString);
28+
var result = connection.Query(args.SqlStatement);
4129

42-
// chat completion
43-
var completion = CompletionProvider.GetChatCompletion(_services,
44-
provider: "azure-openai",
45-
model: model.Name);
46-
47-
var conversations = new List<RoleDialogModel>
30+
if (result == null)
4831
{
49-
new RoleDialogModel(AgentRole.User, prompt)
50-
{
51-
CurrentAgentId = message.CurrentAgentId,
52-
MessageId = message.MessageId,
53-
}
54-
};
55-
56-
var response = await completion.GetChatCompletions(new Agent
32+
message.Content = "Record not found";
33+
}
34+
else
5735
{
58-
Id = message.CurrentAgentId,
59-
Instruction = ""
60-
}, conversations);
61-
62-
message.Content = response.Content;
36+
message.Content = JsonSerializer.Serialize(result);
37+
}
38+
var states = _services.GetRequiredService<IConversationStateService>();
39+
var dictionaryItems = states.GetState("dictionary_items", "");
40+
dictionaryItems += "\r\n\r\n" + args.Reason + ":\r\n" + message.Content + "\r\n";
41+
states.SetState("dictionary_items", dictionaryItems);
6342

6443
return true;
6544
}
66-
67-
private string GetPrompt(Agent agent, List<string> task, string keyword)
68-
{
69-
var template = agent.Templates.First(x => x.Name == "lookup_dictionary").Content;
70-
71-
var render = _services.GetRequiredService<ITemplateRender>();
72-
return render.Render(template, new Dictionary<string, object>
73-
{
74-
{ "items", task },
75-
{ "keyword", keyword }
76-
});
77-
}
7845
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
using BotSharp.Abstraction.Agents.Enums;
2+
using BotSharp.Abstraction.Agents.Settings;
3+
using BotSharp.Abstraction.Functions.Models;
4+
using BotSharp.Abstraction.Repositories;
5+
using System.Collections.Generic;
6+
7+
namespace BotSharp.Plugin.SqlDriver.Hooks;
8+
9+
public class SqlDictionaryLookupHook : AgentHookBase, IAgentHook
10+
{
11+
private const string SQL_EXECUTOR_TEMPLATE = "sql_dictionary_lookup.fn";
12+
private IEnumerable<string> _targetSqlExecutorFunctions = new List<string>
13+
{
14+
"sql_dictionary_lookup",
15+
};
16+
17+
public override string SelfId => BuiltInAgentId.Planner;
18+
19+
public SqlDictionaryLookupHook(IServiceProvider services, AgentSettings settings) : base(services, settings)
20+
{
21+
}
22+
23+
public override void OnAgentLoaded(Agent agent)
24+
{
25+
var conv = _services.GetRequiredService<IConversationService>();
26+
var isConvMode = conv.IsConversationMode();
27+
var isEnabled = !agent.Utilities.IsNullOrEmpty() && agent.Utilities.Contains(Utility.SqlDictionaryLookup);
28+
29+
if (isConvMode && isEnabled)
30+
{
31+
var (prompt, fns) = GetPromptAndFunctions();
32+
if (!fns.IsNullOrEmpty())
33+
{
34+
if (!string.IsNullOrWhiteSpace(prompt))
35+
{
36+
agent.Instruction += $"\r\n\r\n{prompt}\r\n\r\n";
37+
}
38+
39+
if (agent.Functions == null)
40+
{
41+
agent.Functions = fns;
42+
}
43+
else
44+
{
45+
agent.Functions.AddRange(fns);
46+
}
47+
}
48+
}
49+
50+
base.OnAgentLoaded(agent);
51+
}
52+
53+
private (string, List<FunctionDef>?) GetPromptAndFunctions()
54+
{
55+
var db = _services.GetRequiredService<IBotSharpRepository>();
56+
var agent = db.GetAgent(BuiltInAgentId.UtilityAssistant);
57+
var fns = agent?.Functions?.Where(x => _targetSqlExecutorFunctions.Contains(x.Name))?.ToList();
58+
59+
var prompt = agent?.Templates?.FirstOrDefault(x => x.Name.IsEqualTo(SQL_EXECUTOR_TEMPLATE))?.Content ?? string.Empty;
60+
var dbType = GetDatabaseType();
61+
var render = _services.GetRequiredService<ITemplateRender>();
62+
prompt = render.Render(prompt, new Dictionary<string, object>
63+
{
64+
{ "db_type", dbType }
65+
});
66+
67+
return (prompt, fns);
68+
}
69+
70+
private string GetDatabaseType()
71+
{
72+
var settings = _services.GetRequiredService<SqlDriverSetting>();
73+
var dbType = "MySQL";
74+
75+
if (!string.IsNullOrWhiteSpace(settings?.SqlServerConnectionString))
76+
{
77+
dbType = "SQL Server";
78+
}
79+
else if (!string.IsNullOrWhiteSpace(settings?.SqlLiteConnectionString))
80+
{
81+
dbType = "SQL Lite";
82+
}
83+
return dbType;
84+
}
85+
}
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
namespace BotSharp.Plugin.SqlDriver.Hooks;
22

3-
public class SqlExecutorUtilityHook : IAgentUtilityHook
3+
public class SqlUtilityHook : IAgentUtilityHook
44
{
55
public void AddUtilities(List<string> utilities)
66
{
77
utilities.Add(Utility.SqlExecutor);
8+
utilities.Add(Utility.SqlDictionaryLookup);
89
}
910
}

src/Plugins/BotSharp.Plugin.SqlDriver/Models/LookupDictionary.cs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,12 @@ namespace BotSharp.Plugin.SqlDriver.Models;
44

55
public class LookupDictionary
66
{
7-
[JsonPropertyName("table")]
8-
public string Table { get; set; }
9-
10-
[JsonPropertyName("keyword")]
11-
public string Keyword { get; set; }
7+
[JsonPropertyName("sql_statement")]
8+
public string SqlStatement { get; set; }
129

1310
[JsonPropertyName("reason")]
1411
public string Reason { get; set; }
1512

16-
[JsonPropertyName("columns")]
17-
public string[] Columns { get; set; }
13+
[JsonPropertyName("table")]
14+
public string Table { get; set; }
1815
}

src/Plugins/BotSharp.Plugin.SqlDriver/SqlDriverPlugin.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ public void RegisterDI(IServiceCollection services, IConfiguration config)
2121
services.AddScoped<DbKnowledgeService>();
2222
services.AddScoped<IKnowledgeHook, SqlDriverKnowledgeHook>();
2323
services.AddScoped<IAgentHook, SqlExecutorHook>();
24-
services.AddScoped<IAgentUtilityHook, SqlExecutorUtilityHook>();
24+
services.AddScoped<IAgentUtilityHook, SqlUtilityHook>();
2525
services.AddScoped<IPlanningHook, SqlDriverPlanningHook>();
26+
services.AddScoped<IAgentHook, SqlDictionaryLookupHook>();
2627
}
2728
}

0 commit comments

Comments
 (0)