This commit is contained in:
2026-07-02 18:25:56 +07:00
parent c4e255ec2a
commit 1577d7ae25
2 changed files with 114 additions and 145 deletions
+49 -65
View File
@@ -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]
thoughtDict["action_result"] = GeneralUtils.dfToString(response[:result])
rawresponse = response[:result]
(rawresponse=response[:result], result=extracted, errormsg=nothing, success=true)
else
thoughtDict["action_result"] = response[:errormsg]
rawresponse = nothing
(result=nothing, errormsg=response[:errormsg], success=false)
end
else else
error("undefined LLM function. Requesting $(thoughtDict["action_name"])") error("undefined LLM function. Requesting $(thoughtDict["action_name"])")
end end
# this section allow LLM functions above to have different return values. newNodeKey, newstate = makeNewState(state, thoughtDict, response)
success::Bool = haskey(response, :success) ? response[:success] : false progressvalue::Integer =
result = success ? response[:result] : response[:errormsg] if response[:success]
select = haskey(response, :select) ? response[:select] : nothing 8 # for faster agent response. if success just skip evaluation
reward::Integer = haskey(response, :reward) ? response[:reward] : 0 else
isterminal::Bool = haskey(response, :isterminal) ? response[:isterminal] : false evaluatorF(newstate, text2textInstructLLM, llmFormatName)
newNodeKey, newstate = makeNewState(state, thoughtDict, rawresponse, JSON.json(result), end
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
@@ -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,
+13 -28
View File
@@ -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,20 +497,15 @@ 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)
end else
df1 = df1 =
if row > 2 if row > 2
# ramdom row to pick # ramdom row to pick
@@ -529,18 +513,20 @@ function SQLexecution(executeSQL::Function, sql::T
else else
df df
end end
result = GeneralUtils.dfToString(df1)
println("\n~~~ SQLexecution() result: ", @__FILE__, " ", @__LINE__) println("\n~~~ SQLexecution() result: ", @__FILE__, " ", @__LINE__)
println(sql)
println(df1) println(df1)
return (result=df1, success=true, errormsg=nothing) println("\n")
return (result_str=result, result_raw=df1, success=true, errormsg=nothing)
end
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"])