Due prompt, quattro condizioni, otto sessioni: cosa cambia quando una regola di comunicazione incontra una funzione di Fibonacci.
Se chiedi a un assistente IA:
Who was Dante Alighieri?
Ottieni una biografia. Aggiungi una piccola istruzione:
no-fluff Who was Dante Alighieri?
Nella mia prova, la risposta è diventata più breve. Fin qui, nulla di particolarmente sorprendente.
Ora sostituisci la domanda con:
no-fluff Develop a fibonacci function
L'agente dovrebbe scrivere una spiegazione più breve, una funzione più corta o una soluzione con meno funzionalità? Dovrebbe comunque creare file ed eseguire test?
Nel mio precedente articolo sulla sicofanzia, ho esplorato come alcune istruzioni comportamentali potessero spingere gli agenti di coding a mettere in discussione le mie richieste, invece di assecondarle subito. Questa volta volevo indagare un altro confine: un'istruzione, che di primo acchito sembra riguardare la comunicazione tra utente e assistente, può influenzare anche il codice e perfino come un agente svolge il suo lavoro?
Ho confrontato due richieste, discriminandole con quattro condizioni. Un totale di otto sessioni all'interno di un unico piccolo esperimento esplorativo, motivato solo dalla mia curiosità di capire: non un benchmark, né una misura controllata del comportamento di tutti i modelli.
Le differenze non si sono fermate al numero di parole nelle risposte.
Indice
-
Oltre il "No Fluff": la stratificazione semantica negli agenti di coding
- Indice
- 1. L'esperimento: due richieste, quattro condizioni
- 2. Dante: meno testo, ma anche una diversa selezione delle informazioni
- Cosa resta e cosa scompare
- 3. Fibonacci: cambia anche ciò che l'agente consegna
- 4. La funzione: non si tratta soltanto di togliere commenti
- 5. La mia interpretazione: la stratificazione semantica negli LLM
- Discutiamone
1. L'esperimento: due richieste, quattro condizioni
Sono partito dalle stesse due richieste:
Who was Dante Alighieri?
Develop a fibonacci function
Per ciascuna ho confrontato quattro condizioni:
- Default: nessuna istruzione aggiuntiva.
-
No-fluff: il prefisso letterale
no-fluff. -
Caveman: invocazione esplicita della skill
caveman. - Zero-fluff: invocazione esplicita di una skill minima di comunicazione.
Nelle due condizioni con skill, le richieste di coding erano:
/skill:caveman Develop a fibonacci function
/skill:zero-fluff Develop a fibonacci function
Le sessioni si sono svolte in Pi. Il modello usato era gemini-3.8-flash-tiered. Gli export delle sessioni sono tutti consultabili su GitHub.
C'è subito una distinzione importante: il comando di una skill non è soltanto una parola in più nel prompt. L'ambiente dell'agente lo espande in un insieme di istruzioni. La skill caveman contiene una specifica più lunga, che si apre così:
Respond terse like smart caveman. All technical substance stay. Only fluff die.
In sostanza: rispondi in modo telegrafico, da cavernicolo intelligente; mantieni tutta la sostanza tecnica, elimina soltanto il superfluo.
La skill zero-fluff, invece, era definita così:
---
name: zero-fluff
description: Maintain dry and synthesis-oriented communication.
disable-model-invocation: true
---
# The Rule
Never use words that do not serve mutual understanding.
L'ultima frase compariva anche nella skill del mio precedente articolo. Qui rimane da sola: «Non usare mai parole che non servano alla comprensione reciproca».
Non dice «scrivi la risposta più breve possibile». Non parla di algoritmi, validazione degli input, file o test. Esprime un criterio: conserva ciò che serve a capirsi.
Volevo vedere come questo criterio avrebbe influenzato in concreto il lavoro dell'agente.
2. Dante: meno testo, ma anche una diversa selezione delle informazioni
Il primo confronto sembrava piuttosto semplice:
| Condizione | Caratteri della risposta finale, inclusi Markdown e spazi | Forma della risposta |
|---|---|---|
| Default | 2167 | Un profilo esteso, con sezioni, sottopunti e informazioni di contesto |
| No-fluff | 872 | Un'introduzione e quattro punti sintetici |
| Caveman | 384 | Tre brevi paragrafi, senza titoli né elenchi |
| Zero-fluff | 927 | Un'introduzione e quattro punti strutturati, in prosa ordinaria |
Cosa resta e cosa scompare
Tutte e quattro le risposte presentavano Dante come un poeta italiano di Firenze, riportavano gli anni 1265–1321, citavano la Commedia e le sue tre cantiche, descrivevano l'uso del toscano al posto del latino e ricordavano l'esilio del 1302 e la morte a Ravenna. Tutte nominavano anche la Vita Nuova — scritta Vita Nova nella risposta caveman — e il De Vulgari Eloquentia.
Piccola parentesi: Vita Nuova è il titolo nella forma tradizionale e più diffusa nella storia editoriale e scolastica italiana; Vita Nova è la forma latina originaria, presente nei manoscritti più antichi e riproposta da importanti edizioni critiche.
Le differenze diventano più chiare se confrontiamo i contenuti:
- La risposta default citava le guide di Dante lungo il viaggio della Divina Commedia; includeva il Convivio, le Tre Corone e un resoconto più ampio della vita politica di Dante.
- No-fluff manteneva quattro aree principali: la Commedia, l'importanza linguistica di Dante, le altre opere e la politica. Eliminava buona parte dei dettagli di contorno.
- Caveman comprimeva di più. Non ripeteva nemmeno il nome di Dante all'inizio, affidandosi al contesto della domanda. Conservava il nucleo biografico, ma citava meno opere.
- Zero-fluff rimaneva vicino alla risposta strutturata di no-fluff. Era leggermente più lungo, con dettagli più espliciti sull'appartenenza politica di Dante e sul De Monarchia.
Nelle quattro condizioni, a cambiare non era soltanto la quantità delle parole usate, ma soprattutto la selezione delle informazioni.
Ecco la versione caveman:
Italian poet (1265–1321) from Florence. Best known for _Divine Comedy_ (_Inferno_, _Purgatorio_, _Paradiso_).
Established Tuscan vernacular as literary standard instead of Latin. Called father of modern Italian.
Exiled from Florence in 1302 during political conflict between Black and White Guelphs. Died in Ravenna. Major works also include _Vita Nova_ and _De Vulgari Eloquentia_.
Ed ecco la risposta zero-fluff:
**Dante Alighieri** (c. 1265–1321) was an Italian poet, philosopher, and political thinker from Florence, best known as the author of the _Divine Comedy_ (_Divina Commedia_).
### Key Aspects
- **Major Work:** The _Divine Comedy_, an epic poem describing the soul's journey through Hell (_Inferno_), Purgatory (_Purgatorio_), and Paradise (_Paradiso_).
- **Linguistic Impact:** Often called the "Father of the Italian Language" for writing in the Tuscan vernacular rather than Latin, establishing standard literary Italian.
- **Other Works:** _Vita Nuova_ (love poetry dedicated to Beatrice), _De Monarchia_ (political treatise on universal empire), and _De Vulgari Eloquentia_ (treatise on vernacular eloquence).
- **Political Life:** A White Guelph in Florentine politics; exiled permanently in 1302 following a rival faction's coup, spending his remaining life in various northern Italian cities until his death in Ravenna.
Su Dante, caveman comprimeva maggiormente, mentre zero-fluff sembrava selezionare una sintesi strutturata, non il minimo testo possibile.
Ma il confronto su Fibonacci si è rivelato più interessante.
3. Fibonacci: cambia anche ciò che l'agente consegna
La richiesta di coding era aperta:
Develop a fibonacci function
Non avevo specificato un linguaggio. Non avevo chiesto un generatore della sequenza, un'interfaccia a riga di comando, una suite di test o se l'agente doveva creare file anziché rispondere con uno snippet. Avevo dato per scontato che in matematica la sequenza di Fibonacci (che prende il nome dal matematico pisano del XIII secolo Leonardo Fibonacci) è indicata come F_n e definita ricorsivamente: con F_0 = 0, F_1 = 1 e con i restanti numeri descritti come F_n = F_{n-1} + F_{n-2}.
Piccola parentesi: "to develop" è un concetto ampio che probabilmente include semanticamente l'atto di creare file e scrivere codice e che forse non si limita solo a questo.
Questa libertà, che derivava dall'ambiguità della richiesta, è diventata parte del risultato.
| Condizione | Cosa ha prodotto l'agente | Verifiche registrate nella sessione | Chiamate ai tool |
|---|---|---|---|
| Default | Un modulo Python con funzione, generatore della sequenza, documentazione, CLI e un file di test separato | Sette metodi unittest superati; eseguiti anche esempi della CLI | 10 |
| No-fluff | Un modulo Python con funzione e generatore, meno documentazione e un file di test separato; nessuna CLI | Cinque metodi unittest superati | 5 |
| Caveman | Una funzione e un'asserzione nella chat; nessun file Python scritto | L'asserzione è stata mostrata, non eseguita | 1 |
| Zero-fluff | Un solo file Python con la funzione e un'asserzione incorporata | L'agente ha avviato lo script con l'asserzione senza errori | 8 |
Tutte e quattro le funzioni usavano un approccio iterativo, non ricorsivo.
Cambiava, però, l'ampiezza della soluzione.
La risposta finale di coding più breve non corrispondeva alla minore attività dell'agente, ma più tool non significa automaticamente più verifica.
Zero-fluff effettuava otto chiamate ai tool anziché una di caveman. Tuttavia, cinque servivano a esplorare il filesystem e non erano passaggi di verifica utili.
4. La funzione: non si tratta soltanto di togliere commenti
Confrontare le risposte senza farne menzione nasconderebbe una differenza importante: no-fluff mostrava sia la funzione sia un generatore, mentre zero-fluff mostrava soltanto la funzione.
Ho quindi confrontato la funzione in sé tra le quattro condizioni.
Ecco la versione default:
def fibonacci(n: int) -> int:
if isinstance(n, bool) or not isinstance(n, int):
raise TypeError(f"n must be an integer, got {type(n).__name__}")
if n < 0:
raise ValueError("n must be a non-negative integer")
if n == 0:
return 0
if n == 1:
return 1
a, b = 0, 1
for _ in range(2, n + 1):
a, b = b, a + b
return b
Ecco quella no-fluff:
def fibonacci(n: int) -> int:
"""Return the n-th Fibonacci number (0-indexed: F(0) = 0, F(1) = 1).
Time Complexity: O(n)
Space Complexity: O(1)
"""
if not isinstance(n, int):
raise TypeError(f"n must be an integer, got {type(n).__name__}")
if n < 0:
raise ValueError("n must be non-negative")
if n <= 1:
return n
a, b = 0, 1
for _ in range(2, n + 1):
a, b = b, a + b
return b
Ed ecco la funzione caveman:
def fibonacci(n: int) -> int:
if n < 0:
raise ValueError("n must be non-negative")
if n <= 1:
return n
prev, curr = 0, 1
for _ in range(2, n + 1):
prev, curr = curr, prev + curr
return curr
E quella zero-fluff:
def fibonacci(n: int) -> int:
"""Return the nth Fibonacci number (0-indexed)."""
if n < 0:
raise ValueError("n must be a non-negative integer")
a, b = 0, 1
for _ in range(n):
a, b = b, a + b
return a
La zero-fluff non si limita a ridurre la documentazione. Elimina il controllo esplicito del tipo e gestisce i casi base attraverso il ciclo, invece di farlo con uno o due rami logici separati.
Nelle quattro implementazioni cambia anche il comportamento su alcuni input:
| Input | Default | No-fluff | Caveman | Zero-fluff |
|---|---|---|---|---|
True |
TypeError |
Restituisce True
|
Restituisce True
|
Restituisce 1
|
0.5 |
TypeError |
TypeError |
Restituisce 0.5
|
TypeError da range
|
Ecco altre differenze significative su cui porre attenzione:
- tra default e no-fluff cambia l'ampiezza della soluzione, ma in entrambe le sessioni l'agente scrive file e svolge separatamente i test.
- tra caveman e zero-fluff cambia anche il significato operativo della consegna: mostrare una soluzione contro produrre e invocare un solo file che includeva implementazione e una semplice autoverifica.
5. La mia interpretazione: la stratificazione semantica negli LLM
Chiamo stratificazione semantica negli LLM l'ipotesi interpretativa con cui sto leggendo questo esperimento: per cui ogni parola aggiunta al contesto eredita una stratificazione di senso.
Intendo questo: un'espressione può portare con sé più aspettative collegate.
Un'istruzione può orientare criteri applicabili a più dimensioni del compito, oltre quella che il suo autore intendeva modificare. Un'indicazione rivolta a un ambito può influenzare altri ambiti.
"No fluff" può suggerire meno spiegazioni, meno commenti, un esempio più piccolo o un'interpretazione più ristretta di ciò che occorre consegnare. Una regola sulla "comprensione reciproca" può diventare un criterio di selezione anche nel coding.
La mia ipotesi è che i concetti all'interno degli LLM non sono compartimenti stagni (dizionari separati per "storia" e "programmazione"), ma sono proiettati su un continuum semantico.
Questo esperimento, però, ha solo la valenza di un gioco dettato dalla curiosità.
C'è poi un punto da sottolineare, anche più banale: un effetto può essere inatteso dal punto di vista dell'utente, senza essere estraneo a un'interpretazione plausibile dell'istruzione.
Nella progettazione di skill, prompt e system prompt, questa distinzione conta più di una spiegazione sul funzionamento interno del modello:
L'ambito che abbiamo in mente quando scriviamo una regola non corrisponde necessariamente all'ambito all'interno del quale l'agente la applica.
Discutiamone
Ti è mai capitato che un'istruzione pensata per altro cambiasse il codice o le azioni del tuo agente? Come verificheresti che una skill rimanga nell'ambito per cui l'hai progettata?
Fammi sapere cosa ne pensi nei commenti qui sotto!
Top comments (0)