From 7066f46504832dce24c6fe5340256e9503522d80 Mon Sep 17 00:00:00 2001 From: tonaerospace Date: Thu, 14 Dec 2023 13:45:51 +0000 Subject: [PATCH] update --- src/interface.jl | 298 ++++++++++++++++++++++++++++++++++++----------- src/utils.jl | 94 +++------------ 2 files changed, 251 insertions(+), 141 deletions(-) diff --git a/src/interface.jl b/src/interface.jl index b24e4e2..01650b8 100755 --- a/src/interface.jl +++ b/src/interface.jl @@ -234,8 +234,8 @@ function chat_mistral_openorca(a::agentReflex) return response end - -function planner_mistral_openorca(a::agentReflex) +#WORKING +function planner_mistral_openorca(a::agentReflex, objective::T) where {T<:AbstractString} """ general prompt format: @@ -263,66 +263,126 @@ function planner_mistral_openorca(a::agentReflex) " """ - prompt = - """ + assistant_plan_prompt = + """ <|im_start|>system - {role} - {roleSpecificKnowledge} - {tools} - {thinkingFormat} - {context} - <|im_end|> - <|im_start|>user - {usermsg} + $(a.roles[a.role]) + The info you need from the user to be able to help them selecting their best wine: + - type of food + - occasion + - user's personal taste of wine + - wine price range + - ambient temperature at the serving location + - wines we have in stock + You provide a personalized recommendation of up to two wines based on the user's info above, and you describe the benefits of each wine in detail. + + You have access to the following tools: + $toollines + + Use the following format: + Objective: the objective you intend to do + Plan: first you should always think about the objective, the info you need and the info you have thoroughly then extract and devise a step by step plan (pay attention to correct numeral calculation and commonsense). + p.s.1 each step should be a single action. + p.s.2 don't respond to the stimulus yet. <|im_end|> <|im_start|>assistant + Objective: $objective Plan: - """ - prompt = replace(prompt, "{role}" => a.roles[a.role]) - prompt = replace(prompt, "{thinkingFormat}" => a.thinkingFormat[:planner]) - roleSpecificKnowledge = - """ - Info you need from the user to be able to help them selecting their best wine: - - type of food - - occasion - - user's personal taste of wine - - wine price range - - ambient temperature at the serving location - - wines we have in stock - You job is to provide a personalized recommendation of up to two wines based on the user's info above, and you describe the benefits of each wine in detail. - """ - prompt = replace(prompt, "{roleSpecificKnowledge}" => roleSpecificKnowledge) - toolnames = "" - toollines = "" - for (toolname, v) in a.tools - toolline = "$toolname: $(v[:description]) $(v[:input]) $(v[:output])\n" - toollines *= toolline - toolnames *= "$toolname," - end - - prompt = replace(prompt, "{toolnames}" => toolnames) - prompt = replace(prompt, "{tools}" => "You have access to the following tools:\n$toollines") - + """ + plan = sendReceivePrompt(a, assistant_plan_prompt, temperature=0.2) - # prepare contex - context = - """ - My earlier talk with the user: - $(a.earlierConversation) - - My earlier experience - $(experience(a.memory[:longterm])) - """ - - prompt = replace(prompt, "{context}" => context) - - # initialize short term memory - prompt = replace(prompt, "{usermsg}" => "Stimulus: $(a.memory[:shortterm]["user:"])") - - return prompt + return plan end +# function planner_mistral_openorca(a::agentReflex) +# """ +# general prompt format: + +# " +# <|im_start|>system +# {role} +# {tools} +# {thinkingFormat} +# <|im_end|> +# {context} +# <|im_start|>user +# {usermsg} +# <|im_end|> +# <|im_start|>assistant + +# " + +# Note: +# {context} = +# " +# {earlierConversation} +# {env state} +# {shortterm memory} +# {longterm memory} +# " +# """ + +# prompt = +# """ +# <|im_start|>system +# {role} +# {roleSpecificKnowledge} +# {tools} +# {thinkingFormat} +# {context} +# <|im_end|> +# <|im_start|>user +# {usermsg} +# <|im_end|> +# <|im_start|>assistant +# Plan: +# """ +# prompt = replace(prompt, "{role}" => a.roles[a.role]) +# prompt = replace(prompt, "{thinkingFormat}" => a.thinkingFormat[:planner]) +# roleSpecificKnowledge = +# """ +# Info you need from the user to be able to help them selecting their best wine: +# - type of food +# - occasion +# - user's personal taste of wine +# - wine price range +# - ambient temperature at the serving location +# - wines we have in stock +# You job is to provide a personalized recommendation of up to two wines based on the user's info above, and you describe the benefits of each wine in detail. +# """ +# prompt = replace(prompt, "{roleSpecificKnowledge}" => roleSpecificKnowledge) +# toolnames = "" +# toollines = "" +# for (toolname, v) in a.tools +# toolline = "$toolname: $(v[:description]) $(v[:input]) $(v[:output])\n" +# toollines *= toolline +# toolnames *= "$toolname," +# end + +# prompt = replace(prompt, "{toolnames}" => toolnames) +# prompt = replace(prompt, "{tools}" => "You have access to the following tools:\n$toollines") + + +# # prepare contex +# context = +# """ +# My earlier talk with the user: +# $(a.earlierConversation) + +# My earlier experience +# $(experience(a.memory[:longterm])) +# """ + +# prompt = replace(prompt, "{context}" => context) + +# # initialize short term memory +# prompt = replace(prompt, "{usermsg}" => "Stimulus: $(a.memory[:shortterm]["user:"])") + +# return prompt +# end + + function actor_mistral_openorca(a::agentReflex) """ general prompt format: @@ -407,7 +467,7 @@ end julia> mqttClientSpec = ( clientName= "someclient", # name of this client clientID= "$(uuid4())", - broker= "mqtt.yiem.ai", + broker= "mqtt.yiem.cc", pubtopic= (imgAI="img/api/v0.0.1/gpu/request", txtAI="txt/api/v0.1.0/gpu/request"), subtopic= (imgAI="agent/api/v0.1.0/img/response", @@ -441,15 +501,14 @@ function conversation(a::agentReflex, usermsg::String; attemptlimit::Int=3) # a.earlierConversation = conversationSummary(a) _ = addNewMessage(a, "user", usermsg) - isusetools, whattodo = isUseTools(a) + isusetools, objective = isUseTools(a) # newinfo = extractinfo(a, usermsg) # a.env = newinfo !== nothing ? updateEnvState(a, newinfo) : a.env @show isusetools - #WORKING - # if isusetools # use tools before responseing - # response = work(a, usermsg) - # end + if isusetools # use tools before responseing + response = work(a, objective) + end response = chat_mistral_openorca(a) response = removeTrailingCharacters(response) @@ -461,14 +520,14 @@ end """ Continuously run llm functions except when llm is getting Answer: or chatbox. There are many work() depend on thinking mode. -""" -function work(a::agentReflex, usermsg::String) +""" #WORKING add plan and actor +function work(a::agentReflex, objective::T) where {T<:AbstractString} response = nothing - + error(1) a.memory[:shortterm] = OrderedDict{String, Any}() a.memory[:log] = OrderedDict{String, Any}() - a.memory[:shortterm]["user:"] = usermsg - a.memory[:log]["user:"] = usermsg + a.memory[:shortterm]["user:"] = objective + a.memory[:log]["user:"] = objective a.newplan = true while true # Work loop @@ -570,6 +629,115 @@ function work(a::agentReflex, usermsg::String) return response end + +# function work(a::agentReflex, usermsg::String) +# response = nothing + +# a.memory[:shortterm] = OrderedDict{String, Any}() +# a.memory[:log] = OrderedDict{String, Any}() +# a.memory[:shortterm]["user:"] = usermsg +# a.memory[:log]["user:"] = usermsg +# a.newplan = true + +# while true # Work loop +# # plan +# if a.attempt <= a.attemptlimit +# toolname = nothing +# toolinput = nothing +# if a.newplan == true +# a.attempt += 1 +# a.step = 0 +# prompt_plan = planner_mistral_openorca(a) +# println("") +# @show prompt_plan +# response = sendReceivePrompt(a, prompt_plan, max_tokens=1024) + +# # sometimes LLM add not-need word I don't want +# plan = splittext(response, ["Step 1", "<|im_end|>", "Response", "Execution", +# "Result", "Recommendation", "My response"]) +# # plan = replace(plan, "Plan:"=>"") +# println("") +# @show plan + +# a.newplan = false +# a.memory[:shortterm]["Plan $(a.attempt):"] = plan +# a.memory[:log]["Plan $(a.attempt):"] = plan +# end + +# println("") +# @show a.attempt + +# # enter actor loop +# actorstate, msgToUser = actor(a) + +# if actorstate == "chatbox" +# response = msgToUser +# break +# elseif actorstate == "all steps done" || actorstate == "formulateUserresponse" +# println("all steps done") + +# response = formulateUserresponse(a) + +# println("") +# formulatedresponse = response +# @show formulatedresponse + +# a.memory[:shortterm]["response $(a.attempt):"] = response +# a.memory[:log]["response $(a.attempt):"] = response + +# # evaluate. if score < 8/10 try again. +# guideline = writeEvaluationGuideline(a, a.memory[:shortterm]["user:"]) + +# println("") +# @show guideline + +# score = grading(a, guideline, response) +# @show score +# if score >= 6 # good enough answer +# break +# else # self evaluate and reflect then try again +# analysis = analyze(a) +# println("") +# @show analysis + +# lessonwithcontext = selfReflext(a, analysis) + +# println("") +# @show lessonwithcontext + +# newdict = OrderedDict() + +# a.memory[:shortterm] = keepOnlyKeys(a.memory[:shortterm], ["user:"]) + +# headerToDetect = ["Lesson:", "Context:", ] +# headers = detectCharacters(lessonwithcontext, headerToDetect) +# chunkedtext = chunktext(lessonwithcontext, headers) + +# a.memory[:longterm][chunkedtext["Context:"]] = chunkedtext["Lesson:"] +# a.newplan = true +# println("") +# println("RETRY $(a.attempt +1)") +# println("") + +# end +# else +# error("undefied condition, actorstate $actorstate $(@__LINE__)") +# break +# end +# else +# error("attempt limit reach") +# break +# end +# end + +# # good enough answer + + +# # communicates with user +# _ = addNewMessage(a, "assistant", response) +# return response +# end + # function work(a::agentReflex, usermsg::String) # response = nothing diff --git a/src/utils.jl b/src/utils.jl index b96aa4d..8b904b1 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -363,12 +363,19 @@ end # return thinkingmode # end -#WORKING + + +""" Determine from a user message whether an assistant need to use tools. + +Arguments: + a, one of ChatAgent's agent. + +Return: + 1. true/false # is LLM going to use tools + 2. objective # what LLM going to do +""" function isUseTools(a::agentReflex) - - # response = chat_mistral_openorca(a) - toollines = "" for (toolname, v) in a.tools if toolname ∉ ["chatbox"] @@ -396,81 +403,16 @@ function isUseTools(a::agentReflex) # if LLM mentions any tools, use Plan/Thought/Act loop isusetool = false - result = sendReceivePrompt(a, prompt, temperature=0.2) + objective = sendReceivePrompt(a, prompt, temperature=0.2) for (toolname, v) in a.tools - if occursin(toolname, result) + if occursin(toolname, objective) isusetool = true break end end - @show result - plan = "N/A" - if isusetool - # toollines = "" - # for (toolname, v) in a.tools - # if toolname ∉ [""] - # toolline = "$toolname: $(v[:description]) $(v[:input]) $(v[:output])\n" - # toollines *= toolline - # end - # end - # assistant_objective_prompt = - # """ - # <|im_start|>system - # $(a.roles[a.role]) - # The info you need from the user to be able to help them selecting their best wine: - # - type of food - # - occasion - # - user's personal taste of wine - # - wine price range - # - ambient temperature at the serving location - # - wines we have in stock - # You provide a personalized recommendation of up to two wines based on the user's info above, and you describe the benefits of each wine in detail. - - # You have access to the following tools: - # $toollines - - # Your conversation with the user: - # $conversation - - # Use the following format: - # Objective: From your conversation with the user, ask yourself what do you need to do now? - # <|im_end|> - - # """ - # result_objective = sendReceivePrompt(a, assistant_objective_prompt, temperature=0.2) - # @show result_objective - - assistant_plan_prompt = - """ - <|im_start|>system - $(a.roles[a.role]) - The info you need from the user to be able to help them selecting their best wine: - - type of food - - occasion - - user's personal taste of wine - - wine price range - - ambient temperature at the serving location - - wines we have in stock - You provide a personalized recommendation of up to two wines based on the user's info above, and you describe the benefits of each wine in detail. - - You have access to the following tools: - $toollines - - Use the following format: - Objective: the objective you intend to do - Plan: first you should always think about the objective, the info you need and the info you have thoroughly then extract and devise a step by step plan (pay attention to correct numeral calculation and commonsense). - p.s.1 each step should be a single action. - p.s.2 don't respond to the stimulus yet. - <|im_end|> - <|im_start|>assistant - Objective: $result - Plan: - """ - plan = sendReceivePrompt(a, assistant_plan_prompt, temperature=0.2) - @show plan - end - - return isusetool, plan + @show objective + + return isusetool, objective end @@ -650,7 +592,7 @@ julia> agent.messages = [Dict(:role=> "user", :content=> "Hi there."), julia> messagesToString(agent.messages) "<|im_start|>user: Hi there.\n<|im_end|><|im_start|>assistant: Hello! How can I assist you today?\n<|im_end|>" ``` -""" #WORKING +""" function messagesToString(messages::AbstractVector{T}; addressAIas="assistant") where {T<:AbstractDict} conversation = "" if length(messages)!= 0 @@ -681,7 +623,7 @@ function messagesToString(messages::AbstractVector{T}; addressAIas="assistant") return conversation end -#WORKING + function messagesToString_nomark(messages::AbstractVector{T}; addressAIas="assistant") where {T<:AbstractDict} conversation = "" if length(messages)!= 0