diff --git a/src/interface.jl b/src/interface.jl index 90bdc22..ecd9539 100644 --- a/src/interface.jl +++ b/src/interface.jl @@ -133,7 +133,7 @@ function decisionMaker(state::T1, context, text2textInstructLLM::Function, systemmsg = """ - You are a helpful assistant that get the data from a database to satisfy the user's query. + You are a helpful assistant that find the data from a database to satisfy the user's query. You are also eager to improve your helpfulness. At each round of conversation, the user will give you the current situation: @@ -146,12 +146,12 @@ function decisionMaker(state::T1, context, text2textInstructLLM::Function, You should consider 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. - If you are unable to find the requested information, kindly inform the user, "The current data in our database does not provide the specific answer to your query". - Text information in the database usually stored in lower case. If your search returns empty, try using lower case to search. - - Do not use backticks (`). Use double quotes instead. You should then respond to the user with interleaving Understanding, Reasoning, Plan, Action: 1) Understanding: @@ -224,59 +224,103 @@ function decisionMaker(state::T1, context, text2textInstructLLM::Function, <|start_header_id|>assistant<|end_header_id|> """ - try - response = text2textInstructLLM(prompt) + # try + # response = text2textInstructLLM(prompt) - # textToDict() search for action_input - responsedict = GeneralUtils.textToDict(response, - ["Understanding", "Reasoning", "Plan", "Action_name", "Action_input", "Observation"], - rightmarker=":", symbolkey=true, lowercasekey=true) + # # 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) + # delete!(responsedict, :observation) - # remove backticks - if occursin("```", responsedict[:action_input]) - responsedict[:action_input] = - GeneralUtils.extract_triple_backtick_text(responsedict[:action_input]) - end + # # [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 + # 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 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 + # 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 + # # 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 + # 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("") + # 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) + + # 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.") + 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 end error("DecisionMaker failed to generate a thought ", response) end @@ -945,7 +989,9 @@ function query(query::T, executeSQL::Function, text2textInstructLLM::Function; extracted = resultState[:thoughtHistory][latestKey] # add to vectorDB only if the answer is achieved and the state is terminal - if addSQLVectorDB !== nothing && resultState[:isterminal] == true + if addSQLVectorDB !== nothing && resultState[:isterminal] == true && + resultState[:rawresponse] !== nothing + addSQLVectorDB(resultState[:thoughtHistory][:question], sql) end @@ -1017,7 +1063,7 @@ function generatequestion(state::T1, context, text2textInstructLLM::Function; systemmsg = """ - You are a helpful assistant that generate multiple questions about the current situation. + You are a SQL expert that generate multiple questions about the current situation. At each round of conversation, the user will give you the current situation: User query: ... @@ -1035,6 +1081,9 @@ 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: + - 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: 1) Understanding: - State your understanding about the current situation. @@ -1052,6 +1101,13 @@ function generatequestion(state::T1, context, text2textInstructLLM::Function; A3: ... ... + Here are some examples: + Q: What information in the hints is not necessary based on the query? + A: Country is not specified in the query thus it should not be included in an SQL + + Q: How can I modify a SQL example to fit my specific query needs? + A: ... + Let's begin! """ diff --git a/src/llmfunction.jl b/src/llmfunction.jl index 99f1cee..261b9e4 100644 --- a/src/llmfunction.jl +++ b/src/llmfunction.jl @@ -613,7 +613,7 @@ function SQLexecution(executeSQL::Function, sql::T tablesize = size(df) row, column = tablesize if row == 0 # if 0 row - error("The resulting table has 0 row. Possible causes: 1) You might be searching in the wrong place 2) There could be a typo in your search query.") + error("The resulting table has 0 row. Possible causes: 1) Your search criteria might be too specific. Relaxing some conditions could yield better results. Remember, you can always refine your search later. 2) There could be a typo in your search query. 3) You might be searching in the wrong place.") elseif column > 30 error("SQL execution failed. An unexpected error occurred. Please try again.") end