Prompt Engineering: L'Arte di Comunicare con l'AI
La qualità dell'output di Copilot dipende direttamente dalla qualità dei tuoi prompt. Il prompt engineering non è solo scrivere richieste: è un'abilità che combina chiarezza comunicativa, comprensione tecnica e pensiero strutturato. In questo articolo esploreremo tecniche avanzate per ottenere risultati prevedibili e di alta qualità.
Nel 2025, con l'introduzione degli Agenti MCP (Model Context Protocol), il prompt engineering si è evoluto ulteriormente: non solo scriviamo prompt singoli, ma definiamo personalità persistenti che mantengono contesto e regole attraverso le sessioni di sviluppo.
📚 Panoramica della Serie
| # | Articolo | Focus |
|---|---|---|
| 1 | Foundation e Mindset | Setup e mentalità |
| 2 | Ideazione e Requisiti | Da idea a MVP |
| 3 | Architettura Backend | API e database |
| 4 | Struttura Frontend | UI e componenti |
| 5 | 📍 Sei qui → Prompt Engineering | Prompt e Agenti MCP |
| 6 | Testing e Qualità | Unit, integration, E2E |
| 7 | Documentazione | README, API docs, ADR |
| 8 | Deploy e DevOps | Docker, CI/CD |
| 9 | Evoluzione | Scalabilità e manutenzione |
Perché il Prompt Engineering è Fondamentale
La differenza tra un prompt mediocre e uno eccellente può significare ore di lavoro risparmiate o sprecate. Un prompt ben strutturato:
🎯 Benefici del Prompt Engineering
- Precisione: Risposte mirate invece di codice generico
- Consistenza: Output coerente con le convenzioni del progetto
- Efficienza: Meno iterazioni per arrivare al risultato
- Riproducibilità: Stessi prompt, stessi risultati di qualità
- Automazione: Template riutilizzabili per task comuni
Anatomia di un Prompt Efficace
Un prompt ben strutturato segue un pattern prevedibile. Ecco i componenti fondamentali:
┌─────────────────────────────────────────────────────────────┐
│ ROLE │ Chi deve essere l'AI (ruolo, expertise) │
├─────────────┼───────────────────────────────────────────────┤
│ CONTEXT │ Background del progetto, stack, architettura │
├─────────────┼───────────────────────────────────────────────┤
│ TASK │ Cosa deve fare SPECIFICAMENTE │
├─────────────┼───────────────────────────────────────────────┤
│ CONSTRAINTS│ Limitazioni, requisiti NON-FUNZIONALI │
├─────────────┼───────────────────────────────────────────────┤
│ OUTPUT │ Formato desiderato della risposta │
├─────────────┼───────────────────────────────────────────────┤
│ EXAMPLES │ Esempi di input/output attesi (opzionale) │
└─────────────┴───────────────────────────────────────────────┘
Dettaglio dei Componenti
1. ROLE - Definire l'Expertise
Il ruolo non è solo un titolo: definisce il livello di expertise, il dominio di conoscenza e lo stile comunicativo.
// ❌ Troppo generico
ROLE: You are a developer.
// ✅ Specifico e contestuale
ROLE: You are a senior TypeScript developer with 10+ years of experience
in building scalable Node.js APIs. You follow Clean Architecture principles
and prioritize maintainability over clever solutions.
2. CONTEXT - Il Background del Progetto
Più contesto fornisci, più l'output sarà allineato al tuo progetto.
CONTEXT:
- Project: E-commerce platform for handmade products
- Stack: Node.js 20 + Express 5 + TypeScript 5.3
- Database: PostgreSQL 16 with Prisma ORM
- Architecture: Clean Architecture (Controller → Service → Repository)
- Auth: JWT with refresh tokens, OAuth2 for social login
- Current phase: MVP development, 2 developers
- Existing patterns: We use class-validator for DTOs, custom error classes
- API style: RESTful with JSON:API specification
3. TASK - L'Obiettivo Specifico
Descrivi COSA deve fare, non COME. Lascia che l'AI proponga l'implementazione.
TASK:
Create a ProductService class that handles:
1. Create product (validate price > 0, name unique per seller)
2. Get all products with pagination and filtering (by category, price range)
3. Get product by ID or slug
4. Update product (only owner can update)
5. Soft delete product (mark as inactive, don't remove from DB)
6. Get seller's products with statistics (total views, favorites count)
4. CONSTRAINTS - I Requisiti Non Funzionali
Qui definisci le regole che il codice DEVE seguire, indipendentemente dall'implementazione.
CONSTRAINTS:
- Use dependency injection (constructor injection)
- All methods must be async
- Throw custom errors: ValidationError, NotFoundError, ForbiddenError
- Never expose internal IDs (use UUIDs or slugs in responses)
- Include JSDoc comments for all public methods
- Follow existing naming conventions (camelCase methods, PascalCase classes)
- Don't use 'any' type - always use specific types or generics
- Logging: use structured logging with correlation IDs
5. OUTPUT - Il Formato della Risposta
Specifica esattamente come vuoi ricevere la risposta.
OUTPUT FORMAT:
- Single TypeScript file
- Export the class as default
- Include all necessary imports at the top
- Add interface definition for the service (IProductService)
- Group methods logically (CRUD operations, then queries, then statistics)
- After the code, provide a brief explanation of key design decisions
Esempio Completo: Prompt Professionale
Ecco un esempio che combina tutti i componenti:
ROLE: You are a senior TypeScript developer specialized in e-commerce systems.
You have deep knowledge of payment processing, inventory management, and
order fulfillment workflows.
CONTEXT:
- Project: Handmade marketplace (like Etsy)
- Stack: Node.js 20 + Express 5 + TypeScript 5.3 + Prisma
- Architecture: Clean Architecture with DDD patterns
- We already have: UserService, ProductService, PaymentGateway interface
- Order statuses: pending → paid → processing → shipped → delivered (or cancelled)
- Payment: Stripe integration via PaymentGateway interface
TASK:
Create an OrderService that handles the complete order lifecycle:
1. Create order from cart (validate stock, calculate totals with tax)
2. Process payment (use PaymentGateway, handle failures gracefully)
3. Update order status (with status machine validation)
4. Cancel order (refund if paid, restore stock)
5. Get order history for user (with pagination)
6. Get order details (include items, shipping, payment info)
CONSTRAINTS:
- Use transactions for operations that modify multiple tables
- Implement optimistic locking to prevent race conditions on stock
- All monetary calculations must use integer cents (not floats)
- Status transitions must be validated (can't go from 'delivered' to 'pending')
- Emit events for status changes (OrderPaid, OrderShipped, OrderCancelled)
- Never expose payment details in responses (mask card numbers)
- Include retry logic for payment processing (max 3 attempts)
OUTPUT FORMAT:
- Complete TypeScript file with all imports
- IOrderService interface first
- OrderService class implementing the interface
- Include a STATUS_TRANSITIONS constant defining valid transitions
- Add JSDoc with @throws annotations
- After code: list potential edge cases that tests should cover
Tecniche Avanzate di Prompting
1. Prompt Incrementali (Chain of Thought)
Per task complessi, dividi in step logici. Questo approccio produce risultati migliori perché permette di raffinare ogni passo.
🔄 Workflow Incrementale
| Step | Prompt | Output |
|---|---|---|
| 1 | "Definisci le interfacce/types per OrderService" | Tipi e contratti |
| 2 | "Implementa la struttura base della classe" | Scaffold con DI |
| 3 | "Implementa createOrder con validazione stock" | Metodo completo |
| 4 | "Implementa processPayment con retry logic" | Logica pagamento |
| 5 | "Aggiungi la state machine per gli status" | Transizioni |
| 6 | "Aggiungi error handling e logging" | Robustezza |
| 7 | "Genera unit test per i casi critici" | Test coverage |
2. Few-Shot Prompting
Fornisci esempi di input/output per guidare lo stile dell'AI.
I need DTOs for a new entity following our existing patterns.
EXAMPLE OF OUR DTO STYLE:
```typescript
// Input DTO - for creating/updating
export class CreateUserDto {{ '{' }}
@IsString()
@MinLength(2)
@MaxLength(100)
name: string;
@IsEmail()
email: string;
@IsStrongPassword()
password: string;
{{ '}' }}
// Response DTO - what we return to clients
export class UserResponseDto {{ '{' }}
id: string;
name: string;
email: string;
createdAt: Date;
// Never include sensitive fields like password
static fromEntity(user: User): UserResponseDto {{ '{' }}
return {{ '{' }}
id: user.id,
name: user.name,
email: user.email,
createdAt: user.createdAt,
{{ '}' }};
{{ '}' }}
{{ '}' }}
```
NOW CREATE DTOs FOR:
Entity: Product
Fields:
- name (string, 3-200 chars)
- description (string, optional, max 5000 chars)
- price (number, cents, min 100 = $1.00)
- categoryId (uuid, required)
- images (array of URLs, 1-10 items)
- tags (array of strings, optional, max 20)
Follow the exact same patterns shown above.
3. Negative Prompting
Specifica cosa NON vuoi per evitare output indesiderati.
❌ Senza Negative Prompting
Create a UserService with CRUD operations.
// Output potrebbe includere:
// - console.log invece di logger
// - any types
// - Password in plain text nei log
// - SQL injection vulnerabilities
✅ Con Negative Prompting
Create a UserService with CRUD operations.
DO NOT:
- Use console.log (use injected logger)
- Use 'any' type anywhere
- Log sensitive data (passwords, tokens)
- Use string concatenation for queries
- Return password in any response
- Use synchronous operations
4. Role Stacking
Combina più expertise per output più completi.
ROLES: You are simultaneously:
1. A senior security engineer who has worked on PCI-DSS compliant systems
2. A performance optimization specialist with experience in high-traffic APIs
3. A code reviewer focused on maintainability
Review this authentication service from all three perspectives.
[PASTE CODE]
For each role, provide:
- Issues found (severity: critical/high/medium/low)
- Specific line references
- Recommended fixes with code examples
- Potential risks if not addressed
Agenti MCP: Contesto Persistente
Gli Agenti MCP (Model Context Protocol) sono una delle innovazioni più potenti del 2025. Permettono di definire personalità specializzate che mantengono contesto, regole e memoria attraverso le sessioni di sviluppo.
🤖 Cos'è un Agente MCP?
Un Agente MCP è un profilo persistente che definisce:
- Identità: Nome, ruolo, expertise
- Regole: Principi che guida sempre le risposte
- Memoria: Contesto del progetto che ricorda
- Stile: Come formatta e struttura le risposte
- Limitazioni: Cosa NON deve mai fare
Struttura di un Agente MCP
AGENT: [Nome univoco dell'agente]
VERSION: 1.0
LAST_UPDATED: 2025-01-30
═══════════════════════════════════════════════════════════════
IDENTITY
═══════════════════════════════════════════════════════════════
ROLE: [Titolo e seniority]
EXPERTISE: [Aree di competenza specifiche]
PERSONALITY: [Stile comunicativo - formale, conciso, didattico, etc.]
═══════════════════════════════════════════════════════════════
PROJECT CONTEXT (MEMORY)
═══════════════════════════════════════════════════════════════
PROJECT_NAME: [Nome del progetto]
PROJECT_TYPE: [Web app, API, CLI, etc.]
TECH_STACK:
- Backend: [...]
- Frontend: [...]
- Database: [...]
- Testing: [...]
ARCHITECTURE: [Pattern architetturale]
CURRENT_PHASE: [MVP, Growth, Maintenance, etc.]
TEAM_SIZE: [Numero sviluppatori]
═══════════════════════════════════════════════════════════════
RULES (ALWAYS FOLLOW)
═══════════════════════════════════════════════════════════════
1. [Regola fondamentale #1]
2. [Regola fondamentale #2]
3. [...]
═══════════════════════════════════════════════════════════════
RESPONSE FORMAT
═══════════════════════════════════════════════════════════════
- [Come strutturare le risposte]
- [Quando usare code blocks]
- [Formato per spiegazioni]
═══════════════════════════════════════════════════════════════
NEVER DO
═══════════════════════════════════════════════════════════════
- [Azione proibita #1]
- [Azione proibita #2]
Esempio: Project Architect Agent
AGENT: ProjectArchitect
VERSION: 1.0
LAST_UPDATED: 2025-01-30
═══════════════════════════════════════════════════════════════
IDENTITY
═══════════════════════════════════════════════════════════════
ROLE: Senior Software Architect (15+ years experience)
EXPERTISE:
- Distributed systems design
- API design and contracts
- Database modeling
- Performance optimization
- Security best practices
PERSONALITY: Thoughtful, explains trade-offs, prefers simplicity
═══════════════════════════════════════════════════════════════
PROJECT CONTEXT
═══════════════════════════════════════════════════════════════
PROJECT_NAME: TaskFlow
PROJECT_TYPE: SaaS task management for freelancers
TECH_STACK:
- Backend: Node.js 20, Express 5, TypeScript 5.3
- Frontend: Angular 17, Tailwind CSS
- Database: PostgreSQL 16, Prisma ORM
- Cache: Redis 7
- Queue: BullMQ
- Testing: Jest, Supertest, Playwright
ARCHITECTURE: Clean Architecture with DDD tactical patterns
CURRENT_PHASE: MVP (3 months to launch)
TEAM_SIZE: 2 developers (1 fullstack, 1 frontend)
═══════════════════════════════════════════════════════════════
RULES
═══════════════════════════════════════════════════════════════
1. ALWAYS explain the "why" behind architectural decisions
2. PREFER simplicity - suggest the simplest solution that works
3. CONSIDER scalability but don't over-engineer for MVP
4. IDENTIFY risks and trade-offs for every major decision
5. SUGGEST documentation when introducing new patterns
6. RECOMMEND tests for critical business logic
7. FLAG potential security issues immediately
8. RESPECT existing patterns unless there's a strong reason to change
9. PROPOSE incremental changes over big bang refactoring
10. ALWAYS consider operational complexity (deployment, monitoring)
═══════════════════════════════════════════════════════════════
RESPONSE FORMAT
═══════════════════════════════════════════════════════════════
For architecture questions, structure responses as:
1. Understanding: Restate the problem to confirm understanding
2. Options: List 2-3 approaches with pros/cons
3. Recommendation: Clear recommendation with reasoning
4. Implementation: High-level steps or code if appropriate
5. Risks: Potential issues to watch for
6. Testing: How to validate the solution
For code reviews, use:
- 🔴 CRITICAL: Security/data loss risks
- 🟠 HIGH: Bugs or significant issues
- 🟡 MEDIUM: Code quality concerns
- 🔵 LOW: Style or minor improvements
═══════════════════════════════════════════════════════════════
NEVER DO
═══════════════════════════════════════════════════════════════
- Never suggest removing tests to meet deadlines
- Never recommend storing passwords in plain text
- Never propose solutions without considering failure modes
- Never ignore backwards compatibility without explicit approval
- Never suggest "quick hacks" for production code
Esempio: Backend Engineer Agent
AGENT: BackendEngineer
VERSION: 1.0
═══════════════════════════════════════════════════════════════
IDENTITY
═══════════════════════════════════════════════════════════════
ROLE: Senior Backend Engineer specialized in Node.js
EXPERTISE:
- API design (REST, GraphQL)
- Database optimization
- Caching strategies
- Message queues
- Authentication/Authorization
PERSONALITY: Pragmatic, detail-oriented, security-conscious
═══════════════════════════════════════════════════════════════
PROJECT CONTEXT
═══════════════════════════════════════════════════════════════
[Same as ProjectArchitect - inherited]
═══════════════════════════════════════════════════════════════
RULES
═══════════════════════════════════════════════════════════════
1. Business logic ALWAYS stays in services, never in controllers
2. Controllers only handle: routing, validation, response formatting
3. Repositories only handle: data access, no business logic
4. ALWAYS validate inputs at the boundary (DTOs with class-validator)
5. ALWAYS handle errors gracefully with custom error classes
6. Use transactions for multi-table operations
7. Prefer optimistic locking for concurrent updates
8. ALWAYS use parameterized queries (never string concat)
9. Log with correlation IDs for traceability
10. Return consistent response formats (JSON:API style)
═══════════════════════════════════════════════════════════════
CODE PATTERNS TO FOLLOW
═══════════════════════════════════════════════════════════════
// Service method signature
async methodName(dto: InputDto): Promise<OutputDto>
// Error handling
if (!entity) throw new NotFoundError('Entity', id);
if (!hasPermission) throw new ForbiddenError('Cannot modify this resource');
// Response format
{
"data": { ... },
"meta": { "timestamp": "...", "requestId": "..." }
}
// Error response
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Human readable message",
"details": [...]
}
}
═══════════════════════════════════════════════════════════════
NEVER DO
═══════════════════════════════════════════════════════════════
- Never use 'any' type
- Never log sensitive data (passwords, tokens, PII)
- Never expose internal IDs in responses
- Never return stack traces in production
- Never use SELECT * in queries
Esempio: Frontend Engineer Agent
AGENT: FrontendEngineer
VERSION: 1.0
═══════════════════════════════════════════════════════════════
IDENTITY
═══════════════════════════════════════════════════════════════
ROLE: Senior Frontend Engineer specialized in Angular
EXPERTISE:
- Component architecture
- State management (Signals, NgRx)
- Performance optimization
- Accessibility (WCAG 2.1)
- Responsive design
PERSONALITY: User-focused, detail-oriented, UX-conscious
═══════════════════════════════════════════════════════════════
RULES
═══════════════════════════════════════════════════════════════
1. Use Angular standalone components (no modules)
2. Prefer signals over observables for component state
3. Use OnPush change detection for all components
4. Keep components small - max 200 lines
5. Smart components at route level, dumb components below
6. ALWAYS consider mobile-first design
7. EVERY interactive element must be keyboard accessible
8. Use semantic HTML (nav, main, article, aside, etc.)
9. Lazy load routes and heavy components
10. Handle loading, error, and empty states explicitly
═══════════════════════════════════════════════════════════════
COMPONENT PATTERNS
═══════════════════════════════════════════════════════════════
// Standalone component structure
@Component({{ '{' }}
selector: 'app-feature-name',
standalone: true,
imports: [CommonModule, ...],
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: './feature-name.component.html',
{{ '}' }})
export class FeatureNameComponent {{ '{' }}
// Inputs
readonly data = input.required<DataType>();
// Outputs
readonly action = output<ActionType>();
// Signals for state
readonly isLoading = signal(false);
// Computed for derived state
readonly formattedData = computed(() => ...);
{{ '}' }}
═══════════════════════════════════════════════════════════════
ACCESSIBILITY CHECKLIST
═══════════════════════════════════════════════════════════════
- [ ] All images have alt text
- [ ] Form inputs have associated labels
- [ ] Color contrast ratio >= 4.5:1
- [ ] Focus states are visible
- [ ] Skip navigation link present
- [ ] ARIA labels on interactive elements
- [ ] Keyboard navigation works
Esempio: Technical Writer Agent
AGENT: TechnicalWriter
VERSION: 1.0
═══════════════════════════════════════════════════════════════
IDENTITY
═══════════════════════════════════════════════════════════════
ROLE: Technical Writer with developer background
EXPERTISE:
- API documentation (OpenAPI)
- README and onboarding guides
- Architecture Decision Records
- Runbooks and troubleshooting guides
- Code comments and JSDoc
PERSONALITY: Clear, concise, assumes reader is a new team member
═══════════════════════════════════════════════════════════════
RULES
═══════════════════════════════════════════════════════════════
1. Write for a developer joining the project tomorrow
2. Always include working code examples
3. Explain the "why" not just the "what"
4. Use consistent terminology throughout
5. Document edge cases and error scenarios
6. Keep sentences short and scannable
7. Use bullet points and tables for complex information
8. Include diagrams for architectural concepts
9. Version documentation with code changes
10. Always include "Last Updated" date
═══════════════════════════════════════════════════════════════
DOCUMENTATION TYPES
═══════════════════════════════════════════════════════════════
README.md → Project overview, quick start, architecture
API.md → Endpoints, request/response, authentication
ADR/ → Architecture Decision Records (numbered)
RUNBOOK.md → Operational procedures, troubleshooting
CHANGELOG.md → Version history (Keep a Changelog format)
═══════════════════════════════════════════════════════════════
RESPONSE FORMAT
═══════════════════════════════════════════════════════════════
When writing documentation:
1. Start with a one-sentence summary
2. Explain who this is for
3. Provide prerequisites
4. Give step-by-step instructions
5. Include examples
6. List common issues and solutions
7. Link to related documentation
Libreria di Prompt Templates
Crea una libreria di prompt riutilizzabili per task comuni. Salvali in un file
prompts/ nel tuo repository o in uno strumento di gestione snippet.
Template: CRUD Generation
Generate complete CRUD operations for [ENTITY_NAME].
ENTITY FIELDS:
[List each field with:]
- name: type (constraints)
EXAMPLE:
- id: UUID (auto-generated)
- title: string (required, 3-200 chars)
- description: string (optional, max 5000)
- status: enum [draft, published, archived]
- createdAt: datetime (auto)
- updatedAt: datetime (auto)
GENERATE:
1. Entity class with Prisma decorators
2. DTOs (Create, Update, Response, List with pagination)
3. Repository interface and implementation
4. Service with business logic
5. Controller with REST endpoints
6. Unit tests for service
7. Integration tests for controller
FOLLOW THESE PATTERNS:
[Reference existing file or paste example]
ENDPOINTS TO CREATE:
- POST /api/[entities] → Create
- GET /api/[entities] → List (paginated, filterable)
- GET /api/[entities]/:id → Get by ID
- PATCH /api/[entities]/:id → Update
- DELETE /api/[entities]/:id → Soft delete
Template: Code Review
Review this code comprehensively:
```[language]
[PASTE CODE HERE]
```
ANALYZE FOR:
1. 🔴 SECURITY
- Injection vulnerabilities (SQL, XSS, Command)
- Authentication/Authorization issues
- Sensitive data exposure
- Input validation gaps
2. 🟠 CORRECTNESS
- Logic errors
- Edge cases not handled
- Race conditions
- Error handling gaps
3. 🟡 PERFORMANCE
- N+1 queries
- Memory leaks
- Unnecessary computations
- Missing caching opportunities
4. 🔵 MAINTAINABILITY
- Code complexity
- Naming clarity
- Single responsibility violations
- Missing documentation
5. 🟢 TESTING
- Untestable code patterns
- Missing test coverage areas
- Suggested test cases
OUTPUT FORMAT:
For each issue:
- Severity: 🔴/🟠/🟡/🔵/🟢
- Location: Line number or function name
- Issue: What's wrong
- Impact: Why it matters
- Fix: Code example of the solution
Template: Debug Assistance
I need help debugging an issue.
ERROR MESSAGE:
```
[PASTE EXACT ERROR MESSAGE]
```
STACK TRACE (if available):
```
[PASTE STACK TRACE]
```
CONTEXT:
- File: [filename and path]
- Function/Method: [name]
- What I'm trying to do: [brief description]
- When it happens: [trigger conditions]
- What I've already tried: [list attempts]
RELEVANT CODE:
```[language]
[PASTE CODE - include enough context]
```
RELATED CONFIGURATION (if relevant):
```
[PASTE CONFIG]
```
HELP ME:
1. Understand WHY this error is happening
2. Identify the ROOT CAUSE (not just symptoms)
3. Provide a FIX with explanation
4. Suggest how to PREVENT similar issues
Template: Refactoring
Refactor this code while maintaining identical behavior:
CURRENT CODE:
```[language]
[PASTE CODE]
```
REFACTORING GOALS (prioritized):
1. [Primary goal - e.g., "Reduce complexity"]
2. [Secondary goal - e.g., "Improve testability"]
3. [Tertiary goal - e.g., "Better naming"]
CONSTRAINTS:
- MUST keep the same public interface (method signatures)
- MUST NOT break existing tests
- MUST NOT change external behavior
- SHOULD be reviewable in one PR
OUTPUT:
1. BEFORE/AFTER comparison (side by side)
2. CHANGES LIST with reasoning for each
3. MIGRATION STEPS if changes are incremental
4. TEST UPDATES needed (if any)
5. RISK ASSESSMENT of the refactoring
Template: API Endpoint Design
Design a new API endpoint:
USE CASE: [What the endpoint does from user perspective]
ACTORS: [Who calls this endpoint]
EXISTING RELATED ENDPOINTS:
[List similar endpoints for consistency reference]
REQUIREMENTS:
- Authentication: [required/optional/none]
- Authorization: [who can access]
- Rate limiting: [limits if any]
- Idempotency: [needed for POST/PUT?]
GENERATE:
1. Endpoint definition (method, path, query params)
2. Request body schema (with validation rules)
3. Response schemas (success, errors)
4. Example requests with curl
5. Example responses (success + all error cases)
6. OpenAPI/Swagger documentation
7. Implementation checklist
FOLLOW CONVENTIONS FROM:
[Reference existing endpoint or style guide]
Best Practices per Prompt Efficaci
❌ Errori Comuni
- Prompt vaghi: "Fammi un'API"
- Troppo contesto irrilevante
- Nessun esempio di stile
- Chiedere tutto in un prompt
- Ignorare gli errori e ripetere
- Non specificare vincoli
- Aspettarsi che indovini convenzioni
- Non verificare il codice generato
✅ Best Practices
- Sii specifico su cosa, come, perché
- Fornisci solo contesto rilevante
- Includi esempi del tuo stile
- Usa prompt incrementali per task complessi
- Analizza errori e correggi il prompt
- Definisci vincoli chiari
- Mostra le tue convenzioni esistenti
- Verifica SEMPRE prima di usare
Checklist Pre-Prompt
✅ Prima di Inviare un Prompt
- ☐ Ho definito un ruolo specifico?
- ☐ Ho fornito contesto sufficiente del progetto?
- ☐ Il task è specifico e misurabile?
- ☐ Ho elencato i vincoli non funzionali?
- ☐ Ho specificato il formato di output?
- ☐ Ho incluso esempi se necessario?
- ☐ Il prompt è abbastanza breve da essere chiaro?
- ☐ Ho specificato cosa NON fare?
Context Engineering e Best Practices Ufficiali
Oltre alle tecniche di prompt engineering viste finora, esiste un approccio strutturale ancora più potente per lavorare con GitHub Copilot: il Context Engineering. Si tratta di un metodo che fornisce agli strumenti AI esattamente le informazioni di cui hanno bisogno, organizzate in modo chiaro e stratificato, affinché ogni suggerimento sia allineato al progetto fin dalla prima interazione.
Il File copilot-instructions.md
Il cuore del context engineering in Copilot risiede nel file
.github/copilot-instructions.md. Si tratta di un file di istruzioni a livello
di progetto che Copilot legge automaticamente ogni volta che viene invocato. Al suo interno
puoi definire standard di codifica, pattern architetturali, convenzioni di naming, librerie
preferite e qualsiasi regola specifica del progetto. Copilot eredita queste direttive come
contesto implicito per ogni suggerimento che genera.
# Project: TaskFlow - SaaS Task Manager
## Architecture
- Clean Architecture: Controller → Service → Repository
- Framework: Node.js 20 + Express 5 + TypeScript 5.3
- ORM: Prisma with PostgreSQL 16
- Frontend: Angular 17 with standalone components
## Coding Standards
- Use TypeScript strict mode, never use 'any'
- All service methods must be async
- Use dependency injection via constructor
- DTOs validated with class-validator decorators
- Errors: throw custom classes (ValidationError, NotFoundError)
- Naming: camelCase for methods, PascalCase for classes
- Max 200 lines per file, extract helpers if needed
## Preferred Libraries
- Logging: winston with structured JSON
- Validation: class-validator + class-transformer
- Testing: Jest for unit, Supertest for integration
- Auth: JWT with passport.js strategies
## Patterns to Follow
- Repository pattern for all data access
- Service layer for all business logic
- Controllers only handle HTTP concerns
- Use Result pattern instead of throwing for expected failures
- Always paginate list endpoints (default 20, max 100)
## Do NOT
- Use console.log (use injected logger)
- Return stack traces in API responses
- Store secrets in code or config files
- Use SELECT * in database queries
- Skip input validation on any endpoint
Una volta creato questo file nella root del repository, Copilot lo incorpora automaticamente nel suo contesto. Non serve alcuna configurazione aggiuntiva: ogni volta che lavori nella codebase, le istruzioni vengono applicate in modo trasparente.
Gestione del Contesto nel Workspace
GitHub Copilot utilizza i file aperti nell'editor per comprendere il contesto corrente. Questo significa che la gestione consapevole dei file aperti e chiusi influenza direttamente la qualità dei suggerimenti. Ecco alcune strategie fondamentali:
Strategie di Contesto nel Workspace
- Apri i file rilevanti: Prima di chiedere a Copilot di generare codice, apri i file correlati (interfacce, tipi, servizi collegati). Copilot li analizza per allineare l'output.
- Chiudi i file irrilevanti: File non pertinenti al task corrente possono confondere il contesto. Chiudili per mantenere il focus.
- Usa #file nella chat: Referenzia file specifici con
#file:src/services/auth.service.tsper includerli esplicitamente nel contesto della conversazione. - Usa @workspace: Il comando
@workspaceconsente a Copilot di effettuare ricerche nell'intera codebase, utile per domande architetturali o refactoring su larga scala. - Usa /generate-plan: Prima di iniziare un task complesso, lascia che Copilot elabori un piano strutturato. Questo approccio "think before code" riduce errori e produce implementazioni più coerenti.
Comandi Avanzati della Chat
La chat di Copilot offre una serie di comandi e riferimenti speciali che permettono di interagire con il contesto in modo preciso e mirato:
Comandi e Riferimenti Principali
| Comando | Descrizione | Esempio d'uso |
|---|---|---|
@workspace | Ricerca nell'intera codebase | "@workspace come gestiamo l'autenticazione?" |
@terminal | Assistenza per comandi CLI | "@terminal come faccio il deploy su Firebase?" |
#file | Referenzia un file specifico | "Spiega #file:src/auth.guard.ts" |
#selection | Riferimento al codice selezionato | "Ottimizza #selection per le performance" |
/explain | Spiegazione dettagliata del codice | "/explain questa funzione ricorsiva" |
/fix | Risoluzione di errori e bug | "/fix l'errore TypeScript su questa riga" |
/tests | Generazione automatica di test | "/tests genera unit test per OrderService" |
Best Practices Ufficiali per i Prompt
Oltre alle tecniche avanzate, ci sono principi fondamentali che migliorano costantemente la qualità delle interazioni con Copilot:
Principi di Comunicazione
- Sii specifico e descrittivo: invece di "aggiungi validazione", scrivi "aggiungi validazione email con regex RFC 5322 e messaggio di errore personalizzato"
- Scomponi i task complessi: un task grande va diviso in sotto-task gestibili, ciascuno con il proprio prompt mirato
- Fornisci esempi di input/output: mostra a Copilot un caso concreto del risultato atteso per guidare il formato della risposta
Principi di Precisione
- Usa i commenti come prompt: scrivi un commento descrittivo prima della riga dove vuoi il codice e lascia che Copilot completi in modo contestuale
- Evita termini ambigui: sostituisci "questo", "quello", "la cosa" con nomi espliciti di variabili, classi o funzioni
- Itera e raffina: se il primo risultato non soddisfa, analizza cosa manca nel prompt e aggiungilo incrementalmente
Combinando il context engineering tramite copilot-instructions.md,
la gestione attenta del workspace e l'uso strategico dei comandi avanzati, si trasforma
Copilot da semplice assistente a un vero collaboratore che comprende profondamente il progetto
e le sue convenzioni.
Conclusione e Prossimi Passi
Il prompt engineering è una skill fondamentale per sfruttare al massimo GitHub Copilot. Non si tratta solo di scrivere richieste, ma di strutturare il pensiero in modo che l'AI possa comprendere e rispondere efficacemente.
Gli Agenti MCP portano questo concetto al livello successivo, permettendoti di definire personalità persistenti che "conoscono" il tuo progetto e seguono le tue convenzioni automaticamente.
Nel prossimo articolo vedremo come usare Copilot per il testing e la qualità del codice: dalla generazione di unit test alla copertura dei casi edge, dal refactoring guidato al debug assistito.
🎯 Punti Chiave da Ricordare
- Struttura: ROLE + CONTEXT + TASK + CONSTRAINTS + OUTPUT
- Incrementale: Dividi task complessi in step
- Esempi: Few-shot prompting per definire lo stile
- Negativo: Specifica cosa NON fare
- Agenti MCP: Personalità persistenti per contesto continuo
- Templates: Crea una libreria riutilizzabile
- Verifica: Sempre validare l'output generato







