From b419a5629c18852645161935ca6abcb392a4a040 Mon Sep 17 00:00:00 2001 From: tonaerospace Date: Thu, 18 Jan 2024 18:58:52 +0000 Subject: [PATCH] update --- src/interface.jl | 461 +++++++++++++-------------------------------- src/llmfunction.jl | 304 +++++++++++++++++++++++++++--- src/type.jl | 5 +- src/utils.jl | 36 ++-- 4 files changed, 435 insertions(+), 371 deletions(-) diff --git a/src/interface.jl b/src/interface.jl index 42c063b..0d90a73 100755 --- a/src/interface.jl +++ b/src/interface.jl @@ -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) $aboutYourself - - $(a.earlierConversation) - $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) 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 @@ -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.\"} - <|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|>", "", "<|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, ""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|> -# -# $aboutYourself -# -# -# $toollines -# -# -# $(a.memory[:shortterm]["Plan 1:"]) -# -# -# 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 -# -# -# Thought: Greet user and begin the conversation. -# Act: askbox -# Actinput: {\"askbox\": \"Hello! Welcome to our wine store.\"} -# - -# -# <|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|>", "", "<|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, " 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]) 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|> + + 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. + + + $guideline + + + $text + - - $guideline - - - $text - - - - Evaluate your response using the evaluation guideline then give yourself a score out of 9 for your response. - - - {"Evaluate": "Evaluate your response using the evaluation guideline.", "Score": 6} - + + Evaluate your response using the evaluation guideline then give yourself a score out of 9 for your response. + + + {"Evaluate": "Evaluate your response using the evaluation guideline.", "Score": 6} + - + <|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|> + + 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. + + + $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? + + + <|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|> + + 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. + + + $analysis + + + 1. Lesson: what lesson could you learn from your report?. + 2. Context: what is the context this lesson could apply to? + + + <|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|> + + $text + + + Determine whether there are important info in the user's message. Answer: {Yes/No/Not sure} + + 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|> + + $text + + + 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. + + """ diff --git a/src/llmfunction.jl b/src/llmfunction.jl index d059ea5..95e6777 100644 --- a/src/llmfunction.jl +++ b/src/llmfunction.jl @@ -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|> + # + # Your are a helpful assistant. + # + # + # 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 + # + # + # 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 + # + # + # 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; + # + # + # 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; + # + # + # <|query|> + # $query + # + # <|assistant|> + # """ + + # prompt = + # """ + # <|system|> + # + # Your are a helpful assistant. + # + # + # 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 + # + # + # 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 + # + # + # 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; + # + # + # 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; + # + # + # <|user's info|> + # $(actorResult[:selfaware]) + # + # <|assistant|> + # """ + prompt = """ - <|system|> + [INST] Your are a helpful assistant. - 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 - - Consult the conversion table then write a specific SQL command using only available info from a JSON-format query. + + + 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 + + + Consult the conversion table then write a specific SQL command using the query info. List of keywords not allowed in SQL: ["BETWEEN", "--", "WHEN", "IN"] - - - 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; - - - 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; - + + 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; - <|query|> - $query - - <|assistant|> + [INST] + + $(actorResult[:selfaware]) + + + 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", "<|", """) @@ -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|> +# +# Your are a helpful assistant. +# + +# +# 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 +# +# +# 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"] +# +# +# 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; +# +# +# 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; +# +# +# <|query|> +# $query +# +# <|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", "<|", """) + +# # 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 + + diff --git a/src/type.jl b/src/type.jl index 9d3029f..cc7bd8e 100644 --- a/src/type.jl +++ b/src/type.jl @@ -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 """ diff --git a/src/utils.jl b/src/utils.jl index e6d9b89..346689a 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -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) $toollines + + $conversation + - 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? 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. 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. - $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=["<|", "