Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dispatch prompt template variations on the model name #1

Merged
merged 5 commits into from
Jul 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/scripts/build_sdist_and_wheel.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#!/bin/bash

# Build sdist and wheel
python -m pip install -U pip
python -m pip install build
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/build_docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Build the documentation

on:
pull_request:
branches: [main]
branches: [master]

jobs:
build:
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/publish_docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: Publish the documentation
on:
push:
branches:
- main
- master

permissions:
contents: write
Expand All @@ -23,10 +23,10 @@ jobs:
path: .cache
restore-keys: |
mkdocs-material-
- run:
- run: |
python -m pip install --upgrade pip
pip install .[docs]
pip install -r requirements-doc.txt
- name: Build documentation
run:
run: |
mkdocs gh-deploy --force
6 changes: 3 additions & 3 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: Tests

on:
pull_request:
branches: [main]
branches: [master]
push:
branches: [main]
branches: [master]

jobs:
style:
Expand Down Expand Up @@ -43,4 +43,4 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Build SDist and Wheel
run: ./.github/scripts/build_sdist_and_wheel.sh
run: bash ./.github/scripts/build_sdist_and_wheel.sh
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

## Prompt functions

The `prompt` decorator takes a function as an argument whose docstring is a Jinja template, and return a `Prompt` object:
The `template` decorator takes a function as an argument whose docstring is a Jinja template, and return a `Template` object:

```python
from prompts import prompt
from prompts import template

@prompt
@template
def few_shots(instructions, examples, question):
"""{{ instructions }}

Expand All @@ -21,7 +21,7 @@ def few_shots(instructions, examples, question):
A: """
```

Caling the `Prompt` object renders the Jinja template:
Caling the `Template` object renders the Jinja template:

```python
instructions = "Please answer the following question following the examples" examples = [
Expand Down
1 change: 1 addition & 0 deletions docs/reference/dispatch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Model-based prompt dispatching
1 change: 1 addition & 0 deletions docs/reference/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Reference
306 changes: 306 additions & 0 deletions docs/reference/template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,306 @@
# Prompt templating

Prompts provides a powerful domain-specific language to write and manage
prompts, via what we call *prompt functions*. Prompt functions are Python
functions that contain a template for the prompt in their docstring, and their
arguments correspond to the variables used in the prompt. When called, a prompt
function returns the template rendered with the values of the arguments.

The aim of prompt functions is to solve several recurrent problems with prompting:

1. **Building complex prompts quickly leads to messy code.** This problem has
already been solved in the web development community by using templating, so
why not use it here?
2. **Composing prompts is difficult.** Why not just compose functions?
3. **Separating prompts from code.** Encapsulation in functions allows a clean
separation between prompts and code. Moreover, like any function, prompt
functions can be imported from other modules.

Prompts uses the [Jinja templating
engine](https://jinja.palletsprojects.com/en/3.1.x/) to render prompts, which
allows to easily compose complex prompts.

!!! warning "Prompt rendering"

Prompt functions are opinionated when it comes to prompt rendering. These opinions are meant to avoid common prompting errors, but can have unintended consequences if you are doing something unusual. We advise to always print the prompt before using it. You can also [read the
reference](#formatting-conventions) section if you want to know more.

## Your first prompt

The following snippet showcases a very simple prompt. The variables between
curly brackets `{{ }}` are placeholders for the values of the arguments you
will pass to the prompt function.

=== "Code"

```python
import prompts

@prompts.template
def greetings(name, question):
"""Hello, {{ name }}!
{{ question }}
"""

prompt = greetings("user", "How are you?")
print(prompt)
```

=== "Output"

```text
Hello, user!
How are you?
```

If a variable is missing in the function's arguments, Jinja2 will throw an `UndefinedError` exception:

=== "Code"

```python
import prompts

@prompts.template
def greetings(name):
"""Hello, {{ surname }}!"""

