This commit is contained in:
2023-12-11 06:57:39 +00:00
parent c590c49a1d
commit 2e55921074
3 changed files with 191 additions and 133 deletions

View File

@@ -3,7 +3,7 @@ module interface
export agentReact, agentReflex,
addNewMessage, clearMessage, removeLatestMsg, conversation, writeEvaluationGuideline,
grading, analyze, selfReflext, actor_mistral_openorca2, formulateUserRespond,
grading, analyze, selfReflext, actor_mistral_openorca2, formulateUserresponse,
extractinfo, updateEnvState
using JSON3, DataStructures, Dates, UUIDs, HTTP
@@ -424,18 +424,18 @@ end
broker= "mqtt.yiem.ai",
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/respond",
txtAI="agent/api/v0.1.0/txt/respond"),
subtopic= (imgAI="agent/api/v0.1.0/img/response",
txtAI="agent/api/v0.1.0/txt/response"),
keepalive= 30,
)
julia> msgMeta = Dict(
:msgPurpose=> "updateStatus",
:from=> "agent",
:to=> "llmAI",
:requestrespond=> "request",
:requestresponse=> "request",
:sendto=> "", # destination topic
:replyTo=> "agent/api/v0.1.0/txt/respond", # requester ask responder to send reply to this topic
:repondToMsgId=> "", # responder is responding to this msg id
:replyTo=> "agent/api/v0.1.0/txt/response", # requester ask responseer to send reply to this topic
:repondToMsgId=> "", # responseer is responseing to this msg id
:taskstatus=> "", # "complete", "fail", "waiting" or other status
:timestamp=> Dates.now(),
:msgId=> "$(uuid4())",
@@ -446,34 +446,36 @@ end
role=:assistant_react,
msgMeta=msgMeta
)
julia> respond = ChatAgent.conversation(newAgent, "Hi! how are you?")
julia> response = ChatAgent.conversation(newAgent, "Hi! how are you?")
```
"""
function conversation(a::agentReflex, usermsg::String; attemptlimit::Int=3)
a.attemptlimit = attemptlimit
respond = nothing
response = nothing
a.earlierConversation = conversationSummary(a)
_ = addNewMessage(a, "user", usermsg)
isusetools = isUseTools(a, usermsg)
newinfo = extractinfo(a, usermsg)
a.env = newinfo !== nothing ? updateEnvState(a, newinfo)
#WORKING
if isusetools # use tools before responding
respond = work(a, usermsg)
if isusetools # use tools before responseing
response = work(a, usermsg)
end
#WORKING
prompt = chat_mistral_openorca(a, usermsg)
println("")
@show prompt
respond = sendReceivePrompt(a, prompt)
respond = split(respond, "<|im_end|>")[1]
respond = replace(respond, "\n" => "")
_ = addNewMessage(a, "assistant", respond)
response = sendReceivePrompt(a, prompt)
response = split(response, "<|im_end|>")[1]
response = replace(response, "\n" => "")
_ = addNewMessage(a, "assistant", response)
println("")
@show respond
@show response
return respond
return response
end
"""
@@ -481,7 +483,7 @@ end
There are many work() depend on thinking mode.
"""
function work(a::agentReflex, usermsg::String)
respond = nothing
response = nothing
if a.thinkingmode == :new_thinking
_ = addNewMessage(a, "user", usermsg)
@@ -510,10 +512,10 @@ function work(a::agentReflex, usermsg::String)
prompt_plan = planner_mistral_openorca(a)
println("")
@show prompt_plan
respond = sendReceivePrompt(a, prompt_plan, max_tokens=1024)
response = sendReceivePrompt(a, prompt_plan, max_tokens=1024)
# sometimes LLM add not-need word I don't want
plan = splittext(respond, ["Step 1", "<|im_end|>", "Response", "Execution",
plan = splittext(response, ["Step 1", "<|im_end|>", "Response", "Execution",
"Result", "Recommendation", "My response"])
# plan = replace(plan, "Plan:"=>"")
println("")
@@ -531,19 +533,19 @@ function work(a::agentReflex, usermsg::String)
actorstate, msgToUser = actor(a)
if actorstate == "chatbox"
respond = msgToUser
response = msgToUser
break
elseif actorstate == "all steps done" || actorstate == "formulateUserRespond"
elseif actorstate == "all steps done" || actorstate == "formulateUserresponse"
println("all steps done")
respond = formulateUserRespond(a)
response = formulateUserresponse(a)
println("")
formulatedRespond = respond
@show formulatedRespond
formulatedresponse = response
@show formulatedresponse
a.memory[:shortterm]["Respond $(a.attempt):"] = respond
a.memory[:log]["Respond $(a.attempt):"] = respond
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:"])
@@ -551,7 +553,7 @@ function work(a::agentReflex, usermsg::String)
println("")
@show guideline
score = grading(a, guideline, respond)
score = grading(a, guideline, response)
@show score
if score >= 6 # good enough answer
break
@@ -594,8 +596,8 @@ function work(a::agentReflex, usermsg::String)
# communicates with user
_ = addNewMessage(a, "assistant", respond)
return respond
_ = addNewMessage(a, "assistant", response)
return response
end
@@ -610,7 +612,7 @@ end
Arguments:
a, one of ChatAgent's agent.
plan, a step by step plan to respond
plan, a step by step plan to response
Return:
case 1) if actor complete the plan successfully.
@@ -643,8 +645,8 @@ function actor(a::agentReflex)
a.memory[:shortterm] = removeHeaders(a.memory[:shortterm], a.step, ["Plan"])
a.memory[:log] = removeHeaders(a.memory[:log], a.step, ["Plan"])
println("repeating step $(a.step)")
elseif decision == "formulateUserRespond"
actorState = "formulateUserRespond"
elseif decision == "formulateUserresponse"
actorState = "formulateUserresponse"
msgToUser = nothing
break
else
@@ -661,11 +663,11 @@ function actor(a::agentReflex)
println("")
@show prompt_actor
respond = sendReceivePrompt(a, prompt_actor)
respond = splittext(respond, ["Obs", "<|im_end|>"])
response = sendReceivePrompt(a, prompt_actor)
response = splittext(response, ["Obs", "<|im_end|>"])
if !occursin("Thought", respond)
respond = "Thought: " * respond
if !occursin("Thought", response)
response = "Thought: " * response
end
headerToDetect = ["Question:", "Plan:", "Thought:",
@@ -673,13 +675,13 @@ function actor(a::agentReflex)
"Answer:", "Conclusion:", "Summary:"]
# replace headers with headers with correct attempt and step number
respond = replaceHeaders(respond, headerToDetect, a.step)
response = replaceHeaders(response, headerToDetect, a.step)
headers = detectCharacters(respond, headerToDetect)
headers = detectCharacters(response, headerToDetect)
println("")
respond_actor = respond
@show respond_actor
response_actor = response
@show response_actor
headerToDetect = ["Plan $(a.attempt):",
"Thought $(a.step):",
@@ -687,8 +689,8 @@ function actor(a::agentReflex)
"Actinput $(a.step):",
"Obs $(a.step):",
"Check $(a.step):",]
headers = detectCharacters(respond, headerToDetect)
chunkedtext = chunktext(respond, headers)
headers = detectCharacters(response, headerToDetect)
chunkedtext = chunktext(response, headers)
# add to memory
@@ -704,7 +706,7 @@ function actor(a::agentReflex)
msgToUser = toolinput
actorState = toolname
break
elseif toolname == "formulateUserRespond"
elseif toolname == "formulateUserresponse"
msgToUser = toolinput
actorState = toolname
break
@@ -760,13 +762,13 @@ function writeEvaluationGuideline(a::agentReflex, usermsg::T) where {T<:Abstrac
$usermsg
Your job are:
1. Write an evaluation guideline for your work in order to be able to evaluate your respond.
2. An example of what the respond should be.
1. Write an evaluation guideline for your work in order to be able to evaluate your response.
2. An example of what the response should be.
<|im_end|>
"""
respond = sendReceivePrompt(a, prompt)
return respond
response = sendReceivePrompt(a, prompt)
return response
end
@@ -795,7 +797,7 @@ julia> shorttermMemory = OrderedDict{String, Any}(
"Act 2:" => " wikisearch\n",
"Actinput 2:" => " amd graphics card latest\n",
"Obs 2:" => "No info available for your search query.")
julia> guideline = "\nEvaluation Guideline:\n1. Check if the user's question has been understood correctly.\n2. Evaluate the steps taken to provide the information requested by the user.\n3. Assess whether the correct tools were used for the task.\n4. Determine if the user's request was successfully fulfilled.\n5. Identify any potential improvements or alternative approaches that could be used in the future.\n\nThe respond should include:\n1. A clear understanding of the user's question.\n2. The steps taken to provide the information requested by the user.\n3. An evaluation of whether the correct tools were used for the task.\n4. A confirmation or explanation if the user's request was successfully fulfilled.\n5. Any potential improvements or alternative approaches that could be used in the future."
julia> guideline = "\nEvaluation Guideline:\n1. Check if the user's question has been understood correctly.\n2. Evaluate the steps taken to provide the information requested by the user.\n3. Assess whether the correct tools were used for the task.\n4. Determine if the user's request was successfully fulfilled.\n5. Identify any potential improvements or alternative approaches that could be used in the future.\n\nThe response should include:\n1. A clear understanding of the user's question.\n2. The steps taken to provide the information requested by the user.\n3. An evaluation of whether the correct tools were used for the task.\n4. A confirmation or explanation if the user's request was successfully fulfilled.\n5. Any potential improvements or alternative approaches that could be used in the future."
julia> score = grading(agent, guideline, shorttermMemory)
2
```
@@ -810,11 +812,11 @@ function grading(a, guideline::T, text::T) where {T<:AbstractString}
$guideline
Your respond: $text
Your response: $text
You job are:
1. Evaluate your respond using the evaluation guideline and an example respond.
2. Give yourself a score out of 10 for your respond.
1. Evaluate your response using the evaluation guideline and an example response.
2. Give yourself a score out of 10 for your response.
Use the following format to answer:
{Evaluation} Score {}/10.
@@ -824,13 +826,13 @@ function grading(a, guideline::T, text::T) where {T<:AbstractString}
prompt_grading = prompt
@show prompt_grading
respond = sendReceivePrompt(a, prompt)
response = sendReceivePrompt(a, prompt)
println("")
respond_grading = respond
@show respond_grading
response_grading = response
@show response_grading
_score = split(respond[end-5:end], "/")[1]
_score = split(response[end-5:end], "/")[1]
_score = split(_score, " ")[end]
score = parse(Int, _score)
return score
@@ -879,15 +881,15 @@ function analyze(a)
1. What happened?
2. List all relationships, each with cause and effect.
3. Look at each relationship, figure out why it behaved that way.
4. What could you do to improve the respond?
4. What could you do to improve the response?
<|im_end|>
<|im_start|>assistant
"""
respond = sendReceivePrompt(a, prompt, max_tokens=1024, timeout=180)
response = sendReceivePrompt(a, prompt, max_tokens=1024, timeout=180)
return respond
return response
end
@@ -940,18 +942,18 @@ function selfReflext(a, analysis::T) where {T<:AbstractString}
<|im_end|>
"""
respond = sendReceivePrompt(a, prompt, max_tokens=2048)
return respond
response = sendReceivePrompt(a, prompt, max_tokens=2048)
return response
end
""" Formulate a respond from work for user's stimulus.
""" Formulate a response from work for user's stimulus.
Arguments:
a, one of ChatAgent's agent.
Return:
A respond for user's stimulus.
A response for user's stimulus.
# Example
```jldoctest
@@ -967,10 +969,10 @@ julia> shorttermMemory = OrderedDict{String, Any}(
"Actinput 2:" => " amd graphics card latest\n",
"Obs 2:" => "No info available for your search query.")
julia> report = formulateUserRespond(agent, shorttermMemory)
julia> report = formulateUserresponse(agent, shorttermMemory)
```
"""
function formulateUserRespond(a)
function formulateUserresponse(a)
stimulus = a.memory[:shortterm]["user:"]
work = dictToString(a.memory[:shortterm], ["user:"])
@@ -979,7 +981,7 @@ function formulateUserRespond(a)
"""
<|im_start|>system
Symbol:
Stimulus: the input user gives to you and you must respond
Stimulus: the input user gives to you and you must response
Plan: a plan
Thought: your thought
Act: the action you took
@@ -992,12 +994,12 @@ function formulateUserRespond(a)
Your work:
$work
From your work, formulate a respond for user's stimulus.
From your work, formulate a response for user's stimulus.
<|im_end|>
Respond:
response:
"""
respond = sendReceivePrompt(a, prompt)
return respond
response = sendReceivePrompt(a, prompt)
return response
end
@@ -1036,7 +1038,7 @@ function goNogo(a)
# """
# <|im_start|>system
# Symbol meaning:
# Stimulus: the input user gives to you and you must respond
# Stimulus: the input user gives to you and you must response
# Plan: a plan
# Thought: your thought
# Act: the action you took
@@ -1052,7 +1054,7 @@ function goNogo(a)
# From your work, you job is to decide what to do next by choosing one of the following choices:
# If you are ready to do the next step of the plan say, "{Yes}". And what is the rationale behind the decision?
# If you need to repeat the latest step say, "{No}". And what is the rationale behind the decision?
# If you are ready to formulate a final respond to user original stimulus say, {formulateUserRespond}. And what is the rationale behind the decision?
# If you are ready to formulate a final response to user original stimulus say, {formulateUserresponse}. And what is the rationale behind the decision?
# <|im_end|>
# """
@@ -1060,7 +1062,7 @@ function goNogo(a)
"""
<|im_start|>system
Symbol meaning:
Stimulus: the input user gives to you and you must respond
Stimulus: the input user gives to you and you must response
Plan: a plan
Thought: your thought
Act: the action you took
@@ -1081,36 +1083,36 @@ function goNogo(a)
"""
respond = sendReceivePrompt(a, prompt)
response = sendReceivePrompt(a, prompt)
decision = nothing
reason = nothing
if occursin("Yes", respond)
if occursin("Yes", response)
decision = "Yes"
elseif occursin("No", respond)
elseif occursin("No", response)
decision = "No"
elseif occursin("formulateUserRespond", respond)
decision = "formulateUserRespond"
elseif occursin("formulateUserresponse", response)
decision = "formulateUserresponse"
else
error("undefied condition, decision $decision $(@__LINE__)")
end
startInd = findfirst(decision, respond)[end] +2
startInd = findfirst(decision, response)[end] +2
if occursin(":", respond[startInd:end]) # check for ":" after decision cha
startInd2 = findnext(":", respond, startInd)[end]+1
reason = respond[startInd2:end]
if occursin(":", response[startInd:end]) # check for ":" after decision cha
startInd2 = findnext(":", response, startInd)[end]+1
reason = response[startInd2:end]
else
reason = respond[startInd:end]
reason = response[startInd:end]
end
return decision, reason
end
#WORKING
""" Extract important info from text into key-value pair text.
Arguments:
@@ -1118,7 +1120,7 @@ Arguments:
text, a text you want to extract info
Return:
a text with important info are in key-value format.
key-value pair text.
# Example
```jldoctest
@@ -1130,29 +1132,64 @@ julia> extract(agent, text)
```
"""
function extractinfo(a, text::T) where {T<:AbstractString}
# determine whether there are any important info in an input text
prompt =
"""
<|im_start|>system
User message:
User's message:
$text
Your job is to extract important info from user's message into keys and values using this format: key=value ,.
p.s.1 you can extract many key-value pairs.
Your job is determine whether there are important info in the user's message. Answer: {Yes/No/Not sure}
<|im_end|>
Answer:
"""
response = sendReceivePrompt(a, prompt, temperature=0.0)
if occursin("Yes", response)
prompt =
"""
<|im_start|>system
User's message:
$text
Your job is to extract important info from the user's message into keys and values using this format: key=value,.
p.s.1 you can extract many key-value pairs.
<|im_end|>
respond = sendReceivePrompt(a, prompt, temperature=0.0)
end
"""
response = sendReceivePrompt(a, prompt, temperature=0.0)
return response
else
return nothing
end
end
function updateEnvState(a, currentinfo, newinfo)
""" Update important info from key-value pair text into another key-value pair text.
Arguments:
a, one of ChatAgent's agent
text, a key-value pair text
Return:
updated key-value pair text
# Example
```jldoctest
julia> using ChatAgent
julia> agent = ChatAgent.agentReflex("Jene")
julia> currentinfo = "location=beach, event=wedding party"
julia> newinfo = "wine_type=full body, dry and medium tannin\nprice_range=50 dollars"
julia> updateEnvState(agent, currentinfo, newinfo)
" location=beach, event=wedding party, wine_type=full body, dry and medium tannin, price_range=50 dollars"
```
"""
function updateEnvState(a, newinfo)
prompt =
"""
<|im_start|>system
Current state:
$currentinfo
$(a.env)
New info:
$newinfo
@@ -1162,7 +1199,7 @@ function updateEnvState(a, currentinfo, newinfo)
Updated Current State:\n
"""
respond = sendReceivePrompt(a, prompt, temperature=0.0)
response = sendReceivePrompt(a, prompt, temperature=0.0)
end
@@ -1179,4 +1216,51 @@ end
end # module

