Skip to content
This repository has been archived by the owner on Aug 4, 2024. It is now read-only.

Commit

Permalink
Checkpoint on serializers
Browse files Browse the repository at this point in the history
  • Loading branch information
nhorton committed Aug 10, 2023
1 parent ca3ce7e commit 498520a
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 7 deletions.
58 changes: 58 additions & 0 deletions examples/agents-prettier.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Note: There is a workaround in line 29. Details in Guidance issue at
# https://github.com/microsoft/guidance/issues/278

# Ruby version of https://github.com/microsoft/guidance/blob/main/notebooks/chat.ipynb
require "./lib/guidance" unless defined?(Guidance)

Guidance.llm = Guidance.llms.OpenAI("gpt-4")

role_simulator = Guidance::Program.new(%Q(
{{#system~}}
You are a helpful assistant
{{~/system}}
{{#user~}}
You will answer the user as {{role}} in the following conversation. At every step, I will provide you with the user input, as well as a comment reminding you of your instructions. Never talk about the fact that you are an AI, even if the user asks you. Always answer as {{role}}.
{{#if first_question}}You can also start the conversation.{{/if}}
{{~/user}}
{{~! The assistant either starts the conversation or not, depending on if this is the first or second agent }}
{{#assistant~}}
Ok, I will follow these instructions.
{{#if first_question}}Let me start the conversation now:
{{role}}: {{first_question}}{{/if}}
{{~/assistant}}
{{~! Then the conversation unrolls }}
{{~#geneach 'conversation' stop=False}}
{{#user~}}
User: {{set 'this.input' (await 'input') hidden=False}}
Comment: Remember, answer as a {{role}}. Start your utterance with {{role}}:
{{~/user}}
{{#assistant~}}
{{gen 'this.response' temperature=0 max_tokens=300}}
{{~/assistant}}
{{~/geneach}}'''
))

republican = role_simulator.call(role: 'Republican', await_missing: true)
democrat = role_simulator.call(role: 'Democrat', await_missing: true)

first_question = "What do you think is the best way to stop inflation?"
republican.call!(input: first_question, first_question: nil)
democrat.call!(input: republican["conversation"][-2]["response"].gsub('Republican: ', ""), first_question: first_question)
2.times do
republican.call!(input: democrat["conversation"][-2]["response"].gsub('Democrat: ', ''))
democrat.call!(input: republican["conversation"][-2]["response"].gsub('Republican: ', ''))
# This is an extra demo section to demonstrate serializing and deserializing programs as it is an important
# part of the flow that Guidance itself never really shows
# stored_republican = republican.serialize
# republican = Guidance.deserialize(stored_republican)
end
puts('Democrat: ' + first_question)
democrat['conversation'][0..-2].map do |x|
puts("Republican: #{x['input']}")
puts ""
puts(x['response'])
end
2 changes: 1 addition & 1 deletion examples/agents.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
democrat = democrat.call(input: republican["conversation"][-2]["response"].gsub('Republican: ', ''))
end
puts('Democrat: ' + first_question)
democrat['conversation'][0..-2].each do |x|
democrat['conversation'][0..-2].map do |x|
puts("Republican: #{x['input']}")
puts ""
puts(x['response'])
Expand Down
13 changes: 11 additions & 2 deletions lib/guidance.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,17 @@
require_relative "guidance/llms"

module Guidance
include Guidance::Serializer
autoload :Program, "guidance/program"
autoload :Version, "guidance/version"
autoload :LLMs, "guidance/llms"

def self.llm=(llm)
@llm = llm
write_class_store :llm, llm
PythonGuidance.llm = llm
end

def self.llm = @llm
def self.llm = read_class_store :llm

def self.llms = @llms ||= LLMs.new

Expand All @@ -38,4 +39,12 @@ def self.raise_if_python_exception(python_exception)
python_exception.__traceback__
)
end

private_class_method def read_class_store(key)
Thread.current[key]
end

private_class_method def write_class_store(key, value)
Thread.current[key] = value
end
end
21 changes: 17 additions & 4 deletions lib/guidance/program.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
module Guidance
class Program
attr_reader :python_guidance_program
def initialize(template, **kwargs)
@python_guidance_program = PythonGuidance.call(
def initialize(template, python_guidance_program: nil, **kwargs)
@python_guidance_program = python_guidance_program
@python_guidance_program ||= PythonGuidance.call(
template,
**{
streaming: false,
Expand All @@ -15,14 +16,26 @@ def initialize(template, **kwargs)
)
end

def call(**kwargs)
@python_guidance_program.call(**kwargs).tap do |result|
def [](*args) = @python_guidance_program[*args]

def call(wrap_result: true, **kwargs)
result = python_guidance_program.call(**kwargs).tap do |result|
# Guidance hides exceptions in an _exception attribute so we pull that
# out and raise it if it exists.
Guidance.raise_if_python_exception(result._exception)
end
result = Program.new(nil, python_guidance_program: result) if wrap_result
result
end

def call!(**kwargs)
@python_guidance_program = call(wrap_result: false, **kwargs)
self
end

def serialize = Guidance.serialize(self)

alias :run :call
alias :run! :call!
end
end
Empty file added lib/guidance/serializer.rb
Empty file.

0 comments on commit 498520a

Please sign in to comment.