Skip to content

Commit 572373a

Browse files
authored
Release (#160)
New models Signed-off-by: Mandana Vaziri <[email protected]>
1 parent 78cb58c commit 572373a

File tree

124 files changed

+1776
-1298
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

124 files changed

+1776
-1298
lines changed

.github/workflows/publish-quay.yaml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: Quay Publish
2+
3+
on:
4+
release:
5+
types: [published]
6+
7+
permissions:
8+
contents: read
9+
10+
env:
11+
REGISTRY: quay.io
12+
# github.repository as account/repo
13+
IMAGE_NAME: project_pdl/pdl
14+
15+
jobs:
16+
# Build and push a multi-platform Docker image to Docker Hub
17+
publish-image:
18+
runs-on: ubuntu-latest
19+
permissions:
20+
contents: read
21+
packages: write
22+
23+
steps:
24+
- name: Checkout repository
25+
uses: actions/checkout@v3
26+
27+
- name: Docker Setup QEMU
28+
uses: docker/setup-qemu-action@v2
29+
30+
- name: Set up Docker Buildx
31+
uses: docker/setup-buildx-action@v2
32+
33+
- name: Login to Docker Hub
34+
uses: docker/login-action@v2
35+
with:
36+
registry: ${{ env.REGISTRY }}
37+
username: ${{ secrets.QUAYIO_USERNAME }}
38+
password: ${{ secrets.QUAYIO_TOKEN }}
39+
40+
- name: Build and push ${{ github.ref_name }} to ${{ env.REGISTRY }}
41+
uses: docker/build-push-action@v4
42+
with:
43+
context: .
44+
platforms: linux/amd64,linux/arm64
45+
push: true
46+
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }},${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest

.github/workflows/run-examples.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,5 @@ jobs:
4444
WATSONX_PROJECT_ID: ${{ secrets.WATSONX_PROJECT_ID }}
4545
WATSONX_APIKEY: ${{ secrets.WATSONX_APIKEY }}
4646
WATSONX_URL: ${{ secrets.WATSONX_URL }}
47+
REPLICATE_API_TOKEN: ${{ secrets.REPLICATE_API_TOKEN }}
4748
run: py.test -v --capture=tee-sys tests/test_examples_run.py

README.md

Lines changed: 60 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
LLMs will continue to change the way we build software systems. They are not only useful as coding assistants, providing snipets of code, explanations, and code transformations, but they can also help replace components that could only previously be achieved with rule-based systems. Whether LLMs are used as coding assistants or software components, reliability remains an important concern. LLMs have a textual interface and the structure of useful prompts is not captured formally. Programming frameworks do not enforce or validate such structures since they are not specified in a machine-consumable way. The purpose of the Prompt Declaration Language (PDL) is to allow developers to specify the structure of prompts and to enforce it, while providing a unified programming framework for composing LLMs with rule-based systems.
44

5-
PDL is based on the premise that interactions between users, LLMs and rule-based systems form a *document*. Consider for example the interactions between a user and a chatbot. At each interaction, the exchanges form a document that gets longer and longer. Similarly, chaining models together or using tools for specific tasks result in outputs that together form a document. PDL allows users to specify the shape and contents of such documents in a declarative way (in YAML), and is agnostic of any programming language. Because of its document-oriented nature, it can be used to easily express a variety of data generation tasks (inference, data synthesis, data generation for model training, etc...).
5+
PDL is based on the premise that interactions between users, LLMs and rule-based systems form a *document*. Consider for example the interactions between a user and a chatbot. At each interaction, the exchanges form a document that gets longer and longer. Similarly, chaining models together or using tools for specific tasks result in outputs that together form a document. PDL allows users to specify the shape of data in such documents in a declarative way (in YAML), and is agnostic of any programming language. Because of its document-oriented nature, it can be used to easily express a variety of data generation tasks (inference, data synthesis, data generation for model training, etc...).
66

77
PDL provides the following features:
88
- Ability to use any LLM locally or remotely via [LiteLLM](https://www.litellm.ai/), including [IBM's watsonx](https://www.ibm.com/watsonx)
@@ -26,6 +26,7 @@ See below for a quick reference, followed by [installation notes](#interpreter_i
2626

2727
(See also [PDF version](https://github.com/IBM/prompt-declaration-language/blob/main/docs/assets/pdl_quick_reference.pdf).)
2828

29+
Pro Tip: When writing loops and conditionals with `repeat`, `for`, and `if-then-else`, start the body of the loop or conditional (`then`/`else`) with `text` in order to see the results of every block in the body. See for example this [file](https://github.com/IBM/prompt-declaration-language/blob/main/examples/tutorial/conditionals_loops.pdl).
2930

3031
## Interpreter Installation
3132

@@ -39,13 +40,16 @@ pip install prompt-declaration-language
3940

4041
To install the dependencies for development of PDL and execute all the example, execute the command:
4142
```
42-
pip install 'prompt-declaration-language[dev]'
4343
pip install 'prompt-declaration-language[examples]'
44-
pip install 'prompt-declaration-language[docs]'
4544
```
4645

47-
In order to run the examples that use foundation models hosted on [watsonx](https://www.ibm.com/watsonx) via LiteLLM, you need a watsonx account (a free plan is available) and set up the following environment variables:
48-
- `WATSONX_URL`, the API url (set to `https://{region}.ml.cloud.ibm.com`) of your watsonx instance
46+
Most examples in this repository use IBM Granite models on [Replicate](https://replicate.com/).
47+
In order to run these examples, you need to create a free account
48+
on Replicate, get an API key and store it in the environment variable:
49+
- `REPLICATE_API_TOKEN`
50+
51+
In order to use foundation models hosted on [Watsonx](https://www.ibm.com/watsonx) via LiteLLM, you need a WatsonX account (a free plan is available) and set up the following environment variables:
52+
- `WATSONX_URL`, the API url (set to `https://{region}.ml.cloud.ibm.com`) of your WatsonX instance. The region can be found by clicking in the upper right corner of the Watsonx dashboard (for example a valid region is `us-south` ot `eu-gb`).
4953
- `WATSONX_APIKEY`, the API key (see information on [key creation](https://cloud.ibm.com/docs/account?topic=account-userapikey&interface=ui#create_user_key))
5054
- `WATSONX_PROJECT_ID`, the project hosting the resources (see information about [project creation](https://www.ibm.com/docs/en/watsonx/saas?topic=projects-creating-project) and [finding project ID](https://dataplatform.cloud.ibm.com/docs/content/wsj/analyze-data/fm-project-id.html?context=wx)).
5155

@@ -117,30 +121,44 @@ In PDL, we can write some YAML to create a prompt and call an LLM:
117121
```yaml
118122
description: Hello world
119123
text:
120-
- Hello,
121-
- model: watsonx/ibm/granite-34b-code-instruct
124+
- "Hello\n"
125+
- model: replicate/ibm-granite/granite-20b-code-instruct-8k
122126
parameters:
123-
decoding_method: greedy
124-
stop:
125-
- '!'
126-
include_stop_sequence: true
127+
stop_sequences: '!'
128+
temperature: 0
127129
```
128130
129-
The `description` field is a description for the program. Field `text` contains a list of either strings or *block*s which together form the text to be produced. In this example, the text starts with the string `"Hello"` followed by a block that calls out to a model. In this case, it is model with id `watsonx/ibm/granite-34b-code-instruct` from [watsonx](https://www.ibm.com/watsonx), via LiteLLM, with the indicated parameters: the stop sequence is `!`, which is to be included in the output. The input to the model call is everything that has been produced so far in the document (here `Hello`).
131+
The `description` field is a description for the program. Field `text` contains a list of either strings or *block*s which together form the text to be produced. In this example, the text starts with the string `"Hello\n"` followed by a block that calls out to a model. In this case, it is model with id `replicate/ibm-granite/granite-20b-code-instruct-8k` on Replicate, via LiteLLM, with the indicated parameters: the stop sequence is `!`, and temperature set to `0`. Stop sequences are provided with a comman separated list of strings. The input to the model call is everything that has been produced so far in the program (here `"Hello\n"`).
130132

131133
When we execute this program using the PDL interpreter:
132134

133135
```
134136
pdl examples/hello/hello.pdl
135137
```
136138

137-
we obtain the following document:
139+
we obtain the following:
138140

139141
```
140-
Hello, World!
142+
Hello
143+
Hello
141144
```
142145

143-
where the portion `, World!` was produced by granite. In general, PDL provides blocks for calling models, Python code, and makes it easy to compose them together with control structures (sequencing, conditions, loops).
146+
where the second `Hello` was produced by Granite. In general, PDL provides blocks for calling models, Python code, and makes it easy to compose them together with control structures (sequencing, conditions, loops).
147+
148+
A similar example on WatsonX would look as follows:
149+
150+
```yaml
151+
description: Hello world
152+
text:
153+
- Hello,
154+
- model: watsonx/ibm/granite-34b-code-instruct
155+
parameters:
156+
decoding_method: greedy
157+
stop:
158+
- '!'
159+
```
160+
161+
Notice the syntactic differences. Model ids on WatsonX start with `watsonx`. The `decoding_method` can be set to `greedy`, rather than setting the temperature to `0`. Also, `stop_sequences` are indicated with the keyword `stop` instead as a list of strings.
144162

145163
A PDL program computes 2 data structures. The first is a JSON corresponding to the result of the overall program, obtained by aggregating the results of each block. This is what is printed by default when we run the interpreter. The second is a conversational background context, which is a list of role/content pairs, where we implicitly keep track of roles and content for the purpose of communicating with models that support chat APIs. The contents in the latter correspond to the results of each block. The conversational background context is what is used to make calls to LLMs via LiteLLM.
146164

@@ -210,7 +228,7 @@ defs:
210228
parser: yaml
211229
text:
212230
- "\n${ CODE.source_code }\n"
213-
- model: watsonx/ibm/granite-34b-code-instruct
231+
- model: replicate/ibm-granite/granite-3.0-8b-instruct
214232
input:
215233
- |
216234
Here is some info about the location of the function in the repo.
@@ -248,11 +266,19 @@ public static Map<String, String> deserializeOffsetMap(String lastSourceOffset)
248266
return offsetMap;
249267
}
250268
269+
This Java function, `deserializeOffsetMap`, is designed to deserialize a JSON string into a `Map<String, String>`. Here's a breakdown of what it does:
270+
271+
1. It takes a single argument, `lastSourceOffset`, which is expected to be a JSON string.
272+
273+
2. It initializes a `Map<String, String>` called `offsetMap`.
251274
275+
3. If `lastSourceOffset` is either `null` or an empty string, it creates a new `HashMap` and assigns it to `offsetMap`.
252276
253-
The function `deserializeOffsetMap` takes a string as input and returns a map. It first checks if the input string is null or empty. If it is, it creates a new empty map and returns it. Otherwise, it uses the Jackson library to parse the input string into a map and returns it.
277+
4. If `lastSourceOffset` is not `null` or an empty string, it uses the `JSON_MAPPER` object (which is presumably an instance of a JSON deserialization library like Jackson) to deserialize the JSON string into a `Map<String, String>` and assigns it to `offsetMap`.
254278
255-
The `@SuppressWarnings("unchecked")` annotation is used to suppress the warning that the type of the parsed map is not checked. This is because the Jackson library is used to parse the input string into a map, but the specific type of the map is not known at compile time. Therefore, the warning is suppressed to avoid potential issues.
279+
5. Finally, it returns the `offsetMap`.
280+
281+
The `@SuppressWarnings("unchecked")` annotation is used to suppress a compile-time warning about the raw use of the `Map` type. This is because the `JSON_MAPPER.readValue` method returns a `Map` object, but the compiler doesn't know that this `Map` will be a `Map<String, String>`. The `unchecked` warning is suppressed to avoid this compile-time warning.
256282
```
257283

258284
Notice that in PDL variables are used to templatize any entity in the document, not just textual prompts to LLMs. We can add a block to this document to evaluate the quality of the output using a similarity metric with respect to our [ground truth](https://github.com/IBM/prompt-declaration-language/blob/main/examples/code/ground_truth.txt). See [file](https://github.com/IBM/prompt-declaration-language/blob/main/examples/code/code-eval.pdl):
@@ -267,7 +293,7 @@ defs:
267293
read: ./ground_truth.txt
268294
text:
269295
- "\n${ CODE.source_code }\n"
270-
- model: watsonx/ibm/granite-34b-code-instruct
296+
- model: replicate/ibm-granite/granite-3.0-8b-instruct
271297
def: EXPLANATION
272298
input: |
273299
Here is some info about the location of the function in the repo.
@@ -316,14 +342,23 @@ public static Map<String, String> deserializeOffsetMap(String lastSourceOffset)
316342
return offsetMap;
317343
}
318344
345+
This Java method, `deserializeOffsetMap`, is designed to convert a JSON string into a `Map<String, String>`. Here's a breakdown of the code:
346+
347+
1. The method takes a single argument, `lastSourceOffset`, which is expected to be a JSON string.
348+
349+
2. It initializes a `Map<String, String>` called `offsetMap`.
319350

320-
The function `deserializeOffsetMap` takes a string as input and returns a map. It first checks if the input string is null or empty. If it is, it creates a new empty map and returns it. Otherwise, it uses the Jackson library to parse the input string into a map and returns it.
351+
3. If `lastSourceOffset` is either `null` or an empty string, it creates a new `HashMap` and assigns it to `offsetMap`.
321352

322-
The `@SuppressWarnings("unchecked")` annotation is used to suppress the warning that the type of the parsed map is not checked. This is because the Jackson library is used to parse the input string into a map, but the specific type of the map is not known at compile time. Therefore, the warning is suppressed to avoid potential issues.
353+
4. If `lastSourceOffset` is not `null` or empty, it uses the `JSON_MAPPER` object (which is presumably an instance of `ObjectMapper` from the Jackson library) to convert the JSON string into a `Map<String, String>` and assigns it to `offsetMap`.
354+
355+
5. Finally, it returns the `offsetMap`.
356+
357+
The `@SuppressWarnings("unchecked")` annotation is used to suppress a potential unchecked warning that might occur if the JSON string does not match the expected `Map<String, String>` type.
323358

324359
EVALUATION:
325360
The similarity (Levenshtein) between this answer and the ground truth is:
326-
0.9967637540453075
361+
0.30199115044247793
327362
```
328363

329364
PDL allows rapid prototyping of prompts by allowing the user to change prompts and see their immediate effects on metrics. Try it!
@@ -339,7 +374,7 @@ defs:
339374
TRUTH:
340375
read: ./ground_truth.txt
341376
text:
342-
- model: watsonx/ibm/granite-34b-code-instruct
377+
- model: replicate/ibm-granite/granite-3.0-8b-instruct
343378
def: EXPLANATION
344379
contribute: []
345380
input:
@@ -401,8 +436,8 @@ This is similar to a spreadsheet for tabular data, where data is in the forefron
401436
402437
## Additional Notes
403438
404-
When using Granite models on watsonx, we use the following defaults for model parameters (except `granite-20b-code-instruct-r1.1`):
405-
- `decoding_method`: `greedy`
439+
When using Granite models, we use the following defaults for model parameters (except `granite-20b-code-instruct-r1.1`):
440+
- `decoding_method`: `greedy`, (`temperature`: 0)
406441
- `max_new_tokens`: 1024
407442
- `min_new_tokens`: 1
408443
- `repetition_penalty`: 1.05

0 commit comments

Comments
 (0)