Class: RubyBots::OpenAIReactBot

Inherits:
OpenAIBot show all
Defined in:
lib/ruby_bots/bots/openai_react_bot.rb

Overview

This bot uses the ReAct framework to select from the provide tools and respond to the user. The input from the tools that are called by the bot are fed back into the messages as observations.

Constant Summary collapse

DEFAULT_DESCRIPTION =
<<~DESCRIPTION.strip_heredoc
  This bot will use the ReAct framework to determine the appropriate response. It is powered by OpenAI and the ReAct framework.
DESCRIPTION
DEFAULT_TOOLS =
[
  RubyBots::Tool.new(
    name: 'search',
    description: 'Search the web for information. Input should be the string to search for.'
  ),
  RubyBots::Tool.new(
    name: 'calculate',
    description: <<~DESC.strip_heredoc
      Solve math problems. Input should be a mathematical expression with no additional details or context.
    DESC
  )
].freeze
EXAMPLE_ONE =
<<~EXAMPLE.strip_heredoc
  User: What is the current temperature in the city Julia Roberts was born in?
  Thought: I need to know where Julia Roberts was born.
  Action: search[Julia Roberts birthplace]
  Observation: Smyrna, Georgia
  Thought: I need to know the current temperature in Smyrna, Georgia.
  Action: search[current temperature Smyrna, Georgia]
  Observation: 72 degrees Fahrenheit
  Thought: I need to tell the user the current temperature in the city Julia Roberts was born in.
  Answer: 72 degrees Fahrenheit
EXAMPLE
EXAMPLE_TWO =
<<~EXAMPLE.strip_heredoc
  User: What is half of the amount of years that have passed since the year the first airplane flew?
  Thought: I need to know the year the first airplane flew.
  Action: search[first airplane flight year]
  Observation: 1903
  Thought: I need to know the current year.
  Action: search[current year]
  Observation: 2023
  Thought: I need to know the amount of years that have passed since 1903.
  Action: calculate[2023 - 1903]
  Observation: 120
  Thought: I need to know half of 120.
  Action: calculate[120 / 2]
  Observation: 60
  Thought: I need to tell the user half of the amount of years that have passed since the year the first airplane flew.
  Answer: 60
EXAMPLE

Instance Attribute Summary collapse

Attributes inherited from Tool

#description, #errors, #name

Instance Method Summary collapse

Methods inherited from OpenAITool

#client, #default_params

Methods inherited from Tool

#response, validate_input, validate_output

Constructor Details

#initialize(tools: DEFAULT_TOOLS, name: 'OpenAI ReAct bot', description: DEFAULT_DESCRIPTION) ⇒ OpenAIReactBot

Returns a new instance of OpenAIReactBot.



24
25
26
# File 'lib/ruby_bots/bots/openai_react_bot.rb', line 24

def initialize(tools: DEFAULT_TOOLS, name: 'OpenAI ReAct bot', description: DEFAULT_DESCRIPTION)
  super(tools:, name:, description:)
end

Instance Attribute Details

#toolsObject

Returns the value of attribute tools.



5
6
7
# File 'lib/ruby_bots/bots/openai_react_bot.rb', line 5

def tools
  @tools
end

Instance Method Details

#examplesObject



28
29
30
# File 'lib/ruby_bots/bots/openai_react_bot.rb', line 28

def examples
  [EXAMPLE_ONE, EXAMPLE_TWO]
end

#prefixObject



62
63
64
65
66
# File 'lib/ruby_bots/bots/openai_react_bot.rb', line 62

def prefix
  <<~PROMPT.strip_heredoc
    You are an assistant designed to provide solutions for a user. You are provided with the user's input.
  PROMPT
end

#suffixObject



68
69
70
# File 'lib/ruby_bots/bots/openai_react_bot.rb', line 68

def suffix
  ''
end

#system_instructionsObject



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/ruby_bots/bots/openai_react_bot.rb', line 72

def system_instructions
  <<~PROMPT
    #{prefix}

    You run in a loop of thought, action, observation, and reflection until you have a solution for the user.
    You can utilize the following actions (name - description):
    #{tools.map { |t| "#{t.name} - #{t.description}" }.join("\n")}

    You should begin by providing a thought and an action with the necessary input for the action. The action will be executed externally, and then you will be called again with the observation returned from the action.

    You should then begin the loop again and provide a thought and action.

    If you have a solution for the user, return the solution instead of a new action.
    The final answer should only answer the question without additional information about reasoning or process.

    #{suffix}

    Examples:
    #{examples.join("\n\n")}
  PROMPT
end