A structured, production-ready prompt package for classifying fresh produce images using a vision-capable large language model. Designed for warehouse intake pipelines where a single image arrives per item and a single routing label must be returned.
This repository contains a complete, ready-to-deploy prompt package for automated fruit ripeness classification. Given a single image, the classifier returns exactly one of four labels:
| Label | Meaning |
|---|---|
Ripe |
Fruit is fresh and at optimal maturity for delivery |
Unripe |
Fruit is biologically immature; not ready for delivery |
Other |
Not classifiable as fresh fruit — damaged, processed, ambiguous, non-fruit, or poor image quality |
Error |
Technical image failure — black frame, white frame, corrupted file |
The system is intentionally minimal: one image in, one label out. No explanations, no confidence scores, no follow-up questions.
This prompt package is designed for produce quality triage at intake stations. Images are captured one at a time from a camera on a sorting line. The classifier automates the initial label so that:
Ripeitems can be routed directly to available inventoryUnripeitems can be held or reroutedOtheritems are flagged for human reviewErrorlabels indicate a camera or transmission fault requiring technical attention
The goal is to reduce manual review burden while keeping humans in the loop for genuine edge cases.
fruit-ripeness-classifier/
│
├── README.md ← You are here
│
├── prompt_package/
│ ├── system_prompt.txt ← Core system prompt (role, rules, decision flowchart)
│ ├── class_definitions.yaml ← Per-label definitions and visual indicators
│ ├── edge_case_policy.yaml ← Handling rules for ambiguous scenarios
│ └── few_shot_examples.txt ← Input/output examples for in-context learning
│
├── sample_data/
│ ├── ripe/ ← Example images labeled Ripe
│ ├── unripe/ ← Example images labeled Unripe
│ └── other/ ← Example images labeled Other
│
└── docs/
└── prompt_design_notes.md ← Design rationale and known limitations
The prompt is composed of four modular files that work together:
The core instruction set. Defines the model's role as a classification engine, enumerates the four allowed output labels, establishes global rules (no explanations, no invented labels, conservative defaults), and provides a step-by-step decision flowchart. This is the file you pass as the system parameter in your API call.
Detailed definitions for each label class. Each entry includes:
- A plain-language definition
- Visual indicators the model should look for
- Explicit exclusions to prevent misclassification
A policy table for scenarios that fall outside clean classification: motion blur, partial visibility, multiple fruits, mixed ripeness, exotic varieties, processed produce, artificial fruit, and more. Each case has a defined policy so the model has deterministic guidance rather than guessing.
A small set of labeled input/output pairs. These are appended to the prompt (or passed as early conversation turns) to anchor the model's output format and reinforce label usage before it sees the real image.
import anthropic
import base64
client = anthropic.Anthropic()
# Load prompt components
with open("prompt_package/system_prompt.txt") as f:
system_prompt = f.read()
# Load your image
with open("sample_data/ripe/banana_ripe.jpg", "rb") as f:
image_data = base64.standard_b64encode(f.read()).decode("utf-8")
response = client.messages.create(
model="claude-opus-4-5", # or any vision-capable model
max_tokens=10,
system=system_prompt,
messages=[
{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/jpeg",
"data": image_data,
},
}
],
}
],
)
label = response.content[0].text.strip()
print(label) # → "Ripe", "Unripe", "Other", or "Error"from openai import OpenAI
import base64
client = OpenAI()
with open("prompt_package/system_prompt.txt") as f:
system_prompt = f.read()
with open("sample_data/ripe/banana_ripe.jpg", "rb") as f:
image_data = base64.b64encode(f.read()).decode("utf-8")
response = client.chat.completions.create(
model="gpt-4o",
max_tokens=10,
messages=[
{"role": "system", "content": system_prompt},
{
"role": "user",
"content": [
{
"type": "image_url",
"image_url": {"url": f"data:image/jpeg;base64,{image_data}"},
}
],
},
],
)
label = response.choices[0].message.content.strip()
print(label)To use the few-shot examples, prepend them to the user message or inject them as early conversation turns before the image. The few_shot_examples.txt file is formatted as INPUT DESCRIPTION / OUTPUT pairs and can be adapted to either pattern.
The model is instructed to return exactly one word with no additional text:
Ripe
Unripe
Other
Error
Downstream systems can treat the response as a simple string match. No parsing, no JSON decoding required.
Minimal output surface. A single-word response eliminates parsing complexity and reduces the chance of the model embedding reasoning or hedging language in the output.
Conservative defaults. When evidence is ambiguous, the prompt defaults to Other (flag for human review) rather than guessing between Ripe and Unripe. At the boundary between the two, the model defaults to Unripe (Rule 5 — Conservative Boundary Rule).
Variety-aware classification. The prompt explicitly instructs the model not to rely on color alone. Green-ripe varieties (Granny Smith apple, lime, certain mango and banana cultivars) are handled through the Variety Awareness rule.
Botanical, not culinary. Ripeness is defined botanically. A green mango used in a chutney is still Unripe. A tomato is treated as a fruit.
Modular prompt architecture. The four-file structure separates concerns: the system prompt handles role and rules, the class definitions handle semantics, the edge case policy handles ambiguity, and the few-shot examples handle format anchoring. Each file can be updated independently.
This prompt package is designed to be model-agnostic. It has been written for use with any vision-capable LLM that accepts a system prompt and an image input. Tested prompt structures are compatible with:
- Anthropic Claude (claude-3-5-sonnet, claude-opus-4, etc.)
- OpenAI GPT-4o
- Google Gemini 1.5 Pro / 2.0 Flash
Performance may vary across models, particularly on edge cases involving exotic fruit varieties or borderline ripeness. Evaluation across providers is recommended before production deployment.
- The classifier operates on visual information only. It cannot detect internal defects, taste, smell, or firmness that isn't visible in the image.
- Exotic or rare fruit varieties with non-standard ripeness color signatures are intentionally handled conservatively — the model will return
Otherwhen ripeness evidence is unclear for an unfamiliar variety. - Camera angle and lighting at the intake station significantly affect accuracy. Consistent, well-lit, close-up photography of a single fruit produces the most reliable results.
- The system is designed for one fruit per image. Multi-fruit images with unclear dominance return
Other.
See docs/prompt_design_notes.md for extended discussion of design decisions and tradeoffs.
MIT License. See LICENSE for details.