View File

@@ -20,9 +20,9 @@ julia> mqttClientSpec = (
clientID= "$(uuid4())",
broker= "mqtt.yiem.ai",
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/respond",
txtAI="agent/api/v0.1.0/txt/respond"),
txtAI="txt/api/v0.1.0/gpu/request"), # this is where LLM server located
subtopic= (imgAI="agent/api/v0.1.0/img/respond",
txtAI="agent/api/v0.1.0/txt/respond"), # this is where this agent located
keepalive= 30,
)
julia> msgMeta = Dict(
@@ -96,7 +96,7 @@ julia> agent = ChatAgent.agentReflex(
attemptlimit::Int = 5 # thinking round limit
attempt::Int = 0 # attempted number
step::Int = 0 # step number
env::Dict = Dict()
env::AbstractString = ""
thinkingFormat::Union{Dict, Nothing} = nothing
memory::Dict = Dict(
:shortterm=> OrderedDict{String, Any}(),

View File

@@ -59,28 +59,6 @@ end
```jldoctest
julia> using JSON3, UUIDs, Dates, FileIO, CommUtils, ChatAgent
julia> mqttClientSpec = (
clientName= "someclient", # name of this client
clientID= "$(uuid4())",
broker= "mqtt.yiem.ai",
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/respond",
txtAI="agent/api/v0.1.0/txt/respond"),
keepalive= 30,
)
julia> msgMeta = Dict(
:msgPurpose=> "updateStatus",
:from=> "agent",
:to=> "llmAI",
:requestrespond=> "request",
:sendto=> "", # destination topic
:replyTo=> "agent/api/v0.1.0/txt/respond", # requester ask responder to send reply to this topic
:repondToMsgId=> "", # responder is responding to this msg id
:taskstatus=> "", # "complete", "fail", "waiting" or other status
:timestamp=> Dates.now(),
:msgId=> "$(uuid4())",
)
julia> newAgent = ChatAgent.agentReact(
"Jene",
mqttClientSpec,
@@ -226,9 +204,9 @@ function extractStepFromPlan(a::agent, plan::T, step::Int) where {T<:AbstractStr
"""
respond = sendReceivePrompt(a, prompt)
response = sendReceivePrompt(a, prompt)
return respond
return response
end
function checkTotalStepInPlan(a::agent)
@@ -265,8 +243,8 @@ function checkTotalStepInPlan(a::agent)
<|im_start|>assistant
"""
respond = sendReceivePrompt(a, prompt)
result = extract_number(respond)
response = sendReceivePrompt(a, prompt)
result = extract_number(response)
return result
end
@@ -351,13 +329,13 @@ end
# """
# <|im_start|>system
# {systemMsg}
# You always use tools if there is a chance to impove your respond.
# You always use tools if there is a chance to impove your response.
# You have access to the following tools:
# {tools}
# Your job is to determine whether you will use tools or actions to respond.
# Your job is to determine whether you will use tools or actions to response.
# Choose one of the following choices:
# Choice 1: If you don't need to use tools or actions to respond to the stimulus say, "{no}".
# Choice 1: If you don't need to use tools or actions to response to the stimulus say, "{no}".
# Choice 2: If you think the user want to get wine say, "{yes}".
# <|im_end|>
@@ -393,11 +371,10 @@ function isUseTools(a::agentReflex, usermsg::String)
You have access to the following tools:
{tools}
User message:
User's message:
{input}
Your job is to answer the following questions:
Question 1: From the user's message, Do you need to any tools before responding? Answer: {Yes/No/Not sure}. What will the you do?
From the user's message, Do you need to any tools before responseing? Answer: {Yes/No/Not sure}. What will the you do?
<|im_end|>
<|im_start|>assistant
Answer:
@@ -415,9 +392,6 @@ function isUseTools(a::agentReflex, usermsg::String)
result = sendReceivePrompt(a, prompt, temperature=0.2)
# headers = detectCharacters(result, ["Question 1:", "Question 2:"])
# chunkedtext = chunktext(result, headers)
if occursin("Yes", result)
return true
else