Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

Last active December 12, 2023 06:22
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save hooopo/f07afc3da54e704b4d462a19f9a1fbe3 to your computer and use it in GitHub Desktop.
Save hooopo/f07afc3da54e704b4d462a19f9a1fbe3 to your computer and use it in GitHub Desktop.
require 'openai'
require 'erb'
require 'json'
require 'open-uri'
class GithubUserInfoTool
attr_reader :input
def initialize(input: )
@input = input.to_s.gsub(/^"|"$/, '')
def self.description
Return the Github user info, include location, bio, followers_count, followings_count, public_repos_count, created_at etc with json format. The action input is the GitHub user's login name, without quotation marks.
def call
puts "Calling GithubUserInfoTool with input -> #{input}"
JSON.parse("{input}").read).slice("bio", "twitter_username", "location", "followers", "following", "created_at", "public_repos")
class CalculatorTool
attr_reader :input
def initialize(input: )
@input = input
def self.description
Runs a calculation and returns the number - uses Ruby so be sure to use floating point syntax if necessary
def call
puts "Calling CalculatorTool with input -> #{input}"
eval(input).to_s rescue "I don't know how to calculate that"
class ReAct
attr_reader :debug, :access_token, :question, :max_retries, :client, :tools
def initialize(question: , access_token: , debug: false, max_retries: 5, tools: [])
@client = access_token)
@debug = debug
@question = question
@tools = tools
def prompt_temple
Answer the following questions as best you can. You have access to the following tools:
<% tools.each do |tool| %>
<%= tool %>: <%= tool.description %>
<% end %>
Use the following format for each step. You can take multiple steps, but never number them. If the tools provided above cannot answer the question, feel free to improvise and begin your response start with "Final Answer:".
In regards to things unrelated to the tool mentioned above, you don't need the Thought and Action modes.
Question: the input question you must answer
Thought: you should always think about what to do
Action: the action to take, should be one of [<%=", ") %>] if it needed.
Action Input: the input to the action
Observation: the result of the action
... (this Thought/Action/Action Input/Observation can repeat N times)
Thought: I now know the final answer
Final Answer: the final answer to the original input question
Question: <%= question %>
Thought: <%= thought %>
def call
thought = ""
i = 0
loop do
prompt =
puts i.to_s * 10 if debug
puts prompt if debug
messages = messages = [
{ role: "user", content: prompt }
response =
parameters: {
model: "gpt-3.5-turbo",
messages: messages,
temperature: 0.6,
stop: "Observation: " # Inject observation of AI, and use the custom tool to get the observation
output = response.dig("choices", 0, "message", "content")
puts "output from OpenAI 👇"
puts output
puts "\n\n"
# extract the final answer, action and action input from the output
answer = output[/Final Answer:(.*?)$/m, 1]
action = output[/^Action( \d+)?: (.*?)$/m, 2]
action_input = output[/^Action Input( \d+)?: (.*?)$/m, 2]
# if the action is one of the tools, we call the tool with the action input, and get the observation
if action && action_input
if tool = tools.find{|tool| tool.to_s == action}
observation = action_input.strip).call
# Append the Thought/Action/Action Input/Observation to the last of original prompt, and use it as the new prompt
thought = thought + output
thought = thought + "Observation: #{observation}\n"
# some times, the AI think too much, and the action is not one of the tools, so we just return the output without the last Thought/Action/Action Input/Observation
return output.to_s.gsub(/\nAction:(.*?)\nAction Input:(.*?)\n$/m, '')
if answer
return answer.strip
return "I don't know how to answer this question"
i = i+1
end ENV["OPENAI_API_TOKEN"], question: "tj的GitHub粉丝数除以2是多少?", tools: [CalculatorTool, GithubUserInfoTool], debug: true).call
Copy link

hooopo commented Mar 28, 2023


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment