9 Commits

Author SHA1 Message Date
38108d7e8d update 2024-12-27 20:33:24 +07:00
1e36ea96e9 update 2024-12-23 07:20:40 +07:00
4f7f23565e update 2024-12-22 11:32:11 +07:00
narawat lamaiin
d7d97454a9 update 2024-12-19 18:49:20 +07:00
narawat lamaiin
debd663f44 update 2024-12-10 13:13:36 +07:00
narawat lamaiin
d0262124d3 update 2024-12-09 21:46:02 +07:00
narawat lamaiin
726599bab3 update 2024-12-09 21:44:58 +07:00
narawat lamaiin
ba74688143 update 2024-12-09 21:27:15 +07:00
narawat lamaiin
d1a05741ba update 2024-12-09 21:17:54 +07:00
4 changed files with 56 additions and 28 deletions

View File

@@ -2,7 +2,7 @@
julia_version = "1.11.2" julia_version = "1.11.2"
manifest_format = "2.0" manifest_format = "2.0"
project_hash = "7276bacf2126ccf319f58f1cc1aab4f9a73ac360" project_hash = "6e88822413ea4a623cd914d84de127dc6c57fceb"
[[deps.AliasTables]] [[deps.AliasTables]]
deps = ["PtrArrays", "Random"] deps = ["PtrArrays", "Random"]
@@ -306,11 +306,11 @@ version = "1.19.3+0"
[[deps.LLMMCTS]] [[deps.LLMMCTS]]
deps = ["GeneralUtils", "JSON3"] deps = ["GeneralUtils", "JSON3"]
git-tree-sha1 = "5be792515b65e464d15ac8db6a9f6f6628c7d81a" git-tree-sha1 = "c8ad9715e78bbd19f5ac79e1f1cacf85f141449d"
repo-rev = "main" repo-rev = "main"
repo-url = "https://git.yiem.cc/ton/LLMMCTS" repo-url = "https://git.yiem.cc/ton/LLMMCTS"
uuid = "d76c5a4d-449e-4835-8cc4-dd86ec44f241" uuid = "d76c5a4d-449e-4835-8cc4-dd86ec44f241"
version = "0.1.0" version = "0.1.2"
[[deps.LaTeXStrings]] [[deps.LaTeXStrings]]
git-tree-sha1 = "dda21b8cbd6a6c40d9d02a73230f9d70fed6918c" git-tree-sha1 = "dda21b8cbd6a6c40d9d02a73230f9d70fed6918c"

View File

@@ -1,7 +1,7 @@
name = "SQLLLM" name = "SQLLLM"
uuid = "2ebc79c7-cc10-4a3a-9665-d2e1d61e63d3" uuid = "2ebc79c7-cc10-4a3a-9665-d2e1d61e63d3"
authors = ["narawat lamaiin <narawat@outlook.com>"] authors = ["narawat lamaiin <narawat@outlook.com>"]
version = "0.1.0" version = "0.2.1"
[deps] [deps]
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
@@ -24,4 +24,4 @@ UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
[compat] [compat]
GeneralUtils = "0.1.0" GeneralUtils = "0.1.0"
LLMMCTS = "0.1.0" LLMMCTS = "0.1.2"

View File

