Skip to content

Commit f790afd

Browse files
akotylasbetlewski
andauthored
feat: new API for attachments in prompts (#716)
Co-authored-by: Szymon Betlewski <[email protected]>
1 parent 21f8ae2 commit f790afd

File tree

20 files changed

+560
-269
lines changed

20 files changed

+560
-269
lines changed

docs/how-to/llms/use_llms.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ Ragbits provides a flexible way to interact with LLMs by allowing you to use [`P
5858

5959
## Using prompts with LLMs
6060

61-
Prompts in Ragbits are powerful tools for structuring inputs and outputs when interacting with LLMs. They allow you to define **system prompts**, **user prompts**, and even **structured output formats** using Pydantic models. For more details on using prompts, check out the [Prompting Guide](https://ragbits.deepsense.ai/how-to/use_prompting/). For more advanced use cases, such as using images in prompts, check out the guide: [How-To: Use images in prompts wirh Ragbits](../prompts/use_images_in_prompts.md).
61+
Prompts in Ragbits are powerful tools for structuring inputs and outputs when interacting with LLMs. They allow you to define **system prompts**, **user prompts**, and even **structured output formats** using Pydantic models. For more details on using prompts, check out the [Prompting Guide](https://ragbits.deepsense.ai/how-to/use_prompting/). For more advanced use cases, such as using attachments in prompts, check out the guide: [How-To: Use attachments in prompts with Ragbits](../prompts/use_attachments_in_prompts.md).
6262

6363
```python
6464
from ragbits.core.prompt import Prompt
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
# How-To: Use attachments in prompts with Ragbits
2+
3+
This guide will walk you through defining and using prompts in Ragbits that accept attachments as input.
4+
It covers handling single and multiple attachment inputs, incorporating conditionals in prompt templates based on the presence of attachments, and using such prompts with an LLM.
5+
6+
Attachment types currently supported include standard image formats (such as JPEG, PNG) and PDF documents.
7+
8+
## How to define a prompt with an attachment input
9+
10+
The attachment is represented by the `prompt.Attachment` class.
11+
It can be initialized in multiple ways depending on the source of the file data.
12+
The class supports both binary data and URLs, with optional MIME type specification.
13+
14+
```python
15+
from ragbits.core.prompt import Attachment
16+
17+
file_bytes = Attachment(data=b"file_bytes")
18+
image_url = Attachment(url="http://image.jpg")
19+
pdf_url = Attachment(url="http://document.pdf")
20+
file_with_url_and_mime = Attachment(url="http://address.pl/file_with_no_extension", mime_type="jpeg")
21+
```
22+
23+
To define a prompt that takes an attachment as input, create a Pydantic model representing the input structure.
24+
The model should include a field for the attachment that holds an instance of `prompt.Attachment` class - its name does not matter.
25+
26+
To pass multiple attachments, just define multiple fields of type `Attachment` or a single field that is a list of `Attachment` instances.
27+
28+
29+
```python
30+
import asyncio
31+
from pydantic import BaseModel
32+
from ragbits.core.prompt import Attachment, Prompt
33+
from ragbits.core.llms.litellm import LiteLLM
34+
35+
class EmployeeOnboardingInput(BaseModel):
36+
"""
37+
Input model for employee onboarding files.
38+
"""
39+
headshot: Attachment
40+
contract: Attachment
41+
documents: list[Attachment]
42+
43+
44+
class EmployeeOnboardingPrompt(Prompt):
45+
"""
46+
A prompt to process employee onboarding files.
47+
"""
48+
49+
user_prompt = "Review the employee onboarding files and provide feedback."
50+
51+
52+
async def main():
53+
llm = LiteLLM("gpt-4o")
54+
55+
headshot = Attachment(data=b"<your_photo_here>")
56+
contract = Attachment(data=b"<your_contract_here>")
57+
documents = [
58+
Attachment(data=b"<your_document_1_here>"),
59+
Attachment(data=b"<your_document_2_here>"),
60+
]
61+
prompt = EmployeeOnboardingPrompt(
62+
EmployeeOnboardingInput(headshot=headshot, contract=contract, documents=documents)
63+
)
64+
response = await llm.generate(prompt)
65+
print(response)
66+
67+
68+
asyncio.run(main())
69+
```
70+
71+
## Using conditionals in templates
72+
73+
Sometimes, you may want to modify the prompt based on whether an attachment is provided. Jinja conditionals can help achieve this.
74+
75+
```python
76+
import asyncio
77+
from pydantic import BaseModel
78+
from ragbits.core.prompt import Attachment, Prompt
79+
from ragbits.core.llms.litellm import LiteLLM
80+
81+
class QuestionWithOptionalPhotoInput(BaseModel):
82+
"""
83+
Input model that optionally includes a photo.
84+
"""
85+
question: str
86+
reference_photo: Attachment | None = None
87+
88+
89+
class QuestionWithPhotoPrompt(Prompt[QuestionWithOptionalPhotoInput]):
90+
"""
91+
A prompt that considers whether a photo is provided.
92+
"""
93+
94+
system_prompt = """
95+
You are a knowledgeable assistant providing detailed answers.
96+
If a photo is provided, use it as a reference for your response.
97+
"""
98+
99+
user_prompt = """
100+
User asked: {{ question }}
101+
{% if reference_photo %}
102+
Here is a reference photo: {{ reference_photo }}
103+
{% else %}
104+
No photo was provided.
105+
{% endif %}
106+
"""
107+
108+
109+
async def main():
110+
llm = LiteLLM("gpt-4o")
111+
input_with_photo = QuestionWithOptionalPhotoInput(
112+
question="What animal do you see in this photo?", reference_photo=Attachment(data=b"<your_photo_here>")
113+
)
114+
input_without_photo = QuestionWithOptionalPhotoInput(question="What is the capital of France?")
115+
116+
print(await llm.generate(QuestionWithPhotoPrompt(input_with_photo)))
117+
print(await llm.generate(QuestionWithPhotoPrompt(input_without_photo)))
118+
119+
120+
asyncio.run(main())
121+
```

docs/how-to/prompts/use_images_in_prompts.md

Lines changed: 0 additions & 124 deletions
This file was deleted.

examples/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ All necessary details are provided in the comments at the top of each script.
1616
|:-------------------------------------------------------------------------------------------------|:------------------------------------------------------------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------|
1717
| [Text Prompt](/examples/core/prompt/text.py) | [ragbits-core](/packages/ragbits-core) | Example of how to use the `Prompt` class to generate themed text using an LLM with a simple text prompt. |
1818
| [Text Prompt with Few Shots](/examples/core/prompt/text_with_few_shots.py) | [ragbits-core](/packages/ragbits-core) | Example of how to use the `Prompt` class to generate themed text using an LLM with a text prompt and few-shot examples. |
19-
| [Multimodal Prompt](/examples/core/prompt/multimodal.py) | [ragbits-core](/packages/ragbits-core) | Example of how to use the `Prompt` class to generate themed text using an LLM with both text and image inputs. |
19+
| [Multimodal Prompt with Image Input](/examples/core/prompt/multimodal_with_image.py) | [ragbits-core](/packages/ragbits-core) | Example of how to use the `Prompt` class to generate themed text using an LLM with both text and image inputs. |
20+
| [Multimodal Prompt with PDF Input](/examples/core/prompt/multimodal_with_pdf.py) | [ragbits-core](/packages/ragbits-core) | Example of how to use the `Prompt` class to answer the question using an LLM with both text and PDF inputs. |
2021
| [Multimodal Prompt with Few Shots](/examples/core/prompt/multimodal_with_few_shots.py) | [ragbits-core](/packages/ragbits-core) | Example of how to use the `Prompt` class to generate themed text using an LLM with multimodal inputs and few-shot examples. |
2122
| [Tool Use with LLM](/examples/core/llms/tool_use.py) | [ragbits-core](/packages/ragbits-core) | Example of how to provide tools and return tool calls from LLM. |
2223
| [OpenTelemetry Audit](/examples/core/audit/otel.py) | [ragbits-core](/packages/ragbits-core) | Example of how to collect traces and metrics using Ragbits audit module with OpenTelemetry. |

examples/core/prompt/multimodal_with_few_shots.py

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
from pydantic import BaseModel
2525

2626
from ragbits.core.llms import LiteLLM
27-
from ragbits.core.prompt import Prompt
27+
from ragbits.core.prompt import Attachment, Prompt
2828

2929

3030
class ImagePromptInput(BaseModel):
@@ -33,7 +33,7 @@ class ImagePromptInput(BaseModel):
3333
"""
3434

3535
theme: str
36-
image_url: str
36+
image: Attachment
3737

3838

3939
class ImagePromptOutput(BaseModel):
@@ -57,20 +57,18 @@ class ImagePrompt(Prompt[ImagePromptInput, ImagePromptOutput]):
5757
Theme: {{ theme }}
5858
"""
5959

60-
image_input_fields = ["image_url"]
61-
6260
few_shots = [
6361
(
6462
ImagePromptInput(
6563
theme="pirates",
66-
image_url="https://upload.wikimedia.org/wikipedia/commons/5/55/Acd_a_frame.jpg",
64+
image=Attachment(url="https://upload.wikimedia.org/wikipedia/commons/5/55/Acd_a_frame.jpg"),
6765
),
6866
ImagePromptOutput(description="Arrr, that would be a dog!"),
6967
),
7068
(
7169
ImagePromptInput(
7270
theme="fairy tale",
73-
image_url="https://upload.wikimedia.org/wikipedia/commons/6/62/Red_Wolf.jpg",
71+
image=Attachment(url="https://upload.wikimedia.org/wikipedia/commons/6/62/Red_Wolf.jpg"),
7472
),
7573
ImagePromptOutput(
7674
description="Once upon a time, in an enchanted forest, a noble wolf roamed under the moonlit sky."
@@ -79,7 +77,9 @@ class ImagePrompt(Prompt[ImagePromptInput, ImagePromptOutput]):
7977
(
8078
ImagePromptInput(
8179
theme="sci-fi",
82-
image_url="https://upload.wikimedia.org/wikipedia/commons/thumb/9/91/Bruce_McCandless_II_during_EVA_in_1984.jpg/2560px-Bruce_McCandless_II_during_EVA_in_1984.jpg",
80+
image=Attachment(
81+
url="https://upload.wikimedia.org/wikipedia/commons/thumb/9/91/Bruce_McCandless_II_during_EVA_in_1984.jpg/2560px-Bruce_McCandless_II_during_EVA_in_1984.jpg"
82+
),
8383
),
8484
ImagePromptOutput(
8585
description="A lone astronaut drifts through the void, bathed in the eerie glow of distant galaxies."
@@ -93,10 +93,8 @@ async def main() -> None:
9393
Run the example.
9494
"""
9595
llm = LiteLLM(model_name="gpt-4o-2024-08-06", use_structured_output=True)
96-
prompt_input = ImagePromptInput(
97-
image_url="https://upload.wikimedia.org/wikipedia/en/8/85/Cute_Dom_cat.JPG",
98-
theme="dramatic",
99-
)
96+
image = Attachment(url="https://upload.wikimedia.org/wikipedia/en/8/85/Cute_Dom_cat.JPG")
97+
prompt_input = ImagePromptInput(image=image, theme="dramatic")
10098
prompt = ImagePrompt(prompt_input)
10199
response = await llm.generate(prompt)
102100
print(response.description)

examples/core/prompt/multimodal.py renamed to examples/core/prompt/multimodal_with_image.py

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""
2-
Ragbits Core Example: Multimodal Prompt
2+
Ragbits Core Example: Multimodal Prompt with Image Input
33
44
This example demonstrates how to use the `Prompt` class to generate themed text using an LLM
55
with both text and image inputs. We define an `ImagePrompt` that generates a themed description
@@ -8,7 +8,7 @@
88
To run the script, execute the following command:
99
1010
```bash
11-
uv run examples/core/prompt/multimodal.py
11+
uv run examples/core/prompt/multimodal_with_image.py
1212
```
1313
"""
1414

@@ -24,7 +24,7 @@
2424
from pydantic import BaseModel
2525

2626
from ragbits.core.llms import LiteLLM
27-
from ragbits.core.prompt import Prompt
27+
from ragbits.core.prompt import Attachment, Prompt
2828

2929

3030
class ImagePromptInput(BaseModel):
@@ -33,7 +33,7 @@ class ImagePromptInput(BaseModel):
3333
"""
3434

3535
theme: str
36-
image_url: str
36+
image: Attachment
3737

3838

3939
class ImagePromptOutput(BaseModel):
@@ -57,18 +57,14 @@ class ImagePrompt(Prompt[ImagePromptInput, ImagePromptOutput]):
5757
Theme: {{ theme }}
5858
"""
5959

60-
image_input_fields = ["image_url"]
61-
6260

6361
async def main() -> None:
6462
"""
6563
Run the example.
6664
"""
6765
llm = LiteLLM(model_name="gpt-4o-2024-08-06", use_structured_output=True)
68-
prompt_input = ImagePromptInput(
69-
image_url="https://upload.wikimedia.org/wikipedia/en/8/85/Cute_Dom_cat.JPG",
70-
theme="dramatic",
71-
)
66+
image = Attachment(url="https://upload.wikimedia.org/wikipedia/en/8/85/Cute_Dom_cat.JPG")
67+
prompt_input = ImagePromptInput(image=image, theme="dramatic")
7268
prompt = ImagePrompt(prompt_input)
7369
response = await llm.generate(prompt)
7470
print(response.description)

0 commit comments

Comments
 (0)