Skip to content

Commit

Permalink
update docs
Browse files Browse the repository at this point in the history
  • Loading branch information
lbeurerkellner committed Jul 14, 2023
1 parent ee5d49f commit e34fed3
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 116 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
LMQL is a programming language for large language models (LLMs) based on a *superset of Python*. LMQL offers a novel way of interweaving traditional programming with the ability to call LLMs in your code. It goes beyond traditional templating languages by integrating LLM interaction natively at the level of your program code.
## Explore LMQL

An LMQL program reads like standard Python, but top-level strings are interpreted as query strings, i.e. they are passed to an LLM , where template variables like `[GREETINGS]` are completed by the model:
An LMQL program reads like standard Python, but top-level strings are interpreted as query strings: They are passed to an LLM, where template variables like `[GREETINGS]` are automatically completed by the model:

```python
"Greet LMQL:[GREETINGS]\n" where stops_at(GREETINGS, ".") and not "\n" in GREETINGS
Expand Down
6 changes: 5 additions & 1 deletion docs/source/_static/css/lmql-docs.css
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ html[data-theme="dark"] .highlight.lmql {
border: none;
}

.highlight.lmql pre span.c1 {
opacity: 0.5 !important;
}

.highlight pre {
padding-top: 20pt !important;
padding-bottom: 20pt !important;
Expand Down Expand Up @@ -172,7 +176,7 @@ html[data-theme="dark"] .getting-started>a.primary {
}

.highlight-model-output::before {
content: "Model Output";
content: "Model Transcript";
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
position: absolute;
top: 4pt;
Expand Down
4 changes: 1 addition & 3 deletions docs/source/_static/js/lmql-playground.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,8 @@ function getPlaygroundUrl(next) {

if (host === "docs.lmql.ai") {
return "https://lmql.ai/playground";
} else if (host.startsWith("localhost") || host.startsWith("127.0.0.1")) {
return "http://localhost:3000/playground";
} else {
return "https://lbeurerkellner.github.io/green-gold-dachshund-web/playground";
return "http://localhost:8081/playground/";
}
}

Expand Down
126 changes: 57 additions & 69 deletions docs/source/language/overview.md
Original file line number Diff line number Diff line change
@@ -1,65 +1,41 @@
# Overview

LMQL is a declarative, SQL-like programming language for language model interaction. As an example consider the following query, demonstrating the basic syntax of LMQL:
LMQL is a Python-based programming language for LLM programming with declarative elements. As a simple example consider the following program, demonstrating the basic syntax of LMQL:

```{lmql}
name::overview-query
argmax
"""Review: We had a great stay. Hiking in the mountains was fabulous and the food is really good.
Q: What is the underlying sentiment of this review and why?
A:[ANALYSIS]
Based on this, the overall sentiment of the message can be considered to be[CLASSIFICATION]"""
from
"openai/text-davinci-003"
where
not "\n" in ANALYSIS and CLASSIFICATION in [" positive", " neutral", " negative"]
# review to be analyzed
review = """We had a great stay. Hiking in the mountains
was fabulous and the food is really good."""
# use prompt statements to pass information to the model
"Review: {review}"
"Q: What is the underlying sentiment of this review and why?"
# template variables like [ANALYSIS] are used to generate text
"A:[ANALYSIS]" where not "\n" in ANALYSIS
# use constrained variable to produce a classification
"Based on this, the overall sentiment of the message\
can be considered to be[CLS]" where CLS in [" positive", " neutral", " negative"]
CLS # positive
model-output::
Review: We had a great stay. Hiking in the mountains was fabulous and the food is really good.⏎
Q: What is the underlying sentiment of this review and why?⏎
A: [ANALYSIS The underlying sentiment of this review is positive because the reviewer had a great stay, enjoyed the hiking and found the food to be good.]⏎
Based on this, the overall sentiment of the message can be considered to be [CLASSIFICATION positive]
Based on this, the overall sentiment of the message can be considered to be [CLS positive]
```

In this program, we use the language model `openai/text-davinci-003` (GPT-3.5) to perform a sentiment analysis on a provided user review. We first ask the model to provide some basic analysis of the review, and then we ask the model to classify the overall sentiment as one of `positive`, `neutral`, or `negative`. The model is able to correctly identify the sentiment of the review as `positive`.

Overall, the query consists of four main clauses:

1. **Decoder Clause** First, we specify the decoding algorithm to use for text generation. In this case we use `argmax` decoding, however, LMQL also support branching decoding algorithms like beam search. See [Decoders](./decoders.md) to learn more about this.

2. **Prompt Clause**

```python
"""Review: We had a great stay. Hiking in the mountains was fabulous and the food is really good.
Q: What is the underlying sentiment of this review and why?
A:[ANALYSIS]
Based on this, the overall sentiment of the message can be considered to be[CLASSIFICATION]"""
```

In this part of the program, you specify your prompt. Here, we include the user review, as well as the two questions we want to ask the model. Template variables like `[ANALYSIS]` are automatically completed by the model. Apart from simple textual prompts, LMQL also support multi-part and scripted prompts. To learn more, see [Scripted Prompting](./scripted_prompts.md).
In this program, we program an LLM to perform sentiment analysis on a provided user review. We first ask the model to provide some basic analysis, and then we ask it to classify the overall sentiment as one of `positive`, `neutral`, or `negative`. The model is able to correctly identify the sentiment of the review as `positive`.

3. **Model Clause**
To implement this workflow, we use two template variables `[ANALYSIS]` and `[CLS]`, both of which are constrained using designated `where` expressions.

```python
from "openai/text-davinci-003"
```
For `ANALYSIS` we constrain the model to not output any newlines, which prevents it from outputting multiple lines that could potentially break the program. For `CLS` we constrain the model to output one of the three possible values. Using these constraints allows us to decode a fitting answer from the model, where both the analysis and the classification are well-formed and in an expected format.

Next, we specify what model we want to use for text generation. In this case, we use the language model `openai/text-davinci-003`. To learn more about the different models available in LMQL, see [Models](./models.md).

4. **Constraint Clause**

```python
not "\n" in ANALYSIS and CLASSIFICATION in [" positive", " neutral", " negative"]
```

In this part of the query, users can specify logical, high-level constraints on the generated text.<br>

Here, we specify two constraints: For `ANALYSIS` we constrain the model to not output any newlines, which prevents the model from outputting multiple lines, which could potentially breaking the prompt. For `CLASSIFICATION` we constrain the model to output one of the three possible values. Using these constraints allows us to decode a fitting answer from the model, where both the analysis and the classification are well-formed and in an expected format.

Without constraints, the prompt above could produce different final classifications, such as `good`, `bad`, or `neutral`. To handle this in an automated way, one would again have to employ some model of language understanding to parse the model's CLASSIFICATION result.

To learn more about the different types of constraints available in LMQL, see [Constraints](./constraints.md).
Without constraints, the prompt above could produce different final classifications, such as `good` or `bad`. To handle this in an automated way, one would have to employ ad-hoc parsing to CLS result to obtain a clear result. Using LMQL's constraints, however, we can simply restrict the model to only output one of the desired values, thereby enabling robust and reliable integration. To learn more about the different types of constraints available in LMQL, see [Constraints](./constraints.md).

### Extracting More Information With Distributions

Expand All @@ -69,38 +45,45 @@ While the query above allows us to extract the sentiment of a review, we do not
name::sentiment-distribution
argmax
"""Review: We had a great stay. Hiking in the mountains was fabulous and the food is really good.
Q: What is the underlying sentiment of this review and why?
A:[ANALYSIS]
Based on this, the overall sentiment of the message can be considered to be[CLASSIFICATION]"""
from
"openai/text-davinci-003"
where
not "\n" in ANALYSIS
# review to be analyzed
review = """We had a great stay. Hiking in the mountains was fabulous and the food is really good."""
# use prompt statements to pass information to the model
"Review: {review}"
"Q: What is the underlying sentiment of this review and why?"
# template variables like [ANALYSIS] are used to generate text
"A:[ANALYSIS]" where not "\n" in ANALYSIS
# use constrained variable to produce a classification
"Based on this, the overall sentiment of the message can be considered to be[CLS]"
distribution
CLASSIFICATION in [" positive", " neutral", " negative"]
CLS in [" positive", " neutral", " negative"]
model-output::
Review: We had a great stay. Hiking in the mountains was fabulous and the food is really good.⏎
Q: What is the underlying sentiment of this review and why?⏎
A: [ANALYSIS The underlying sentiment of this review is positive because the reviewer had a great stay, enjoyed the hiking and found the food to be good.]⏎
Based on this, the overall sentiment of the message can be considered to be [CLASSIFICATION]
Based on this, the overall sentiment of the message can be considered to be [CLS]
P(CLASSIFICATION)
P(CLS)
- positive (*) 0.9999244826658527
- neutral 7.513155848720942e-05
- negative 3.8577566019560874e-07
```

