add context

This commit is contained in:
2026-06-24 21:02:56 +07:00
parent 9c22cf2e31
commit 57dd6df942
2 changed files with 167 additions and 140 deletions

View File

@@ -78,7 +78,7 @@ julia> config = Dict(
)
),
)
)
)
julia> output_thoughtDict = Dict(
"thought_1" => "The customer wants to buy a bottle of wine. This is a good start!",
@@ -93,7 +93,7 @@ julia> output_thoughtDict = Dict(
- [] use customerinfo
- [] user storeinfo
""" #WORKING
"""
function decisionMaker(a::T; recentevents::Integer=20, maxattempt=10
) where {T<:agent}
println("\nExecuting YiemAgent decisionMaker()")
@@ -127,159 +127,172 @@ function decisionMaker(a::T; recentevents::Integer=20, maxattempt=10
requiredKeys = ["plan", "actionname", "actioninput"]
context =
"""
<internal_context_for_LLM>
$(a.memory["scratchpad"])
</internal_context_for_LLM>
"""
#WORKING add context to the latest message (in the front)
for d in enumerate(a.chathistory[end]["content"])
if d["type"] == "text"
d["text"] = context * d["text"]
break
end
end
errornote = "N/A"
response = nothing # placeholder for show when error msg show up
for attempt in 1:maxattempt
if attempt > 1
println("\nYiemAgent decisionMaker() attempt $attempt/$maxattempt ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
end
unformatPrompt =
[
Dict("name" => "system", "text" => systemmsg),
]
for attempt in 1:maxattempt
if attempt > 1
println("\nYiemAgent decisionMaker() attempt $attempt/$maxattempt ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
end
unformatPrompt =
[
Dict("name" => "system", "text" => systemmsg),
]
unformatPrompt = vcat(unformatPrompt, recentEvents)
# put in model format
prompt = GeneralUtils.formatLLMtext(unformatPrompt, a.llmFormatName)
# add info
prompt = prompt * context
unformatPrompt = vcat(unformatPrompt, recentEvents)
# put in model format
prompt = GeneralUtils.formatLLMtext(unformatPrompt, a.llmFormatName)
# add info
prompt = prompt * context
response = a.context.text2textInstructLLM(prompt; senderId=a.id)
response = GeneralUtils.deFormatLLMtext(response, a.llmFormatName)
response = GeneralUtils.remove_french_accents(response)
think, response = GeneralUtils.extractthink(response)
response = String(split(response, ", observation")[1]) # in case LLM generate observation key which it isn't supposed to
response = strip(response)
responsedict = nothing
try
responsedict = copy(JSON.parsefile(response))
catch
println("\nERROR YiemAgent decisionMaker() failed to parse response: $response", @__FILE__, ":", @__LINE__, " $(Dates.now())")
continue
end
response = a.context.text2textInstructLLM(prompt; senderId=a.id)
response = GeneralUtils.deFormatLLMtext(response, a.llmFormatName)
response = GeneralUtils.remove_french_accents(response)
think, response = GeneralUtils.extractthink(response)
response = String(split(response, ", observation")[1]) # in case LLM generate observation key which it isn't supposed to
response = strip(response)
responsedict = nothing
try
responsedict = copy(JSON.parsefile(response))
catch
println("\nERROR YiemAgent decisionMaker() failed to parse response: $response", @__FILE__, ":", @__LINE__, " $(Dates.now())")
continue
end
# check whether all answer's key points are in responsedict
ispass, errormsg = checkAgentResponse_JSON(responsedict, requiredKeys)
if !ispass
errornote = errormsg
println("\nERROR YiemAgent decisionMaker() $errornote --(not qualify response)> $responsedict", @__FILE__, ":", @__LINE__, " $(Dates.now())\n")
continue
end
# _responsedictKey = keys(responsedict)
# responsedictKey = [i for i in _responsedictKey] # convert into a list
# is_requiredKeys_in_responsedictKey = [i ∈ responsedictKey for i in requiredKeys]
# check whether all answer's key points are in responsedict
ispass, errormsg = checkAgentResponse_JSON(responsedict, requiredKeys)
if !ispass
errornote = errormsg
println("\nERROR YiemAgent decisionMaker() $errornote --(not qualify response)> $responsedict", @__FILE__, ":", @__LINE__, " $(Dates.now())\n")
continue
end
# _responsedictKey = keys(responsedict)
# responsedictKey = [i for i in _responsedictKey] # convert into a list
# is_requiredKeys_in_responsedictKey = [i ∈ responsedictKey for i in requiredKeys]
# if length(is_requiredKeys_in_responsedictKey) > length(requiredKeys)
# errornote = "Your previous attempt has more key points than answer's required key points."
# println("\nERROR YiemAgent decisionMaker() $errornote ----(not qualify response)--> $response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
# continue
# elseif !all(is_requiredKeys_in_responsedictKey)
# zeroind = findall(x -> x == 0, is_requiredKeys_in_responsedictKey)
# missingkeys = [requiredKeys[i] for i in zeroind]
# errornote = "$missingkeys are missing from your previous response"
# println("\nERROR YiemAgent decisionMaker() $errornote --(not qualify response)--> $response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
# continue
# end
# if length(is_requiredKeys_in_responsedictKey) > length(requiredKeys)
# errornote = "Your previous attempt has more key points than answer's required key points."
# println("\nERROR YiemAgent decisionMaker() $errornote ----(not qualify response)--> $response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
# continue
# elseif !all(is_requiredKeys_in_responsedictKey)
# zeroind = findall(x -> x == 0, is_requiredKeys_in_responsedictKey)
# missingkeys = [requiredKeys[i] for i in zeroind]
# errornote = "$missingkeys are missing from your previous response"
# println("\nERROR YiemAgent decisionMaker() $errornote --(not qualify response)--> $response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
# continue
# end
if responsedict["actionname"] ["CHATBOX", "CHECKWINE", "PRESENTBOX", "ENDCONVERSATION"]
errornote = "Your previous attempt didn't use the given functions"
println("\nERROR YiemAgent decisionMaker() $errornote --(not qualify response)--> $(responsedict["actionname"])", @__FILE__, ":", @__LINE__, " $(Dates.now())")
continue
end
if responsedict["actionname"] ["CHATBOX", "CHECKWINE", "PRESENTBOX", "ENDCONVERSATION"]
errornote = "Your previous attempt didn't use the given functions"
println("\nERROR YiemAgent decisionMaker() $errornote --(not qualify response)--> $(responsedict["actionname"])", @__FILE__, ":", @__LINE__, " $(Dates.now())")
continue
end
println("\nYiem decisionMaker() ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
pprintln(Dict(responsedict))
println("\nYiem decisionMaker() ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
pprintln(Dict(responsedict))
# check whether an agent recommend wines before checking inventory or recommend wines
# outside its inventory
# ask LLM whether there are any winery mentioned in the response
mentioned_winery = detectWineryName(a, response)
if mentioned_winery != "None"
mentioned_winery = String.(strip.(split(mentioned_winery, ",")))
# check whether an agent recommend wines before checking inventory or recommend wines
# outside its inventory
# ask LLM whether there are any winery mentioned in the response
mentioned_winery = detectWineryName(a, response)
if mentioned_winery != "None"
mentioned_winery = String.(strip.(split(mentioned_winery, ",")))
# check whether the wine is in event
isWineInEvent = false
for winename in mentioned_winery
for event in a.memory["events"]
if event["observation"] !== nothing && occursin(winename, event["observation"])
isWineInEvent = true
break
end
# check whether the wine is in event
isWineInEvent = false
for winename in mentioned_winery
for event in a.memory["events"]
if event["observation"] !== nothing && occursin(winename, event["observation"])
isWineInEvent = true
break
end
end
# then the agent is not supposed to recommend the wine
if isWineInEvent == false
errornote = "You recommended wines that are not in your inventory before. Please only recommend wines that you have previously found in your inventory."
println("\nERROR YiemAgent decisionMaker() $errornote $response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
continue
end
end
delete!(responsedict, :mentioned_winery)
# check whether responsedict["actioninput"] is the same as previous dialogue
if !isempty(a.chathistory) && responsedict["actioninput"] == a.chathistory[end]["text"]
errornote = "In your previous attempt, you repeated the previous dialogue. Please try again."
println("\nERROR YiemAgent decisionMaker() $response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
# then the agent is not supposed to recommend the wine
if isWineInEvent == false
errornote = "You recommended wines that are not in your inventory before. Please only recommend wines that you have previously found in your inventory."
println("\nERROR YiemAgent decisionMaker() $errornote $response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
continue
end
evaluationdict = evaluator(a, timeline, responsedict, context)
if evaluationdict[:approval] == "no"
mentor_comment = evaluationdict[:suggestion]
errornote = "Your previous attempt was not good enough. Please try again. Here is the mentor's suggestion: $mentor_comment"
println("\nERROR YiemAgent decisionMaker() $errornote --(not qualify response)--> \n$response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
continue
end
# store for later training
responsedict["system"] = systemmsg
responsedict["unformatPrompt"] = unformatPrompt
responsedict["prompt"] = prompt
responsedict["context"] = context
responsedict["think"] = think
responsedict["response"] = response
# responsedict["QandA"] = QandA
# check whether there is a file path exists before writing to it
if !haskey(a.memory["shortmem"], "decisionlog")
a.memory["shortmem"]["decisionlog"] = [responsedict]
else
push!(a.memory["shortmem"]["decisionlog"], responsedict)
end
# # save to filename ./log/decisionlog.txt
# println("\nsaving YiemAgent decisionMaker() to disk ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
# filename = "agent_decision_log_$(a.id).json"
# filepath = "/appfolder/app/log/$filename"
# # check whether there is a file path exists before writing to it
# if !isfile(filepath)
# decisionlist = [responsedict]
# println("Creating file $filepath")
# open(filepath, "w") do io
# JSON.pretty(io, decisionlist)
# end
# else
# # read the file and append new data
# decisionlist = copy(JSON.parsefile(filepath))
# push!(decisionlist, responsedict)
# println("Appending new data to file $filepath")
# open(filepath, "w") do io
# JSON.pretty(io, decisionlist)
# end
# end
# println("\nYiemAgent decisionMaker() saved to disk is done. agent $(a.id)")
responsedict["prompt"] = prompt
return responsedict
end
error("DecisionMaker failed to generate a thought ", response)
delete!(responsedict, :mentioned_winery)
# check whether responsedict["actioninput"] is the same as previous dialogue
if !isempty(a.chathistory) && responsedict["actioninput"] == a.chathistory[end]["text"]
errornote = "In your previous attempt, you repeated the previous dialogue. Please try again."
println("\nERROR YiemAgent decisionMaker() $response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
continue
end
evaluationdict = evaluator(a, timeline, responsedict, context)
if evaluationdict[:approval] == "no"
mentor_comment = evaluationdict[:suggestion]
errornote = "Your previous attempt was not good enough. Please try again. Here is the mentor's suggestion: $mentor_comment"
println("\nERROR YiemAgent decisionMaker() $errornote --(not qualify response)--> \n$response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
continue
end
# store for later training
responsedict["system"] = systemmsg
responsedict["unformatPrompt"] = unformatPrompt
responsedict["prompt"] = prompt
responsedict["context"] = context
responsedict["think"] = think
responsedict["response"] = response
# responsedict["QandA"] = QandA
# check whether there is a file path exists before writing to it
if !haskey(a.memory["shortmem"], "decisionlog")
a.memory["shortmem"]["decisionlog"] = [responsedict]
else
push!(a.memory["shortmem"]["decisionlog"], responsedict)
end
# # save to filename ./log/decisionlog.txt
# println("\nsaving YiemAgent decisionMaker() to disk ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
# filename = "agent_decision_log_$(a.id).json"
# filepath = "/appfolder/app/log/$filename"
# # check whether there is a file path exists before writing to it
# if !isfile(filepath)
# decisionlist = [responsedict]
# println("Creating file $filepath")
# open(filepath, "w") do io
# JSON.pretty(io, decisionlist)
# end
# else
# # read the file and append new data
# decisionlist = copy(JSON.parsefile(filepath))
# push!(decisionlist, responsedict)
# println("Appending new data to file $filepath")
# open(filepath, "w") do io
# JSON.pretty(io, decisionlist)
# end
# end
# println("\nYiemAgent decisionMaker() saved to disk is done. agent $(a.id)")
responsedict["prompt"] = prompt
return responsedict
end
error("DecisionMaker failed to generate a thought ", response)
end

View File

@@ -321,16 +321,30 @@ function virtualcustomer(
)
""" Memory
Ref: Chat prompt format https://huggingface.co/TheBloke/Llama-2-7B-Chat-GGML/discussions/3
NO "system" message in chathistory because I want to add it at the inference time
chathistory= [
Dict("name"=>"user", "text"=> "Wassup!", "timestamp"=> Dates.now()),
Dict("name"=>"assistant", "text"=> "Hi I'm your assistant.", "timestamp"=> Dates.now()),
Ref: Chat prompt format is openai
chathistory = [
Dict(
"role" => "system",
"content" => [
Dict("type" => "text", "text" => system_msg),
]
),
Dict(
"role" => "user",
"content" => [
Dict("type" => "text", "text" => "Do you know this wine? Just give me brief intro."),
Dict(
"type" => "image_url",
"image_url" => Dict("url" => data1_uri)
)
]
)
]
"""
memory = Dict{String, Any}(
"shortmem"=> OrderedDict{String, Any}(
),
"scratchpad"=> "",
"events"=> Vector{Dict{String, Any}}(),
"state"=> Dict{String, Any}(
),