update
This commit is contained in:
@@ -10,6 +10,8 @@ using ..util, ..llmfunction
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
""" Think and choose action.
|
||||
|
||||
# Arguments
|
||||
@@ -871,15 +873,24 @@ function query(query::T, executeSQL::Function, text2textInstructLLM::Function;
|
||||
|
||||
earlystop(state) = state[:reward] >= 8 ? true : false
|
||||
|
||||
root, _, resultState = LLMMCTS.runMCTS(initialstate, transition, transitionargs;
|
||||
horizontalSampleExpansionPhase=5,
|
||||
horizontalSampleSimulationPhase=2,
|
||||
maxSimulationDepth=5,
|
||||
maxiterations=1,
|
||||
explorationweight=1.0,
|
||||
earlystop=earlystop,
|
||||
saveSimulatedNode=true,
|
||||
multithread=true)
|
||||
root, _, resultState, highValueState =
|
||||
LLMMCTS.runMCTS(initialstate, transition, transitionargs;
|
||||
horizontalSampleExpansionPhase=5,
|
||||
horizontalSampleSimulationPhase=2,
|
||||
maxSimulationDepth=5,
|
||||
maxiterations=1,
|
||||
explorationweight=1.0,
|
||||
earlystop=earlystop,
|
||||
saveSimulatedNode=true,
|
||||
multithread=true)
|
||||
|
||||
#[WORKING] compare all high value state answer then select the best one
|
||||
if length(highValueState) > 0
|
||||
open("/appfolder/app/highValueState.json", "w") do io
|
||||
JSON3.pretty(io, highValueState)
|
||||
end
|
||||
resultState = compareState(query, highValueState)
|
||||
end
|
||||
latestKey, latestInd = GeneralUtils.findHighestIndexKey(resultState[:thoughtHistory], "observation")
|
||||
action_input = Symbol("action_input_$latestInd") # latest sql
|
||||
sql = resultState[:thoughtHistory][action_input]
|
||||
@@ -1119,8 +1130,6 @@ end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
module llmfunction
|
||||
|
||||
export listAllTable_json, listAllTable_str, tableinfo, getdata, finalAnswerBox,
|
||||
getTableNameFromSQL, extractContent_dataframe, SQLexecution
|
||||
getTableNameFromSQL, extractContent_dataframe, SQLexecution, compareState
|
||||
|
||||
using HTTP, JSON3, URIs, Random, PrettyPrinting, UUIDs, LibPQ, Tables, DataFrames, CSV,
|
||||
DataStructures, StatsBase
|
||||
@@ -788,6 +788,154 @@ function getTableNameFromSQL(sql::T, text2textInstructLLM::Function)::Vector{Str
|
||||
end
|
||||
|
||||
|
||||
""" 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,
|
||||
serving as a heuristic to steer the search algorithm towards the most promising regions of the tree.
|
||||
|
||||
# Arguments
|
||||
- `state<:AbstractDict`
|
||||
one of Yiem's agent
|
||||
- `text2textInstructLLM::Function`
|
||||
A function that handles communication to LLM service
|
||||
|
||||
# Return
|
||||
- `score::Integer`
|
||||
|
||||
# Example
|
||||
```jldoctest
|
||||
julia>
|
||||
```
|
||||
|
||||
# TODO
|
||||
- [] update docs
|
||||
- [WORKING] implement
|
||||
|
||||
# Signature
|
||||
"""
|
||||
function compareState(query, highValueStateList)
|
||||
|
||||
systemmsg =
|
||||
"""
|
||||
<Your profile>
|
||||
- You are a helpful assistant
|
||||
</Your profile>
|
||||
<Situation>
|
||||
The user has made multiple attempts to solve the question, resulting in various answers
|
||||
<Your mission>
|
||||
- Identify and select the most accurate and relevant response from these multiple results for the user
|
||||
</Your mission>
|
||||
<At each round of conversation, you will be given the following>
|
||||
- The user's question
|
||||
- The user's attempted actions and their corresponding results
|
||||
</At each round of conversation, you will be given the following>
|
||||
<You should then respond to the user with the following>
|
||||
- Selected_response: the number of the most accurate and relevant response
|
||||
- Rationale: a brief explanation of why you selected this response
|
||||
</You should then respond to the user with the following>
|
||||
<You should only respond in format as described below>
|
||||
- Selected_response: ...
|
||||
- Rationale: ...
|
||||
</You should only respond in format as described below>
|
||||
<Here are some examples>
|
||||
User's question: "How many German wines do you have?"
|
||||
Attempt 1:
|
||||
Action: SELECT * FROM wines WHERE country = 'Germany'
|
||||
Result: 100 wines
|
||||
Attempt 2:
|
||||
Action: SELECT * FROM wines WHERE country = 'Germany' AND type = 'Red'
|
||||
Result: 50 red wines
|
||||
Selected_response: 1
|
||||
Rationale: The question is about German wines, so the most accurate response is the one that includes all German wines.
|
||||
</Here are some examples>
|
||||
|
||||
Let's begin!
|
||||
"""
|
||||
|
||||
thoughthistory = ""
|
||||
for (k, v) in state[:thoughtHistory]
|
||||
thoughthistory *= "$k: $v\n"
|
||||
end
|
||||
|
||||
errornote = ""
|
||||
|
||||
for attempt in 1:10
|
||||
errorFlag = false
|
||||
|
||||
usermsg =
|
||||
"""
|
||||
Trajectory: $thoughthistory
|
||||
Error_note: $errornote
|
||||
"""
|
||||
|
||||
_prompt =
|
||||
[
|
||||
Dict(:name=> "system", :text=> systemmsg),
|
||||
Dict(:name=> "user", :text=> usermsg)
|
||||
]
|
||||
|
||||
# put in model format
|
||||
prompt = GeneralUtils.formatLLMtext(_prompt; formatname="qwen")
|
||||
|
||||
header = ["Trajectory_evaluation:", "Answer_evaluation:", "Accepted_as_answer:", "Score:", "Suggestion:"]
|
||||
dictkey = ["trajectory_evaluation", "answer_evaluation", "accepted_as_answer", "score", "suggestion"]
|
||||
|
||||
response = text2textInstructLLM(prompt)
|
||||
|
||||
# sometime LLM output something like **Comprehension**: which is not expected
|
||||
response = replace(response, "**"=>"")
|
||||
response = replace(response, "***"=>"")
|
||||
|
||||
# make sure every header is in the response
|
||||
for i in header
|
||||
detected = GeneralUtils.detect_keyword(i, response)
|
||||
if detected === nothing
|
||||
errornote = "Your previous response didn't provide $i"
|
||||
errorFlag = true
|
||||
end
|
||||
end
|
||||
if errorFlag
|
||||
continue # skip to the next iteration
|
||||
end
|
||||
|
||||
responsedict = GeneralUtils.textToDict(response, header;
|
||||
dictKey=dictkey, symbolkey=true)
|
||||
|
||||
responsedict[:score] = responsedict[:score][1] # some time "6\nThe trajectories are incomplete" is generated but I only need the number.
|
||||
try
|
||||
responsedict[:score] = parse(Int, responsedict[:score]) # convert string "5" into integer 5
|
||||
catch
|
||||
continue
|
||||
end
|
||||
|
||||
accepted_as_answer::AbstractString = responsedict[:accepted_as_answer]
|
||||
|
||||
if accepted_as_answer ∉ ["Yes", "No"] # [PENDING] add errornote into the prompt
|
||||
error("generated accepted_as_answer has wrong format")
|
||||
end
|
||||
|
||||
# add to state here instead to in transition() because the latter causes julia extension crash (a bug in julia extension)
|
||||
state[:evaluation] = "$(responsedict[:trajectory_evaluation]) $(responsedict[:answer_evaluation])"
|
||||
state[:evaluationscore] = responsedict[:score]
|
||||
state[:accepted_as_answer] = responsedict[:accepted_as_answer]
|
||||
state[:suggestion] = responsedict[:suggestion]
|
||||
|
||||
# mark as terminal state when the answer is achieved
|
||||
if accepted_as_answer == "Yes"
|
||||
|
||||
# mark the state as terminal state because the evaluation say so.
|
||||
state[:isterminal] = true
|
||||
|
||||
# evaluation score as reward because different answers hold different value for the user.
|
||||
state[:reward] = responsedict[:score]
|
||||
end
|
||||
println("\n~~~ Evaluator() ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
|
||||
pprintln(Dict(responsedict))
|
||||
|
||||
return responsedict[:score]
|
||||
end
|
||||
error("Evaluator failed to generate an evaluation, Response: \n$response\n<|End of error|>")
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user