prompt = greetings("user")
```

=== "Output"

```text
Traceback (most recent call last):
File "<stdin>", line 9, in <module>
File "/home/remi/projects/normal/prompts/prompts.templates.py", line 38, in __call__
return render(self.template, **bound_arguments.arguments)
File "/home/remi/projects/normal/prompts/prompts.templates.py", line 213, in render
return jinja_template.render(**values)
File "/home/remi/micromamba/envs/prompts/lib/python3.9/site-packages/jinja2/environment.py", line 1301, in render
self.environment.handle_exception()
File "/home/remi/micromamba/envs/prompts/lib/python3.9/site-packages/jinja2/environment.py", line 936, in handle_exception
raise rewrite_traceback_stack(source=source)
File "<template>", line 1, in top-level template code
jinja2.exceptions.UndefinedError: 'surname' is undefined
```

## Importing prompt functions

Prompt functions are functions, and thus can be imported from other modules:

=== "prompts.py"
```python
import prompts

@prompts.template
def greetings(name, question):
"""Hello, {{ name }}!
{{ question }}
"""
```

=== "generate.py"

```python
from .prompts import greetings

prompt = greetings("John Doe", "How are you today?")
```

=== "Output"

```text
Hello, John Doe!
How are you today?
```

## Few-shot prompting

Few-shot prompting can lead to messy code. Prompt functions allow you to loop
over lists or dictionaries from the template. In the following example we
demonstrate how we can generate a prompt by passing a list of dictionaries with
keys `question` and `answer` to the prompt function:

=== "Code"

```python
import prompts

@prompts.template
def few_shots(instructions, examples, question):
"""{{ instructions }}

Examples
--------

{% for example in examples %}
Q: {{ example.question }}
A: {{ example.answer }}

{% endfor %}
Question
--------

Q: {{ question }}
A:
"""

instructions = "Please answer the following question following the examples"
examples = [
{"question": "2+2=?", "answer":4},
{"question": "3+3=?", "answer":6}
]
question = "4+4 = ?"

prompt = few_shots(instructions, examples, question)
print(prompt)
```

=== "Output"

```text
Please answer the following question following the examples

Examples
--------

Q: 2+2=?
A: 4

Q: 3+3=?
A: 6

Question
--------

Q: 4+4 = ?
A:
```

## Conditionals, filters, etc.

Jinja2 has many features beyond looping that are not described here:
conditionals, filtering, formatting, etc. Please refer to the [Jinja
documentation](https://jinja.palletsprojects.com/en/3.1.x/>) for more
information about the syntax of the templating language. The Jinja syntax is
powerful, and we recommend you take some time to read their documentation if you
are building complex prompts.

## Formatting conventions

Prompt functions are opinionated when it comes to rendering, and these opinions
are meant to avoid prompting mistakes and help with formatting.

### Whitespaces

If you have experience working with strings between triple quotes you know that
indenting has an influence on the string's formatting. Prompt functions adopt
a few conventions so you don't have to think about indents when writing prompt.

First, whether you start the prompt right after the triple quotes or on the line
below does not matter for formatting:

=== "Code"

```python
import prompts

@prompts.template
def prompt1():
"""My prompt
"""

@prompts.template
def prompt2():
"""
My prompt
"""

print(prompt1())
print(prompt2())
```

=== "Output"

```text
My prompt
My prompt
```

Indentation is relative to the second line of the docstring, and leading spaces are removed:

=== "Code"

```python
import prompts

@prompts.template
def example1():
"""First line
Second line
"""

@prompts.template
def example2():
"""
Second line
Third line
"""

@prompts.template
def example3():
"""
Second line
Third line
"""

print(example1())
print(example2())
print(example3())
```

=== "Output"

```text
First line
Second line

Second line
Third line

Second line
Third line
```

Trailing whitespaces are not removed, unless they follow a linebreak symbol `\` (see [linebreaks](#linebreaks)).

### Linebreaks

You can use the backslash `\` to break a long line of text. It will render as a single line:

=== "Code"

```python
import prompts

@prompts.template
def example():
"""
Break in \
several lines \
But respect the indentation
on line breaks.
And after everything \
Goes back to normal
"""

print(example())
```

=== "Output"

```text
Break in several lines But respect the indentation
on line breaks.
And after everything Goes back to normal
```
Loading
Loading