ntoes on output freezing

This commit is contained in:
William Guss
2024-07-31 16:01:54 -07:00
parent db3e7ce563
commit bcfad80f9a
3 changed files with 351 additions and 10 deletions

View File

@@ -115,6 +115,20 @@ python -m ell.studio --storage-dir ./sqlite_example --dev # the dev flag is impo
You can then visualize your promtps by visiting the frontend on `http://localhost:3000`
## v1 release todos
- LMP UX Finished entirely
- Postgres backend
- Clean all of the pydantic schema serialziation santiziation etc that we do throughout the codebase
- Full version history UX
- Package on pypy
- Docs
- Jupyter compatability
- Tests
- Convert all of our todos into issues and milestones
- Multimodality
- Output parsing.
## Todos
### Metrics
@@ -172,7 +186,7 @@ You can then visualize your promtps by visiting the frontend on `http://localhos
## LM Functionality
- [ ] Freezing and unfreezing LMPs
- [x] Freezing and unfreezing LMPs
- [ ] Support multimodal inputs
- [ ] Implement function calling
- [ ] Add persistent chatting capability

View File

@@ -0,0 +1,335 @@
import dataclasses
import random
from typing import Callable, List, Tuple
import ell
from ell.lstr import lstr
ell.config.verbose = True
# Option 0 (pythonic.)
# This going to be NON Native to ell
def parse_outputs(result : lstr) -> str:
name = result.split(":")[0]
backstory = result.split(":")[1]
return Personality(name, backstory)
@ell.lm(model="gpt-4o-mini", temperature=1.0, output_parser=parse_outputs)
def create_random_personality():
"""You are backstoryGPT. You come up with a backstory for a character incljuding name. Choose a completely random name from the list. Format as follows.
Name: <name>
Backstory: <3 sentence backstory>'""" # System prompt
return "Come up with a backstory about " + random.choice(names_list) # User prompt
def get_personality():
return parse_outputs(create_random_personality())
# Option 1.
def parse_outputs(result : lstr) -> str:
name = result.split(":")[0]
backstory = result.split(":")[1]
return Personality(name, backstory)
@ell.lm(model="gpt-4o-mini", temperature=1.0, output_parser=parse_outputs)
def create_random_personality():
"""You are backstoryGPT. You come up with a backstory for a character incljuding name. Choose a completely random name from the list. Format as follows.
Name: <name>
Backstory: <3 sentence backstory>'""" # System prompt
return "Come up with a backstory about " + random.choice(names_list) # User prompt
## Option 2.
@dataclasses.dataclass
class Personality:
name : str
backstory : str
@staticmethod
def parse_outputs(result : lstr) -> str:
name = result.split(":")[0]
backstory = result.split(":")[1]
return Personality(name, backstory)
@ell.lm(model="gpt-4o-mini", temperature=1.0, output_parser=Personality.parse_outputs)
def create_random_personality():
"""You are backstoryGPT. You come up with a backstory for a character incljuding name. Choose a completely random name from the list. Format as follows.
Name: <name>
Backstory: <3 sentence backstory>'""" # System prompt
return "Come up with a backstory about " + random.choice(names_list) # User prompt
# Option 3. Another decorator
def parse_outputs(result : lstr) -> str:
name = result.split(":")[0]
backstory = result.split(":")[1]
return Personality(name, backstory)
@ell.structure(parser=parse_outputs, retries=3)
@ell.lm(model="gpt-4o-mini", temperature=1.0)
def create_random_personality():
"""You are backstoryGPT. You come up with a backstory for a character incljuding name. Choose a completely random name from the list. Format as follows.
Name: <name>
Backstory: <3 sentence backstory>'""" # System prompt
return "Come up with a backstory about " + random.choice(names_list) # User prompt
create_random_personality: Callable[..., Personality]
# This really boils down to what is the role of ell
# Are there high level Keras like braries that use our low level primatives.
# if we say that it also provides high level functionality:
class PersonalitySchema(ell.Schema):
name : str
backstory : str
def parse_outputs(result : lstr) -> str:
name = result.split(":")[0]
backstory = result.split(":")[1]
return Personality(name, backstory)
@ell.structured_lm(
schema=PersonalitySchema,
model="gpt-4o-mini",
temperature=1.0,
)
def create_random_personality():
"""You are backstoryGPT. You come up with a backstory for a character incljuding name. Choose a completely random name from the list. Format as follows.""" # System prompt
return "Come up with a backstory about " + random.choice(names_list) # User prompt
# under the hood this mutates the system promtp of create random.
# https://python.langchain.com/v0.1/docs/modules/model_io/output_parsers/quick_start/
# Optiona 5. Langchain verison of this with ell
# or
def parser(result : lstr) -> OutputFormat:
name = result.split(":")[0]
backstory = result.split(":")[1]
return OutputFormat(name, backstory)
# 3. Define our LM we can use the format from our schema or something else
@ell.structures(parserer=parser, retries=3)
@ell.lm(model="gpt-4o-mini", temperature=1.0)
def create_random_personality():
f"""Answer in the format {OutputFormat.get_format_prompt()}"""
return "Come up with a backstory about " + random.choice(names_list)
def f(arg = None, * , lol=3, **kwargs):
print(arg, lol, kwargs)
pass
#############################
#############################
# These first two violate our strict storage schema.
def parser(pstr):
name = pstr.split("name:")[1].split("\n")[0].strip()
backstory = pstr.split("backstory:")[1].split("\n")[0].strip()
return name, backstory
@ell.structure(parserer=parser, retries=3)
@ell.lm(model="gpt-4o-mini", temperature=1.0)
def create_random_personality():
f"""Answer in the format {format}"""
return "Come up with a backstory about " + random.choice(names_list)
############################
############################
@ell.lm(model="gpt-4o-mini", temperature=1.0)
def create_random_personality_str():
f"""Answer in the format {format}"""
return "Come up with a backstory about " + random.choice(names_list)
@retry(tries=3)
def get_random_personality():
pstr = create_random_personality_str()
json.parse(pstr)
name = pstr.split("name:")[1].split("\n")[0].strip()
backstory = pstr.split("backstory:")[1].split("\n")[0].strip()
return pstr
#############################
#############################
def parser(pstr):
name = pstr.split("name:")[1].split("\n")[0].strip()
backstory = pstr.split("backstory:")[1].split("\n")[0].strip()
return name, backstory
@ell.lm(model="gpt-4o-mini", temperature=1.0, parser=parser)
def create_random_personality():
f"""Answer in the format {format}"""
return "Come up with a backstory about " + random.choice(names_list)
"""
Authors notes: I think if we dont implement parsing, people can build lightweight opinionated libraries on top of ell for parsing.
Langchain could be built on top of ell (?)
ell
# all python packages that we could build that dont effect ell as a library.
ell-agents
ell-structure
The whole conversation ultimatels boils down to if we decide to store strucutred data in the ell.db.
If I have
"""
@ell.lm(model="gpt-4o-mini", temperature=1.0, parser=parser)
def create_random_personality():
f"""Answer in the format {format}"""
return "Come up with a backstory about " + random.choice(names_list)
"""
And now I wrap it in my parser:
"""
def parse_to_my_fucked_up_unserializable_format(pstr):
return MyFuckedUpObject(pstr)
@ell.structure(parser=parse_to_my_fucked_up_unserializable_format, retries=3)
@ell.lm(model="gpt-4o-mini", temperature=1.0)
def create_random_personality():
f"""Answer in the format {format}"""
return "Come up with a backstory about " + random.choice(names_list)
"""
Now when I run this program what appears in the database? Do we attempt to store the MyFuckedObject instance in the ell.db as a result of the invocation of the LMP.
Is there a utility to doing so. Do we have two types of invocations
(I look graph and there is a node for create random personality and I can expadn it and look inside and there are two nodes tracing to each other:)
(create_personality) -> parse_to_my_fucked_unserializable_format
This is equivalent to the following
"""
@ell.lm(model="gpt-4o-mini", temperature=1.0)
def create_random_personality():
return "Come up with a backstory about " + random.choice(names_list)
@ell.track
@retry(tries=3)
def parse_to_my_fucked_up_unserializable_format(pstr):
return MyFuckedUpObject(pstr)
@ell.track
def get_fucked_up_llm_object():
return parse_to_my_fucked_up_unserializable_format(create_random_personality())
# Lol langchain is the following:
get_fucked_up_llm_object = ell.track(create_random_personality | parse_to_my_fucked_up_unserializable_format)
"""
What hapopens when we can't serialize MyFuckedUpObject. We build the best dill dumper into our db of these objects.
"""
# Build a hand holdy structured_lm framework
# structured_lm@v0.1.0
# description = 'allows you to prompt engineer llms that attempt to conform to schemas using state of the art prompt techniques'
"""
This is same quesiton as do we have ell.cot or is ell-cot a package
cot_llm = ell.cot(
task=""
)
"""
# base prompt override!
@structured_lm.json(RPGSchema, model='gpt-4o-mini', temperature=1.0):
def make_a_rpg_character(name : str):
return f"Make a rpg character that slaps. They should be called {name}"
"""
What the this does is:
"""
# structured_lm.py
def json(schema : ell.Schema,**lm_kwargs):
def decorator(func):
def converted_lm_func():
system_prompt, user_prompt = func()
new_system_prompt = [
system_prompt + " You must respond only in JSON in the following format: " + schema.get_format_prompt(),
user_prompt
]
return new_system_prompt, user_prompt
return retry(schema.parse(
ell.lm(**lm_kwargs)(converted_lm_func)), tries=3)
return decorator
# This does this:
@ell.lm(model="gpt-4o-mini", temperature=1.0)
def internal_make_a_rpg_character(name : str):
return [
ell.system("You are a rpg character creator. You create rpg characters. You must respond only in JSON in the following format: " + {RPGSchema.get_format_prompt()}),
ell.user(f"Make a rpg character that slaps. They should be called {name}")
]
@ell.track
@retry(tries=3)
def parse(result : lstr):
return json.parse(result)
@ell.track
def make_a_rpg_character(name : str):
return result(internal_make_a_rpg_character(name))

View File

@@ -19,7 +19,7 @@ def create_a_python_class(user_spec : str):
def write_unit_for_a_class(class_def : str):
return [
ell.system(
f"{BASE_PROMPT}\n\nYour goal is to write unit tests for a specific class definition."
f"{BASE_PROMPT}\n\nYour goal is to write only a single unit test for a specific class definition. Don't use `unittest` package"
),
ell.user(
f"Here is the class definition: {class_def}"
@@ -27,17 +27,9 @@ def write_unit_for_a_class(class_def : str):
]
def somewhere_else_I_want_to_cache():
store = ell.get_store()
with store.freeze(create_a_python_class):
_class_def = create_a_python_class("A class that represents a bank")
return _class_def
if __name__ == "__main__":
store = SQLiteStore("sqlite_example")
ell.set_store(store, autocommit=True)
with store.freeze(create_a_python_class):
_class_def = create_a_python_class("A class that represents a bank")