Skip to content

Commit f99467c

Browse files
author
Daniel Lorch
committed
chore: use working bucket from GenAIIDP for dataset + adapt threshold
1 parent 21c9855 commit f99467c

File tree

2 files changed

+183
-108
lines changed

2 files changed

+183
-108
lines changed

plugins/dynamic-few-shot-lambda/README.md

Lines changed: 177 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,77 @@
1-
# Dynamic-Few Shot Prompting - Complete Guide
1+
# Dynamic Few-Shot Prompting Lambda - Complete Guide
22

3-
This directory contains the **complete implementation and demonstration** of the dynamic-few shot prompting feature for GenAI IDP Accelerator. This feature enables users to dynamically retrieve few-shot examples using S3 Vectors similarity search to improve extraction accuracy for Pattern 2.
3+
This directory contains the **complete implementation** of the dynamic few-shot prompting Lambda function for GenAI IDP Accelerator. This Lambda function integrates with Pattern 2 extraction as a custom prompt generator, dynamically retrieving similar examples using S3 Vectors similarity search to improve extraction accuracy.
44

55
## 🎯 Overview
66

7-
The dynamic-few shot prompting feature allows you to:
7+
The dynamic few-shot prompting Lambda function allows you to:
88

99
- **Dynamically retrieve similar examples** based on document content using vector similarity search
10-
- **Provide few-shot examples** to improve extraction accuracy through example-based prompting
10+
- **Automatically inject few-shot examples** into extraction prompts using the `{FEW_SHOT_EXAMPLES}` placeholder
1111
- **Leverage S3 Vectors** for efficient similarity search across large example datasets
1212
- **Integrate multimodal embeddings** using Amazon Nova models for image-based similarity
13-
- **Customize example selection** based on document characteristics and business rules
13+
- **Seamlessly integrate** with existing IDP extraction workflows as a custom prompt Lambda
1414

1515
## 📁 Files in This Directory
1616

17-
- **`GENAIIDP-dynamic-few-shot.py`** - Dynamic few-shot Lambda function with S3 Vectors lookup
18-
- **`template.yml`** - CloudFormation SAM template to deploy the complete stack
19-
- **`requirements.txt`** - Python dependencies for the Lambda function
17+
- **`src/GENAIIDP-dynamic-few-shot.py`** - Dynamic few-shot Lambda function with S3 Vectors lookup
18+
- **`src/requirements.txt`** - Python dependencies for the Lambda function
19+
- **`template.yml`** - CloudFormation SAM template to deploy the Lambda function
2020
- **`README.md`** - This comprehensive documentation and guide
2121

2222
## 🏗️ Architecture
2323

2424
```mermaid
2525
flowchart TD
26-
A[Document Processing] --> B{Dynamic-few shot configured?}
27-
B -->|No| C[Use Default Extraction]
28-
B -->|Yes| D[Invoke Dynamic-few shot Lambda]
29-
30-
subgraph Lambda
31-
D --> E[Receive Document Images]
32-
E --> F[Generate Embeddings with Nova]
33-
F --> G[Query S3 Vectors Index]
34-
G --> H[Retrieve Similar Examples]
35-
H --> I[Load Example Images from S3]
36-
I --> J[Format Examples for Bedrock]
26+
A[IDP Document Processing] --> B{Custom Prompt Lambda ARN configured?}
27+
B -->|No| C[Use Default Task Prompt]
28+
B -->|Yes| D[Invoke Dynamic Few-Shot Lambda]
29+
30+
subgraph "Lambda Function: GENAIIDP-dynamic-few-shot"
31+
D --> E[Receive IDP Context & Placeholders]
32+
E --> F[Extract Document Images from DOCUMENT_IMAGE]
33+
F --> G[Generate Nova Multimodal Embeddings]
34+
G --> H[Query S3 Vectors Index]
35+
H --> I[Filter by Distance Threshold]
36+
I --> J[Merge & Deduplicate Results]
37+
J --> K[Load Example Images from S3]
38+
K --> L[Build Prompt Content Array]
39+
L --> M[Replace FEW_SHOT_EXAMPLES Placeholder]
3740
end
3841
39-
J --> K[Use Examples in Extraction Prompt]
40-
C --> L[Continue with Standard Extraction]
41-
K --> L
42+
M --> N[Return Modified Task Prompt Content]
43+
C --> O[Continue with Bedrock Extraction]
44+
N --> O
4245
43-
subgraph Input
44-
M[Document Class]
45-
N[Document Text]
46-
O[Document Images]
46+
subgraph "Input Payload"
47+
P[config: IDP Configuration]
48+
Q[prompt_placeholders: DOCUMENT_TEXT, DOCUMENT_CLASS, etc.]
49+
R[default_task_prompt_content: Original prompt]
50+
S[serialized_document: Document metadata]
4751
end
4852
49-
subgraph Output
50-
P[Example Attributes Prompts]
51-
Q[Example Images]
52-
R[Similarity Distances]
53+
subgraph "Output Payload"
54+
T[system_prompt: Unchanged]
55+
U[task_prompt_content: Array with Prompt segments and Example images]
5356
end
5457
55-
D -.-> M
56-
D -.-> N
57-
D -.-> O
58+
D -.-> P
59+
D -.-> Q
60+
D -.-> R
61+
D -.-> S
5862
59-
J -.-> P
60-
J -.-> Q
61-
J -.-> R
63+
N -.-> T
64+
N -.-> U
65+
66+
subgraph "S3 Vectors Infrastructure"
67+
X[Vector Bucket: Encrypted storage]
68+
Y[Vector Index: 3072-dim cosine similarity]
69+
Z[Metadata: classPrompt, attributesPrompt, imagePath]
70+
end
71+
72+
H -.-> X
73+
H -.-> Y
74+
H -.-> Z
6275
```
6376

