This commit is contained in:
Your Name
2024-02-09 19:39:04 +07:00
parent 62fa62253f
commit 9de820808c
3 changed files with 216 additions and 143 deletions

View File

@@ -308,100 +308,6 @@ function updatePlan(a::agentReflex)
end
# function selfAwareness(a::agentReflex)
# getonlykeys = ["Actinput", "Obs"]
# worknoplan = similar(a.memory[:shortterm])
# for (k, v) in a.memory[:shortterm]
# count = 0
# for i in getonlykeys
# if occursin(i, k)
# count += 1
# end
# end
# if count != 0
# worknoplan[k] = v
# end
# end
# work = dictToString(worknoplan)
# aboutYourself =
# """
# Your name is $(a.agentName)
# $(a.roles[a.role])
# """
# prompt =
# """
# <|system|>
# <About yourself>
# $aboutYourself
# $(a.roleSpecificInstruction[a.role])
# </About yourself>
# <Your earlier work>
# $work
# </Your earlier work>
# <Your keyword memory>
# $(JSON3.write(a.memory[:keyword]))
# </Your keyword memory>
# <Your job>
# Use the following format strictly:
# Info extraction: repeat all important info from the latest observed result thoroughly
# Info mapping: based on extracted info, explicitly state what each info could match which keyword memory's key
# Info matching: using JSON format, what key in my memory matches which info
# </Your job>
# <Example>
# <Your earlier work>
# The user wants to buy an electric SUV car under 20000 dollars.
# </Your earlier work>
# <Your keyword memory>
# {"car type": null, "color": null, "financing": null}
# </Your keyword memory>
# Info extraction:
# - The user is buying an electric SUV car.
# Info mapping:
# - SUV could matches "car type" key
# - electric could matches "engine type" key
# Info matching: {"car type": "SUV", "engine type": "electric motor", "color": null, "financing": null}
# </Example>
# </s>
# <|assistant|>
# Info extraction:
# """
# response = sendReceivePrompt(a, prompt, max_tokens=1024, temperature=0.2, timeout=180,
# stopword=["/n/n", "END", "End", "Obs", "<|", "</"])
# response = split(response, "<|")[1]
# response = split(response, "</")[1]
# response = "Info extraction:" * response
# println("")
# @show selfaware_1 = response
# headerToDetect = ["Info extraction:", "Info mapping:", "Info matching:", "Actinput"]
# headers = detectCharacters(response, headerToDetect)
# # headers[1:2] is for when LLM generate more than a paire of "Info extraction" and "Info matching", discard the rest
# chunkedtext = chunktext(response, headers[1:3])
# println("")
# _infomatch = chunkedtext["Info matching:"]
# _infomatch = GeneralUtils.getStringBetweenCharacters(_infomatch, '{', '}', endCharLocation="next")
# infomatch = copy(JSON3.read(_infomatch))
# println("")
# @show chunkedtext
# keywordMemoryUpdate!(a.memory[:keyword], infomatch)
# response = "What I know about user:" * JSON3.write(a.memory[:keyword]) # * response
# println("")
# @show selfaware_2 = response
# return response
# end
function selfAwareness(a::agentReflex)
@@ -433,7 +339,7 @@ function selfAwareness(a::agentReflex)
$(a.roles[a.role])
"""
#WORKING may be I need to use "- $k is $v" because LLM skip the key for sweetness
prompt =
"""
<s>
@@ -514,6 +420,189 @@ function selfAwareness(a::agentReflex)
return response
end
function sentenceToKeywordMemory(a::agentReflex)
getonlykeys = ["Actinput", "Obs"]
worknoplan = similar(a.memory[:shortterm])
worklength = length(a.memory[:shortterm])
for (i, (k, v)) in enumerate(a.memory[:shortterm])
if i >= worklength - 1
count = 0
for i in getonlykeys
if occursin(i, k)
count += 1
end
end
if count != 0
worknoplan[k] = v
end
end
end
println("")
@show worknoplan
work = dictToString(worknoplan)
aboutYourself =
"""
Your name is $(a.agentName)
$(a.roles[a.role])
"""
prompt =
"""
<s>
<|system|>
<About yourself>
$aboutYourself
$(a.roleSpecificInstruction[a.role])
</About yourself>
<Your job>
Use the following format strictly:
Info extraction: repeat all important info from the latest observed result thoroughly
Info mapping: based on extracted info, explicitly state what each info could match which keyword memory's key
Info matching: using JSON format, what key in my memory matches which info
</Your job>
</|system|>
<Example>
<Your earlier work>
The user wants to buy an electric SUV car under 20000 dollars.
</Your earlier work>
<Your keyword memory>
{\"car type\": null, \"engine type\": null, \"price\": null, \"color\": null, \"financing\": null}
</Your keyword memory>
<|assistant|>
Info extraction:
- The user is buying an electric SUV car.
- price is under 20000 dollars
Info mapping:
- "SUV" could matches "car type" key
- "electric" could matches "engine type" key
- "under 20000 dollars" could match "price" key
Info matching: {\"car type\": \"SUV\", \"engine type\": \"electric motor\", \"price\": \"under 20000\", \"color\": null, \"financing\": null}
</|assistant|>
</Example>
</s>
<Your earlier work>
$work
</Your earlier work>
<Your keyword memory>
$(JSON3.write(a.memory[:keyword]))
</Your keyword memory>
<|assistant|>
Info extraction:
"""
response = sendReceivePrompt(a, prompt, max_tokens=1024, temperature=0.2, timeout=180,
stopword=["/n/n", "END", "End", "Obs", "<|", "</"])
response = split(response, "<|")[1]
response = split(response, "</")[1]
response = split(response, "</|assistant|>")[1]
response = "Info extraction:" * response
println("")
@show selfaware_1 = response
headerToDetect = ["Info extraction:", "Info mapping:", "Info matching:", "Actinput"]
headers = detectCharacters(response, headerToDetect)
# headers[1:2] is for when LLM generate more than a paire of "Info extraction" and "Info matching", discard the rest
chunkedtext = chunktext(response, headers[1:3])
println("")
_infomatch = chunkedtext["Info matching:"]
_infomatch = GeneralUtils.getStringBetweenCharacters(_infomatch, '{', '}', endCharLocation="end")
infomatch = GeneralUtils.JSON3read_stringKey(_infomatch)
# infomatch = copy(JSON3.read(_infomatch))
println("")
@show chunkedtext
println("")
@show infomatch
keywordMemoryUpdate!(a.memory[:keyword], infomatch)
end
function keywordMemoryToPlanMatching(a::agentReflex)
aboutYourself =
"""
Your name is $(a.agentName)
$(a.roles[a.role])
"""
prompt =
"""
<s>
<|system|>
<About yourself>
$aboutYourself
$(a.roleSpecificInstruction[a.role])
</About yourself>
<Your job>
Use the following format strictly:
Info mapping: explicitly state what each step of the plan could match which keyword memory's key
Info matching: using JSON format, what key in my memory matches which info
</Your job>
</|system|>
<Example 1>
<My plan>
1. ask the user for car type,
2. ask the user for color
</My plan>
<User info>
{\"car type\": "SUV", \"color\": null}
</User info>
<|assistant|>
Info mapping:
-In step 1 of the plan, I need to ask the user about the car type. From user info, the car type is "SUV". Therefore this step is done.
-In step 2 of the plan, I need to ask the user about the color . From user info, the color is null. Therefore this step is not done yet and I'll need to do this step.
</|assistant|>
</Example 1>
</s>
<Your earlier work>
$work
</Your earlier work>
<User info>
$(JSON3.write(a.memory[:keyword]))
</User info>
<|assistant|>
Info mapping:
"""
response = sendReceivePrompt(a, prompt, max_tokens=1024, temperature=0.2, timeout=180,
stopword=["/n/n", "END", "End", "Obs", "<|", "</"])
response = split(response, "<|")[1]
response = split(response, "</")[1]
response = split(response, "</|assistant|>")[1]
response = "Info mapping:" * response
println("")
@show keywordMemoryToPlanMatching = response
error(1111)
headerToDetect = ["Info extraction:", "Info mapping:", "Info matching:", "Actinput"]
headers = detectCharacters(response, headerToDetect)
# headers[1:2] is for when LLM generate more than a paire of "Info extraction" and "Info matching", discard the rest
chunkedtext = chunktext(response, headers[1:3])
println("")
_infomatch = chunkedtext["Info matching:"]
_infomatch = GeneralUtils.getStringBetweenCharacters(_infomatch, '{', '}', endCharLocation="end")
infomatch = GeneralUtils.JSON3read_stringKey(_infomatch)
# infomatch = copy(JSON3.read(_infomatch))
println("")
@show chunkedtext
println("")
@show infomatch
keywordMemoryUpdate!(a.memory[:keyword], infomatch)
end
# function actor_mistral_openorca(a::agentReflex, selfaware=nothing)
# getonlykeys = ["Actinput", "Obs"]
# worknoplan = similar(a.memory[:shortterm])
@@ -844,37 +933,19 @@ function actor_mistral_openorca(a::agentReflex, selfaware=nothing)
</You have access to the following tools>
<Your job>
Use the following format:
Thought: based on what you know about the user, where are you at according to the plan? what to do next?. (PS. 1. let's think only one thing at a time. 2. pay attention to correct numeral calculation and commonsense.)
Thought: based on your user info, think about what to do to next according to the plan. (PS. 1. let's think only one thing at a time. 2. pay attention to correct numeral calculation and commonsense.)
Act: based on your thought what action to choose?, must be one of [{toolnames}].
Actinput: your input to the action using JSON format (pay attention to the tool's input)
Obs: observed result of the action
</Your job>
</|system|>
<Example 1>
<my plan>
I'll ask the user for car type, brand, price, color, financing method and luxury level before I'll give them any advice.
</my plan>
<What I know about the user>
- Car type is SUV
- Brand is Lexus
- Price is 20k dollar
- No info on the car color yet
- No info on the financing method yet
- Luxury level is high
</What I know about the user>
<|assistant|>
Thought: after checking what I know about the user against my plan, I still don't know the color and financing method yet. Next, I need to know what color the user like.
Act: askbox
Actinput:
</|assistant|>
</Example 1>
</s>
<My plan>
$(a.memory[:shortterm]["Plan 1:"])
</My plan>
<What I know about the user>
$keywordmemory)
</What I know about the user>
<User info>
$keywordmemory
</User info>
<|assistant|>
Thought:
"""
@@ -890,7 +961,7 @@ function actor_mistral_openorca(a::agentReflex, selfaware=nothing)
while true # while Thought or Act is empty, run actor again
response = sendReceivePrompt(a, prompt, max_tokens=1024, temperature=0.4, timeout=300,
response = sendReceivePrompt(a, prompt, max_tokens=1024, temperature=0.0, timeout=300,
stopword=["Thought:", "Obs:", "<|system|>", "</s>", "<|end|>"],
seed=rand(1000000:2000000))
println("")
@@ -1246,6 +1317,7 @@ function actor(a::agentReflex)
selfaware = nothing
if length(a.memory[:shortterm]) > 2 # must have User:, Plan:, Thought:, Act:, Actinput: already
selfaware = selfAwareness(a)
# result = keywordMemoryToPlanMatching(a)
end
actorResult = actor_mistral_openorca(a, selfaware)

View File

@@ -174,29 +174,29 @@ function winestock(a::agentReflex, input::NamedTuple)
Dessert = table for wine type "dessert"
Fortified = table for wine type "fortified"
Intensity level:
intensity = 1, light bodied
intensity = 2, semi-light bodied
intensity = 3, medium bodied
intensity = 4, semi-full bodied
intensity = 5, full bodied
light bodied = 1
semi-light bodied = 2
medium bodied = 3
semi-full bodied = 4
full bodied = 5
Sweetness level:
sweetness = 1, dry
sweetness = 2, off-dry
sweetness = 3, semi-sweet
sweetness = 4, sweet
sweetness = 5, very sweet
dry = 1
off-dry = 2
semi-sweet = 3
sweet = 4
very sweet = 5
Tannin level:
tannin = 1, low tannin
tannin = 2, semi-low tannin
tannin = 3, medium tannin
tannin = 4, semi-high tannin
tannin = 5, high tannin
low tannin = 1
semi-low tannin = 2
medium tannin = 3
semi-high tannin = 4
high tannin = 4
Acidity level:
acidity = 1, low acidity
acidity = 2, semi-low acidity
acidity = 3, medium acidity
acidity = 4, semi-high acidity
acidity = 5, high acidity
low acidity = 1
semi-low acidity = 2
medium acidity = 3
semi-high acidity = 4
high acidity = 5
</You have the following conversion table>
<Your job>
Write a specific SQL command from a query using a conversion table
@@ -270,15 +270,13 @@ function winestock(a::agentReflex, input::NamedTuple)
body = newsql
uri = URI(scheme="http", host="192.168.88.12", port="9010", path="/sql", userinfo="root:root")
r = HTTP.request("POST", uri, ["Accept" => "application/json", "NS"=>"yiem", "DB"=>"Blossom_wines"], body)
println("")
@show r
a.memory[:r] = r
result = copy(JSON3.read(r.body))
wines = shuffle(result[1][:result]) # shuffle in case there are more than 1 result
println("")
@show wines
# choose only 2 wines
if length(wines) > 2
@@ -286,6 +284,9 @@ function winestock(a::agentReflex, input::NamedTuple)
wines = wines[1:2]
end
println("")
@show wines
result = nothing
if length(wines) == 0
result =

View File

@@ -152,7 +152,7 @@ function agentReflex(
"""
Request the users input for the following info initially, and use alternative sources of information only if they are unable to provide it:
- wine price range: ask the user
- wine type (Rose, White, Red, Rose, Sparkling, Dessert)
- wine type (rose, white, red, sparkling, dessert)
- food type that will be served with wine
- wine sweetness level (dry to very sweet)
- wine intensity level (light to full bodied)