diff --git a/src/interface.jl b/src/interface.jl
index b330672..ec1c1ec 100644
--- a/src/interface.jl
+++ b/src/interface.jl
@@ -193,9 +193,9 @@ function decisionMaker(state::T1, text2textInstructLLM::Function, llmFormatName:
end
end
- println("\nSQLLLM decisionMaker() ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
- pprintln(responsedict)
- println("---")
+ # println("\nSQLLLM decisionMaker() ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
+ # pprintln(responsedict)
+ # println("---")
return responsedict
end
@@ -770,36 +770,25 @@ function transition(state::T, args::NamedTuple
# getting SQL from vectorDB
thoughtDict = decisionMakerF(state, text2textInstructLLM, llmFormatName;
querySQLVectorDBF)
- println("\n--- SQLLLM transition() ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
- pprintln(thoughtDict)
- println("---")
- rawresponse = nothing
+ # println("\n--- SQLLLM transition() ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
+ # pprintln(thoughtDict)
+ # println("---")
# map action and input() to llm function
- response =
- if thoughtDict["action_name"] == "RUNSQL"
- 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
+ response = nothing
+ if thoughtDict["action_name"] == "RUNSQL"
+ response = SQLexecution(executeSQL, thoughtDict["action_input"])
+ else
+ error("undefined LLM function. Requesting $(thoughtDict["action_name"])")
+ end
+
+ newNodeKey, newstate = makeNewState(state, thoughtDict, response)
+ progressvalue::Integer =
+ if response[:success]
+ 8 # for faster agent response. if success just skip evaluation
else
- error("undefined LLM function. Requesting $(thoughtDict["action_name"])")
+ evaluatorF(newstate, text2textInstructLLM, llmFormatName)
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)
end
@@ -891,19 +880,20 @@ function query(query::T, executeSQL::Function, text2textInstructLLM::Function;
insertSQLVectorDB::Union{Function, Nothing}=nothing,
similarSQLVectorDB::Union{Function, Nothing}=nothing,
llmFormatName="qwen3"
- )::NamedTuple{(:text, :rawresponse), Tuple{Any, Any}} where {T<:AbstractString}
+ ) where {T<:AbstractString}
# use similarSQLVectorDB to find similar SQL for the query
sql, distance = similarSQLVectorDB(query)
+
+ # if sql is really match, immediately check database then return
if sql !== nothing && distance <= 1
# query vector db to get wine
response = SQLexecution(executeSQL, sql)
if response[:success]
- # intention = Dict(:intention=> "$(thoughtDict[:plan])")
- extracted = extractContent_dataframe(response[:result], text2textInstructLLM, sql,
- llmFormatName)
- return (text=extracted, rawresponse=response[:result])
- end
+ return (result_str=response[:result_str], result_raw=response[:result_raw])
+ else
+ error(response[:errormsg])
+ end
end
"""
@@ -918,44 +908,44 @@ function query(query::T, executeSQL::Function, text2textInstructLLM::Function;
"""
systemmsg =
- """
-
- - 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.
- 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 ';'.
-
-
- At each round of conversation, you will be given the following:
- - user question
- You are working under your mentor supervision and you are also eager to improve your helpfulness.
-
-
- Consult the database search guidelines. Then find the data from a database to satisfy the user's question.
-
-
- Fulfill the objective.
-
-
- - Keep SQL queries focused only on the provided information.
- - 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.
- - 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.
- - If there is no search result from the database, remove the restrictive criteria until a search result is available, and proceed from there.
-
-
- 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
- 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.
-
-
- "plan": "...",
- "action_name": "...",
- "action_input": "..."
-
- """
+ """
+
+ - 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.
+ 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 ';'.
+
+
+ At each round of conversation, you will be given the following:
+ - user question
+ You are working under your mentor supervision and you are also eager to improve your helpfulness.
+
+
+ Consult the database search guidelines. Then find the data from a database to satisfy the user's question.
+
+
+ Fulfill the objective.
+
+
+ - Keep SQL queries focused only on the provided information.
+ - 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.
+ - 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.
+ - If there is no search result from the database, remove the restrictive criteria until a search result is available, and proceed from there.
+
+
+ 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
+ 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.
+
+
+ "plan": "...",
+ "action_name": "...",
+ "action_input": "..."
+
+ """
@@ -1129,11 +1119,11 @@ function query(query::T, executeSQL::Function, text2textInstructLLM::Function;
root, _, resultState, highValueState =
LLMMCTS.runMCTS(initialstate, transition, transitionargs;
- horizontalSampleExpansionPhase=1,
- horizontalSampleSimulationPhase=1,
- maxSimulationDepth=1,
- maxiterations=1,
- explorationweight=1.0,
+ horizontalSampleExpansionPhase=2,
+ horizontalSampleSimulationPhase=2,
+ maxSimulationDepth=2,
+ maxiterations=2,
+ explorationweight=0.2,
earlystop=earlystop,
saveSimulatedNode=true,
multithread=false)
@@ -1144,11 +1134,6 @@ function query(query::T, executeSQL::Function, text2textInstructLLM::Function;
resultState = highValueState[selected]
end
-
- println("\n--- SQLLLM query() resultState ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
- pprintln(resultState)
- println("---")
-
max_ind =
if length(resultState["action_history"]) == 0
0
@@ -1157,25 +1142,20 @@ function query(query::T, executeSQL::Function, text2textInstructLLM::Function;
maximum(parse.(Int, k))
end
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
- if insertSQLVectorDB !== nothing && resultState["isterminal"] == true &&
- resultState["accepted_as_answer"] == "yes"
-
- insertSQLVectorDB(resultState["question"], sql)
- end
- if latest_action["action_result"] === nothing
- 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
+ #CHANGE add to vectorDB only if the answer is achieved and the state is terminal
+ # sql = latest_action["action_input"]
+ # if insertSQLVectorDB !== nothing && resultState["isterminal"] == true &&
+ # resultState["accepted_as_answer"] == "yes"
+ # insertSQLVectorDB(resultState["question"], sql)
+ # end
+
+ # println("\n--- SQLLLM query() ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
+ # println(latest_action)
+ # println("---")
+ # error("SQLLLM query() end")
+
+ return (result_str=latest_action["action_result"], result_raw=resultState["result_raw"])
end
@@ -1192,9 +1172,14 @@ julia>
# Signature
"""
-function makeNewState(currentstate::T1, thoughtDict::T4, rawresponse, response::T2, select::Union{T3, Nothing},
- reward::T3, isterminal::Bool
- )::NamedTuple{(:newNodeKey, :newstate), Tuple{String, Dict{String, <:Any}}} where {T1<:AbstractDict, T2<:AbstractString, T3<:Number, T4<:AbstractDict}
+function makeNewState(currentstate::T1, thoughtDict::T2, response::NamedTuple,
+ )::NamedTuple{(:newNodeKey, :newstate), Tuple{String, Dict{String, <:Any}}} where {T1<:AbstractDict, T2<:AbstractDict}
+
+ if response[:success]
+ thoughtDict["action_result"] = response[:result_str]
+ else
+ error(response[:errormsg])
+ end
newstate = deepcopy(currentstate)
max_ind =
@@ -1205,17 +1190,16 @@ function makeNewState(currentstate::T1, thoughtDict::T4, rawresponse, response::
maximum(parse.(Int, k))
end
newstate["action_history"]["$(max_ind + 1)"] = thoughtDict
- newstate["reward"] = reward
- newstate["select"] = select
- newstate["isterminal"] = isterminal
- newstate["rawresponse"] = rawresponse # whatever return from action
+ newstate["reward"] = haskey(response, :reward) ? response[:reward] : 0
+ newstate["select"] = haskey(response, :select) ? response[:select] : nothing
+ newstate["isterminal"] = haskey(response, :isterminal) ? response[:isterminal] : false
+ newstate["result_raw"] = response[:result_raw] # whatever return from action
newNodeKey = GeneralUtils.uuid4snakecase()
return (newNodeKey=newNodeKey, newstate=newstate)
end
-
function generatequestion(state::T1, context, text2textInstructLLM::Function,
llmFormatName::String;
similarSQL::Union{T2, Nothing}=nothing, maxattempt=10,
diff --git a/src/llmfunction.jl b/src/llmfunction.jl
index 6d16059..33fa2fb 100644
--- a/src/llmfunction.jl
+++ b/src/llmfunction.jl
@@ -481,20 +481,9 @@ julia> response = SQLLLM.SQLexecution(executeSQL, sql)
# Signature
"""
function SQLexecution(executeSQL::Function, sql::T
-) where {T<:AbstractString}
+ )::NamedTuple where {T<:AbstractString}
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
sql = strip(sql)
@@ -508,39 +497,36 @@ function SQLexecution(executeSQL::Function, sql::T
else
sql = sql * ";"
end
- println("\n~~~ SQLexecution() SQL: ", @__FILE__, " ", @__LINE__)
- println(sql)
-
result = executeSQL(sql)
df = DataFrame(result)
-
tablesize = size(df)
row, column = tablesize
if row == 0
- error("\nThe resulting table has 0 row. Please try again.")
- elseif column > 50
- error("\nSQL execution success but there are more than 50 rows Please be more specific.")
+ return (result_str="The resulting table has 0 row.", result_raw=df, success=true, errormsg=nothing)
+ elseif column > 30
+ 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
-
- 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
io = IOBuffer()
showerror(io, e)
errorMsg = String(take!(io))
st = sprint((io, v) -> show(io, "text/plain", v), stacktrace(catch_backtrace()))
println(errorMsg)
- response = (result=nothing, success=false, errormsg=errorMsg)
- return response
+ return (result_str=nothing, result_raw=nothing, success=false, errormsg=errorMsg)
end
end
@@ -559,7 +545,7 @@ end
- `result::String`
# Signature
-"""
+""" #WORKING
function extractContent_dataframe(df::DataFrame, text2textInstructLLM::Function, action::String,
llmFormatName::String
)::String
@@ -633,7 +619,7 @@ function extractContent_dataframe(df::DataFrame, text2textInstructLLM::Function,
dictkey = ["about_resulting_table", "search_summary"]
for i in 1:5
- response = text2textInstructLLM(prompt, modelsize="medium")
+ response = text2textInstructLLM("ramdom_id", prompt)
response = GeneralUtils.deFormatLLMtext(response, llmFormatName)
think, response = GeneralUtils.extractthink(response)
@@ -653,7 +639,6 @@ function extractContent_dataframe(df::DataFrame, text2textInstructLLM::Function,
responsedict = GeneralUtils.textToDict(response, header;
dictKey=dictkey, symbolkey=false)
- # result = dfstr
result =
"""
Summary: $(responsedict["search_summary"])