Prompt Engineering Pattern

Craft effective prompts for reliable, high-quality AI outputs with structured responses and consistent behavior.

Overview#

Prompt engineering is the practice of designing inputs to AI models that produce desired outputs reliably. Well-crafted prompts reduce errors, improve consistency, and enable complex behaviors.

When to use:

  • Any AI-powered feature
  • Structured data extraction
  • Content generation
  • Classification tasks
  • Complex reasoning tasks

Key features:

  • System prompt design
  • Output format specification
  • Few-shot examples
  • Chain-of-thought reasoning
  • Structured output with schemas

Code Example#

System Prompt Design#

1// lib/ai/prompts.ts 2export const systemPrompts = { 3 // Clear role and constraints 4 assistant: `You are a helpful customer support assistant for Acme Inc. 5Your role is to help customers with product questions and issues. 6 7Guidelines: 8- Be friendly and professional 9- Only discuss Acme products and services 10- If you don't know something, say so 11- Never make up product features or prices 12- Suggest contacting support for complex issues`, 13 14 // Technical assistant with specific format 15 codeReviewer: `You are an expert code reviewer. 16Review code for: 17- Bugs and potential errors 18- Security vulnerabilities 19- Performance issues 20- Code style and readability 21 22Format your response as: 23## Summary 24Brief overview of the code quality 25 26## Issues Found 27List each issue with severity (Critical/Warning/Info) 28 29## Suggestions 30Specific improvements with code examples`, 31 32 // Data extraction with schema 33 entityExtractor: `You are a data extraction system. 34Extract structured information from text. 35Always return valid JSON matching the requested schema. 36If information is not present, use null. 37Never add fields not in the schema.` 38}

Structured Output with Zod#

1// lib/ai/structured.ts 2import { anthropic } from '@/lib/anthropic' 3import { z } from 'zod' 4 5const ProductSchema = z.object({ 6 name: z.string(), 7 description: z.string(), 8 price: z.number(), 9 category: z.string() 10}) 11 12export async function extractProduct(text: string) { 13 const response = await anthropic.messages.create({ 14 model: 'claude-sonnet-4-20250514', 15 max_tokens: 1024, 16 system: `Extract product information and return as JSON. 17Return only the JSON object, no other text.`, 18 messages: [ 19 { 20 role: 'user', 21 content: `Extract product information from this text: 22 23${text} 24 25Return JSON with: name, description, price (number), category` 26 } 27 ] 28 }) 29 30 const content = response.content[0] 31 if (content.type !== 'text') throw new Error('Unexpected response') 32 33 const jsonMatch = content.text.match(/\{[\s\S]*\}/) 34 if (!jsonMatch) throw new Error('No JSON found') 35 36 const parsed = JSON.parse(jsonMatch[0]) 37 return ProductSchema.parse(parsed) 38}

Few-Shot Examples#

1// lib/ai/classification.ts 2import { anthropic } from '@/lib/anthropic' 3 4const CATEGORIES = ['bug', 'feature', 'question', 'docs'] as const 5 6export async function classifyIssue( 7 title: string, 8 body: string 9): Promise<typeof CATEGORIES[number]> { 10 const response = await anthropic.messages.create({ 11 model: 'claude-sonnet-4-20250514', 12 max_tokens: 50, 13 messages: [ 14 { 15 role: 'user', 16 content: `Classify GitHub issues. Categories: bug, feature, question, docs 17 18Examples: 19Title: "App crashes on login" 20Body: "When I try to log in, the app crashes" 21Category: bug 22 23Title: "Add dark mode support" 24Body: "It would be great to have a dark theme option" 25Category: feature 26 27Title: "How do I reset my password?" 28Body: "I forgot my password and can't find reset option" 29Category: question 30 31Title: "Fix typo in README" 32Body: "Line 42 says 'teh' instead of 'the'" 33Category: docs 34 35Now classify: 36Title: "${title}" 37Body: "${body}" 38Category:` 39 } 40 ] 41 }) 42 43 const text = response.content[0].type === 'text' 44 ? response.content[0].text.trim().toLowerCase() 45 : '' 46 47 if (CATEGORIES.includes(text as any)) { 48 return text as typeof CATEGORIES[number] 49 } 50 51 return 'question' // default 52}

Chain-of-Thought Reasoning#

