Skip to content

Commit

Permalink
Update the README
Browse files Browse the repository at this point in the history
  • Loading branch information
rlouf committed May 17, 2023
1 parent 1018247 commit 546fb9a
Showing 1 changed file with 81 additions and 96 deletions.
177 changes: 81 additions & 96 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,76 +6,97 @@

Build _reliable_ workflows based on interactions with generative models.

[Features](#features)
[Installation](#installation)

</div>

**Outlines** allows you to control and diagnose interactions with LLMs more effectively. Modern language models are powerful and versatile, but the interface with existing systems [can be very brittle](https://github.com/Significant-Gravitas/Auto-GPT/labels/invalid_json), their outputs [can be unreliable](https://arxiv.org/abs/2302.04023), and complex workflows (agents) introduce a lot of error-prone code duplication. Outlines provides robust prompting primitives that separate the prompting from the execution logic, and leads to simple implementations of few-shot generations, ReAct, meta-prompting, etc. and agents. It can control text generation to provide predictible outputs that make the interaction with user code more robust. Its sampling-first approach allows to diagnose issues with generations more easily, and implement more robust generation methods such as [self-consistency](https://arxiv.org/abs/2203.11171) or [DiVeRSe](https://arxiv.org/abs/2206.02336).

## Prompt management
**Outlines** is designed as a library that integrates well with the broader Python environment. Generation can be interleaved with control flow or custom function calls, prompts can be imported from other modules or libraries.

Outlines makes it easier to write and manage prompts by encapsulating templates
inside "template functions". These functions make it possible to neatly separate
the prompt logic from the general program logic; they can be imported from other
modules and libraries.

Template functions use the Jinja2 templating engine to help build complex
prompts (like few-shot examples) in a concise manner:

``` python
import outlines.text as text
## Features

- [x] Simple and powerful prompting primitives based on the [Jinja templating engine](https://jinja.palletsprojects.com/).
- [x] Interleave completions with loops, conditionals, and custom python functions
- [x] Caching of generations
- [x] Integration with OpenAI and HuggingFace models
- [x] Controlled generation, including multiple choice, type constraint and dynamic stopping
- [x] Sampling of multiple sequences

@text.prompt
def few_shot_examples(question, examples):
"""Something something

{% for example in examples %}
EXAMPLE: {{ example }}
{% endfor %}
## Installation

QUESTION: {{ question }}
Let's think step by step.
**Outlines** is available on PyPi:

"""
``` bash
pip install outlines
```

Functions can also be _partially evaluated_ just like any function, which can be useful when building agents:
## Prompting

**Outlines** makes it easier to write and manage prompts by encapsulating templates
inside "template functions". These functions make it possible to neatly separate
the prompt logic from the general program logic; they can be imported from other
modules and libraries.

Template functions use the Jinja2 templating engine to help build complex
prompts in a concise manner:

``` python
import functools as ft
import outlines.text as text
import outlines.models as models


examples = [
("The food was digusting", "Negative"),
("We had a fantastic night", "Positive"),
("Recommended", "Positive"),
("The waiter was rude", "Negative")
]

@text.prompt
def my_agent(name, goals):
"""Your name is {{ name }}.
def labelling(to_label, examples):
"""You are a sentiment-labelling assistant.
GOALS:
{% for goal in goals %}
{{ loop.counter }}. {{ goal }}
{% for example in examples %}
{{ example[0] }} // {{ example[1] }}
{% endfor %}
{{ to_label }} //
"""


jarvis = ft.partial(my_agent, "JARVIS")
model = models.text_completion.openai("text-davinci-003")
prompt = labelling("Just awesome", examples)
answer = complete(prompt)
```

The template contained in template functions remains accessible:
## Chaining with loops and conditionals ([example](https://github.com/normal-computing/outlines/blob/readme/examples/react.py))

**Outlines** comes with very few abstractions, and is designed to blend in
existing code and integrate with the rest of the ecosystem.

``` python
import outlines.text as text
reviews = ["Just awesome", "Avoid", "Will come back"]

def send_notification(review):
"""This function sends a notification with the review's content."""
...

@text.prompt
def prompt():
"I am accessible"
for review in reviews:
prompt = labelling(review, examples)
answer = model(prompt)
if answer == "Positive":
send_notification(review)
```

## Agents ([example](https://github.com/normal-computing/outlines/blob/readme/examples/babyagi.py))

prompt.template
# I am accessible
```
**Outlines** makes building agents like [AutoGPT](https://github.com/Significant-Gravitas/Auto-GPT), [BabyAGI](https://github.com/yoheinakajima/babyagi), [ViperGPT](https://viper.cs.columbia.edu/) or [Transformers Agent](https://huggingface.co/docs/transformers/transformers_agents) easier by removing boilerplate prompting code.

### Tools

Prior work has shown that we can teach language models to call external functions to get additional informations or perform tasks, by encoding the functions' description in the prompt. To avoid duplicating information between the function definition and the description passed to the prompt we define custom Jinja filters that can extract the function's name, description, signature and source:
We can teach language models to call external functions to get additional informations or perform tasks, by encoding the functions' description in the prompt. To avoid duplicating information between the function definition and the description passed to the prompt we define custom Jinja filters that can extract the function's name, description, signature and source:


``` python
Expand All @@ -94,7 +115,7 @@ def wikipedia_search(query: str):


@text.prompt
def my_commands(tools: List[Callable]):
def agent(tools: List[Callable]):
"""AVAILABLE COMMANDS:
{% for tool in tools %}
Expand Down Expand Up @@ -141,83 +162,47 @@ joke_ppt(Joke)
# }
```

## Controlled generation

## Natural language functions
The first step towards reliability of systems that include large language models is to ensure that there is a well-defined interface between their output and user-defined code. **Outlines** provides ways to control the generation of language models to make their output more predictable.

Large language models can be prompted so their output can be parsed into a data structure that can be manipulated by programming languages. The combination prompt + model call + output parser can thus be thought as a "natural language" function.
You can stop the generation after a given sequence has been found:

``` python
import json
import outlines.text as text
import outlines.models as models


@text.prompt
def prime_numbers(n: int):
"""Return a list that contains all prime numbers between 1 and {{ n }}.
The output must be parsable as a Python list.
"""


def parse(result):
return json.loads(result)


get_prime_numbers = text.function(
models.text_completion.openai("gpt-3.5-turbo"),
prime_numbers,
parse
)


get_prime_numbers(10)
# [2, 3, 5, 7]
answer = model("Tell me a one-sentence joke.", stop_at=["."])
```

For more complex outputs one can pass a Pydantic model to `text.function`, which will be used to parse the output:
You can reduce the completion to a choice between multiple possibilities:

``` python
from pydantic import BaseModel
import outlines.text as text
prompt = labelling("Just awesome", examples)
answer = model(prompt, is_in=["Positive", "Negative"])
```


class Joke(BaseModel):
joke: str
explanation: str
You can require the generated sequence to be an int or a float:

``` python
import outlines.models as models

@text.prompt
def joke_ppt(response_model):
"""Tell a joke and explain why the joke is funny.
RESPONSE FORMAT:
{{ response_model | schema }}
"""

tell_a_joke = text.function(
models.text_completion.openai("gpt-3.5-turbo"),
joke_ppt,
Joke
)
model = models.text_completion.hf("sshleifer/tiny-gpt2")
answer = model("2 + 2 = ", type="int")
print(answer)
# 4

tell_a_joke(Joke)
# [2, 3, 5, 7]
model = models.text_completion.hf("sshleifer/tiny-gpt2")
answer = model("1.7 + 3.2 = ", type="float")
print(answer)
# 4.9
```

# Controlled generation

Outlines offers mechanisms to specify high-level constraints on the text generations:
The development of Outlines is currently focused on the topic on controlled generation. You will soon be able to constrain the output of a large language model to JSON format, a string parseable by a Pydantic `BaseModel`, or valid Python code.

- `stop_at` allows to stop the generation once a particular word, sequence of symbol had been generated;
- `is_in` allows to constrain the model to generate an answer chosen among a set of possible answers;
- `type` allows to constrain the model's output to either `"int"`s or `"float"`s;
## Sampling ([example](([example](https://github.com/normal-computing/outlines/blob/readme/examples/self_consistency.py))))

Coming:
Self-consistency

- Ability to constrain the output to a JSON with a given structure;
- Ability to constrain the output to a List;
- Ability to constrain the output to be Python code;

# Examples

Expand Down

0 comments on commit 546fb9a

Please sign in to comment.