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( julia> output_thoughtDict = Dict(
"thought_1" => "The customer wants to buy a bottle of wine. This is a good start!", "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 - [] use customerinfo
- [] user storeinfo - [] user storeinfo
""" #WORKING """
function decisionMaker(a::T; recentevents::Integer=20, maxattempt=10 function decisionMaker(a::T; recentevents::Integer=20, maxattempt=10
) where {T<:agent} ) where {T<:agent}
println("\nExecuting YiemAgent decisionMaker()") println("\nExecuting YiemAgent decisionMaker()")
@@ -127,159 +127,172 @@ function decisionMaker(a::T; recentevents::Integer=20, maxattempt=10
requiredKeys = ["plan", "actionname", "actioninput"] 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" errornote = "N/A"
response = nothing # placeholder for show when error msg show up response = nothing # placeholder for show when error msg show up
for attempt in 1:maxattempt for attempt in 1:maxattempt
if attempt > 1 if attempt > 1
println("\nYiemAgent decisionMaker() attempt $attempt/$maxattempt ", @__FILE__, ":", @__LINE__, " $(Dates.now())") println("\nYiemAgent decisionMaker() attempt $attempt/$maxattempt ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
end end
unformatPrompt = unformatPrompt =
[ [
Dict("name" => "system", "text" => systemmsg), Dict("name" => "system", "text" => systemmsg),
] ]
unformatPrompt = vcat(unformatPrompt, recentEvents) unformatPrompt = vcat(unformatPrompt, recentEvents)
# put in model format # put in model format
prompt = GeneralUtils.formatLLMtext(unformatPrompt, a.llmFormatName) prompt = GeneralUtils.formatLLMtext(unformatPrompt, a.llmFormatName)
# add info # add info
prompt = prompt * context prompt = prompt * context
response = a.context.text2textInstructLLM(prompt; senderId=a.id) response = a.context.text2textInstructLLM(prompt; senderId=a.id)
response = GeneralUtils.deFormatLLMtext(response, a.llmFormatName) response = GeneralUtils.deFormatLLMtext(response, a.llmFormatName)
response = GeneralUtils.remove_french_accents(response) response = GeneralUtils.remove_french_accents(response)
think, response = GeneralUtils.extractthink(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 = String(split(response, ", observation")[1]) # in case LLM generate observation key which it isn't supposed to
response = strip(response) response = strip(response)
responsedict = nothing responsedict = nothing
try try
responsedict = copy(JSON.parsefile(response)) responsedict = copy(JSON.parsefile(response))
catch catch
println("\nERROR YiemAgent decisionMaker() failed to parse response: $response", @__FILE__, ":", @__LINE__, " $(Dates.now())") println("\nERROR YiemAgent decisionMaker() failed to parse response: $response", @__FILE__, ":", @__LINE__, " $(Dates.now())")
continue continue
end end
# check whether all answer's key points are in responsedict # check whether all answer's key points are in responsedict
ispass, errormsg = checkAgentResponse_JSON(responsedict, requiredKeys) ispass, errormsg = checkAgentResponse_JSON(responsedict, requiredKeys)
if !ispass if !ispass
errornote = errormsg errornote = errormsg
println("\nERROR YiemAgent decisionMaker() $errornote --(not qualify response)> $responsedict", @__FILE__, ":", @__LINE__, " $(Dates.now())\n") println("\nERROR YiemAgent decisionMaker() $errornote --(not qualify response)> $responsedict", @__FILE__, ":", @__LINE__, " $(Dates.now())\n")
continue continue
end end
# _responsedictKey = keys(responsedict) # _responsedictKey = keys(responsedict)
# responsedictKey = [i for i in _responsedictKey] # convert into a list # responsedictKey = [i for i in _responsedictKey] # convert into a list
# is_requiredKeys_in_responsedictKey = [i ∈ responsedictKey for i in requiredKeys] # is_requiredKeys_in_responsedictKey = [i ∈ responsedictKey for i in requiredKeys]
# if length(is_requiredKeys_in_responsedictKey) > length(requiredKeys) # if length(is_requiredKeys_in_responsedictKey) > length(requiredKeys)
# errornote = "Your previous attempt has more key points than answer's required key points." # 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())") # println("\nERROR YiemAgent decisionMaker() $errornote ----(not qualify response)--> $response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
# continue # continue
# elseif !all(is_requiredKeys_in_responsedictKey) # elseif !all(is_requiredKeys_in_responsedictKey)
# zeroind = findall(x -> x == 0, is_requiredKeys_in_responsedictKey) # zeroind = findall(x -> x == 0, is_requiredKeys_in_responsedictKey)
# missingkeys = [requiredKeys[i] for i in zeroind] # missingkeys = [requiredKeys[i] for i in zeroind]
# errornote = "$missingkeys are missing from your previous response" # errornote = "$missingkeys are missing from your previous response"
# println("\nERROR YiemAgent decisionMaker() $errornote --(not qualify response)--> $response ", @__FILE__, ":", @__LINE__, " $(Dates.now())") # println("\nERROR YiemAgent decisionMaker() $errornote --(not qualify response)--> $response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
# continue # continue
# end # end
if responsedict["actionname"] ["CHATBOX", "CHECKWINE", "PRESENTBOX", "ENDCONVERSATION"] if responsedict["actionname"] ["CHATBOX", "CHECKWINE", "PRESENTBOX", "ENDCONVERSATION"]
errornote = "Your previous attempt didn't use the given functions" errornote = "Your previous attempt didn't use the given functions"
println("\nERROR YiemAgent decisionMaker() $errornote --(not qualify response)--> $(responsedict["actionname"])", @__FILE__, ":", @__LINE__, " $(Dates.now())") println("\nERROR YiemAgent decisionMaker() $errornote --(not qualify response)--> $(responsedict["actionname"])", @__FILE__, ":", @__LINE__, " $(Dates.now())")
continue continue
end end
println("\nYiem decisionMaker() ", @__FILE__, ":", @__LINE__, " $(Dates.now())") println("\nYiem decisionMaker() ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
pprintln(Dict(responsedict)) pprintln(Dict(responsedict))
# check whether an agent recommend wines before checking inventory or recommend wines # check whether an agent recommend wines before checking inventory or recommend wines
# outside its inventory # outside its inventory
# ask LLM whether there are any winery mentioned in the response # ask LLM whether there are any winery mentioned in the response
mentioned_winery = detectWineryName(a, response) mentioned_winery = detectWineryName(a, response)
if mentioned_winery != "None" if mentioned_winery != "None"
mentioned_winery = String.(strip.(split(mentioned_winery, ","))) mentioned_winery = String.(strip.(split(mentioned_winery, ",")))
# check whether the wine is in event # check whether the wine is in event
isWineInEvent = false isWineInEvent = false
for winename in mentioned_winery for winename in mentioned_winery
for event in a.memory["events"] for event in a.memory["events"]
if event["observation"] !== nothing && occursin(winename, event["observation"]) if event["observation"] !== nothing && occursin(winename, event["observation"])
isWineInEvent = true isWineInEvent = true
break break
end
end end
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 end
delete!(responsedict, :mentioned_winery) # then the agent is not supposed to recommend the wine
if isWineInEvent == false
# check whether responsedict["actioninput"] is the same as previous dialogue errornote = "You recommended wines that are not in your inventory before. Please only recommend wines that you have previously found in your inventory."
if !isempty(a.chathistory) && responsedict["actioninput"] == a.chathistory[end]["text"] println("\nERROR YiemAgent decisionMaker() $errornote $response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
errornote = "In your previous attempt, you repeated the previous dialogue. Please try again."
println("\nERROR YiemAgent decisionMaker() $response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
continue continue
end 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 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 end
error("DecisionMaker failed to generate a thought ", response)
end end

View File

@@ -321,16 +321,30 @@ function virtualcustomer(
) )
""" Memory """ Memory
Ref: Chat prompt format https://huggingface.co/TheBloke/Llama-2-7B-Chat-GGML/discussions/3 Ref: Chat prompt format is openai
NO "system" message in chathistory because I want to add it at the inference time chathistory = [
chathistory= [ Dict(
Dict("name"=>"user", "text"=> "Wassup!", "timestamp"=> Dates.now()), "role" => "system",
Dict("name"=>"assistant", "text"=> "Hi I'm your assistant.", "timestamp"=> Dates.now()), "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}( memory = Dict{String, Any}(
"shortmem"=> OrderedDict{String, Any}( "shortmem"=> OrderedDict{String, Any}(
), ),
"scratchpad"=> "",
"events"=> Vector{Dict{String, Any}}(), "events"=> Vector{Dict{String, Any}}(),
"state"=> Dict{String, Any}( "state"=> Dict{String, Any}(
), ),