6477
## Quick Start
@@ -88,7 +101,7 @@ aws cloudformation describe-stacks \
88101

89102
Use the [fewshot_dataset_import.ipynb](notebooks/fewshot_dataset_import.ipynb) notebook to import a dataset into S3 Vectors, or manually upload your example documents and metadata to the S3 bucket and vector index created by the stack.
90103

91-
### Step 4: Configure IDP to Use Dynamic-few shot
104+
### Step 4: Configure IDP to Use Dynamic Few-Shot
92105

93106
Add the Lambda ARN to your IDP extraction configuration:
94107

@@ -97,42 +110,81 @@ extraction:
97110
custom_prompt_lambda_arn: "arn:aws:lambda:region:account:function:GENAIIDP-dynamic-few-shot"
98111
```
99112
113+
**Important**: Your extraction task prompt must include the `{FEW_SHOT_EXAMPLES}` placeholder where you want the dynamic examples to be inserted.
114+
115+
### Step 5: Run the Demo Notebook
116+
117+
0. Run `notebooks/examples` steps 0, 1, 2
118+
1. Open `plugins/dynamic-few-shot-lambda/notebooks/step3_extraction_with_custom_lambda.ipynb`
119+
2. Run all cells to see the comparison
120+
100121
## Lambda Interface
101122

102123
### Input Payload Structure
124+
125+
The Lambda receives the full IDP context as a custom prompt Lambda:
126+
103127
```json
104128
{
105-
"class_label": "invoice",
106-
"document_text": "Text or markdown from section 1 (pages 1-3)...",
107-
"image_content": [
108-
"base64_encoded_image_1",
109-
"base64_encoded_image_2"
110-
]
129+
"config": {
130+
"extraction": {...},
131+
"classes": [...],
132+
...
133+
},
134+
"prompt_placeholders": {
135+
"DOCUMENT_TEXT": "Full OCR text from all pages",
136+
"DOCUMENT_CLASS": "invoice",
137+
"ATTRIBUTE_NAMES_AND_DESCRIPTIONS": "LineItems: List of line items in the invoice...",
138+
"DOCUMENT_IMAGE": ["s3://bucket/document/page1.jpg", "s3://bucket/document/page2.jpg"]
139+
},
140+
"default_task_prompt_content": [
141+
{"text": "Resolved default task prompt..."},
142+
{"image_uri": "s3://..."}, // if images present
143+
{"cachePoint": true} // if cache points present
144+
],
145+
"serialized_document": {
146+
"id": "document-123",
147+
"input_bucket": "my-bucket",
148+
"pages": {...},
149+
"sections": [...],
150+
...
151+
}
111152
}
112153
```
113154

114155
### Output Payload Structure
156+
157+
The Lambda returns modified prompt content with dynamic few-shot examples:
158+
115159
```json
116-
[
117-
{
118-
"attributes_prompt": "Expected attributes are: invoice_number [Unique identifier], invoice_date [Invoice date], total_amount [Total amount]...",
119-
"class_prompt": "This is an example of the class 'invoice'",
120-
"distance": 0.122344521145, # lower is more similar
121-
"image_content": ["<base64_image_content_1>", "<base64_image_content_2>", ...]
122-
}
123-
]
160+
{
161+
"system_prompt": "Custom system prompt text",
162+
"task_prompt_content": [
163+
{"text": "Extract the following attributes from this invoice document:\n\nLineItems: List of line items in the invoice...\n\n<few_shot_examples>"},
164+
{"text": "expected attributes are:\n \"invoice_number\": \"INV-2024-001\",\n \"total_amount\": \"$1,250.00\""},
165+
{"image_uri": "s3://examples-bucket/invoices/example-001/page1.jpg"},
166+
{"text": "</few_shot_examples>\n\n<<CACHEPOINT>>\n\nDocument content:\nINVOICE\nInvoice #: INV-2024-002..."}
167+
]
168+
}
124169
```
125170

126171
## Core Functionality
127172

128-
### 1. Vector Similarity Search
173+
### 1. Custom Prompt Integration
174+
175+
The Lambda integrates with IDP's custom prompt system by:
176+
- Receiving the full extraction context and configuration
177+
- Processing the `{FEW_SHOT_EXAMPLES}` placeholder in task prompts
178+
- Returning modified prompt content with dynamically retrieved examples
179+
180+
### 2. Vector Similarity Search
129181

130182
The Lambda uses Amazon Nova multimodal embeddings to find similar examples:
131183

132184
```python
133185
# Generate embedding from document image
134-
embedding = bedrock.generate_embedding(
135-
image_source=image_data,
186+
embedding = bedrock_client.generate_embedding(
187+
image_source=page_image,
136188
model_id=MODEL_ID,
137189
dimensions=S3VECTOR_DIMENSIONS,
138190
)
@@ -148,34 +200,36 @@ response = s3vectors.query_vectors(
148200
)
149201
```
150202

151-
### 2. Example Merging and Deduplication
203+
### 3. Example Merging and Deduplication
152204

153205
Multiple document images are processed and results are merged to avoid duplicates:
154206

155207
```python
156-
def merge_examples(combined_examples, new_examples):
208+
def _merge_examples(examples, new_examples):
157209
"""Merge examples, keeping the best similarity score for duplicates"""
158210
for new_example in new_examples:
159211
key = new_example["key"]
160-
if combined_examples.get(key):
161-
# Keep the better (lower) distance score
162-
combined_examples[key]["distance"] = min(
163-
new_example.get("distance"),
164-
combined_examples[key]["distance"]
165-
)
212+
new_distance = new_example.get("distance", 1.0)
213+
214+
if examples.get(key):
215+
existing_distance = examples[key].get("distance", 1.0)
216+
examples[key]["distance"] = min(new_distance, existing_distance)
166217
```
167218

168-
### 3. Example Image Loading
219+
### 4. Prompt Content Building
169220

170-
The Lambda loads example images from S3 paths stored in vector metadata:
221+
The Lambda builds structured prompt content handling multiple placeholders:
171222

172223
```python
173-
def get_image_files_from_s3_path(image_path: str) -> List[str]:
174-
"""Get list of image files from S3 path or prefix"""
175-
if image_path.endswith((".jpg", ".jpeg", ".png", ".gif", ".bmp", ".tiff", ".tif", ".webp")):
176-
return [image_path] # Direct file
177-
else:
178-
return s3.list_images_from_path(image_path) # Directory/prefix
224+
def _build_prompt_content(prompt_template, substitutions, image_content):
225+
"""
226+
Build prompt content array handling FEW_SHOT_EXAMPLES and DOCUMENT_IMAGE placeholders.
227+
228+
Handles:
229+
- {FEW_SHOT_EXAMPLES}: Inserts few-shot examples from S3 Vectors
230+
- {DOCUMENT_IMAGE}: Inserts images at specific location
231+
- Regular text placeholders: DOCUMENT_TEXT, DOCUMENT_CLASS, etc.
232+
"""
179233
```
180234

181235
## Configuration
@@ -188,7 +242,9 @@ The Lambda function uses these environment variables (set by the CloudFormation
188242
- `S3VECTOR_INDEX` - Name of the S3 Vectors index
189243
- `S3VECTOR_DIMENSIONS` - Embedding dimensions (e.g. `3072` for Nova Multimodal Embedding model)
190244
- `MODEL_ID` - Bedrock model ID for embeddings (e.g. `amazon.nova-2-multimodal-embeddings-v1:0`)
191-
- `TOP_K` - Number of similar examples to retrieve
245+
- `TOP_K` - Number of similar examples to retrieve (default: 3)
246+
- `THRESHOLD` - Maximum distance threshold for filtering results (default: 0.5)
247+
- `LOG_LEVEL` - Logging level (default: INFO)
192248

193249
### S3 Vectors Configuration
194250

@@ -208,16 +264,22 @@ Monitor the Lambda function logs:
208264

209265
**Successful Operation:**
210266
```
211-
Processing document ID: document-123
212-
Document class: invoice
213-
Response contains 2 elements
267+
=== DYNAMIC FEW-SHOT LAMBDA INVOKED ===
268+
=== EXTRACTION CONFIG ===
269+
Model: anthropic.claude-3-5-sonnet-20241022-v2:0
270+
=== HANDLE INPUT DOCUMENT ===
271+
=== OUTPUT ANALYSIS ===
272+
Output keys: ['system_prompt', 'task_prompt_content']
273+
Task prompt content items: 5
274+
=== DYNAMIC FEW-SHOT LAMBDA COMPLETED ===
214275
```
215276
216277
**Error Conditions:**
217278
```
218-
No class_label found in event
219-
No document_texts found in event or not in list format
220-
Failed to load example images from s3://bucket/path: error
279+
Failed to parse environment variables: KeyError('S3VECTOR_BUCKET')
280+
Skipping example with empty attributesPrompt: example_key
281+
Skipping example with distance 0.8 above threshold 0.5: example_key
282+
Invalid file path /local/path - expecting S3 URI
221283
```
222284
223285
### Performance Monitoring
@@ -331,22 +393,53 @@ aws cloudformation delete-stack --stack-name GENAIIDP-dynamic-few-shot-stack
331393

332394
### Configuration in IDP Stack
333395

334-
Add the dynamic-few shot Lambda ARN to your IDP configuration:
396+
Add the dynamic few-shot Lambda ARN to your IDP extraction configuration:
335397

336398
```yaml
337-
# In your IDP stack parameters or configuration
338399
extraction:
339-
dynamic_few_shot_lambda_arn: "arn:aws:lambda:region:account:function:GENAIIDP-dynamic-few-shot"
400+
custom_prompt_lambda_arn: "arn:aws:lambda:region:account:function:GENAIIDP-dynamic-few-shot"
340401
```
341402
403+
### Required Task Prompt Configuration
404+
405+
**Critical**: Your extraction task prompt must include the `{FEW_SHOT_EXAMPLES}` placeholder where you want the dynamic examples to be inserted. The Lambda specifically looks for this placeholder and replaces it with retrieved examples.
406+
342407
### Expected Behavior
343408

344409
When configured:
345410
1. IDP processes document and extracts images/text
346-
2. Dynamic few-shot Lambda is invoked with document data
347-
3. Lambda returns similar examples with prompts and images
348-
4. IDP includes examples in extraction prompt to Bedrock
349-
5. Bedrock uses examples to improve extraction accuracy
411+
2. IDP invokes the dynamic few-shot Lambda with full extraction context
412+
3. Lambda generates embeddings from document images using Amazon Nova
413+
4. Lambda queries S3 Vectors to find similar examples
414+
5. Lambda loads example images and metadata from S3
415+
6. Lambda builds modified prompt content with examples inserted at `{FEW_SHOT_EXAMPLES}` location
416+
7. IDP uses the modified prompt content for Bedrock extraction
417+
8. Bedrock uses the dynamic examples to improve extraction accuracy
418+
419+
### Prompt Flow Example
420+
421+
**Original Task Prompt:**
422+
```
423+
Extract attributes from this invoice:
424+
{ATTRIBUTE_NAMES_AND_DESCRIPTIONS}
425+
{FEW_SHOT_EXAMPLES}
426+
<<CACHEPOINT>>
427+
Document: {DOCUMENT_TEXT}
428+
```
429+
430+
**After Lambda Processing:**
431+
```
432+
Extract attributes from this invoice:
433+
invoice_number [Unique identifier]...
434+
435+
expected attributes are:
436+
"invoice_number": "INV-2024-001",
437+
"total_amount": "$1,250.00"
438+
[Example image content]
439+
440+
<<CACHEPOINT>>
441+
Document: INVOICE #INV-2024-002...
442+
```
350443
351444
## Next Steps
352445

0 commit comments

Comments
 (0)