update
This commit is contained in:
316
src/interface.jl
316
src/interface.jl
@@ -159,11 +159,11 @@ function decisionMaker(state::T1, context, text2textInstructLLM::Function,
|
|||||||
- 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.
|
||||||
|
|
||||||
You should then respond to the user with interleaving Understanding, Reasoning, Plan, Action:
|
You should then respond to the user with interleaving Comprehension, Plan, Action_name, Action_input:
|
||||||
1) Comprehension:
|
Comprehension: state your comprehension about the current situation.
|
||||||
- State your comprehension about the current situation.
|
Plan: Given the current circumstances, outline a detailed, step-by-step plan to accomplish the task. Be specific.
|
||||||
2) Plan: Given the current circumstances, outline a detailed, step-by-step plan to accomplish the task. Be specific.
|
Action_name: (Typically corresponds to the execution of the first step in your plan)
|
||||||
3) Action_name (Must be aligned with your plan): Can be one of the following functions:
|
Can be one of the following function names:
|
||||||
- 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.
|
- 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.
|
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 ';'.
|
||||||
@@ -195,6 +195,8 @@ function decisionMaker(state::T1, context, text2textInstructLLM::Function,
|
|||||||
similarSQL_ = sql !== nothing ? sql : "None"
|
similarSQL_ = sql !== nothing ? sql : "None"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
header = ["Comprehension:", "Plan:", "Action_name:", "Action_input:"]
|
||||||
|
dictkey = ["comprehension", "plan", "action_name", "action_input"]
|
||||||
|
|
||||||
for attempt in 1:10
|
for attempt in 1:10
|
||||||
QandA = generatequestion(state, context, text2textInstructLLM; similarSQL=similarSQL_)
|
QandA = generatequestion(state, context, text2textInstructLLM; similarSQL=similarSQL_)
|
||||||
@@ -252,37 +254,31 @@ function decisionMaker(state::T1, context, text2textInstructLLM::Function,
|
|||||||
continue
|
continue
|
||||||
end
|
end
|
||||||
|
|
||||||
header = ["Comprehension:", "Plan:", "Action_name:", "Action_input:"]
|
# # detect if there are more than 1 key per categories
|
||||||
dictkey = ["comprehension", "plan", "action_name", "action_input"]
|
# wordcount = GeneralUtils.countGivenWords(response, header)
|
||||||
|
# duplicateKeywordFlag = false
|
||||||
# detect if there are more than 1 key per categories
|
# for (i, v) in enumerate(wordcount)
|
||||||
wordcount = GeneralUtils.countGivenWords(response, header)
|
# keyword = header[i]
|
||||||
duplicateKeywordFlag = false
|
# keywordNumber = v
|
||||||
for (i, v) in enumerate(wordcount)
|
# if keywordNumber > 1
|
||||||
keyword = header[i]
|
# errornote = "\nSQL query has duplicated keyword, $keyword"
|
||||||
keywordNumber = v
|
# println("Attempt $attempt $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||||
if keywordNumber > 1
|
# duplicateKeywordFlag = true
|
||||||
errornote = "\nSQL query has duplicated keyword, $keyword"
|
# break
|
||||||
println("Attempt $attempt $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
# end
|
||||||
duplicateKeywordFlag = true
|
# end
|
||||||
break
|
# duplicateKeywordFlag == true ? continue : nothing
|
||||||
end
|
|
||||||
end
|
|
||||||
duplicateKeywordFlag == true ? continue : nothing
|
|
||||||
|
|
||||||
# check whether response has all header
|
# check whether response has all header
|
||||||
kw = []
|
detected_kw = GeneralUtils.detect_keyword(header, response)
|
||||||
# use for loop and detect_keyword function to get the exact variation of each keyword in the text then push to kw list
|
if sum(values(detected_kw)) < length(header)
|
||||||
for keyword in header
|
errornote = "\nSQL decisionMaker() response does not have all header"
|
||||||
detected = GeneralUtils.detect_keyword(keyword, response)
|
continue
|
||||||
push!(kw, detected)
|
elseif sum(values(detected_kw)) > length(header)
|
||||||
end
|
errornote = "\nSQL decisionMaker() response has duplicated header"
|
||||||
if nothing ∈ kw
|
continue
|
||||||
println("Some keywords are missing, Required keywords=$header, Response keywords=$kw ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
|
||||||
continue # try again next loop
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# textToDict() search for action_input
|
|
||||||
responsedict = GeneralUtils.textToDict(response, header;
|
responsedict = GeneralUtils.textToDict(response, header;
|
||||||
dictKey=dictkey, symbolkey=true)
|
dictKey=dictkey, symbolkey=true)
|
||||||
|
|
||||||
@@ -315,7 +311,7 @@ function decisionMaker(state::T1, context, text2textInstructLLM::Function,
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
for i ∈ [:comprehension, :plan, :action_name, :action_input]
|
for i ∈ Symbol.(dictkey)
|
||||||
if length(JSON3.write(responsedict[i])) == 0
|
if length(JSON3.write(responsedict[i])) == 0
|
||||||
errornote = "\n $i is empty"
|
errornote = "\n $i is empty"
|
||||||
println("Attempt $attempt $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
println("Attempt $attempt $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||||
@@ -323,14 +319,14 @@ function decisionMaker(state::T1, context, text2textInstructLLM::Function,
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# check if there are more than 1 key per categories
|
# check whether response has all header
|
||||||
for i ∈ [:comprehension, :plan, :action_name, :action_input]
|
detected_kw = GeneralUtils.detect_keyword(header, response)
|
||||||
matchkeys = GeneralUtils.findMatchingDictKey(responsedict, i)
|
if sum(values(detected_kw)) < length(header)
|
||||||
if length(matchkeys) > 1
|
errornote = "\nSQL decisionMaker() response does not have all header"
|
||||||
errornote = "\n $i has more than one key"
|
continue
|
||||||
println("Attempt $attempt $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
elseif sum(values(detected_kw)) > length(header)
|
||||||
continue
|
errornote = "\nSQL decisionMaker() response has duplicated header"
|
||||||
end
|
continue
|
||||||
end
|
end
|
||||||
|
|
||||||
state[:decisionMaker] = responsedict
|
state[:decisionMaker] = responsedict
|
||||||
@@ -340,244 +336,7 @@ function decisionMaker(state::T1, context, text2textInstructLLM::Function,
|
|||||||
end
|
end
|
||||||
error("DecisionMaker failed to generate a thought \n", response)
|
error("DecisionMaker failed to generate a thought \n", response)
|
||||||
end
|
end
|
||||||
# function decisionMaker(state::T1, context, text2textInstructLLM::Function,
|
|
||||||
# ; querySQLVectorDBF::Union{T2, Nothing}=nothing
|
|
||||||
# )::Dict{Symbol, Any} where {T1<:AbstractDict, T2<:Function}
|
|
||||||
|
|
||||||
# # lessonDict =
|
|
||||||
# # if isfile("lesson.json")
|
|
||||||
# # lessonDict = copy(JSON3.read("lesson.json"))
|
|
||||||
# # else
|
|
||||||
# # lessonDict = nothing
|
|
||||||
# # end
|
|
||||||
|
|
||||||
# # lessonDict = nothing
|
|
||||||
|
|
||||||
# # lesson =
|
|
||||||
# # if lessonDict === nothing
|
|
||||||
# # ""
|
|
||||||
# # else
|
|
||||||
# # """
|
|
||||||
# # You have attempted to help the user before and failed, either because your reasoning for the
|
|
||||||
# # recommendation was incorrect or your response did not exactly match the user expectation.
|
|
||||||
# # The following lesson(s) give a plan to avoid failing to help the user in the same way you
|
|
||||||
# # did previously. Use them to improve your strategy to help the user.
|
|
||||||
|
|
||||||
# # Here are some lessons in JSON format:
|
|
||||||
# # $(JSON3.write(lessonDict))
|
|
||||||
|
|
||||||
# # When providing the thought and action for the current trial, that into account these failed
|
|
||||||
# # trajectories and make sure not to repeat the same mistakes and incorrect answers.
|
|
||||||
# # """
|
|
||||||
# # end
|
|
||||||
|
|
||||||
# systemmsg =
|
|
||||||
# """
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
# For your information:
|
|
||||||
# - Observation: Result of the immediately preceding action
|
|
||||||
|
|
||||||
# At each round of conversation, the user will give you the current situation:
|
|
||||||
# User Query: ...
|
|
||||||
# Example: ...
|
|
||||||
# Your Q&A: ...
|
|
||||||
# Your work progress: ...
|
|
||||||
# Evaluation: Evaluation of the immediately preceding action and observation
|
|
||||||
# Suggestion: Suggestion for the immediately preceding action and observation
|
|
||||||
|
|
||||||
# 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
|
|
||||||
# - 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.
|
|
||||||
|
|
||||||
# You should then respond to the user with interleaving Understanding, Reasoning, Plan, Action:
|
|
||||||
# 1) Comprehension:
|
|
||||||
# - State your comprehension about the current situation.
|
|
||||||
# 2) Plan: Given the current circumstances, outline a detailed, step-by-step plan to accomplish the task. Be specific.
|
|
||||||
# 3) Action_name (Must be aligned with your plan): Can be one of the following functions:
|
|
||||||
# - GETDATA, which you can use to get the data from 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 ';'.
|
|
||||||
# 4) Action_input: Input to the action
|
|
||||||
|
|
||||||
# You should only respond in format as described below:
|
|
||||||
# Comprehension: ...
|
|
||||||
# Plan: ...
|
|
||||||
# Action_name: ...
|
|
||||||
# Action_input: ...
|
|
||||||
|
|
||||||
# Let's begin!
|
|
||||||
# """
|
|
||||||
|
|
||||||
# workprogress = ""
|
|
||||||
# for (k, v) in state[:thoughtHistory]
|
|
||||||
# if k ∉ [:question]
|
|
||||||
# workprogress *= "$k: $v\n"
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
|
|
||||||
# response = nothing # store for show when error msg show up
|
|
||||||
# errornote = ""
|
|
||||||
|
|
||||||
# # provide similar sql only for the first attempt
|
|
||||||
# similarSQL_ = "None"
|
|
||||||
# if length(state[:thoughtHistory]) == 1
|
|
||||||
# sql, distance = querySQLVectorDBF(state[:thoughtHistory][:question])
|
|
||||||
# similarSQL_ = sql !== nothing ? sql : "None"
|
|
||||||
# end
|
|
||||||
|
|
||||||
|
|
||||||
# for attempt in 1:10
|
|
||||||
# QandA = generatequestion(state, context, text2textInstructLLM; similarSQL=similarSQL_)
|
|
||||||
|
|
||||||
# usermsg =
|
|
||||||
# """
|
|
||||||
# $(context[:tablelist])
|
|
||||||
# User query: $(state[:thoughtHistory][:question])
|
|
||||||
# Example: $similarSQL_
|
|
||||||
# Your Q&A: $QandA
|
|
||||||
# Your work progress: $workprogress
|
|
||||||
# Evaluation: $(state[:evaluation])
|
|
||||||
# Suggestion: $(state[:suggestion])
|
|
||||||
# $errornote
|
|
||||||
# """
|
|
||||||
|
|
||||||
# _prompt =
|
|
||||||
# [
|
|
||||||
# Dict(:name=> "system", :text=> systemmsg),
|
|
||||||
# Dict(:name=> "user", :text=> usermsg)
|
|
||||||
# ]
|
|
||||||
|
|
||||||
# # put in model format
|
|
||||||
# prompt = GeneralUtils.formatLLMtext(_prompt; formatname="qwen")
|
|
||||||
# response = text2textInstructLLM(prompt)
|
|
||||||
|
|
||||||
# # LLM tends to generate observation given that it is in the input
|
|
||||||
# response =
|
|
||||||
# if occursin("observation:", response)
|
|
||||||
# string(split(response, "observation:")[1])
|
|
||||||
# elseif occursin("Observation:", response)
|
|
||||||
# string(split(response, "Observation:")[1])
|
|
||||||
# elseif occursin("observation_", response)
|
|
||||||
# string(split(response, "observation_")[1])
|
|
||||||
# elseif occursin("Observation_", response)
|
|
||||||
# string(split(response, "Observation_")[1])
|
|
||||||
# else
|
|
||||||
# response
|
|
||||||
# end
|
|
||||||
|
|
||||||
# # sometime LLM output something like **Comprehension**: which is not expected
|
|
||||||
# response = replace(response, "**"=>"")
|
|
||||||
# response = replace(response, "***"=>"")
|
|
||||||
|
|
||||||
# # some time LLM output Plan_1: so we need to detect and replace topic numbering
|
|
||||||
# regex = r"_[0-1000]+:"
|
|
||||||
# matches = collect(eachmatch(regex, response))
|
|
||||||
# for m in matches
|
|
||||||
# response = replace(response, string(m.match)=>":")
|
|
||||||
# end
|
|
||||||
|
|
||||||
# if occursin("NULL", response)
|
|
||||||
# errornote = "\nSQL decisionMaker() NULL response is not allowed"
|
|
||||||
# println("Attempt $attempt $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
|
||||||
# continue
|
|
||||||
# end
|
|
||||||
|
|
||||||
# header = ["Comprehension:", "Plan:", "Action_name:", "Action_input:"]
|
|
||||||
# dictkey = ["comprehension", "plan", "action_name", "action_input"]
|
|
||||||
|
|
||||||
# # detect if there are more than 1 key per categories
|
|
||||||
# wordcount = GeneralUtils.countGivenWords(response, header)
|
|
||||||
# duplicateKeywordFlag = false
|
|
||||||
# for (i, v) in enumerate(wordcount)
|
|
||||||
# keyword = header[i]
|
|
||||||
# keywordNumber = v
|
|
||||||
# if keywordNumber > 1
|
|
||||||
# errornote = "\nSQL query has duplicated keyword, $keyword"
|
|
||||||
# println("Attempt $attempt $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
|
||||||
# duplicateKeywordFlag = true
|
|
||||||
# break
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
# duplicateKeywordFlag == true ? continue : nothing
|
|
||||||
|
|
||||||
# # check whether response has all header
|
|
||||||
# kw = []
|
|
||||||
# # use for loop and detect_keyword function to get the exact variation of each keyword in the text then push to kw list
|
|
||||||
# for keyword in header
|
|
||||||
# detected = GeneralUtils.detect_keyword(keyword, response)
|
|
||||||
# push!(kw, detected)
|
|
||||||
# end
|
|
||||||
# if nothing ∈ kw
|
|
||||||
# println("Some keywords are missing, Required keywords=$header, Response keywords=$kw ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
|
||||||
# continue # try again next loop
|
|
||||||
# end
|
|
||||||
|
|
||||||
# # textToDict() search for action_input
|
|
||||||
# responsedict = GeneralUtils.textToDict(response, header;
|
|
||||||
# dictKey=dictkey, symbolkey=true)
|
|
||||||
|
|
||||||
# delete!(responsedict, :observation)
|
|
||||||
|
|
||||||
# # remove backticks Error occurred: MethodError: no method matching occursin(::String, ::Vector{String})
|
|
||||||
# if occursin("```", responsedict[:action_input])
|
|
||||||
# sql = GeneralUtils.extract_triple_backtick_text(responsedict[:action_input])[1]
|
|
||||||
# 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
|
|
||||||
|
|
||||||
# toollist = ["TABLEINFO", "GETDATA"]
|
|
||||||
# if responsedict[:action_name] ∉ toollist
|
|
||||||
# errornote = "\nYou must only use the given functions"
|
|
||||||
# println("Attempt $attempt $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
|
||||||
# continue
|
|
||||||
# end
|
|
||||||
|
|
||||||
# for i in toollist
|
|
||||||
# if occursin(i, responsedict[:action_input])
|
|
||||||
# errornote = "\n action_name is in action_input which is not allowed."
|
|
||||||
# println("Attempt $attempt $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
|
||||||
# continue
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
|
|
||||||
# for i ∈ [:comprehension, :plan, :action_name, :action_input]
|
|
||||||
# if length(JSON3.write(responsedict[i])) == 0
|
|
||||||
# errornote = "\n $i is empty"
|
|
||||||
# println("Attempt $attempt $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
|
||||||
# continue
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
|
|
||||||
# # check if there are more than 1 key per categories
|
|
||||||
# for i ∈ [:comprehension, :plan, :action_name, :action_input]
|
|
||||||
# matchkeys = GeneralUtils.findMatchingDictKey(responsedict, i)
|
|
||||||
# if length(matchkeys) > 1
|
|
||||||
# errornote = "\n $i has more than one key"
|
|
||||||
# println("Attempt $attempt $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
|
||||||
# continue
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
|
|
||||||
# state[:decisionMaker] = responsedict
|
|
||||||
|
|
||||||
# return responsedict
|
|
||||||
|
|
||||||
# end
|
|
||||||
# error("DecisionMaker failed to generate a thought \n", response)
|
|
||||||
# end
|
|
||||||
|
|
||||||
""" Assigns a scalar value to each new child node to be used for selec-
|
""" Assigns a scalar value to each new child node to be used for selec-
|
||||||
tion and backpropagation. This value effectively quantifies the agent's progress in task completion,
|
tion and backpropagation. This value effectively quantifies the agent's progress in task completion,
|
||||||
@@ -1429,7 +1188,6 @@ function generatequestion(state::T1, context, text2textInstructLLM::Function;
|
|||||||
|
|
||||||
header = ["Understanding:", "Q1:"]
|
header = ["Understanding:", "Q1:"]
|
||||||
dictkey = ["understanding", "q1"]
|
dictkey = ["understanding", "q1"]
|
||||||
|
|
||||||
responsedict = GeneralUtils.textToDict(response, header;
|
responsedict = GeneralUtils.textToDict(response, header;
|
||||||
dictKey=dictkey, symbolkey=true)
|
dictKey=dictkey, symbolkey=true)
|
||||||
response = "Q1: " * responsedict[:q1]
|
response = "Q1: " * responsedict[:q1]
|
||||||
|
|||||||
41
test/Manifest.toml
Normal file
41
test/Manifest.toml
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# This file is machine-generated - editing it directly is not advised
|
||||||
|
|
||||||
|
julia_version = "1.11.4"
|
||||||
|
manifest_format = "2.0"
|
||||||
|
project_hash = "71d91126b5a1fb1020e1098d9d492de2a4438fd2"
|
||||||
|
|
||||||
|
[[deps.Base64]]
|
||||||
|
uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
|
||||||
|
version = "1.11.0"
|
||||||
|
|
||||||
|
[[deps.InteractiveUtils]]
|
||||||
|
deps = ["Markdown"]
|
||||||
|
uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
|
||||||
|
version = "1.11.0"
|
||||||
|
|
||||||
|
[[deps.Logging]]
|
||||||
|
uuid = "56ddb016-857b-54e1-b83d-db4d58db5568"
|
||||||
|
version = "1.11.0"
|
||||||
|
|
||||||
|
[[deps.Markdown]]
|
||||||
|
deps = ["Base64"]
|
||||||
|
uuid = "d6f4376e-aef5-505a-96c1-9c027394607a"
|
||||||
|
version = "1.11.0"
|
||||||
|
|
||||||
|
[[deps.Random]]
|
||||||
|
deps = ["SHA"]
|
||||||
|
uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
|
||||||
|
version = "1.11.0"
|
||||||
|
|
||||||
|
[[deps.SHA]]
|
||||||
|
uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce"
|
||||||
|
version = "0.7.0"
|
||||||
|
|
||||||
|
[[deps.Serialization]]
|
||||||
|
uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
|
||||||
|
version = "1.11.0"
|
||||||
|
|
||||||
|
[[deps.Test]]
|
||||||
|
deps = ["InteractiveUtils", "Logging", "Random", "Serialization"]
|
||||||
|
uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
|
||||||
|
version = "1.11.0"
|
||||||
2
test/Project.toml
Normal file
2
test/Project.toml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
[deps]
|
||||||
|
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
|
||||||
Reference in New Issue
Block a user