This commit is contained in:
2024-01-18 18:58:52 +00:00
parent 44006c3112
commit b419a5629c
4 changed files with 435 additions and 371 deletions

View File

@@ -99,7 +99,7 @@ function chat_mistral_openorca(a::agentReflex)
general prompt format:
"
<|im_start|>system
<|system|>
{role}
{tools}
{thinkingFormat}
@@ -136,9 +136,6 @@ function chat_mistral_openorca(a::agentReflex)
<About yourself>
$aboutYourself
</About yourself>
<Your earlier talk with the user>
$(a.earlierConversation)
</Your earlier talk with the user>
</s>
$conversation
<|assistant|>
@@ -155,7 +152,7 @@ function planner_mistral_openorca(a::agentReflex)
general prompt format:
"
<|im_start|>system
<|system|>
{role}
{tools}
{thinkingFormat}
@@ -371,6 +368,7 @@ function selfAwareness(a::agentReflex)
<Your job>
Use the following format strictly:
What do I know: based on observed results, repeat all the information you are gathering.
Info match: explicitly state what information matches what variable in my plan.
What am I missing: based on observed results, describe in detail what you are still missing compared to your plan.
P.S. do not mention any toolnames
</Your job>
@@ -408,7 +406,7 @@ function actor_mistral_openorca(a::agentReflex, selfaware=nothing)
general prompt format:
"
<|im_start|>system
<|system|>
{role}
{tools}
{thinkingFormat}
@@ -450,7 +448,7 @@ function actor_mistral_openorca(a::agentReflex, selfaware=nothing)
# aware = "Self-awareness: Based on action's input and observed results, check your progress against the plan. Then, repeat all the details of what you have been gathered. Finally, describe in detail what you are missing."
thought =
"Self-awareness: $selfaware
Thought: based on self-awareness, You should always plan your next steps and focus on what you missed first. (P.S. 1) let's think a single step. 2) pay attention to correct numeral calculation and commonsense.)
Thought: based on self-awareness, think about what to do next and focus on what you missed first. (P.S. 1) let's think a single step. 2) pay attention to correct numeral calculation and commonsense.)
"
end
@@ -484,11 +482,10 @@ function actor_mistral_openorca(a::agentReflex, selfaware=nothing)
Act: askbox
Actinput: {\"askbox\": \"Hello! Welcome to our wine store.\"}
</Example>
</s>
<|assistant|>
$work
"Thought:"
"Thought: "
"""
prompt = replace(prompt, "{toolnames}" => toolnames)
@@ -507,14 +504,16 @@ function actor_mistral_openorca(a::agentReflex, selfaware=nothing)
response = sendReceivePrompt(a, prompt, max_tokens=1024, temperature=0.4, timeout=300,
stopword=["Thought:", "Obs:", "<|system|>", "</s>", "<|end|>"],
seed=seed)
response = splittext(response, ["/n/n", "END", "End", "Obs", "<|im_end|>"])
response = splittext(response, ["/n/n", "END", "End","obs", "Obs", "<|im_end|>"])
latestTask = shortMemLatestTask(a.memory[:shortterm]) +1
response = "Thought:" * response
if occursin("Thought", response) == false
response = "Thought:" * response
end
headerToDetect = ["Question:", "Plan:", "Self-awareness:", "Thought:",
"Act:", "Actinput:", "Obs:", "...",
headerToDetect = ["Plan:", "Self-awareness:", "Thought:",
"Act:", "Actinput:", "Obs:",
"Answer:", "Conclusion:", "Summary:"]
# replace headers with headers with correct attempt and task number
@@ -522,10 +521,10 @@ function actor_mistral_openorca(a::agentReflex, selfaware=nothing)
response = split(response, "<|")[1]
response = split(response, "</")[1]
# headers = detectCharacters(response, headerToDetect)
# sometime LLM use wrong keyword. use regex to detect "actinput5:" and replace it with "Actinput"
regexmatch = match(r"actinput\d+:", response)
respone = regexmatch !== nothing ? response = replace(response, match=>"Actinput:") : response
response = replace(response, "actinput:"=>"Actinput:")
headerToDetect = ["Plan $(a.attempt):",
"Self-awareness $latestTask:",
@@ -542,18 +541,6 @@ function actor_mistral_openorca(a::agentReflex, selfaware=nothing)
check_2 = haskey(chunkedtext, "Act $latestTask:")
check_3 = haskey(chunkedtext, "Actinput $latestTask:")
#check whether the act has valid json
check_7 = true
if occursin('{', response)
try
act = GeneralUtils.getStringBetweenCharacters(response, '{', '}', endCharLocation="end")
act = JSON3.read(act)
check_7 = true
catch
check_7 = false
end
end
# check for a valid toolname
check_4 = false
for i in toolslist
@@ -566,15 +553,36 @@ function actor_mistral_openorca(a::agentReflex, selfaware=nothing)
# check for empty Thought
check_5 = length(chunkedtext["Thought $latestTask:"]) > 5
# check for empty Actinput
check_6 = length(chunkedtext["Actinput $latestTask:"]) > 5
check_6 = nothing
try
check_6 = length(chunkedtext["Actinput $latestTask:"]) > 5
catch
println("")
@show response
println("")
@show chunkedtext
a.memory[:chunkedtext] = chunkedtext
end
#check whether the act has valid json
check_7 = true
if occursin('{', response)
try
act = GeneralUtils.getStringBetweenCharacters(response, '{', '}', endCharLocation="end")
act = JSON3.read(act)
check_7 = true
catch
check_7 = false
end
end
# print all check_1 to check_6
println("check_1: $check_1, check_2: $check_2, check_3: $check_3, check_4: $check_4,
check_5: $check_5, check_6: $check_6, check_7: $check_7")
if check_1 && check_2 && check_3 && check_4 && check_5 && check_6 && check_7
#WORKING paraphrase selfaware
#TODO paraphrase selfaware
break
end
@show response
@@ -597,10 +605,8 @@ function actor_mistral_openorca(a::agentReflex, selfaware=nothing)
"Check $latestTask:",]
headers = detectCharacters(response, headerToDetect)
chunkedtext = chunktext(response, headers)
chunkedtext = delete!(chunkedtext, "Self-awareness $latestTask")
println("")
@show chunkedtext
toolinput = chunkedtext["Actinput $latestTask:"]
@@ -615,237 +621,9 @@ function actor_mistral_openorca(a::agentReflex, selfaware=nothing)
chunkedtext["Act $latestTask:"] = toolname
return toolname, toolinput, chunkedtext
return (toolname=toolname, toolinput=toolinput, chunkedtext=chunkedtext, selfaware=selfaware)
end
# function actor_mistral_openorca(a::agentReflex, selfaware=nothing)
# 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)
# """
# 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}
# "
# """
# toolslist = []
# toolnames = ""
# toollines = ""
# for (toolname, v) in a.tools
# toolline = "$toolname: $(v[:description]) $(v[:input]) $(v[:output])\n"
# toollines *= toolline
# toolnames *= "$toolname, "
# push!(toolslist, toolname)
# end
# thought = "Thought: you should always think about what to do according to the plan (pay attention to correct numeral calculation and commonsense and do one thing at a time.)"
# if selfaware !== nothing
# # aware = "Self-awareness: based on the recap, assess your progress against the plan then identify areas where you need to address."
# # aware = "Self-awareness: based on the recap and the plan, state your current understanding of the matter in details then identify areas where you need to address."
# # aware = "Self-awareness: Based on Obs, review your progress against the plan. Then, describe in detail the results you have achieved so far. Finally, describe in detail what you are missing. (focus on your actions and their results)"
# # aware = "Self-awareness: Based on action's input and observed results, check your progress against the plan. Then, repeat all the details of what you have been gathered. Finally, describe in detail what you are missing."
# thought =
# "Self-awareness: $selfaware
# Thought: you should always think about what to do based on what are you missing. (P.S. 1) let's think a single step. 2) pay attention to correct numeral calculation and commonsense.)
# "
# end
# aboutYourself =
# """
# Your name is $(a.agentName)
# $(a.roles[a.role])
# """
# prompt =
# """
# <|system|>
# <About yourself>
# $aboutYourself
# </About yourself>
# <You have access to the following tools>
# $toollines
# </You have access to the following tools>
# <Your plan>
# $(a.memory[:shortterm]["Plan 1:"])
# </Your plan>
# <Your job>
# Use the following format:
# $thought
# Act: based on your thought what action to choose?, must be one of [{toolnames}].
# Actinput: your input to the action (pay attention to the tool's input)
# Obs: observed result of the action
# </Your job>
# <Example>
# Thought: Greet user and begin the conversation.
# Act: askbox
# Actinput: {\"askbox\": \"Hello! Welcome to our wine store.\"}
# </Example>
# </s>
# <|assistant|>
# $work
# "Thought:"
# """
# prompt = replace(prompt, "{toolnames}" => toolnames)
# println("")
# @show actor_prompt = prompt
# response = nothing
# chunkedtext = nothing
# latestTask = nothing
# tempcounter = 0.2
# seed = nothing
# while true # while Thought or Act is empty, run actor again
# # tempcounter += 0.2
# @show tempcounter
# response = sendReceivePrompt(a, prompt, max_tokens=1024, temperature=0.4, timeout=180,
# stopword=["Thought:", "Obs:", "<|system|>", "</s>", "<|end|>"],
# seed=seed)
# response = splittext(response, ["/n/n", "END", "End", "Obs", "<|im_end|>"])
# latestTask = shortMemLatestTask(a.memory[:shortterm]) +1
# response = "Thought:" * response
# headerToDetect = ["Question:", "Plan:", "Self-awareness:", "Thought:",
# "Act:", "Actinput:", "Obs:", "...",
# "Answer:", "Conclusion:", "Summary:"]
# # replace headers with headers with correct attempt and task number
# response = replaceHeaders(response, headerToDetect, latestTask)
# response = split(response, "<|")[1]
# response = split(response, "</")[1]
# # headers = detectCharacters(response, headerToDetect)
# println("")
# headerToDetect = ["Plan $(a.attempt):",
# "Self-awareness $latestTask:",
# "Thought $latestTask:",
# "Act $latestTask:",
# "Actinput $latestTask:",
# "Obs $latestTask:",
# "Check $latestTask:",]
# headers = detectCharacters(response, headerToDetect)
# chunkedtext = chunktext(response, headers)
# # assuming length more than 10 character means LLM has valid thinking
# check_1 = haskey(chunkedtext, "Thought $latestTask:")
# check_2 = haskey(chunkedtext, "Act $latestTask:")
# check_3 = haskey(chunkedtext, "Actinput $latestTask:")
# # check whether the act has valid json
# # check_4 = false
# # try
# # act = GeneralUtils.getStringBetweenCharacters(response, '{', '}', endCharLocation="end")
# # act = JSON3.read(act)
# # check_4 = true
# # catch
# # end
# # check for a valid toolname
# check_4 = false
# for i in toolslist
# if occursin(i, chunkedtext["Act $latestTask:"])
# check_4 = true
# break
# end
# end
# # check for empty Thought
# check_5 = length(chunkedtext["Thought $latestTask:"]) > 5
# # check for empty Actinput
# check_6 = length(chunkedtext["Actinput $latestTask:"]) > 5
# # print all check_1 to check_6
# println("check_1: $check_1, check_2: $check_2, check_3: $check_3, check_4: $check_4, check_5: $check_5, check_6: $check_6")
# if check_1 && check_2 && check_3 && check_4 && check_5 && check_6
# #WORKING paraphrase selfaware
# break
# end
# end
# toolname = toolNameBeingCalled(chunkedtext["Act $latestTask:"], a.tools)
# # change trailing number to continue a.memory[:shortterm]
# headerToDetect = ["Question:", "Plan:", "Self-awareness:", "Thought:",
# "Act:", "Actinput:", "Obs:", "...",
# "Answer:", "Conclusion:", "Summary:"]
# response = replaceHeaders(response, headerToDetect, latestTask)
# println("")
# @show actor_response_1 = response
# headerToDetect = ["Plan $(a.attempt):",
# "Thought $latestTask:",
# "Act $latestTask:",
# "Actinput $latestTask:",
# "Obs $latestTask:",
# "Check $latestTask:",]
# headers = detectCharacters(response, headerToDetect)
# chunkedtext = chunktext(response, headers)
# chunkedtext = delete!(chunkedtext, "Self-awareness $latestTask")
# println("")
# @show chunkedtext
# toolinput = chunkedtext["Actinput $latestTask:"]
# # because tools has JSON input but sometime LLM output is not JSON, we need to check.
# if occursin("{", toolinput)
# act = GeneralUtils.getStringBetweenCharacters(response, '{', '}', endCharLocation="end")
# act = copy(JSON3.read(act))
# chunkedtext["Actinput $latestTask:"] = JSON3.write(act[Symbol(toolname)])
# toolinput = act[Symbol(toolname)]
# end
# chunkedtext["Act $latestTask:"] = toolname
# return toolname, toolinput, chunkedtext
# end
"""
Chat with llm.
@@ -882,13 +660,12 @@ end
)
julia> response = ChatAgent.conversation(newAgent, "Hi! how are you?")
```
"""
# """
function conversation(a::agentReflex, usermsg::String; attemptlimit::Int=3)
a.attemptlimit = attemptlimit
workstate = nothing
response = nothing
# a.earlierConversation = conversationSummary(a)
_ = addNewMessage(a, "user", usermsg)
isuseplan = isUsePlans(a)
# newinfo = extractinfo(a, usermsg)
@@ -930,7 +707,7 @@ function work(a::agentReflex)
latestTask = shortMemLatestTask(a.memory[:shortterm])
if haskey(a.memory[:shortterm], "Act $latestTask:")
if occursin("askbox", a.memory[:shortterm]["Act $latestTask:"])
a.memory[:shortterm]["Obs $latestTask:"] = "user response: " * a.messages[end][:content]
a.memory[:shortterm]["Obs $latestTask:"] = "(user response) " * a.messages[end][:content]
end
end
end
@@ -1069,8 +846,10 @@ function actor(a::agentReflex)
println("")
@show selfaware
end
toolname, toolinput, chunkedtext = actor_mistral_openorca(a, selfaware)
actorResult = actor_mistral_openorca(a, selfaware)
println("")
toolname, toolinput, chunkedtext, selfaware = actorResult
@show toolname
@show toolinput
println(typeof(toolinput))
@@ -1088,8 +867,8 @@ function actor(a::agentReflex)
actorState = "formulateFinalResponse"
break
else # function call
f = a.tools[toolname][:func]
toolresult = f(a, toolinput)
f = a.tools[toolname][:func]
toolresult = f(a, actorResult)
@show toolresult
if toolname == "temp"
a.winestockResult = toolresult
@@ -1134,7 +913,7 @@ end
function writeEvaluationGuideline(a::agentReflex)
prompt =
"""
<|im_start|>system
<|system|>
$(a.roles[a.role])
<You have access to the following tools>
askbox: Useful for when you need to ask a customer for more context. Input should be a conversation to customer.
@@ -1186,37 +965,44 @@ end
function grading(a, guideline::T, text::T) where {T<:AbstractString}
prompt =
"""
<|im_start|>system
You have access to the following tools:
askbox: Useful for when you need to ask a customer for more context. Input should be a conversation to customer.
wikisearch: Useful for when you need to search an encyclopedia Input is keywords and not a question.
<|system|>
<You have access to the following tools>
askbox: Useful for when you need to ask a customer for more context. Input should be a conversation to customer.
wikisearch: Useful for when you need to search an encyclopedia Input is keywords and not a question.
</You have access to the following tools>
<Guideline>
$guideline
</Guideline>
<Your response>
$text
</Your response>
<Guideline>
$guideline
</Guideline>
<Your response>
$text
</Your response>
<Your job>
Evaluate your response using the evaluation guideline then give yourself a score out of 9 for your response.
</Your job>
<Example>
{"Evaluate": "Evaluate your response using the evaluation guideline.", "Score": 6}
</Example>
<Your job>
Evaluate your response using the evaluation guideline then give yourself a score out of 9 for your response.
</Your job>
<Example>
{"Evaluate": "Evaluate your response using the evaluation guideline.", "Score": 6}
</Example>
</s>
<assistant>
<|assistant|>
{
"""
println("")
prompt_grading = prompt
@show prompt_grading
println("")
response = sendReceivePrompt(a, prompt, timeout=180a)
response = "{" * split(response, "}")[1] * "}"
@show response
@show jsonresponse = JSON3.read(response)
score = jsonresponse["Score"]
score = nothing
while true
response = sendReceivePrompt(a, prompt, timeout=180a)
try
response = "{" * split(response, "}")[1] * "}"
@show response
@show jsonresponse = JSON3.read(response)
score = jsonresponse["Score"]
catch
println("retry grading")
end
end
return score
end
@@ -1252,21 +1038,23 @@ function analyze(a)
shorttermMemory = dictToString(a.memory[:shortterm])
prompt =
"""
<|im_start|>system
You have access to the following tools:
askbox: Useful for when you need to ask a customer for more context. Input should be a conversation to customer.
wikisearch: Useful for when you need to search an encyclopedia Input is keywords and not a question.
Your work:
$shorttermMemory
You job is to do each of the following in detail to analize your work.
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 response?
<|im_end|>
<|im_start|>assistant
<|system|>
<you have access to the following tools>
askbox: Useful for when you need to ask a customer for more context. Input should be a conversation to customer.
wikisearch: Useful for when you need to search an encyclopedia Input is keywords and not a question.
</you have access to the following tools>
<your earlier work>
$shorttermMemory
</your earlier work>
<your job>
You job is to do each of the following in detail to analize your work.
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 response?
</your job>
</s>
<|assistant|>
"""
@@ -1311,18 +1099,21 @@ end
function selfReflext(a, analysis::T) where {T<:AbstractString}
prompt =
"""
<|im_start|>system
You have access to the following tools:
askbox: Useful for when you need to ask a customer for more context. Input should be a conversation to customer.
wikisearch: Useful for when you need to search an encyclopedia Input is keywords and not a question.
Your report:
$analysis
<|system|>
<You have access to the following tools>
askbox: Useful for when you need to ask a customer for more context. Input should be a conversation to customer.
wikisearch: Useful for when you need to search an encyclopedia Input is keywords and not a question.
</You have access to the following tools>
<your report>
$analysis
</your report>
<your job are>
1. Lesson: what lesson could you learn from your report?.
2. Context: what is the context this lesson could apply to?
</your job are>
</s>
<|assistant|>
Your job are:
1. Lesson: what lesson could you learn from your report?.
2. Context: what is the context this lesson could apply to?
<|im_end|>
"""
response = sendReceivePrompt(a, prompt, max_tokens=1024)
@@ -1441,25 +1232,29 @@ function extractinfo(a, text::T) where {T<:AbstractString}
# determine whether there are any important info in an input text
prompt =
"""
<|im_start|>system
User's message:
$text
Your job is determine whether there are important info in the user's message. Answer: {Yes/No/Not sure}
<|im_end|>
<|system|>
<user's message>
$text
</user's message>
<your job>
Determine whether there are important info in the user's message. Answer: {Yes/No/Not sure}
</your job>
</s>
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|>
<|system|>
<user's message>
$text
</user's message>
<your job>
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.
</your job>
</s>
"""

View File

@@ -114,16 +114,132 @@ end
julia> score = grading(agent, guideline, shorttermMemory)
```
"""
function winestock(a::agentReflex, query::Dict)
query = JSON3.write(query)
@show query
function winestock(a::agentReflex, actorResult::NamedTuple)
@show query = actorResult[:toolinput]
# prompt =
# """
# <|system|>
# <About yourself>
# Your are a helpful assistant.
# </About yourself>
# <You have the following conversion table>
# Intensity level:
# intensity = 1, light bodied
# intensity = 2, light-medium bodied
# intensity = 3, medium bodied
# intensity = 4, medium-full bodied
# intensity = 5, full bodied
# Sweetness level:
# sweetness = 1, dry
# sweetness = 2, off-dry
# sweetness = 3, semi-sweet
# sweetness = 4, sweet
# sweetness = 5, very sweet
# Tannin level:
# tannin = 1, low tannin
# tannin = 2, low-medium tannin
# tannin = 3, medium tannin
# tannin = 4, medium-high tannin
# tannin = 5, high tannin
# Acidity level:
# acidity = 1, low acidity
# acidity = 2, low-medium acidity
# acidity = 3, medium acidity
# acidity = 4, medium-high acidity
# acidity = 5, high acidity
# </You have the following conversion table>
# <Your job>
# Consult the conversion table then write a specific SQL command using only available info from a JSON-format query.
# List of keywords not allowed in SQL: ["BETWEEN", "--", "WHEN", "IN"]
# Use the following format:
# Think: How do I map the info in the query to conversion table
# Info map: based on conversion table, map the info in query to appropriate variables
# SQL: write a specific SQL command
# </Your job>
# <Example 1>
# query: {\"wine type\": \"white\", \"wine characteristics\": \"full-bodied | off-dry | low acidity | low to medium tannin\", \"price\": {\"max\": \"50\"}}
# Think: 1) low to medium tannin is not explicitly stated, but assuming it falls within the range of low-medium tannin.
# Info map: {\"wine type\": \"white\", \"intensity\": 5, \"sweetness\": 2, \"tannin\": 2, \"acidity\": 1, \"price\": {\"max\": \"50 USD\"}}
# SQL: SELECT * FROM White WHERE intensity = 5 AND sweetness = 2 AND acidity = 1 AND tannin = 2 AND price <= 50;
# </Example 1>
# <Example 2>
# query: {\"wine characteristics\":\"low-bodied | a little sweet | low-medium tannin\",\"price\":\"22 USD\",\"occasion\":\"anniversary\",\"wine type\":\"Rose\",\"food\":\"American dishes\"}
# Think: 1) medium sweet is not explicitly stated, but assuming it falls within the range of dry and off-dry.
# Info map: {\"wine type\": \"Rose\", \"intensity\": 1, \"sweetness\": 3, \"tannin\": 2, \"acidity\": 3, \"price\": {\"max\": \"22 USD\"}}
# SQL: SELECT * FROM Rose WHERE intensity = 1 AND tannin = 2 AND (sweetness = 1 OR sweetness = 2) AND price <= 22;
# </Example 2>
# </s>
# <|query|>
# $query
# </s>
# <|assistant|>
# """
# prompt =
# """
# <|system|>
# <About yourself>
# Your are a helpful assistant.
# </About yourself>
# <You have the following conversion table>
# Intensity level:
# intensity = 1, light bodied
# intensity = 2, light-medium bodied
# intensity = 3, medium bodied
# intensity = 4, medium-full bodied
# intensity = 5, full bodied
# Sweetness level:
# sweetness = 1, dry
# sweetness = 2, off-dry
# sweetness = 3, semi-sweet
# sweetness = 4, sweet
# sweetness = 5, very sweet
# Tannin level:
# tannin = 1, low tannin
# tannin = 2, low-medium tannin
# tannin = 3, medium tannin
# tannin = 4, medium-high tannin
# tannin = 5, high tannin
# Acidity level:
# acidity = 1, low acidity
# acidity = 2, low-medium acidity
# acidity = 3, medium acidity
# acidity = 4, medium-high acidity
# acidity = 5, high acidity
# </You have the following conversion table>
# <Your job>
# Consult the conversion table then write a specific SQL command using the info from the user.
# List of keywords not allowed in SQL: ["BETWEEN", "--", "WHEN", "IN"]
# Use the following format:
# Think: How do I map the info in the query to conversion table
# Info map: based on conversion table, map the info in query to appropriate variables
# SQL: write a specific SQL command
# </Your job>
# <Example 1>
# Think: 1) low to medium tannin is not explicitly stated, but assuming it falls within the range of low-medium tannin.
# Info map: {\"wine type\": \"white\", \"intensity\": 5, \"sweetness\": 2, \"tannin\": 2, \"acidity\": 1, \"price\": {\"max\": \"50 USD\"}}
# SQL: SELECT * FROM White WHERE intensity = 5 AND sweetness = 2 AND acidity = 1 AND tannin = 2 AND price <= 50;
# </Example 1>
# <Example 2>
# Think: 1) medium sweet is not explicitly stated, but assuming it falls within the range of dry and off-dry.
# Info map: {\"wine type\": \"Rose\", \"intensity\": 1, \"sweetness\": 3, \"tannin\": 2, \"acidity\": 3, \"price\": {\"max\": \"22 USD\"}}
# SQL: SELECT * FROM Rose WHERE intensity = 1 AND tannin = 2 AND (sweetness = 1 OR sweetness = 2) AND price <= 22;
# </Example 2>
# </s>
# <|user's info|>
# $(actorResult[:selfaware])
# </s>
# <|assistant|>
# """
prompt =
"""
<|system|>
<s>[INST]
<About yourself>
Your are a helpful assistant.
</About yourself>
<You have the following conversion table>
Intensity level:
intensity = 1, light bodied
@@ -150,24 +266,35 @@ function winestock(a::agentReflex, query::Dict)
acidity = 4, medium-high acidity
acidity = 5, high acidity
</You have the following conversion table>
<Your job>
Consult the conversion table then write a specific SQL command using only available info from a JSON-format query.
<query info>
The user is planning a wedding party and needs a bottle of wine for the occasion.\n - Thai dishes will be served at the wedding party.\n - The ambient temperature at the serving location is around 22 degrees Celsius.\n - The user prefers a red wine with medium-bodied, dry and low to medium tannin.\n - The user prefers a medium acidity level for the wine.\n - The user's budget for the bottle of wine is around 15 USD.\n\n Info match:\n - Occasion: wedding party\n - Type of food: Thai dishes\n - Ambient temperature: around 22 degrees Celsius\n - Preferred type of wine: red\n - Wine sweetness level: dry\n - Wine intensity level: medium-bodied\n - Wine tannin level: low to medium\n - Wine acidity level: medium\n - Wine price range: around 15 USD\n\n
<query info>
Consult the conversion table then write a specific SQL command using the query info.
List of keywords not allowed in SQL: ["BETWEEN", "--", "WHEN", "IN"]
</Your job>
<Example 1>
query: {\"wine type\": \"white\", \"wine characteristics\": \"full-bodied | off-dry | low acidity | medium tannin\", \"price\": {\"max\": \"50\"}}
assistant: SELECT * FROM White WHERE intensity = 5 AND sweetness = 2 AND acidity = 1 AND tannin = 3 AND price <= 50;
</Example 1>
<Example 2>
query: {\"wine characteristics\":\"low-bodied | semi-sweet | low-medium tannin\",\"price\":\"22 USD\",\"occasion\":\"anniversary\",\"wine type\":\"Rose\",\"food\":\"American dishes\"}
assistant: SELECT * FROM Rose WHERE intensity = 1 AND sweetness = 3 AND (tannin = 2 OR tannin = 3) AND price <= 22;
</Example 2>
Use the following format:
Extract: extract the info from your work
Think: How do I map the info in the query to conversion table
Info map: based on conversion table, map the info in query to appropriate variables
SQL: write a specific SQL command
[/INST]
Think: 1) low to medium tannin is not explicitly stated, but assuming it falls within the range of low-medium tannin.
Info map: {\"wine type\": \"white\", \"intensity\": 5, \"sweetness\": 2, \"tannin\": 2, \"acidity\": 1, \"price\": {\"max\": \"50 USD\"}}
SQL: SELECT * FROM White WHERE intensity = 5 AND sweetness = 2 AND acidity = 1 AND tannin = 2 AND price <= 50;
</s>
<|query|>
$query
</s>
<|assistant|>
[INST]
<query info>
$(actorResult[:selfaware])
<query info>
Consult the conversion table then write a specific SQL command using the query info.
List of keywords not allowed in SQL: ["BETWEEN", "--", "WHEN", "IN"]
[/INST]
"""
println("")
@show db_prompt = prompt
_sql = nothing
@@ -175,6 +302,7 @@ function winestock(a::agentReflex, query::Dict)
_sql = sendReceivePrompt(a, prompt, max_tokens=256, temperature=0.2,
stopword=["/n/n", "END", "End", "Obs", "<|", "</"])
_sql = split(_sql, ";")[1] * ";"
@show _sql
# check for valid SQL command
check_1 = occursin("BETWEEN", _sql)
check_2 = occursin("--", _sql)
@@ -183,8 +311,10 @@ function winestock(a::agentReflex, query::Dict)
if check_1 == false && check_2 == false && check_3 == false
break
end
println("illegal SQL command")
println("invalid SQL command")
end
_sql = split(_sql, "SQL:")[end]
println("")
@show db_sql = replace(_sql, '\n'=>"")
@@ -246,6 +376,138 @@ function winestock(a::agentReflex, query::Dict)
end
# function winestock(a::agentReflex, query::Dict)
# query = JSON3.write(query)
# @show query
# prompt =
# """
# <|system|>
# <About yourself>
# Your are a helpful assistant.
# </About yourself>
# <You have the following conversion table>
# Intensity level:
# intensity = 1, light bodied
# intensity = 2, light-medium bodied
# intensity = 3, medium bodied
# intensity = 4, medium-full bodied
# intensity = 5, full bodied
# Sweetness level:
# sweetness = 1, dry
# sweetness = 2, off-dry
# sweetness = 3, semi-sweet
# sweetness = 4, sweet
# sweetness = 5, very sweet
# Tannin level:
# tannin = 1, low tannin
# tannin = 2, low-medium tannin
# tannin = 3, medium tannin
# tannin = 4, medium-high tannin
# tannin = 5, high tannin
# Acidity level:
# acidity = 1, low acidity
# acidity = 2, low-medium acidity
# acidity = 3, medium acidity
# acidity = 4, medium-high acidity
# acidity = 5, high acidity
# </You have the following conversion table>
# <Your job>
# Consult the conversion table then write a specific SQL command using only available info from a JSON-format query.
# List of keywords not allowed in SQL: ["BETWEEN", "--", "WHEN", "IN"]
# </Your job>
# <Example 1>
# query: {\"wine type\": \"white\", \"wine characteristics\": \"full-bodied | off-dry | low acidity | medium tannin\", \"price\": {\"max\": \"50\"}}
# assistant: SELECT * FROM White WHERE intensity = 5 AND sweetness = 2 AND acidity = 1 AND tannin = 3 AND price <= 50;
# </Example 1>
# <Example 2>
# query: {\"wine characteristics\":\"low-bodied | semi-sweet | low-medium tannin\",\"price\":\"22 USD\",\"occasion\":\"anniversary\",\"wine type\":\"Rose\",\"food\":\"American dishes\"}
# assistant: SELECT * FROM Rose WHERE intensity = 1 AND sweetness = 3 AND (tannin = 2 OR tannin = 3) AND price <= 22;
# </Example 2>
# </s>
# <|query|>
# $query
# </s>
# <|assistant|>
# """
# println("")
# @show db_prompt = prompt
# _sql = nothing
# while true
# _sql = sendReceivePrompt(a, prompt, max_tokens=256, temperature=0.2,
# stopword=["/n/n", "END", "End", "Obs", "<|", "</"])
# _sql = split(_sql, ";")[1] * ";"
# # check for valid SQL command
# check_1 = occursin("BETWEEN", _sql)
# check_2 = occursin("--", _sql)
# check_3 = occursin("IN", _sql)
# if check_1 == false && check_2 == false && check_3 == false
# break
# end
# println("illegal SQL command")
# end
# println("")
# @show db_sql = replace(_sql, '\n'=>"")
# # remove any blank character in front of a string
# newsql = nothing
# for i in eachindex(_sql)
# if _sql[i] != ' '
# newsql = _sql[i:end]
# break
# end
# end
# 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
# println("$(length(wines)) wines found")
# wines = wines[1:2]
# end
# result = nothing
# if length(wines) == 0
# result =
# """
# Wine not found.
# """
# else
# # write wines dictionary in to string
# wines_str = ""
# for (i, wine) in enumerate(wines)
# winename = wine[:wine_name]
# wines_str *= "$i: $(JSON3.write(wines[i])),"
# end
# result =
# """
# I found the following wines in our stock:
# {
# $wines_str
# }
# """
# end
# @show result
# return result
# end

View File

@@ -141,7 +141,10 @@ function agentReflex(
- type of food that will be served with wine: ask the user
- ambient temperature at the serving location: ask the user
- type of wine (we have Rose, White, Red, Rose and Sparkling): ask the user
- wine characteristics: ask the user
- wine sweetness level (dry to very sweet)
- wine intensity level (light to full bodied)
- wine tannin level (low to high)
- wine acidity level (low to high)
- wine price range: ask the user
- wines we have in stock: use winestock tool
"""

View File

@@ -338,7 +338,7 @@ function isUsePlans(a::agentReflex)
toollines = ""
for (toolname, v) in a.tools
if toolname ["chatbox"] # LLM will always use chatbox
toolline = "$toolname: $(v[:description]) $(v[:input]) $(v[:output])\n"
toolline = "$toolname is $(v[:description])\n"
toollines *= toolline
end
end
@@ -360,37 +360,45 @@ function isUsePlans(a::agentReflex)
<You have access to the following tools>
$toollines
</You have access to the following tools>
<Your earlier conversation with the user>
$conversation
</Your earlier conversation with the user>
<Your job>
Your job is to decide whether you need think thoroughly or use tools in order to respond to the user's question.
Your job is to decide whether you need think thoroughly or use tools in order to respond to the user.
Use the following format:
Thought: Do you need to think thoroughly or use tools before responding to the user?
</Your job>
<Example 1>
user: Hello!. How are you?
assistant: {"thought": "the user is greeting me, I don't need to think about it.", "anwer": "no"}
assistant: The user is greeting me, I don't need to think about it.
</Example 1>
<Example 2>
user: "What's tomorrow weather like?"
assistant: {"thought": "I will need to use weather tools to check for tomorrow's temperature.", "anwer": "yes"}
assistant: I will need to use weather tools to check for tomorrow's temperature.
</Example 2>
</s>
$conversation
<|assistant|>
"""
isuseplan = false
if length(a.memory[:shortterm]) != 0
isuseplan = true
elseif a.role == :sommelier
isuseplan = true
elseif a.role == :assistant
isuseplan = false
else
# if LLM mentions any tools, use Plan/Thought/Act loop
response = sendReceivePrompt(a, prompt, temperature=0.2, max_tokens=64, stopword=["<|", "</"])
for (toolname, v) in a.tools
if occursin("Yes", String(response))
isuseplan = true
break
response = split(response, "<|")[1]
if occursin("yes", String(response))
isuseplan = true
else
for (toolname, v) in a.tools
if occursin(toolname, String(response))
isuseplan = true
break
end
end
end
end
return isuseplan
@@ -979,10 +987,6 @@ end