1// lib/ai/reasoning.ts 2import { anthropic } from '@/lib/anthropic' 3 4export async function analyzeWithReasoning(problem: string) { 5 const response = await anthropic.messages.create({ 6 model: 'claude-sonnet-4-20250514', 7 max_tokens: 2048, 8 system: `You are an analytical assistant. 9When solving problems, think step by step: 101. First, understand what is being asked 112. Break down the problem into parts 123. Analyze each part 134. Synthesize your findings 145. Provide a clear conclusion 15 16Format: 17## Understanding 18What the problem is asking 19 20## Analysis 21Step-by-step reasoning 22 23## Conclusion 24Final answer with confidence level`, 25 messages: [ 26 { role: 'user', content: problem } 27 ] 28 }) 29 30 return response.content[0].type === 'text' 31 ? response.content[0].text 32 : null 33}

Entity Extraction#

1// lib/ai/extract.ts 2import { anthropic } from '@/lib/anthropic' 3import { z } from 'zod' 4 5const EntitiesSchema = z.object({ 6 people: z.array(z.string()), 7 organizations: z.array(z.string()), 8 locations: z.array(z.string()), 9 dates: z.array(z.string()) 10}) 11 12export async function extractEntities(text: string) { 13 const response = await anthropic.messages.create({ 14 model: 'claude-sonnet-4-20250514', 15 max_tokens: 1024, 16 system: `Extract named entities from text. 17Return a JSON object with arrays for: people, organizations, locations, dates. 18Use empty arrays if no entities found for a category.`, 19 messages: [ 20 { 21 role: 'user', 22 content: `Extract named entities from: 23 24${text} 25 26Return only the JSON object.` 27 } 28 ] 29 }) 30 31 const content = response.content[0] 32 if (content.type !== 'text') throw new Error('Unexpected response') 33 34 const jsonMatch = content.text.match(/\{[\s\S]*\}/) 35 if (!jsonMatch) throw new Error('No JSON found') 36 37 return EntitiesSchema.parse(JSON.parse(jsonMatch[0])) 38}

Conversation Context Management#

1// lib/ai/conversation.ts 2import { anthropic } from '@/lib/anthropic' 3 4interface Message { 5 role: 'user' | 'assistant' 6 content: string 7} 8 9export async function chat( 10 messages: Message[], 11 systemPrompt: string 12) { 13 // Keep conversation within token limits 14 const recentMessages = messages.slice(-10) 15 16 // Add context summary for long conversations 17 let contextSummary = '' 18 if (messages.length > 10) { 19 contextSummary = `Previous conversation summary: ${await summarizeConversation(messages.slice(0, -10))}\n\n` 20 } 21 22 const response = await anthropic.messages.create({ 23 model: 'claude-sonnet-4-20250514', 24 max_tokens: 1024, 25 system: systemPrompt + (contextSummary ? `\n\n${contextSummary}` : ''), 26 messages: recentMessages 27 }) 28 29 return response.content[0].type === 'text' 30 ? response.content[0].text 31 : null 32} 33 34async function summarizeConversation(messages: Message[]): Promise<string> { 35 const response = await anthropic.messages.create({ 36 model: 'claude-sonnet-4-20250514', 37 max_tokens: 200, 38 messages: [ 39 { 40 role: 'user', 41 content: `Summarize this conversation in 2-3 sentences: 42 43${messages.map(m => `${m.role}: ${m.content}`).join('\n')}` 44 } 45 ] 46 }) 47 48 return response.content[0].type === 'text' 49 ? response.content[0].text 50 : '' 51}

Usage Instructions#

  1. Define clear roles - Start system prompts with the AI's role and purpose
  2. Set constraints - Explicitly state what the AI should and shouldn't do
  3. Specify output format - Tell the AI exactly how to structure responses
  4. Use examples - Provide few-shot examples for complex tasks
  5. Validate outputs - Parse and validate structured responses with Zod

Best Practices#

  1. Be specific - Vague prompts produce vague results
  2. Show, don't just tell - Include examples of desired outputs
  3. Separate concerns - Use system prompt for behavior, user message for task
  4. Handle edge cases - Tell the AI what to do when uncertain
  5. Iterate and test - Refine prompts based on real outputs
  6. Version your prompts - Track changes to important prompts
  7. Use structured output - Request JSON for data extraction
  8. Set constraints early - Put important rules at the beginning