update
This commit is contained in:
+90
-106
@@ -193,9 +193,9 @@ function decisionMaker(state::T1, text2textInstructLLM::Function, llmFormatName:
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
println("\nSQLLLM decisionMaker() ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
# println("\nSQLLLM decisionMaker() ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||||
pprintln(responsedict)
|
# pprintln(responsedict)
|
||||||
println("---")
|
# println("---")
|
||||||
|
|
||||||
return responsedict
|
return responsedict
|
||||||
end
|
end
|
||||||
@@ -770,36 +770,25 @@ function transition(state::T, args::NamedTuple
|
|||||||
# getting SQL from vectorDB
|
# getting SQL from vectorDB
|
||||||
thoughtDict = decisionMakerF(state, text2textInstructLLM, llmFormatName;
|
thoughtDict = decisionMakerF(state, text2textInstructLLM, llmFormatName;
|
||||||
querySQLVectorDBF)
|
querySQLVectorDBF)
|
||||||
println("\n--- SQLLLM transition() ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
# println("\n--- SQLLLM transition() ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||||
pprintln(thoughtDict)
|
# pprintln(thoughtDict)
|
||||||
println("---")
|
# println("---")
|
||||||
rawresponse = nothing
|
|
||||||
# map action and input() to llm function
|
# map action and input() to llm function
|
||||||
response =
|
response = nothing
|
||||||
if thoughtDict["action_name"] == "RUNSQL"
|
if thoughtDict["action_name"] == "RUNSQL"
|
||||||
response = SQLexecution(executeSQL, thoughtDict["action_input"])
|
response = SQLexecution(executeSQL, thoughtDict["action_input"])
|
||||||
if response[:success]
|
else
|
||||||
thoughtDict["action_result"] = GeneralUtils.dfToString(response[:result])
|
error("undefined LLM function. Requesting $(thoughtDict["action_name"])")
|
||||||
rawresponse = response[:result]
|
end
|
||||||
(rawresponse=response[:result], result=extracted, errormsg=nothing, success=true)
|
|
||||||
else
|
newNodeKey, newstate = makeNewState(state, thoughtDict, response)
|
||||||
thoughtDict["action_result"] = response[:errormsg]
|
progressvalue::Integer =
|
||||||
rawresponse = nothing
|
if response[:success]
|
||||||
(result=nothing, errormsg=response[:errormsg], success=false)
|
8 # for faster agent response. if success just skip evaluation
|
||||||
end
|
|
||||||
else
|
else
|
||||||
error("undefined LLM function. Requesting $(thoughtDict["action_name"])")
|
evaluatorF(newstate, text2textInstructLLM, llmFormatName)
|
||||||
end
|
end
|
||||||
|
|
||||||
# this section allow LLM functions above to have different return values.
|
|
||||||
success::Bool = haskey(response, :success) ? response[:success] : false
|
|
||||||
result = success ? response[:result] : response[:errormsg]
|
|
||||||
select = haskey(response, :select) ? response[:select] : nothing
|
|
||||||
reward::Integer = haskey(response, :reward) ? response[:reward] : 0
|
|
||||||
isterminal::Bool = haskey(response, :isterminal) ? response[:isterminal] : false
|
|
||||||
newNodeKey, newstate = makeNewState(state, thoughtDict, rawresponse, JSON.json(result),
|
|
||||||
select, reward, isterminal)
|
|
||||||
progressvalue::Integer = evaluatorF(newstate, text2textInstructLLM, llmFormatName)
|
|
||||||
return (newNodeKey=newNodeKey, newstate=newstate, progressvalue=progressvalue)
|
return (newNodeKey=newNodeKey, newstate=newstate, progressvalue=progressvalue)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -891,18 +880,19 @@ function query(query::T, executeSQL::Function, text2textInstructLLM::Function;
|
|||||||
insertSQLVectorDB::Union{Function, Nothing}=nothing,
|
insertSQLVectorDB::Union{Function, Nothing}=nothing,
|
||||||
similarSQLVectorDB::Union{Function, Nothing}=nothing,
|
similarSQLVectorDB::Union{Function, Nothing}=nothing,
|
||||||
llmFormatName="qwen3"
|
llmFormatName="qwen3"
|
||||||
)::NamedTuple{(:text, :rawresponse), Tuple{Any, Any}} where {T<:AbstractString}
|
) where {T<:AbstractString}
|
||||||
|
|
||||||
# use similarSQLVectorDB to find similar SQL for the query
|
# use similarSQLVectorDB to find similar SQL for the query
|
||||||
sql, distance = similarSQLVectorDB(query)
|
sql, distance = similarSQLVectorDB(query)
|
||||||
|
|
||||||
|
# if sql is really match, immediately check database then return
|
||||||
if sql !== nothing && distance <= 1
|
if sql !== nothing && distance <= 1
|
||||||
# query vector db to get wine
|
# query vector db to get wine
|
||||||
response = SQLexecution(executeSQL, sql)
|
response = SQLexecution(executeSQL, sql)
|
||||||
if response[:success]
|
if response[:success]
|
||||||
# intention = Dict(:intention=> "$(thoughtDict[:plan])")
|
return (result_str=response[:result_str], result_raw=response[:result_raw])
|
||||||
extracted = extractContent_dataframe(response[:result], text2textInstructLLM, sql,
|
else
|
||||||
llmFormatName)
|
error(response[:errormsg])
|
||||||
return (text=extracted, rawresponse=response[:result])
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -918,44 +908,44 @@ function query(query::T, executeSQL::Function, text2textInstructLLM::Function;
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
systemmsg =
|
systemmsg =
|
||||||
"""
|
"""
|
||||||
<available_actions>
|
<available_actions>
|
||||||
- RUNSQL, which you can use to execute SQL against the database.
|
- RUNSQL, which you can use to execute SQL against the database.
|
||||||
action_input for this function must be a single SQL query to be executed against the database.
|
action_input for this function must be a single SQL query 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 ';'.
|
||||||
</available_actions>
|
</available_actions>
|
||||||
<situation>
|
<situation>
|
||||||
At each round of conversation, you will be given the following:
|
At each round of conversation, you will be given the following:
|
||||||
- user question
|
- user question
|
||||||
You are working under your mentor supervision and you are also eager to improve your helpfulness.
|
You are working under your mentor supervision and you are also eager to improve your helpfulness.
|
||||||
</situation>
|
</situation>
|
||||||
<objective>
|
<objective>
|
||||||
Consult the database search guidelines. Then find the data from a database to satisfy the user's question.
|
Consult the database search guidelines. Then find the data from a database to satisfy the user's question.
|
||||||
</objective>
|
</objective>
|
||||||
<your responsibility includes>
|
<your responsibility includes>
|
||||||
Fulfill the objective.
|
Fulfill the objective.
|
||||||
</your responsibility includes>
|
</your responsibility includes>
|
||||||
<database search guidelines>
|
<database search guidelines>
|
||||||
- Keep SQL queries focused only on the provided information.
|
- Keep SQL queries focused only on the provided information.
|
||||||
- Do not create any table in the database
|
- Do not create any table in the database
|
||||||
- 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.
|
||||||
- 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.
|
||||||
- If there is no search result from the database, remove the restrictive criteria until a search result is available, and proceed from there.
|
- If there is no search result from the database, remove the restrictive criteria until a search result is available, and proceed from there.
|
||||||
</database search guidelines>
|
</database search guidelines>
|
||||||
<you should then respond to the user with interleaving plan, action_name, action_input>
|
<you should then respond to the user with interleaving plan, action_name, action_input>
|
||||||
1) plan: Based on the current situation, state a complete action plan to complete the task. Be specific.
|
1) plan: Based on the current situation, state a complete action plan to complete the task. Be specific.
|
||||||
2) action_name: (Typically corresponds to the execution of the first step in your plan) Can be one of the available_actions name
|
2) action_name: (Typically corresponds to the execution of the first step in your plan) Can be one of the available_actions name
|
||||||
3) action_input: The input to the action you are about to perform according to your plan.
|
3) action_input: The input to the action you are about to perform according to your plan.
|
||||||
After the action is executed you gets "action_result". It is the output from the action you selected.
|
After the action is executed you gets "action_result". It is the output from the action you selected.
|
||||||
</you should then respond to the user with interleaving plan, action_name, action_input>
|
</you should then respond to the user with interleaving plan, action_name, action_input>
|
||||||
<you should only respond in JSON format as described below>
|
<you should only respond in JSON format as described below>
|
||||||
"plan": "...",
|
"plan": "...",
|
||||||
"action_name": "...",
|
"action_name": "...",
|
||||||
"action_input": "..."
|
"action_input": "..."
|
||||||
</you should only respond in JSON format as described below>
|
</you should only respond in JSON format as described below>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1129,11 +1119,11 @@ function query(query::T, executeSQL::Function, text2textInstructLLM::Function;
|
|||||||
|
|
||||||
root, _, resultState, highValueState =
|
root, _, resultState, highValueState =
|
||||||
LLMMCTS.runMCTS(initialstate, transition, transitionargs;
|
LLMMCTS.runMCTS(initialstate, transition, transitionargs;
|
||||||
horizontalSampleExpansionPhase=1,
|
horizontalSampleExpansionPhase=2,
|
||||||
horizontalSampleSimulationPhase=1,
|
horizontalSampleSimulationPhase=2,
|
||||||
maxSimulationDepth=1,
|
maxSimulationDepth=2,
|
||||||
maxiterations=1,
|
maxiterations=2,
|
||||||
explorationweight=1.0,
|
explorationweight=0.2,
|
||||||
earlystop=earlystop,
|
earlystop=earlystop,
|
||||||
saveSimulatedNode=true,
|
saveSimulatedNode=true,
|
||||||
multithread=false)
|
multithread=false)
|
||||||
@@ -1144,11 +1134,6 @@ function query(query::T, executeSQL::Function, text2textInstructLLM::Function;
|
|||||||
resultState = highValueState[selected]
|
resultState = highValueState[selected]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
println("\n--- SQLLLM query() resultState ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
|
||||||
pprintln(resultState)
|
|
||||||
println("---")
|
|
||||||
|
|
||||||
max_ind =
|
max_ind =
|
||||||
if length(resultState["action_history"]) == 0
|
if length(resultState["action_history"]) == 0
|
||||||
0
|
0
|
||||||
@@ -1157,25 +1142,20 @@ function query(query::T, executeSQL::Function, text2textInstructLLM::Function;
|
|||||||
maximum(parse.(Int, k))
|
maximum(parse.(Int, k))
|
||||||
end
|
end
|
||||||
latest_action = resultState["action_history"]["$max_ind"]
|
latest_action = resultState["action_history"]["$max_ind"]
|
||||||
sql = latest_action["action_input"]
|
|
||||||
|
|
||||||
# add to vectorDB only if the answer is achieved and the state is terminal
|
#CHANGE add to vectorDB only if the answer is achieved and the state is terminal
|
||||||
if insertSQLVectorDB !== nothing && resultState["isterminal"] == true &&
|
# sql = latest_action["action_input"]
|
||||||
resultState["accepted_as_answer"] == "yes"
|
# if insertSQLVectorDB !== nothing && resultState["isterminal"] == true &&
|
||||||
|
# resultState["accepted_as_answer"] == "yes"
|
||||||
|
# insertSQLVectorDB(resultState["question"], sql)
|
||||||
|
# end
|
||||||
|
|
||||||
insertSQLVectorDB(resultState["question"], sql)
|
# println("\n--- SQLLLM query() ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||||
end
|
# println(latest_action)
|
||||||
|
# println("---")
|
||||||
|
# error("SQLLLM query() end")
|
||||||
|
|
||||||
if latest_action["action_result"] === nothing
|
return (result_str=latest_action["action_result"], result_raw=resultState["result_raw"])
|
||||||
println("\nSQLLLM query() return nothing ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
|
||||||
end
|
|
||||||
#WORKING 1
|
|
||||||
error("SQLLLM query() end")
|
|
||||||
result = (text=latest_action["action_result"], rawresponse=resultState["rawresponse"])
|
|
||||||
println("\n--- SQLLLM query() ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
|
||||||
println("---")
|
|
||||||
error("SQLLLM query() end")
|
|
||||||
return result
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -1192,9 +1172,14 @@ julia>
|
|||||||
|
|
||||||
# Signature
|
# Signature
|
||||||
"""
|
"""
|
||||||
function makeNewState(currentstate::T1, thoughtDict::T4, rawresponse, response::T2, select::Union{T3, Nothing},
|
function makeNewState(currentstate::T1, thoughtDict::T2, response::NamedTuple,
|
||||||
reward::T3, isterminal::Bool
|
)::NamedTuple{(:newNodeKey, :newstate), Tuple{String, Dict{String, <:Any}}} where {T1<:AbstractDict, T2<:AbstractDict}
|
||||||
)::NamedTuple{(:newNodeKey, :newstate), Tuple{String, Dict{String, <:Any}}} where {T1<:AbstractDict, T2<:AbstractString, T3<:Number, T4<:AbstractDict}
|
|
||||||
|
if response[:success]
|
||||||
|
thoughtDict["action_result"] = response[:result_str]
|
||||||
|
else
|
||||||
|
error(response[:errormsg])
|
||||||
|
end
|
||||||
|
|
||||||
newstate = deepcopy(currentstate)
|
newstate = deepcopy(currentstate)
|
||||||
max_ind =
|
max_ind =
|
||||||
@@ -1205,17 +1190,16 @@ function makeNewState(currentstate::T1, thoughtDict::T4, rawresponse, response::
|
|||||||
maximum(parse.(Int, k))
|
maximum(parse.(Int, k))
|
||||||
end
|
end
|
||||||
newstate["action_history"]["$(max_ind + 1)"] = thoughtDict
|
newstate["action_history"]["$(max_ind + 1)"] = thoughtDict
|
||||||
newstate["reward"] = reward
|
newstate["reward"] = haskey(response, :reward) ? response[:reward] : 0
|
||||||
newstate["select"] = select
|
newstate["select"] = haskey(response, :select) ? response[:select] : nothing
|
||||||
newstate["isterminal"] = isterminal
|
newstate["isterminal"] = haskey(response, :isterminal) ? response[:isterminal] : false
|
||||||
newstate["rawresponse"] = rawresponse # whatever return from action
|
newstate["result_raw"] = response[:result_raw] # whatever return from action
|
||||||
|
|
||||||
newNodeKey = GeneralUtils.uuid4snakecase()
|
newNodeKey = GeneralUtils.uuid4snakecase()
|
||||||
|
|
||||||
return (newNodeKey=newNodeKey, newstate=newstate)
|
return (newNodeKey=newNodeKey, newstate=newstate)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function generatequestion(state::T1, context, text2textInstructLLM::Function,
|
function generatequestion(state::T1, context, text2textInstructLLM::Function,
|
||||||
llmFormatName::String;
|
llmFormatName::String;
|
||||||
similarSQL::Union{T2, Nothing}=nothing, maxattempt=10,
|
similarSQL::Union{T2, Nothing}=nothing, maxattempt=10,
|
||||||
|
|||||||
+21
-36
@@ -481,20 +481,9 @@ julia> response = SQLLLM.SQLexecution(executeSQL, sql)
|
|||||||
# Signature
|
# Signature
|
||||||
"""
|
"""
|
||||||
function SQLexecution(executeSQL::Function, sql::T
|
function SQLexecution(executeSQL::Function, sql::T
|
||||||
) where {T<:AbstractString}
|
)::NamedTuple where {T<:AbstractString}
|
||||||
|
|
||||||
try
|
try
|
||||||
#XXX dummy SQL. use for testing
|
|
||||||
# sql = "SELECT w.wine_name FROM wine w JOIN wine_food wf ON w.wine_id = wf.wine_id JOIN food f ON wf.food_id = f.food_id WHERE f.\"food_name\" = 'lamb';"
|
|
||||||
# sql = " SELECT w.wine_name FROM wine w JOIN food f ON f.food_name = 'lamb' JOIN wine_food wf ON w.wine_id = wf.wine_id AND f.food_id = wf.food_id GROUP BY w.wine_name ORDER BY COUNT(DISTINCT w.wine_id) DESC;"
|
|
||||||
# sql = " SELECT COUNT(DISTINCT wf.wine_id) FROM wine w JOIN wine_food wf ON w.wine_id = wf.wine_id JOIN food f ON wf.food_id = f.food_id WHERE f.food_name ILIKE '%lamb%'"
|
|
||||||
|
|
||||||
#XXX use for package testing, remove when done
|
|
||||||
# ans = "1.schilfwein zweigelt 2.cabernet sauvignon reserve limited edition"
|
|
||||||
# ans = "There are 1500 wines that can be paired with lamb."
|
|
||||||
# ans = "1500"
|
|
||||||
# return (response=ans, errormsg=nothing, reward=1, isterminal=true)
|
|
||||||
|
|
||||||
# add LIMIT to the SQL to prevent loading large data
|
# add LIMIT to the SQL to prevent loading large data
|
||||||
sql = strip(sql)
|
sql = strip(sql)
|
||||||
|
|
||||||
@@ -508,39 +497,36 @@ function SQLexecution(executeSQL::Function, sql::T
|
|||||||
else
|
else
|
||||||
sql = sql * ";"
|
sql = sql * ";"
|
||||||
end
|
end
|
||||||
println("\n~~~ SQLexecution() SQL: ", @__FILE__, " ", @__LINE__)
|
|
||||||
println(sql)
|
|
||||||
|
|
||||||
result = executeSQL(sql)
|
result = executeSQL(sql)
|
||||||
df = DataFrame(result)
|
df = DataFrame(result)
|
||||||
|
|
||||||
tablesize = size(df)
|
tablesize = size(df)
|
||||||
row, column = tablesize
|
row, column = tablesize
|
||||||
if row == 0
|
if row == 0
|
||||||
error("\nThe resulting table has 0 row. Please try again.")
|
return (result_str="The resulting table has 0 row.", result_raw=df, success=true, errormsg=nothing)
|
||||||
elseif column > 50
|
elseif column > 30
|
||||||
error("\nSQL execution success but there are more than 50 rows Please be more specific.")
|
return (result_str="There are more than 30 columns. Please be more specific.", result_raw=df, success=true, errormsg=nothing)
|
||||||
|
else
|
||||||
|
df1 =
|
||||||
|
if row > 2
|
||||||
|
# ramdom row to pick
|
||||||
|
df[sample(1:nrow(df), 2, replace=false), :] # random select 2 rows from df
|
||||||
|
else
|
||||||
|
df
|
||||||
|
end
|
||||||
|
result = GeneralUtils.dfToString(df1)
|
||||||
|
println("\n~~~ SQLexecution() result: ", @__FILE__, " ", @__LINE__)
|
||||||
|
println(sql)
|
||||||
|
println(df1)
|
||||||
|
println("\n")
|
||||||
|
return (result_str=result, result_raw=df1, success=true, errormsg=nothing)
|
||||||
end
|
end
|
||||||
|
|
||||||
df1 =
|
|
||||||
if row > 2
|
|
||||||
# ramdom row to pick
|
|
||||||
df[sample(1:nrow(df), 2, replace=false), :] # random select 2 rows from df
|
|
||||||
else
|
|
||||||
df
|
|
||||||
end
|
|
||||||
|
|
||||||
println("\n~~~ SQLexecution() result: ", @__FILE__, " ", @__LINE__)
|
|
||||||
println(df1)
|
|
||||||
return (result=df1, success=true, errormsg=nothing)
|
|
||||||
catch e
|
catch e
|
||||||
io = IOBuffer()
|
io = IOBuffer()
|
||||||
showerror(io, e)
|
showerror(io, e)
|
||||||
errorMsg = String(take!(io))
|
errorMsg = String(take!(io))
|
||||||
st = sprint((io, v) -> show(io, "text/plain", v), stacktrace(catch_backtrace()))
|
st = sprint((io, v) -> show(io, "text/plain", v), stacktrace(catch_backtrace()))
|
||||||
println(errorMsg)
|
println(errorMsg)
|
||||||
response = (result=nothing, success=false, errormsg=errorMsg)
|
return (result_str=nothing, result_raw=nothing, success=false, errormsg=errorMsg)
|
||||||
return response
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -559,7 +545,7 @@ end
|
|||||||
- `result::String`
|
- `result::String`
|
||||||
|
|
||||||
# Signature
|
# Signature
|
||||||
"""
|
""" #WORKING
|
||||||
function extractContent_dataframe(df::DataFrame, text2textInstructLLM::Function, action::String,
|
function extractContent_dataframe(df::DataFrame, text2textInstructLLM::Function, action::String,
|
||||||
llmFormatName::String
|
llmFormatName::String
|
||||||
)::String
|
)::String
|
||||||
@@ -633,7 +619,7 @@ function extractContent_dataframe(df::DataFrame, text2textInstructLLM::Function,
|
|||||||
dictkey = ["about_resulting_table", "search_summary"]
|
dictkey = ["about_resulting_table", "search_summary"]
|
||||||
|
|
||||||
for i in 1:5
|
for i in 1:5
|
||||||
response = text2textInstructLLM(prompt, modelsize="medium")
|
response = text2textInstructLLM("ramdom_id", prompt)
|
||||||
response = GeneralUtils.deFormatLLMtext(response, llmFormatName)
|
response = GeneralUtils.deFormatLLMtext(response, llmFormatName)
|
||||||
think, response = GeneralUtils.extractthink(response)
|
think, response = GeneralUtils.extractthink(response)
|
||||||
|
|
||||||
@@ -653,7 +639,6 @@ function extractContent_dataframe(df::DataFrame, text2textInstructLLM::Function,
|
|||||||
responsedict = GeneralUtils.textToDict(response, header;
|
responsedict = GeneralUtils.textToDict(response, header;
|
||||||
dictKey=dictkey, symbolkey=false)
|
dictKey=dictkey, symbolkey=false)
|
||||||
|
|
||||||
# result = dfstr
|
|
||||||
result =
|
result =
|
||||||
"""
|
"""
|
||||||
Summary: $(responsedict["search_summary"])
|
Summary: $(responsedict["search_summary"])
|
||||||
|
|||||||
Reference in New Issue
Block a user