- Learn
- Prompt Engineering
- Few-Shot Prompting
Learn how to use examples effectively to guide AI output with few-shot prompting techniques for better code generation.
Few-Shot Prompting
Few-shot prompting is one of the most powerful techniques for getting consistent, high-quality output from AI. By providing examples, you show the AI exactly what you want rather than just telling it.
What is Few-Shot Prompting?
Few-shot prompting provides demonstrations (examples) in the prompt to guide the model to better performance. It's called "few-shot" because you're giving a few examples (typically 2-5) before asking for the actual output.
| Approach | Description | Best For |
|---|---|---|
| Zero-shot | No examples, just instructions | Simple, common tasks |
| One-shot | Single example | Format demonstration |
| Few-shot | 2-5 examples | Complex patterns, consistency |
Why Few-Shot Works
OpenAI's research demonstrated that LLMs with large-scale parameters provide significantly better responses with few-shot prompts compared to zero-shot approaches. Examples help the model understand:
- Format: Exactly how output should be structured
- Style: The tone, verbosity, and conventions to follow
- Edge cases: How to handle unusual inputs
- Patterns: The underlying logic to apply
Basic Few-Shot Pattern
Here are examples of the pattern I want:
Example 1:
Input: [input1]
Output: [output1]
Example 2:
Input: [input2]
Output: [output2]
Example 3:
Input: [input3]
Output: [output3]
Now apply this pattern:
Input: [actual input]
Few-Shot for Code Generation
Function Naming Convention
Convert these function names to our camelCase convention:
Example 1:
Input: get_user_data
Output: getUserData
Example 2:
Input: FETCH_ALL_POSTS
Output: fetchAllPosts
Example 3:
Input: Send_Email_Notification
Output: sendEmailNotification
Now convert:
Input: calculate_total_price
Output: ???
Validation Functions
Generate TypeScript validation functions following this pattern:
Example 1 - Email Validation:
export const validateEmail = (email: string): boolean => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
};
Example 2 - Phone Validation:
export const validatePhone = (phone: string): boolean => {
const phoneRegex = /^\+?[\d\s-]{10,}$/;
return phoneRegex.test(phone.replace(/\s/g, ''));
};
Now generate: validateCreditCard
- Should accept 13-19 digits
- Allow spaces and dashes as separators
- Use Luhn algorithm for checksum validation
Error Handling Pattern
Implement error handling following this pattern:
Example 1 - API Error:
try {
const response = await fetch(url);
if (!response.ok) {
throw new ApiError(`HTTP ${response.status}`, response.status);
}
return response.json();
} catch (error) {
if (error instanceof ApiError) {
logger.warn('API error', { status: error.status });
throw error;
}
logger.error('Network error', { error });
throw new NetworkError('Failed to connect');
}
Example 2 - Database Error:
try {
const result = await prisma.user.create({ data });
return result;
} catch (error) {
if (error instanceof Prisma.PrismaClientKnownRequestError) {
if (error.code === 'P2002') {
throw new DuplicateError('User already exists');
}
}
logger.error('Database error', { error });
throw new DatabaseError('Failed to create user');
}
Now implement error handling for: File upload to S3
Best Practices for Few-Shot
1. Use 3-5 Examples
Research shows 3-5 examples is optimal:
- Fewer than 3: May not establish clear pattern
- More than 5: Diminishing returns, wastes tokens
2. Make Examples Diverse
Cover different scenarios to prevent the AI from over-fitting to one pattern:
Generate product descriptions:
Example 1 (Electronics):
Input: { name: "Wireless Mouse", price: 29.99, features: ["Bluetooth", "Ergonomic"] }
Output: "Stay productive with our Wireless Mouse ($29.99). Features Bluetooth connectivity and an ergonomic design for all-day comfort."
Example 2 (Clothing):
Input: { name: "Cotton T-Shirt", price: 19.99, features: ["100% Cotton", "Machine Washable"] }
Output: "Classic comfort meets style with our Cotton T-Shirt ($19.99). Made from 100% cotton and fully machine washable for easy care."
Example 3 (Food):
Input: { name: "Organic Coffee", price: 14.99, features: ["Fair Trade", "Medium Roast"] }
Output: "Start your day right with our Organic Coffee ($14.99). Fair Trade certified with a smooth medium roast profile."
Now generate for:
Input: { name: "Yoga Mat", price: 34.99, features: ["Non-Slip", "6mm Thick"] }
3. Include Edge Cases
Show how to handle unusual inputs:
Format user names for display:
Example 1 (Normal):
Input: { firstName: "John", lastName: "Smith" }
Output: "John Smith"
Example 2 (Single name):
Input: { firstName: "Madonna", lastName: null }
Output: "Madonna"
Example 3 (Empty):
Input: { firstName: "", lastName: "" }
Output: "Anonymous User"
Example 4 (Special characters):
Input: { firstName: "José", lastName: "García-López" }
Output: "José García-López"
Now format:
Input: { firstName: null, lastName: "Chen" }
4. Use Clear Delimiters
Wrap examples in tags for clarity (especially with Claude):
<examples>
<example>
<input>get_user_by_id</input>
<output>getUserById</output>
</example>
<example>
<input>FETCH_ORDERS</input>
<output>fetchOrders</output>
</example>
</examples>
Now apply this pattern to: calculate_shipping_cost
Few-Shot for Code Style Consistency
Establish your project's coding style:
Follow this code style for all generated functions:
Example - Data Transformation:
/**
* Transforms raw API user data into application format
* @param rawUser - User data from API
* @returns Normalized user object
* @throws ValidationError if required fields missing
*/
export const normalizeUser = (rawUser: RawUser): User => {
if (!rawUser.id || !rawUser.email) {
throw new ValidationError('Missing required user fields');
}
return {
id: rawUser.id,
email: rawUser.email.toLowerCase().trim(),
displayName: rawUser.name || 'Anonymous',
createdAt: new Date(rawUser.created_at),
};
};
Note the style:
- JSDoc with @param, @returns, @throws
- Input validation at the start
- Explicit return type
- Data normalization (lowercase, trim)
- Sensible defaults
Now generate: normalizeProduct(rawProduct: RawProduct): Product
Few-Shot for Test Generation
Generate Jest tests following this pattern:
Example Test Suite:
describe('validateEmail', () => {
describe('valid emails', () => {
it('should return true for standard email', () => {
expect(validateEmail('user@example.com')).toBe(true);
});
it('should return true for email with subdomain', () => {
expect(validateEmail('user@mail.example.com')).toBe(true);
});
});
describe('invalid emails', () => {
it('should return false for missing @', () => {
expect(validateEmail('userexample.com')).toBe(false);
});
it('should return false for empty string', () => {
expect(validateEmail('')).toBe(false);
});
});
describe('edge cases', () => {
it('should handle emails with plus signs', () => {
expect(validateEmail('user+tag@example.com')).toBe(true);
});
});
});
Now generate tests for: validatePassword(password: string): boolean
- Must be 8+ characters
- Must contain uppercase
- Must contain number
- Must contain special character
Common Mistakes to Avoid
1. Examples Too Similar
Bad: All examples are happy path
Example 1: valid email -> true
Example 2: another valid email -> true
Example 3: yet another valid email -> true
Good: Diverse scenarios
Example 1: valid email -> true
Example 2: invalid format -> false
Example 3: empty string -> false
Example 4: edge case (plus sign) -> true
2. Inconsistent Format Across Examples
Bad: Different output structures
Example 1 Output: { success: true, data: {...} }
Example 2 Output: { result: "ok", user: {...} }
Example 3 Output: "Success"
Good: Consistent structure
Example 1 Output: { success: true, data: {...} }
Example 2 Output: { success: false, error: "..." }
Example 3 Output: { success: true, data: null }
3. Missing the Pattern
If your examples don't clearly show the pattern, the AI can't learn it:
Bad (What's the pattern?):
Input: "hello" -> Output: "HELLO"
Input: "World" -> Output: "WORLD"
Good (Clear pattern):
Convert to uppercase:
Input: "hello" -> Output: "HELLO"
Input: "World" -> Output: "WORLD"
Input: "TeSt" -> Output: "TEST"
When to Use Few-Shot
| Scenario | Recommendation |
|---|---|
| Standard formatting (JSON, etc.) | Zero-shot often sufficient |
| Custom output format | Few-shot recommended |
| Project-specific conventions | Few-shot essential |
| Complex transformations | Few-shot with edge cases |
| Consistent code style | Few-shot with style guide |
Practice Exercise
Create a few-shot prompt for generating API error responses in your project's format.
Include examples for:
- Validation error (400)
- Not found error (404)
- Authentication error (401)
- Server error (500)
Summary
- Few-shot prompting uses examples to demonstrate desired patterns
- 3-5 diverse examples are optimal
- Include edge cases to show complete behavior
- Use consistent formatting across all examples
- Wrap examples in tags for clarity
Next Steps
Now that you can use examples effectively, let's learn chain-of-thought prompting—a technique for getting AI to reason through complex problems step by step.