**Distribution Clause**

Instead of constraining `CLASSIFICATION` as part of the `where` clause, we now constrain in the `distribution` clause. In LMQL, the `distribution` clause is used to specify whether we want to additionally obtain the distribution over the possible values for a given variable. In this case, we want to obtain the distribution over the possible values for `CLASSIFICATION`.
Instead of constraining `CLS` with a `where` expression, we now constrain it in the separate `distribution` clause. In LMQL, the `distribution` clause can be used to specify whether we want to additionally obtain the distribution over the possible values for a given variable. In this case, we want to obtain the distribution over the possible values for `CLS`.

In addition to using the model to perform the `ANALYSIS`, LMQL now also scores each of the individually provided values for `CLASSIFICATION` and normalizes the resulting sequence scores into a probability distribution `P(CLASSIFICATION)` (printed to the Terminal Output of the Playground or Standard Output of the CLI).
> Note, that to use the `distribution` clause, we have to make our choice of decoding algorithm explicit, by specifying `argmax` at the beginning of our code (see [Decoding Algorithms](./decoding.md) for more information). ¸
>
> In general, indenting your program and explicitly specifying e.g. `argmax` at the beginning of your code is optional, but recommended if you want to use the `distribution` clause. Throughout the documentation we will make use of both options.
In addition to using the model to perform the `ANALYSIS`, LMQL now also scores each of the individually provided values for `CLS` and normalizes the resulting sequence scores into a probability distribution `P(CLS)` (printed to the Terminal Output of the Playground or Standard Output of the CLI).

