From 4f7f23565e8ea452330a9260878344646a6c3507 Mon Sep 17 00:00:00 2001 From: tonaerospace Date: Sun, 22 Dec 2024 11:32:11 +0700 Subject: [PATCH] update --- src/interface.jl | 167 ++++++++++++++++++++--------------------------- 1 file changed, 69 insertions(+), 98 deletions(-) diff --git a/src/interface.jl b/src/interface.jl index 7874d38..a8b44a8 100644 --- a/src/interface.jl +++ b/src/interface.jl @@ -138,15 +138,17 @@ function decisionMaker(state::T1, context, text2textInstructLLM::Function, At each round of conversation, the user will give you the current situation: User Query: ... - Hints: ... + Example: ... Your Q&A: ... Your work progress: ... Evaluation: Evaluation of the latest action and observation Suggestion: ... - You should consider the following guidelines: + You must follow the following guidelines: + - Keep SQL queries focused only on the provided information. + + You should follow the following guidelines: - Do not create any table in the database - - Start only with the infomation the the query. - Column name can be the same in different tables. Refer to column comments to get more details by using TABLEINFO function - A junction table can be used to link tables together. Another use case is for filtering data. - If you can't find a single table that can be used to answer the user's query, try joining multiple tables to see if you can obtain the answer. @@ -161,7 +163,7 @@ function decisionMaker(state::T1, context, text2textInstructLLM::Function, 3) Plan: Given the current circumstances, outline a detailed, step-by-step plan to accomplish the task. Be specific. 4) Action_name (Must be aligned with your plan): Can be one of the following functions: - TABLEINFO[list_of_table_name], which you can use to get the data type of a table column. "list_of_table_name" is a list of table name you want to get info. e.g. TABLEINFO["table name 1", "table name 2"] - - GETDATA[SQL], which you can use to get the data from the database. "SQL" is the single SQL command to be executed against the database. + - GETDATA[SQL], which you can use to get the data from the database. "SQL" is a single SQL command to be executed against the database. For more effective text search, it's necessary to use case-insensitivity and the ILIKE operator. Do not wrap the SQL as it will be executed against the database directly and SQL must be ended with ';'. 5) Action_input: Input to the action @@ -173,7 +175,6 @@ function decisionMaker(state::T1, context, text2textInstructLLM::Function, Plan: ... Action_name: ... Action_input: ... - Observation: ... Let's begin! """ @@ -203,7 +204,7 @@ function decisionMaker(state::T1, context, text2textInstructLLM::Function, """ $(context[:tablelist]) User query: $(state[:thoughtHistory][:question]) - Hints: $similarSQL_ + Example: $similarSQL_ Your Q&A: $QandA Your work progress: $workprogress Evaluation: $(state[:evaluation]) @@ -224,104 +225,74 @@ function decisionMaker(state::T1, context, text2textInstructLLM::Function, <|start_header_id|>assistant<|end_header_id|> """ - # try - # response = text2textInstructLLM(prompt) + try + response = text2textInstructLLM(prompt) + println("\nSQL decisionMaker() rawresponse: ", response) - # # textToDict() search for action_input - # responsedict = GeneralUtils.textToDict(response, - # ["Understanding", "Reasoning", "Plan", "Action_name", "Action_input", "Observation"], - # rightmarker=":", symbolkey=true, lowercasekey=true) + header = ["Understanding", "Reasoning", "Plan", "Action_name", "Action_input", "Observation"] - # delete!(responsedict, :observation) - - # # [WORKING] remove backticks Error occurred: MethodError: no method matching occursin(::String, ::Vector{String}) - # if occursin("```", responsedict[:action_input]) - # responsedict[:action_input] = - # GeneralUtils.extract_triple_backtick_text(responsedict[:action_input]) - # end - - # toollist = ["TABLEINFO", "GETDATA"] - # if responsedict[:action_name] ∉ toollist - # error("SQL decisionMaker() didn't use the given functions ", @__FILE__, " ", @__LINE__) - # end - - # for i in toollist - # if occursin(i, responsedict[:action_input]) - # error("Action_name is in action_input which is not allowed.") - # end - # end - - # for i ∈ [:understanding, :reasoning, :plan, :action_name, :action_input] - # if length(JSON3.write(responsedict[i])) == 0 - # error("$i is empty ", @__FILE__, " ", @__LINE__) - # end - # end - - # # check if there are more than 1 key per categories - # for i ∈ [:understanding, :reasoning, :plan, :action_name, :action_input] - # matchkeys = GeneralUtils.findMatchingDictKey(responsedict, i) - # if length(matchkeys) > 1 - # error("DecisionMaker has more than one key per categories") - # end - # end - - # state[:decisionMaker] = responsedict - - # return responsedict - # catch e - # io = IOBuffer() - # showerror(io, e) - # errorMsg = String(take!(io)) - # st = sprint((io, v) -> show(io, "text/plain", v), stacktrace(catch_backtrace())) - # println("") - # println("\n~~~ SQLLLM decisionMaker() Attempt $attempt. Error occurred: $errorMsg\n$st ", @__FILE__, " ", @__LINE__) - # println("") - # end - - response = text2textInstructLLM(prompt) - println("SQL decisionMaker() rawresponse: ", response) - - # textToDict() search for action_input - responsedict = GeneralUtils.textToDict(response, - ["Understanding", "Reasoning", "Plan", "Action_name", "Action_input", "Observation"], - rightmarker=":", symbolkey=true, lowercasekey=true) - - delete!(responsedict, :observation) - - # [WORKING] remove backticks Error occurred: MethodError: no method matching occursin(::String, ::Vector{String}) - if occursin("```", responsedict[:action_input]) - responsedict[:action_input] = - GeneralUtils.extract_triple_backtick_text(responsedict[:action_input]) - end - - toollist = ["TABLEINFO", "GETDATA"] - if responsedict[:action_name] ∉ toollist - error("SQL decisionMaker() didn't use the given functions ", @__FILE__, " ", @__LINE__) - end - - for i in toollist - if occursin(i, responsedict[:action_input]) - error("Action_name is in action_input which is not allowed.") + # detect if there are more than 1 key per categories + count = GeneralUtils.countGivenWords(response, header) + if sum(count) > length(header) + error("duplicated words", @__FILE__, " ", @__LINE__) end - end - for i ∈ [:understanding, :reasoning, :plan, :action_name, :action_input] - if length(JSON3.write(responsedict[i])) == 0 - error("$i is empty ", @__FILE__, " ", @__LINE__) + # textToDict() search for action_input + responsedict = GeneralUtils.textToDict(response, header, + rightmarker=":", symbolkey=true, lowercasekey=true) + + delete!(responsedict, :observation) + + # remove backticks Error occurred: MethodError: no method matching occursin(::String, ::Vector{String}) + if occursin("```", responsedict[:action_input]) + sql = GeneralUtils.extract_triple_backtick_text(responsedict[:action_input])[1] + if sql[1:4] == "sql\n" + sql = sql[5:end] + end + sql = split(sql, ';') # some time there are comments in the sql + sql = sql[1] * ';' + + responsedict[:action_input] = sql end - end - # check if there are more than 1 key per categories - for i ∈ [:understanding, :reasoning, :plan, :action_name, :action_input] - matchkeys = GeneralUtils.findMatchingDictKey(responsedict, i) - if length(matchkeys) > 1 - error("DecisionMaker has more than one key per categories") + toollist = ["TABLEINFO", "GETDATA"] + if responsedict[:action_name] ∉ toollist + error("SQL decisionMaker() didn't use the given functions ", @__FILE__, " ", @__LINE__) end + + for i in toollist + if occursin(i, responsedict[:action_input]) + error("Action_name is in action_input which is not allowed.") + end + end + + for i ∈ [:understanding, :reasoning, :plan, :action_name, :action_input] + if length(JSON3.write(responsedict[i])) == 0 + error("$i is empty ", @__FILE__, " ", @__LINE__) + end + end + + # check if there are more than 1 key per categories + for i ∈ [:understanding, :reasoning, :plan, :action_name, :action_input] + matchkeys = GeneralUtils.findMatchingDictKey(responsedict, i) + if length(matchkeys) > 1 + error("DecisionMaker has more than one key per categories") + end + end + + state[:decisionMaker] = responsedict + + return responsedict + catch e + io = IOBuffer() + showerror(io, e) + errorMsg = String(take!(io)) + st = sprint((io, v) -> show(io, "text/plain", v), stacktrace(catch_backtrace())) + println("") + println("\n~~~ SQLLLM decisionMaker() Attempt $attempt. Error occurred: $errorMsg\n$st ", @__FILE__, " ", @__LINE__) + println("") end - state[:decisionMaker] = responsedict - - return responsedict end error("DecisionMaker failed to generate a thought ", response) end @@ -1068,7 +1039,7 @@ function generatequestion(state::T1, context, text2textInstructLLM::Function; At each round of conversation, the user will give you the current situation: User query: ... - Hints: ... + Example: ... Your work progress: ... About the tables in the database: @@ -1082,7 +1053,7 @@ function generatequestion(state::T1, context, text2textInstructLLM::Function; 3) Some information can be accessed by joining multiple tables. 4) Do not generate any question or comments at the end. - You should consider the following guidelines: + You should follow the following guidelines: - When querying data in the database, start with broad search terms and refine your query later for more precise results. You should then respond to the user with: @@ -1128,7 +1099,7 @@ function generatequestion(state::T1, context, text2textInstructLLM::Function; """ $(context[:tablelist]) User query: $(state[:thoughtHistory][:question]) - Hints: $similarSQL + Example: $similarSQL Your work progress: $workprogress $errornote $noise