@@ -133,25 +133,27 @@ function decisionMaker(state::T1, context, text2textInstructLLM::Function,
systemmsg = 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. You are also eager to improve your helpfulness.
At each round of conversation, the user will give you the current situation: At each round of conversation, the user will give you the current situation:
User Query: ... User Query: ...
Hints: ... Example: ...
Your Q&A: ... Your Q&A: ...
Your work progress: ... Your work progress: ...
Evaluation: Evaluation of the latest action and observation Evaluation: Evaluation of the latest action and observation
Suggestion: ... 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 - Do not create any table in the database
- Column name can be the same in different tables. Refer to column comments to get more details by using TABLEINFO function - 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. - 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 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". - 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. - 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: You should then respond to the user with interleaving Understanding, Reasoning, Plan, Action:
1) Understanding: 1) Understanding:
@@ -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. 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: 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"] - 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. 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 ';'. 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 5) Action_input: Input to the action
@@ -173,7 +175,6 @@ function decisionMaker(state::T1, context, text2textInstructLLM::Function,
Plan: ... Plan: ...
Action_name: ... Action_name: ...
Action_input: ... Action_input: ...
Observation: ...
Let's begin! Let's begin!
""" """
@@ -203,7 +204,7 @@ function decisionMaker(state::T1, context, text2textInstructLLM::Function,
""" """
$(context[:tablelist]) $(context[:tablelist])
User query: $(state[:thoughtHistory][:question]) User query: $(state[:thoughtHistory][:question])
Hints: $similarSQL_ Example: $similarSQL_
Your Q&A: $QandA Your Q&A: $QandA
Your work progress: $workprogress Your work progress: $workprogress
Evaluation: $(state[:evaluation]) Evaluation: $(state[:evaluation])
@@ -226,18 +227,32 @@ function decisionMaker(state::T1, context, text2textInstructLLM::Function,
try try
response = text2textInstructLLM(prompt) response = text2textInstructLLM(prompt)
println("\nSQL decisionMaker() rawresponse: ", response)
header = ["Understanding", "Reasoning", "Plan", "Action_name", "Action_input", "Observation"]
# detect if there are more than 1 key per categories
count = GeneralUtils.countGivenWords(response, header)
if sum(count) > length(header)
error("\nSQL decisionMaker() duplicated keywords", @__FILE__, " ", @__LINE__)
end
# textToDict() search for action_input # textToDict() search for action_input
responsedict = GeneralUtils.textToDict(response, responsedict = GeneralUtils.textToDict(response, header,
["Understanding", "Reasoning", "Plan", "Action_name", "Action_input", "Observation"],
rightmarker=":", symbolkey=true, lowercasekey=true) rightmarker=":", symbolkey=true, lowercasekey=true)
delete!(responsedict, :observation) delete!(responsedict, :observation)
# remove backticks # remove backticks Error occurred: MethodError: no method matching occursin(::String, ::Vector{String})
if occursin("```", responsedict[:action_input]) if occursin("```", responsedict[:action_input])
responsedict[:action_input] = sql = GeneralUtils.extract_triple_backtick_text(responsedict[:action_input])[1]
GeneralUtils.extract_triple_backtick_text(responsedict[:action_input]) 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
toollist = ["TABLEINFO", "GETDATA"] toollist = ["TABLEINFO", "GETDATA"]
@@ -277,6 +292,7 @@ function decisionMaker(state::T1, context, text2textInstructLLM::Function,
println("\n~~~ SQLLLM decisionMaker() Attempt $attempt. Error occurred: $errorMsg\n$st ", @__FILE__, " ", @__LINE__) println("\n~~~ SQLLLM decisionMaker() Attempt $attempt. Error occurred: $errorMsg\n$st ", @__FILE__, " ", @__LINE__)
println("") println("")
end end
end end
error("DecisionMaker failed to generate a thought ", response) error("DecisionMaker failed to generate a thought ", response)
end end
@@ -302,7 +318,7 @@ julia>
# Signature # Signature
""" """
function evaluator(state::T1, text2textInstructLLM::Function; function evaluator(state::T1, text2textInstructLLM::Function;
addSQLVectorDB::Union{Function, Nothing}=nothing insertSQLVectorDB::Union{Function, Nothing}=nothing
) where {T1<:AbstractDict} ) where {T1<:AbstractDict}
# systemmsg = # systemmsg =
@@ -768,7 +784,7 @@ function transition(state::T, args::NamedTuple
context = args[:context] context = args[:context]
executeSQL::Function = args[:executeSQL] executeSQL::Function = args[:executeSQL]
text2textInstructLLM::Function = args[:text2textInstructLLM] text2textInstructLLM::Function = args[:text2textInstructLLM]
addSQLVectorDBF::Function = args[:addSQLVectorDB] insertSQLVectorDB::Function = args[:insertSQLVectorDB]
querySQLVectorDBF::Function = args[:querySQLVectorDB] querySQLVectorDBF::Function = args[:querySQLVectorDB]
# getting SQL from vectorDB # getting SQL from vectorDB
@@ -804,7 +820,7 @@ function transition(state::T, args::NamedTuple
isterminal::Bool = haskey(response, :isterminal) ? response[:isterminal] : false isterminal::Bool = haskey(response, :isterminal) ? response[:isterminal] : false
newNodeKey, newstate = makeNewState(state, thoughtDict, rawresponse, JSON3.write(result), select, reward, isterminal) newNodeKey, newstate = makeNewState(state, thoughtDict, rawresponse, JSON3.write(result), select, reward, isterminal)
progressvalue::Integer = evaluatorF(newstate, text2textInstructLLM; progressvalue::Integer = evaluatorF(newstate, text2textInstructLLM;
addSQLVectorDB=addSQLVectorDBF) insertSQLVectorDB=insertSQLVectorDB)
return (newNodeKey=newNodeKey, newstate=newstate, progressvalue=progressvalue) return (newNodeKey=newNodeKey, newstate=newstate, progressvalue=progressvalue)
end end
@@ -887,7 +903,7 @@ julia> println(result)
# Signature # Signature
""" """
function query(query::T, executeSQL::Function, text2textInstructLLM::Function; function query(query::T, executeSQL::Function, text2textInstructLLM::Function;
addSQLVectorDB::Union{Function, Nothing}=nothing, insertSQLVectorDB::Union{Function, Nothing}=nothing,
similarSQLVectorDB::Union{Function, Nothing}=nothing, similarSQLVectorDB::Union{Function, Nothing}=nothing,
) where {T<:AbstractString} ) where {T<:AbstractString}
@@ -931,7 +947,7 @@ function query(query::T, executeSQL::Function, text2textInstructLLM::Function;
executeSQL=executeSQL, executeSQL=executeSQL,
text2textInstructLLM=text2textInstructLLM, text2textInstructLLM=text2textInstructLLM,
querySQLVectorDB=similarSQLVectorDB, querySQLVectorDB=similarSQLVectorDB,
addSQLVectorDB=addSQLVectorDB, insertSQLVectorDB=insertSQLVectorDB,
) )
earlystop(state) = state[:reward] >= 8 ? true : false earlystop(state) = state[:reward] >= 8 ? true : false
@@ -945,8 +961,10 @@ function query(query::T, executeSQL::Function, text2textInstructLLM::Function;
extracted = resultState[:thoughtHistory][latestKey] extracted = resultState[:thoughtHistory][latestKey]
# add to vectorDB only if the answer is achieved and the state is terminal # add to vectorDB only if the answer is achieved and the state is terminal
if addSQLVectorDB !== nothing && resultState[:isterminal] == true if insertSQLVectorDB !== nothing && resultState[:isterminal] == true &&
addSQLVectorDB(resultState[:thoughtHistory][:question], sql) resultState[:rawresponse] !== nothing
insertSQLVectorDB(resultState[:thoughtHistory][:question], sql)
end end
return (text=extracted, rawresponse=resultState[:rawresponse]) return (text=extracted, rawresponse=resultState[:rawresponse])
@@ -1017,11 +1035,11 @@ function generatequestion(state::T1, context, text2textInstructLLM::Function;
systemmsg = 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: At each round of conversation, the user will give you the current situation:
User query: ... User query: ...
Hints: ... Example: ...
Your work progress: ... Your work progress: ...
About the tables in the database: About the tables in the database:
@@ -1035,6 +1053,9 @@ function generatequestion(state::T1, context, text2textInstructLLM::Function;
3) Some information can be accessed by joining multiple tables. 3) Some information can be accessed by joining multiple tables.
4) Do not generate any question or comments at the end. 4) Do not generate any question or comments at the end.
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: You should then respond to the user with:
1) Understanding: 1) Understanding:
- State your understanding about the current situation. - State your understanding about the current situation.
@@ -1052,6 +1073,13 @@ function generatequestion(state::T1, context, text2textInstructLLM::Function;
A3: ... 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! Let's begin!
""" """
@@ -1071,7 +1099,7 @@ function generatequestion(state::T1, context, text2textInstructLLM::Function;
""" """
$(context[:tablelist]) $(context[:tablelist])
User query: $(state[:thoughtHistory][:question]) User query: $(state[:thoughtHistory][:question])
Hints: $similarSQL Example: $similarSQL
Your work progress: $workprogress Your work progress: $workprogress
$errornote $errornote
$noise $noise

View File

@@ -613,7 +613,7 @@ function SQLexecution(executeSQL::Function, sql::T
tablesize = size(df) tablesize = size(df)
row, column = tablesize row, column = tablesize
if row == 0 # if 0 row 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 elseif column > 30
error("SQL execution failed. An unexpected error occurred. Please try again.") error("SQL execution failed. An unexpected error occurred. Please try again.")
end end