Here, we can see that the model is indeed quite confident in its classification of the review as `positive`, with an overwhelming probability of `99.9%`.

> Note that currently distribution variables like `CLASSIFICATION` can only occur at the end of a prompt.
> Note that currently distribution variables like `CLS` can only occur at the end of your program.
### Dynamically Reacting To Model Output

Expand All @@ -110,20 +93,22 @@ Another way to improve on our initial query, is to implement a more dynamic prom
name::dynamic-analysis
argmax
"""Review: We had a great stay. Hiking in the mountains was fabulous and the food is really good.
review = """We had a great stay. Hiking in the mountains
was fabulous and the food is really good."""
"""Review: {review}
Q: What is the underlying sentiment of this review and why?
A:[ANALYSIS]
Based on this, the overall sentiment of the message can be considered to be[CLASSIFICATION]"""
if CLASSIFICATION == " positive":
A:[ANALYSIS]""" where not "\n" in ANALYSIS
"Based on this, the overall sentiment of the message can be considered to be[CLS]" where CLS in [" positive", " neutral", " negative"]
if CLS == " positive":
"What is it that they liked about their stay? [FURTHER_ANALYSIS]"
elif CLASSIFICATION == " neutral":
elif CLS == " neutral":
"What is it that could have been improved? [FURTHER_ANALYSIS]"
elif CLASSIFICATION == " negative":
elif CLS == " negative":
"What is it that they did not like about their stay? [FURTHER_ANALYSIS]"
from
"openai/text-davinci-003"
where
not "\n" in ANALYSIS and CLASSIFICATION in [" positive", " neutral", " negative"] and STOPS_AT(FURTHER_ANALYSIS, ".")
STOPS_AT(FURTHER_ANALYSIS, ".")
model-output::
Review: We had a great stay. Hiking in the mountains was fabulous and the food is really good.⏎
Expand All @@ -138,3 +123,6 @@ What is it that they liked about their stay?⏎
As shown here, we can use the `if` statement to dynamically react to the model's output. In this case, we ask the model to provide a more detailed analysis of the review, depending on the overall positive, neutral, or negative sentiment of the review. All intermediate variables like `ANALYSIS`, `CLASSIFICATION` or `FURTHER_ANALYSIS` can be considered the output of query, and may be processed by an surrounding automated system.

To learn more about the capabilities of such control-flow-guided prompts, see [Scripted Prompting](./scripted_prompts.md).

As shown here, in addition to inline `where` expressions as seen earlier, you can also provide a global `where` expression at the end of your program, e.g. to specify constraints that should apply for all variables. Depending on your use case, this can be a convenient way to avoid having to repeat the same constraints multiple times, like for `FURTHER_ANALYSIS` in this example.

Loading

0 comments on commit e34fed3

Please sign in to comment.