update
This commit is contained in:
@@ -753,6 +753,7 @@ function conversation(a::T, userinput::Dict) where {T<:agent}
|
|||||||
addNewMessage(a, "user", userinput[:text])
|
addNewMessage(a, "user", userinput[:text])
|
||||||
|
|
||||||
if isempty(a.plan[:currenttrajectory])
|
if isempty(a.plan[:currenttrajectory])
|
||||||
|
|
||||||
a.plan[:currenttrajectory] = Dict{Symbol, Any}(
|
a.plan[:currenttrajectory] = Dict{Symbol, Any}(
|
||||||
# deepcopy the info to prevent modifying the info unintentionally during MCTS planning
|
# deepcopy the info to prevent modifying the info unintentionally during MCTS planning
|
||||||
:customerinfo=> deepcopy(a.keywordinfo[:customerinfo]),
|
:customerinfo=> deepcopy(a.keywordinfo[:customerinfo]),
|
||||||
@@ -769,7 +770,10 @@ function conversation(a::T, userinput::Dict) where {T<:agent}
|
|||||||
:thoughtHistory=> OrderedDict{Symbol, Any}(
|
:thoughtHistory=> OrderedDict{Symbol, Any}(
|
||||||
#[] :recap=>,
|
#[] :recap=>,
|
||||||
:question=> userinput[:text],
|
:question=> userinput[:text],
|
||||||
)
|
),
|
||||||
|
:virtualCustomerChatHistory=> Vector{Dict{Symbol, Any}}(
|
||||||
|
[Dict(:name=> "user", :text=> userinput[:text])]
|
||||||
|
),
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
_, a.plan[:currenttrajectory] = makeNewState(a.plan[:currenttrajectory],
|
_, a.plan[:currenttrajectory] = makeNewState(a.plan[:currenttrajectory],
|
||||||
@@ -780,7 +784,7 @@ function conversation(a::T, userinput::Dict) where {T<:agent}
|
|||||||
|
|
||||||
while true
|
while true
|
||||||
bestNextState, besttrajectory = runMCTS(a, a.plan[:currenttrajectory], decisionMaker,
|
bestNextState, besttrajectory = runMCTS(a, a.plan[:currenttrajectory], decisionMaker,
|
||||||
evaluator, reflector, totalsample=2, maxDepth=2, maxiterations=1, explorationweight=1.0)
|
evaluator, reflector, totalsample=2, maxDepth=2, maxiterations=2, explorationweight=1.0)
|
||||||
a.plan[:activeplan] = bestNextState
|
a.plan[:activeplan] = bestNextState
|
||||||
|
|
||||||
latestActionKey, latestActionIndice =
|
latestActionKey, latestActionIndice =
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ module llmfunction
|
|||||||
export virtualWineUserChatbox, jsoncorrection, winestock,
|
export virtualWineUserChatbox, jsoncorrection, winestock,
|
||||||
virtualWineUserRecommendbox, userChatbox, userRecommendbox
|
virtualWineUserRecommendbox, userChatbox, userRecommendbox
|
||||||
|
|
||||||
using HTTP, JSON3, URIs, Random
|
using HTTP, JSON3, URIs, Random, PrettyPrinting
|
||||||
using GeneralUtils
|
using GeneralUtils
|
||||||
using ..type, ..util
|
using ..type, ..util
|
||||||
|
|
||||||
@@ -164,28 +164,119 @@ julia>
|
|||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
- [] update docs
|
- [] update docs
|
||||||
|
- [x] write a prompt for virtual customer
|
||||||
|
|
||||||
# Signature
|
# Signature
|
||||||
"""
|
"""
|
||||||
function virtualWineUserChatbox(a::T1, input::T2
|
function virtualWineUserChatbox(a::T1, input::T2, virtualCustomerChatHistory
|
||||||
)::Union{Tuple{String, Number, Number, Bool}, Tuple{String, Nothing, Number, Bool}} where {T1<:agent, T2<:AbstractString}
|
)::Union{Tuple{String, Number, Number, Bool}, Tuple{String, Nothing, Number, Bool}} where {T1<:agent, T2<:AbstractString}
|
||||||
|
|
||||||
# put in model format
|
previouswines =
|
||||||
virtualWineCustomer = a.config[:externalservice][:virtualWineCustomer_1]
|
"""
|
||||||
llminfo = virtualWineCustomer[:llminfo]
|
You have the following wines previously:
|
||||||
prompt =
|
|
||||||
if llminfo[:name] == "llama3instruct"
|
"""
|
||||||
formatLLMtext_llama3instruct("assistant", input)
|
|
||||||
|
systemmsg =
|
||||||
|
"""
|
||||||
|
You find yourself in a well-stocked wine store, engaged in a conversation with the store's knowledgeable sommelier.
|
||||||
|
You're on a quest to find a bottle of wine that aligns with your specific preferences and requirements.
|
||||||
|
|
||||||
|
The ideal wine you're seeking should meet the following criteria:
|
||||||
|
1. It should fit within your budget.
|
||||||
|
2. It should be suitable for the occasion you're planning.
|
||||||
|
3. It should pair well with the food you intend to serve.
|
||||||
|
4. It should be of a particular type of wine you prefer.
|
||||||
|
5. It should possess certain characteristics, including:
|
||||||
|
- The level of sweetness.
|
||||||
|
- The intensity of its flavor.
|
||||||
|
- The amount of tannin it contains.
|
||||||
|
- Its acidity level.
|
||||||
|
|
||||||
|
Here's the criteria details:
|
||||||
|
{
|
||||||
|
"budget": 50,
|
||||||
|
"occasion": "graduation ceremony",
|
||||||
|
"food pairing": "Thai food",
|
||||||
|
"type of wine": "red",
|
||||||
|
"wine sweetness level": "dry",
|
||||||
|
"wine intensity level": "full-bodied",
|
||||||
|
"wine tannin level": "low",
|
||||||
|
"wine acidity level": "medium",
|
||||||
|
}
|
||||||
|
|
||||||
|
You should only respond with "text", "select", "reward", "isterminal" steps.
|
||||||
|
"text" is your conversation.
|
||||||
|
"select" is an integer. Choose an option when presented with choices, or leave it null if none of the options satisfy you or if no choices are available.
|
||||||
|
"reward" is an integer, it can be three number:
|
||||||
|
1) 1 if you find the right wine.
|
||||||
|
2) 0 if you don’t find the ideal wine.
|
||||||
|
3) -1 if you’re dissatisfied with the sommelier’s response.
|
||||||
|
"isterminal" can be false if you still want to talk with the sommelier, true otherwise.
|
||||||
|
|
||||||
|
You should only respond in JSON format as describe below:
|
||||||
|
{
|
||||||
|
"text": "your conversation",
|
||||||
|
"select": null,
|
||||||
|
"reward": 0,
|
||||||
|
"isterminal": false
|
||||||
|
}
|
||||||
|
|
||||||
|
Here are some examples:
|
||||||
|
{
|
||||||
|
"text": "My budget is 30 USD.",
|
||||||
|
"select": null,
|
||||||
|
"reward": 0,
|
||||||
|
"isterminal": false
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"text": "I like the 2nd option.",
|
||||||
|
"select": 2,
|
||||||
|
"reward": 1,
|
||||||
|
"isterminal": true
|
||||||
|
}
|
||||||
|
|
||||||
|
Let's begin!
|
||||||
|
"""
|
||||||
|
|
||||||
|
pushfirst!(virtualCustomerChatHistory, Dict(:name=> "system", :text=> systemmsg))
|
||||||
|
|
||||||
|
# replace the :user key in chathistory to allow the virtual wine customer AI roleplay
|
||||||
|
chathistory::Vector{Dict{Symbol, Any}} = Vector{Dict{Symbol, Any}}()
|
||||||
|
for i in virtualCustomerChatHistory
|
||||||
|
newdict = Dict()
|
||||||
|
newdict[:name] =
|
||||||
|
if i[:name] == "user"
|
||||||
|
"you"
|
||||||
|
elseif i[:name] == "assistant"
|
||||||
|
"sommelier"
|
||||||
else
|
else
|
||||||
error("llm model name is not defied yet $(@__LINE__)")
|
i[:name]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
newdict[:text] = i[:text]
|
||||||
|
push!(chathistory, newdict)
|
||||||
|
end
|
||||||
|
|
||||||
|
push!(chathistory, Dict(:name=> "assistant", :text=> input))
|
||||||
|
|
||||||
|
# put in model format
|
||||||
|
prompt = formatLLMtext(chathistory, "llama3instruct")
|
||||||
|
prompt *=
|
||||||
|
"""
|
||||||
|
<|start_header_id|>you<|end_header_id|>
|
||||||
|
{"text"
|
||||||
|
"""
|
||||||
|
|
||||||
|
pprint(prompt)
|
||||||
|
externalService = a.config[:externalservice][:text2textinstruct]
|
||||||
|
|
||||||
# send formatted input to user using GeneralUtils.sendReceiveMqttMsg
|
# send formatted input to user using GeneralUtils.sendReceiveMqttMsg
|
||||||
msgMeta = GeneralUtils.generate_msgMeta(
|
msgMeta = GeneralUtils.generate_msgMeta(
|
||||||
virtualWineCustomer[:mqtttopic],
|
externalService[:mqtttopic],
|
||||||
senderName= "virtualWineUserChatbox",
|
senderName= "virtualWineUserChatbox",
|
||||||
senderId= a.id,
|
senderId= a.id,
|
||||||
receiverName= "virtualWineCustomer",
|
receiverName= "text2textinstruct",
|
||||||
mqttBroker= a.config[:mqttServerInfo][:broker],
|
mqttBroker= a.config[:mqttServerInfo][:broker],
|
||||||
mqttBrokerPort= a.config[:mqttServerInfo][:port],
|
mqttBrokerPort= a.config[:mqttServerInfo][:port],
|
||||||
msgId = "dummyid" #CHANGE remove after testing finished
|
msgId = "dummyid" #CHANGE remove after testing finished
|
||||||
@@ -201,10 +292,33 @@ function virtualWineUserChatbox(a::T1, input::T2
|
|||||||
attempt = 0
|
attempt = 0
|
||||||
for attempt in 1:5
|
for attempt in 1:5
|
||||||
try
|
try
|
||||||
result = GeneralUtils.sendReceiveMqttMsg(outgoingMsg; timeout=120)
|
response = GeneralUtils.sendReceiveMqttMsg(outgoingMsg; timeout=120)
|
||||||
response = result[:response]
|
_responseJsonStr = response[:response][:text]
|
||||||
|
expectedJsonExample =
|
||||||
|
"""
|
||||||
|
Here is an expected JSON format:
|
||||||
|
{
|
||||||
|
"text": "...",
|
||||||
|
"select": "...",
|
||||||
|
"reward": "...",
|
||||||
|
"isterminal": "..."
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
responseJsonStr = jsoncorrection(a, _responseJsonStr, expectedJsonExample)
|
||||||
|
responseDict = copy(JSON3.read(responseJsonStr))
|
||||||
|
|
||||||
return (response[:text], response[:select], response[:reward], response[:isterminal])
|
text = responseDict[:text]
|
||||||
|
select = responseDict[:select] == "null" ? nothing : responseDict[:select]
|
||||||
|
reward = responseDict[:reward]
|
||||||
|
isterminal = responseDict[:isterminal]
|
||||||
|
|
||||||
|
if text != "" && select != "" && reward != "" && isterminal != ""
|
||||||
|
# pass test
|
||||||
|
else
|
||||||
|
error("virtual customer not answer correctly")
|
||||||
|
end
|
||||||
|
|
||||||
|
return (text, select, reward, isterminal)
|
||||||
catch e
|
catch e
|
||||||
io = IOBuffer()
|
io = IOBuffer()
|
||||||
showerror(io, e)
|
showerror(io, e)
|
||||||
@@ -218,6 +332,57 @@ function virtualWineUserChatbox(a::T1, input::T2
|
|||||||
error("virtualWineUserChatbox failed to get a response")
|
error("virtualWineUserChatbox failed to get a response")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# function virtualWineUserChatbox(a::T1, input::T2
|
||||||
|
# )::Union{Tuple{String, Number, Number, Bool}, Tuple{String, Nothing, Number, Bool}} where {T1<:agent, T2<:AbstractString}
|
||||||
|
|
||||||
|
# # put in model format
|
||||||
|
# virtualWineCustomer = a.config[:externalservice][:virtualWineCustomer_1]
|
||||||
|
# llminfo = virtualWineCustomer[:llminfo]
|
||||||
|
# prompt =
|
||||||
|
# if llminfo[:name] == "llama3instruct"
|
||||||
|
# formatLLMtext_llama3instruct("assistant", input)
|
||||||
|
# else
|
||||||
|
# error("llm model name is not defied yet $(@__LINE__)")
|
||||||
|
# end
|
||||||
|
|
||||||
|
# # send formatted input to user using GeneralUtils.sendReceiveMqttMsg
|
||||||
|
# msgMeta = GeneralUtils.generate_msgMeta(
|
||||||
|
# virtualWineCustomer[:mqtttopic],
|
||||||
|
# senderName= "virtualWineUserChatbox",
|
||||||
|
# senderId= a.id,
|
||||||
|
# receiverName= "virtualWineCustomer",
|
||||||
|
# mqttBroker= a.config[:mqttServerInfo][:broker],
|
||||||
|
# mqttBrokerPort= a.config[:mqttServerInfo][:port],
|
||||||
|
# msgId = "dummyid" #CHANGE remove after testing finished
|
||||||
|
# )
|
||||||
|
|
||||||
|
# outgoingMsg = Dict(
|
||||||
|
# :msgMeta=> msgMeta,
|
||||||
|
# :payload=> Dict(
|
||||||
|
# :text=> prompt,
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
|
||||||
|
# attempt = 0
|
||||||
|
# for attempt in 1:5
|
||||||
|
# try
|
||||||
|
# result = GeneralUtils.sendReceiveMqttMsg(outgoingMsg; timeout=120)
|
||||||
|
# response = result[:response]
|
||||||
|
|
||||||
|
# return (response[:text], response[:select], response[:reward], response[:isterminal])
|
||||||
|
# catch e
|
||||||
|
# io = IOBuffer()
|
||||||
|
# showerror(io, e)
|
||||||
|
# errorMsg = String(take!(io))
|
||||||
|
# st = sprint((io, v) -> show(io, "text/plain", v), stacktrace(catch_backtrace()))
|
||||||
|
# println("")
|
||||||
|
# @warn "Error occurred: $errorMsg\n$st"
|
||||||
|
# println("")
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
# error("virtualWineUserChatbox failed to get a response")
|
||||||
|
# end
|
||||||
|
|
||||||
|
|
||||||
""" Search wine in stock.
|
""" Search wine in stock.
|
||||||
|
|
||||||
@@ -239,7 +404,7 @@ julia> result = winestock(agent, input)
|
|||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
[] update docs
|
[] update docs
|
||||||
[PENDING] implement the function
|
[WORKING] implement the function
|
||||||
|
|
||||||
# Signature
|
# Signature
|
||||||
"""
|
"""
|
||||||
@@ -302,8 +467,8 @@ function jsoncorrection(a::T1, input::T2,
|
|||||||
_prompt =
|
_prompt =
|
||||||
"""
|
"""
|
||||||
Your goal are:
|
Your goal are:
|
||||||
1) Use the info why the given JSON string failed to load and provide a corrected version that can be loaded by Python's json.load function.
|
1) Use the expected JSON format as a guideline to check why the given JSON string failed to load and provide a corrected version that can be loaded by Python's json.load function.
|
||||||
2) The user need Corrected JSON string only. Do not provide any other info.
|
2) Provide Corrected JSON string only. Do not provide any other info.
|
||||||
|
|
||||||
$correctJsonExample
|
$correctJsonExample
|
||||||
|
|
||||||
|
|||||||
21
src/mcts.jl
21
src/mcts.jl
@@ -146,7 +146,6 @@ function expand(a::T1, node::MCTSNode, decisionMaker::Function,
|
|||||||
pprintln(thoughtDict)
|
pprintln(thoughtDict)
|
||||||
newNodeKey, newstate = MCTStransition(a, node.state, thoughtDict)
|
newNodeKey, newstate = MCTStransition(a, node.state, thoughtDict)
|
||||||
|
|
||||||
|
|
||||||
stateevaluation, progressvalue = evaluator(a, newstate)
|
stateevaluation, progressvalue = evaluator(a, newstate)
|
||||||
|
|
||||||
if newstate[:reward] < 0
|
if newstate[:reward] < 0
|
||||||
@@ -302,7 +301,9 @@ function MCTStransition(a::T1, state::T2, thoughtDict::T2
|
|||||||
# map action and input() to llm function
|
# map action and input() to llm function
|
||||||
response, select, reward, isterminal =
|
response, select, reward, isterminal =
|
||||||
if actionname == "chatbox"
|
if actionname == "chatbox"
|
||||||
virtualWineUserChatbox(a, actioninput) # virtual customer
|
# deepcopy(state[:virtualCustomerChatHistory]) because I want to keep it clean
|
||||||
|
# so that other simulation start from this same node is not contaminated with actioninput
|
||||||
|
virtualWineUserChatbox(a, actioninput, deepcopy(state[:virtualCustomerChatHistory])) # virtual customer
|
||||||
elseif actionname == "winestock"
|
elseif actionname == "winestock"
|
||||||
winestock(a, actioninput)
|
winestock(a, actioninput)
|
||||||
elseif actionname == "recommendbox"
|
elseif actionname == "recommendbox"
|
||||||
@@ -311,7 +312,13 @@ function MCTStransition(a::T1, state::T2, thoughtDict::T2
|
|||||||
error("undefined LLM function. Requesting $actionname")
|
error("undefined LLM function. Requesting $actionname")
|
||||||
end
|
end
|
||||||
|
|
||||||
return makeNewState(state, thoughtDict, response, select, reward, isterminal)
|
newNodeKey, newstate = makeNewState(state, thoughtDict, response, select, reward, isterminal)
|
||||||
|
if actionname == "chatbox"
|
||||||
|
push!(newstate[:virtualCustomerChatHistory], Dict(:name=>"assistant", :text=> actioninput) )
|
||||||
|
push!(newstate[:virtualCustomerChatHistory], Dict(:name=>"user", :text=> response))
|
||||||
|
end
|
||||||
|
|
||||||
|
return (newNodeKey, newstate)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -386,7 +393,7 @@ julia>
|
|||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
- [] update docstring
|
- [] update docstring
|
||||||
- [TESTING] implement the function
|
- [x] implement the function
|
||||||
|
|
||||||
# Signature
|
# Signature
|
||||||
"""
|
"""
|
||||||
@@ -520,7 +527,7 @@ julia>
|
|||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
- [] update docs
|
- [] update docs
|
||||||
- [TESTING] implement the function
|
- [x] implement the function
|
||||||
|
|
||||||
# Signature
|
# Signature
|
||||||
"""
|
"""
|
||||||
@@ -573,7 +580,7 @@ julia>
|
|||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
- [] update docs
|
- [] update docs
|
||||||
- [TESTING] implement the function
|
- [x] implement the function
|
||||||
|
|
||||||
# Signature
|
# Signature
|
||||||
"""
|
"""
|
||||||
@@ -675,7 +682,7 @@ function runMCTS(
|
|||||||
leafNode = selectChildNode(node)
|
leafNode = selectChildNode(node)
|
||||||
simTrajectoryReward, terminalstate = simulate(a, leafNode, decisionMaker, evaluator,
|
simTrajectoryReward, terminalstate = simulate(a, leafNode, decisionMaker, evaluator,
|
||||||
reflector; maxDepth=maxDepth, totalsample=totalsample)
|
reflector; maxDepth=maxDepth, totalsample=totalsample)
|
||||||
if terminalstate !== nothing
|
if terminalstate !== nothing #XXX not sure why I need this
|
||||||
terminalstate[:totalTrajectoryReward] = simTrajectoryReward
|
terminalstate[:totalTrajectoryReward] = simTrajectoryReward
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -201,13 +201,13 @@ function formatLLMtext_llama3instruct(name::T, text::T) where {T<:AbstractString
|
|||||||
<|begin_of_text|>
|
<|begin_of_text|>
|
||||||
<|start_header_id|>$name<|end_header_id|>
|
<|start_header_id|>$name<|end_header_id|>
|
||||||
$text
|
$text
|
||||||
<|eot_id|>\n
|
<|eot_id|>
|
||||||
"""
|
"""
|
||||||
else
|
else
|
||||||
"""
|
"""
|
||||||
<|start_header_id|>$name<|end_header_id|>
|
<|start_header_id|>$name<|end_header_id|>
|
||||||
$text
|
$text
|
||||||
<|eot_id|>\n
|
<|eot_id|>
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -286,7 +286,7 @@ end
|
|||||||
TODO\n
|
TODO\n
|
||||||
-----
|
-----
|
||||||
[] update docstring
|
[] update docstring
|
||||||
[TESTING] implement the function
|
[PENDING] implement the function
|
||||||
|
|
||||||
Signature\n
|
Signature\n
|
||||||
-----
|
-----
|
||||||
|
|||||||
@@ -51,8 +51,6 @@ tools=Dict( # update input format
|
|||||||
)
|
)
|
||||||
|
|
||||||
a = YiemAgent.sommelier(
|
a = YiemAgent.sommelier(
|
||||||
receiveUserMsgChannel,
|
|
||||||
receiveInternalMsgChannel,
|
|
||||||
agentConfig,
|
agentConfig,
|
||||||
name="assistant",
|
name="assistant",
|
||||||
id="testingSessionID", # agent instance id
|
id="testingSessionID", # agent instance id
|
||||||
@@ -68,7 +66,7 @@ response = YiemAgent.conversation(a, Dict(:text=> "Hello, I would like a get a b
|
|||||||
) )
|
) )
|
||||||
println("---> YiemAgent: ", response)
|
println("---> YiemAgent: ", response)
|
||||||
|
|
||||||
response = YiemAgent.conversation(a, Dict(:text=> "I'm having a graduation party this evening",
|
response = YiemAgent.conversation(a, Dict(:text=> "I'm having a graduation party this evening. I'll pay at most 30 bucks.",
|
||||||
:select=> nothing,
|
:select=> nothing,
|
||||||
:reward=> 0,
|
:reward=> 0,
|
||||||
:isterminal=> false,
|
:isterminal=> false,
|
||||||
|
|||||||
Reference in New Issue
Block a user