FIX: Made bot more robust (#226)
* FIX: Made bot more robust This is a collection of small fixes - Display "Searching for: ..." while searching instead of showing found 0 results. - Only allow 5 commands in lang chain - 6 feels like too much - On the 5th command stop informing the engine about functions, so it is forced to complete - Add another 30 tokens of buffer and explain why - Typo in command prompt Co-authored-by: Alan Guo Xiang Tan <gxtan1990@gmail.com>
This commit is contained in:
parent
d35c8d5eca
commit
9e94457154
|
@ -113,6 +113,7 @@ en:
|
|||
description: "AI Bot with Google access that can research information for you"
|
||||
default_pm_prefix: "[Untitled AI bot PM]"
|
||||
topic_not_found: "Summary unavailable, topic not found!"
|
||||
searching: "Searching for: '%{query}'"
|
||||
command_summary:
|
||||
categories: "List categories"
|
||||
search: "Search"
|
||||
|
|
|
@ -52,7 +52,7 @@ module DiscourseAi
|
|||
attr_reader :bot_user
|
||||
|
||||
BOT_NOT_FOUND = Class.new(StandardError)
|
||||
MAX_COMPLETIONS = 6
|
||||
MAX_COMPLETIONS = 5
|
||||
|
||||
def self.as(bot_user)
|
||||
available_bots = [DiscourseAi::AiBot::OpenAiBot, DiscourseAi::AiBot::AnthropicBot]
|
||||
|
@ -83,14 +83,6 @@ module DiscourseAi
|
|||
post.topic.save_custom_fields
|
||||
end
|
||||
|
||||
def max_commands_per_reply=(val)
|
||||
@max_commands_per_reply = val
|
||||
end
|
||||
|
||||
def max_commands_per_reply
|
||||
@max_commands_per_reply || 5
|
||||
end
|
||||
|
||||
def reply_to(
|
||||
post,
|
||||
total_completions: 0,
|
||||
|
@ -100,11 +92,14 @@ module DiscourseAi
|
|||
)
|
||||
return if total_completions > MAX_COMPLETIONS
|
||||
|
||||
@persona = DiscourseAi::AiBot::Personas::General.new
|
||||
# do not allow commands when we are at the end of chain (total completions == MAX_COMPLETIONS)
|
||||
allow_commands = (total_completions < MAX_COMPLETIONS)
|
||||
|
||||
@persona = DiscourseAi::AiBot::Personas::General.new(allow_commands: allow_commands)
|
||||
if persona_name = post.topic.custom_fields["ai_persona"]
|
||||
persona_class =
|
||||
DiscourseAi::AiBot::Personas.all.find { |current| current.name == persona_name }
|
||||
@persona = persona_class.new if persona_class
|
||||
@persona = persona_class.new(allow_commands: allow_commands) if persona_class
|
||||
end
|
||||
|
||||
prompt =
|
||||
|
|
|
@ -117,7 +117,7 @@ module DiscourseAi::AiBot::Commands
|
|||
|
||||
@last_query = search_string
|
||||
|
||||
show_progress(localized_description)
|
||||
show_progress(I18n.t("discourse_ai.ai_bot.searching", query: search_string))
|
||||
|
||||
results =
|
||||
Search.execute(
|
||||
|
@ -145,7 +145,14 @@ module DiscourseAi::AiBot::Commands
|
|||
|
||||
search = Search.new(search_string, guardian: Guardian.new)
|
||||
|
||||
results = nil
|
||||
begin
|
||||
results = semantic_search.search_for_topics(search.term)
|
||||
rescue => e
|
||||
Discourse.warn_exception(e, message: "Semantic search failed")
|
||||
end
|
||||
|
||||
if results
|
||||
results = search.apply_filters(results)
|
||||
|
||||
results.each do |post|
|
||||
|
@ -157,6 +164,7 @@ module DiscourseAi::AiBot::Commands
|
|||
break if posts.length >= MAX_RESULTS
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@last_num_results = posts.length
|
||||
# this is the general pattern from core
|
||||
|
|
|
@ -16,8 +16,9 @@ module DiscourseAi
|
|||
# note this is about 100 tokens over, OpenAI have a more optimal representation
|
||||
@function_size ||= tokenize(available_functions.to_json).length
|
||||
|
||||
# provide a buffer of 50 tokens in case our counting is off
|
||||
buffer = @function_size + reply_params[:max_tokens] + 50
|
||||
# provide a buffer of 80 tokens - our function counting is not
|
||||
# 100% accurate so this is a trial and error number
|
||||
buffer = @function_size + reply_params[:max_tokens] + 80
|
||||
|
||||
if bot_user.id == DiscourseAi::AiBot::EntryPoint::GPT4_ID
|
||||
8192 - buffer
|
||||
|
@ -90,7 +91,7 @@ module DiscourseAi
|
|||
fn = partial.dig(:choices, 0, :delta, :function_call)
|
||||
if fn
|
||||
functions.add_function(fn[:name]) if fn[:name].present?
|
||||
functions.add_argument_fragment(fn[:arguments]) if fn[:arguments].present?
|
||||
functions.add_argument_fragment(fn[:arguments]) if !fn[:arguments].nil?
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -22,11 +22,17 @@ module DiscourseAi
|
|||
I18n.t("discourse_ai.ai_bot.personas.#{to_s.demodulize.underscore}.description")
|
||||
end
|
||||
|
||||
def initialize(allow_commands: true)
|
||||
@allow_commands = allow_commands
|
||||
end
|
||||
|
||||
def commands
|
||||
[]
|
||||
end
|
||||
|
||||
def render_commands(render_function_instructions:)
|
||||
return +"" if !@allow_commands
|
||||
|
||||
result = +""
|
||||
if render_function_instructions
|
||||
result << "\n"
|
||||
|
@ -55,12 +61,15 @@ module DiscourseAi
|
|||
end
|
||||
|
||||
def available_commands
|
||||
return [] if !@allow_commands
|
||||
|
||||
return @available_commands if @available_commands
|
||||
|
||||
@available_commands = all_available_commands.filter { |cmd| commands.include?(cmd) }
|
||||
end
|
||||
|
||||
def available_functions
|
||||
return [] if !@allow_commands
|
||||
# note if defined? can be a problem in test
|
||||
# this can never be nil so it is safe
|
||||
return @available_functions if @available_functions
|
||||
|
|
|
@ -84,7 +84,7 @@ module ::DiscourseAi
|
|||
- When you run a command/function you will gain access to real information in a subsequant call!
|
||||
- NEVER EVER pretend to know stuff, you ALWAYS lean on functions to discover the truth!
|
||||
- You have direct access to data on this forum using !functions
|
||||
- You are not a lier, liers are bad bots, you are a good bot!
|
||||
- You are not a liar, liars are bad bots, you are a good bot!
|
||||
- You always prefer to say "I don't know" as opposed to inventing a lie!
|
||||
|
||||
{
|
||||
|
|
|
@ -42,7 +42,6 @@ RSpec.describe DiscourseAi::AiBot::Bot do
|
|||
describe "#reply_to" do
|
||||
it "can respond to a search command" do
|
||||
bot.system_prompt_style!(:simple)
|
||||
bot.max_commands_per_reply = 2
|
||||
|
||||
expected_response = {
|
||||
function_call: {
|
||||
|
|
|
@ -34,6 +34,18 @@ module DiscourseAi::AiBot::Personas
|
|||
topic
|
||||
end
|
||||
|
||||
it "can disable commands via constructor" do
|
||||
persona = TestPersona.new(allow_commands: false)
|
||||
|
||||
rendered =
|
||||
persona.render_system_prompt(topic: topic_with_users, render_function_instructions: true)
|
||||
|
||||
expect(rendered).not_to include("!tags")
|
||||
expect(rendered).not_to include("!search")
|
||||
|
||||
expect(persona.available_functions).to be_empty
|
||||
end
|
||||
|
||||
it "renders the system prompt" do
|
||||
freeze_time
|
||||
|
||||
|
|
Loading…
Reference in New Issue