Il problema: «AutoGen» oggi indica almeno tre cose diverse
Cerchi un tutorial su AutoGen, copi from autogen import AssistantAgent, installi un pacchetto e l'esempio non gira, oppure gira ma con un'API diversa da quella del testo. Non è sfortuna:
il nome copre un articolo di ricerca del 2023, un framework mantenuto da una comunità (AG2) e una linea Microsoft ora archiviata, e il pacchetto che installi decide quale API hai. Questo articolo parte da lì,
perché è la cosa che ti fa perdere più tempo, poi spiega il modello conversazionale con listati eseguiti in locale, senza modelli, con agenti che seguono un copione.
Lo stato dei pacchetti al 2026-11-12, letto sul registro PyPI e sulle pagine ufficiali, è nella tabella.
| Pacchetto PyPI | Versione | Che cosa è |
|---|---|---|
autogen | 0.14.1 | Il framework «classico» (import autogen, ConversableAgent, GroupChat), mantenuto da AG2 |
ag2 | 1.3.1 | AG2 dalla versione 1.0: nuovo framework, si importa come ag2; non fornisce più il nome autogen |
autogen-agentchat | 0.7.5 | La linea Microsoft (AgentChat); la documentazione stabile dichiara il progetto archiviato |
pyautogen | 0.10.0 | Pacchetto «proxy» di autogen-agentchat, secondo la sua descrizione sul registro |
agent-framework | 1.26.0 | Microsoft Agent Framework, il successore indicato da Microsoft |
Il punto della tabella è che gli esempi di questo articolo (ConversableAgent, GroupChat) appartengono alla riga autogen. Il README del repository ag2ai/ag2 dice che quelle classi
stanno ora in «AG2 Classic» e consiglia pip install ag2-classic, ma al 2026-11-12 quel nome non esiste su PyPI (risposta 404 dall'API JSON del registro); il README del repository ag2ai/ag2-classic indica invece
pip install autogen[openai]. Abbiamo quindi installato autogen 0.14.1 in un ambiente virtuale pulito con Python 3.14.4 ed eseguito lì tutti i listati. Se leggi il README e provi ag2-classic, l'installazione fallisce: è una discrepanza della documentazione, non un tuo errore.
Il modello conversazionale
L'articolo che ha presentato il progetto (Wu e coautori, arXiv:2308.08155, agosto 2023) lo descrive come un framework open source con cui costruire applicazioni basate su modelli linguistici tramite più agenti che conversano per completare compiti; gli agenti sono personalizzabili, «conversabili» e lavorano in modi che combinano modelli, input umano e strumenti. L'idea di fondo è che la conversazione sia la primitiva di coordinamento: invece di un grafo di passi (come in LangGraph) o di una sequenza di task assegnati a ruoli (come in CrewAI), gli agenti si scambiano messaggi e ciascuno risponde in base alla storia. Il vantaggio è la flessibilità: non scrivi in anticipo tutti i percorsi. Il costo è speculare: non sai in anticipo quanti turni serviranno, né come finirà.
Il blocco usa due ConversableAgent con llm_config=False, cioè senza modello, e dà a ciascuno una funzione di risposta registrata con register_reply che segue un copione. È il modo più economico di vedere
la meccanica: chi parla, quando si ferma, che cosa finisce nella storia. Il Revisore avvia la conversazione, l'Analista dà una bozza sbagliata, il Revisore la contesta, l'Analista corregge e scrive TERMINATE;
is_termination_msg riconosce quella parola e chiude il giro, e max_turns è un tetto di sicurezza.
from autogen import ConversableAgent
def copione(frasi):
"""Funzione di risposta che segue un copione: nessun modello, nessuna rete."""
it = iter(frasi)
def _reply(recipient, messages=None, sender=None, config=None):
return True, next(it) # (True = risposta definitiva, testo)
return _reply
def finito(msg):
return "TERMINATE" in (msg.get("content") or "")
revisore = ConversableAgent("Revisore", llm_config=False, human_input_mode="NEVER",
is_termination_msg=finito)
analista = ConversableAgent("Analista", llm_config=False, human_input_mode="NEVER",
is_termination_msg=finito)
revisore.register_reply([ConversableAgent, None], copione(["Il numero non torna, ricontrolla."]))
analista.register_reply([ConversableAgent, None],
copione(["Bozza: 3 ordini in ritardo.", "Corretto: 2 ordini in ritardo. TERMINATE"]))
esito = revisore.initiate_chat(analista, message="Quanti ordini sono in ritardo?",
max_turns=6, silent=True)
for m in esito.chat_history:
print(f'{m["name"]:9}: {m["content"]}')
print("messaggi:", len(esito.chat_history))
# Output:
# Revisore : Quanti ordini sono in ritardo?
# Analista : Bozza: 3 ordini in ritardo.
# Revisore : Il numero non torna, ricontrolla.
# Analista : Corretto: 2 ordini in ritardo. TERMINATE
# messaggi: 4
Eseguito due volte con autogen 0.14.1, con uscita identica. La storia contiene quattro messaggi, nell'ordine in cui sono stati scambiati, ed è anche la memoria condivisa: ogni agente vede ciò che è stato detto. Se togli
is_termination_msg, la conversazione non si ferma sulla parola chiave e prosegue fino ai limiti (qui max_turns, e l'esaurimento del copione solleverebbe StopIteration). Con un modello vero la parola chiave
è un patto debole: dipende dal fatto che il modello la scriva davvero, e per questo serve sempre anche un tetto numerico.
Che cosa vale se non scrivi il parametro
Il comportamento di un agente dipende da pochi parametri, e i tutorial tacciono i valori predefiniti. Il blocco li legge dalla firma di ConversableAgent e di GroupChat nella versione installata, e prova un
valore inventato di human_input_mode per vedere se viene respinto.
import inspect
from autogen import ConversableAgent, GroupChat
# Che cosa vale se non scrivi il parametro (letto dalla firma, autogen 0.14.1)
firma = inspect.signature(ConversableAgent.__init__).parameters
for nome in ("human_input_mode", "max_consecutive_auto_reply", "code_execution_config", "llm_config"):
print(f"{nome:28} = {firma[nome].default!r}")
print("MAX_CONSECUTIVE_AUTO_REPLY =", ConversableAgent.MAX_CONSECUTIVE_AUTO_REPLY)
firma = inspect.signature(GroupChat).parameters
for nome in ("max_round", "speaker_selection_method"):
print(f"GroupChat.{nome:19} = {firma[nome].default!r}")
# Un valore inventato NON viene respinto alla creazione
a = ConversableAgent("x", llm_config=False, human_input_mode="FUNCTION_CALL")
print("human_input_mode inventato accettato:", a.human_input_mode)
# Output:
# human_input_mode = 'TERMINATE'
# max_consecutive_auto_reply = None
# code_execution_config = False
# llm_config = None
# MAX_CONSECUTIVE_AUTO_REPLY = 100
# GroupChat.max_round = 10
# GroupChat.speaker_selection_method = 'auto'
# human_input_mode inventato accettato: FUNCTION_CALL
Tre cose si vedono nell'uscita. human_input_mode vale 'TERMINATE': un agente che non lo specifica si ferma a chiedere input umano quando riceve un messaggio di terminazione o raggiunge il limite di risposte automatiche.
In uno script non interattivo significa rimanere bloccato in attesa di tastiera; per questo i listati usano "NEVER". Il limite max_consecutive_auto_reply vale None e il tetto di classe è 100: un agente che non lo scrive può rispondere fino a cento volte di fila.
Infine il valore inventato FUNCTION_CALL viene accettato senza errore: la docstring elenca solo tre modalità, ALWAYS (chiede a ogni messaggio), TERMINATE e NEVER. Un tutorial che parla di una quarta modalità, o un refuso nel nome, non produce
un errore ma un comportamento che non è quello che credi.
Gruppi di agenti: GroupChat e chi parla
Con più di due agenti serve qualcuno che decida chi parla. GroupChat definisce i partecipanti e le regole, GroupChatManager conduce la conversazione. Il parametro speaker_selection_method
accetta, nella versione installata, quattro valori:
"auto"(il predefinito): un modello legge la conversazione e sceglie chi parla, il che aggiunge almeno una chiamata al modello a ogni turno (non misurato qui)."round_robin": parlano a turno, in ordine; nessuna chiamata di selezione, comportamento prevedibile."random": sceglie a caso tra i partecipanti."manual": chiede a una persona chi deve parlare.
L'elenco ha un ordine di costo e di controllo: auto è il più flessibile e il più oneroso, manual il più controllato, round_robin il più semplice da collaudare. Per provare un gruppo senza modello,
il blocco usa round_robin e tre agenti con copione; il manager ha una condizione di terminazione sulla parola TERMINATE e max_round a 6 come tetto. Il manager stampa un resoconto: lo zittiamo con
redirect_stdout per mostrare solo la storia dei messaggi.
import contextlib
import io
from autogen import ConversableAgent, GroupChat, GroupChatManager
def copione(frasi):
it = iter(frasi)
def _reply(recipient, messages=None, sender=None, config=None):
return True, next(it)
return _reply
def agente(nome, frasi):
a = ConversableAgent(nome, llm_config=False, human_input_mode="NEVER")
a.register_reply([ConversableAgent, None], copione(frasi))
return a
autore = agente("Autore", ["Funzione scritta: ordina(lista).", "Aggiunto il caso lista vuota."])
revisore = agente("Revisore", ["Manca il caso lista vuota.", "Ora va bene. TERMINATE"])
collaudatore = agente("Collaudatore", ["Test scritti: 3 casi."])
utente = ConversableAgent("Utente", llm_config=False, human_input_mode="NEVER")
gruppo = GroupChat(agents=[autore, revisore, collaudatore], messages=[], max_round=6,
speaker_selection_method="round_robin") # tocca a turno, nessun modello sceglie
manager = GroupChatManager(groupchat=gruppo, llm_config=False,
is_termination_msg=lambda m: "TERMINATE" in (m.get("content") or ""))
with contextlib.redirect_stdout(io.StringIO()): # il manager stampa il resoconto: lo zittiamo
utente.initiate_chat(manager, message="Scrivete una funzione che ordina una lista.", silent=True)
for m in gruppo.messages:
print(f'{m["name"]:12}: {m["content"]}')
# Output:
# Utente : Scrivete una funzione che ordina una lista.
# Autore : Funzione scritta: ordina(lista).
# Revisore : Manca il caso lista vuota.
# Collaudatore: Test scritti: 3 casi.
# Autore : Aggiunto il caso lista vuota.
# Revisore : Ora va bene. TERMINATE
Eseguito due volte, con uscita identica. L'ordine Autore, Revisore, Collaudatore, Autore, Revisore è quello di round_robin, e la conversazione si ferma al sesto messaggio perché il Revisore scrive TERMINATE. Con auto l'ordine dipenderebbe da un modello e potrebbe cambiare
a ogni esecuzione: non lo abbiamo eseguito. Nota che il Collaudatore parla una volta sola prima della chiusura: in un gruppo reale un agente può ritrovarsi a non parlare mai, o a parlare troppo, e va controllato.
Il ciclo scrivi-esegui-correggi
Il pattern per cui AutoGen è più noto fa lavorare insieme due agenti: uno scrive codice, l'altro lo esegue e restituisce l'esito, errori compresi; chi ha scritto legge il traceback e riprova. Nel blocco l'assistente è a copione
(un primo tentativo che divide per zero, un secondo corretto) e l'esecutore è un ConversableAgent con code_execution_config che usa LocalCommandLineCodeExecutor in una cartella temporanea, che sparisce alla fine.
Il codice viene davvero eseguito, in un sottoprocesso locale: è l'unico listato dell'articolo che lo fa.
import contextlib
import io
import tempfile
from autogen import ConversableAgent
from autogen.coding import LocalCommandLineCodeExecutor
def copione(frasi):
it = iter(frasi)
def _reply(recipient, messages=None, sender=None, config=None):
return True, next(it)
return _reply
FENCE = "`" * 3
tentativo_1 = f"{FENCE}python\nprint(sum([1, 2, 3]) / len([]))\n{FENCE}" # divide per zero
tentativo_2 = f"{FENCE}python\nvalori = [1, 2, 3]\nprint(sum(valori) / len(valori))\n{FENCE}"
assistente = ConversableAgent("Assistente", llm_config=False, human_input_mode="NEVER",
is_termination_msg=lambda m: "TERMINATE" in (m.get("content") or ""))
assistente.register_reply([ConversableAgent, None],
copione([tentativo_1, tentativo_2, "La media è 2.0. TERMINATE"]))
with tempfile.TemporaryDirectory() as cartella: # il codice gira qui, poi la cartella sparisce
esecutore = LocalCommandLineCodeExecutor(work_dir=cartella, timeout=10)
proxy = ConversableAgent("Esecutore", llm_config=False, human_input_mode="NEVER",
code_execution_config={"executor": esecutore},
is_termination_msg=lambda m: "TERMINATE" in (m.get("content") or ""))
with contextlib.redirect_stdout(io.StringIO()):
proxy.initiate_chat(assistente, message="Calcola la media di 1, 2, 3.", max_turns=8, silent=True)
messaggi = proxy.chat_messages[assistente]
for m in messaggi:
righe = [r for r in m["content"].splitlines() if r.strip() and "`" * 3 not in r]
if m["name"] == "Esecutore" and righe[0].startswith("exitcode"):
righe = [righe[0], righe[-1]] # esito e ultima riga (il traceback contiene percorsi locali)
print(f'{m["name"]:10}:', " / ".join(righe))
# Output:
# Esecutore : Calcola la media di 1, 2, 3.
# Assistente: print(sum([1, 2, 3]) / len([]))
# Esecutore : exitcode: 1 (execution failed) / ZeroDivisionError: division by zero
# Assistente: valori = [1, 2, 3] / print(sum(valori) / len(valori))
# Esecutore : exitcode: 0 (execution succeeded) / Code output: 2.0
# Assistente: La media è 2.0. TERMINATE
Eseguito due volte con uscita identica. Il primo tentativo termina con exitcode: 1 e ZeroDivisionError; il secondo restituisce 2.0 con exitcode: 0, e l'assistente chiude. Due avvertenze misurate. La prima: l'esecutore chiama il comando python; su una macchina che ha solo
python3 nel PATH l'esecuzione fallisce con FileNotFoundError: [Errno 2] No such file or directory: 'python' (provato con PATH=/usr/bin:/bin), e noi abbiamo eseguito con l'ambiente virtuale attivato. La seconda riguarda la sicurezza:
LocalCommandLineCodeExecutor esegue sulla tua macchina, con i tuoi permessi, codice scritto da un modello. Chiamarlo «ambiente sicuro» sarebbe sbagliato; per qualsiasi uso diverso da un esperimento serve un isolamento (un contenitore, una macchina dedicata, permessi minimi), come discusso in
Security e Safety. In questo articolo non è stato usato Docker.
Che cosa significa «emergente», e dove fa male
Il titolo parla di conversazione emergente: il flusso nasce dai messaggi, non è scritto. È un vantaggio quando il compito è aperto (una revisione che richiede più passaggi), ma ha tre costi che puoi prevedere dal funzionamento. Primo, il numero di turni non è noto: servono sempre un tetto
(max_turns, max_round, max_consecutive_auto_reply) e una condizione di arresto. Secondo, ogni agente vede l'intera storia, quindi ogni chiamata a un modello porta con sé un contesto che cresce a ogni turno: il costo cresce più in fretta del numero di turni (non misurato qui, perché non abbiamo chiamato modelli).
Terzo, la riproducibilità è bassa: due esecuzioni possono dare conversazioni diverse, il che rende difficile il collaudo; per questo le prove di questo articolo usano copioni, e un agente vero si valuta su molti casi, come in
Testing e Evaluation.
Migrare, e scegliere oggi
La documentazione stabile di AutoGen avverte che il progetto è archiviato e non più mantenuto da Microsoft (nessuna correzione di bug o di sicurezza), sconsiglia l'uso in produzione e indirizza i nuovi utenti al Microsoft Agent Framework, con una guida di migrazione. La pagina Microsoft Learn descrive l'Agent Framework come la combinazione delle astrazioni semplici di AutoGen con le funzioni enterprise di Semantic Kernel (stato di sessione, tipi, middleware, telemetria), più flussi di lavoro basati su grafi per l'orchestrazione esplicita; la stessa pagina ricorda, in modo utile per chi sta per costruire un agente, che se puoi scrivere una funzione che risolve il compito conviene usare la funzione. Dal lato AG2, il README dice che la versione 1.0 non è un aggiornamento compatibile con la classica (modello degli agenti, orchestrazione e importazioni sono cambiati) e rimanda a una guida di migrazione per i gruppi.
| La tua situazione | Che cosa conviene |
|---|---|
Hai codice con import autogen che funziona | Fissa la versione di autogen (0.14.1 al 2026-11-12) e non installare ag2 1.x pensando a un aggiornamento |
Hai codice su AutoGen 0.4 / autogen-agentchat | Prevedi la migrazione: il progetto è archiviato, la guida Microsoft porta ad Agent Framework |
| Parti da zero e il flusso è noto | Considera prima un workflow o un grafo, come negli articoli precedenti: la conversazione libera si paga |
| Parti da zero e vuoi la conversazione tra agenti | Valuta Agent Framework o AG2 1.x, leggendo la loro documentazione attuale; qui non li abbiamo eseguiti |
La tabella non dice «usa X»: dice di leggere prima quale riga ti riguarda, perché le righe hanno costi di migrazione diversi. Non abbiamo installato né eseguito agent-framework o ag2 1.x, quindi non possiamo dire come si scrive oggi lo stesso esempio con loro; sappiamo solo, dalle fonti, che l'API è cambiata.
Il coordinamento di più agenti in produzione è il tema dell'articolo successivo, Orchestrazione Multi-Agente: Architetture Production, e il quadro dei framework è nel
primo articolo.
Domande frequenti
AutoGen è ancora mantenuto?
Dipende da quale: la documentazione stabile di Microsoft dichiara il progetto archiviato e non più mantenuto; il framework classico continua nel repository AG2 (pacchetto autogen, 0.14.1 al 2026-11-12). Per il codice nuovo Microsoft indica Agent Framework.
Perché pip install ag2-classic non funziona?
pip install ag2-classic non funziona?Al 2026-11-12 il pacchetto ag2-classic non esiste su PyPI, anche se un README lo cita; l'altro README indica autogen[openai]. Abbiamo installato autogen 0.14.1 e i listati hanno girato.
Come impedisco a una conversazione tra agenti di non finire mai?
Con più limiti insieme: max_turns o max_round, max_consecutive_auto_reply e una condizione di terminazione con is_termination_msg. Il predefinito di max_consecutive_auto_reply è nessun limite per istanza e un tetto di classe di 100, troppo alto per un agente che chiama un modello a pagamento.
Che cosa sai fare adesso
Sai riconoscere quale AutoGen ha scritto un tutorial dal pacchetto e dall'import, e sai installare quello giusto. Sai far conversare due o più agenti, fermarli con una condizione e un tetto, scegliere chi parla in un gruppo, e far scrivere, eseguire e correggere codice sapendo dove l'esecuzione locale è pericolosa e dove si rompe. Sai inoltre provare tutto con agenti a copione prima di collegare un modello. E sai che la decisione di oggi riguarda il futuro del progetto, non solo la sintassi.
Fonti
- AutoGen: Enabling Next-Gen LLM Applications via Multi-Agent Conversation (Wu et al., arXiv:2308.08155) - descrizione originale del framework conversazionale; abstract letto il 2026-11-12
- AutoGen - documentazione stabile (Microsoft) - avviso di progetto archiviato e rinvio ad Agent Framework; consultata il 2026-11-12
- Repository ag2ai/ag2, README - AG2 1.0, nome
ag2, AG2 Classic, non compatibilità con la classica; consultato il 2026-11-12 - Repository ag2ai/ag2-classic, README - installazione del framework classico con
autogen; consultato il 2026-11-12 - Microsoft Agent Framework - Overview (Microsoft Learn) - descrizione del successore e indicazione di preferire una funzione se basta; consultata il 2026-11-12
- AutoGen to Microsoft Agent Framework Migration Guide (Microsoft Learn) - esistenza della guida di migrazione; consultata il 2026-11-12
- autogen su PyPI - versioni e descrizioni dei pacchetti in tabella, lette con l'API JSON del registro il 2026-11-12. I valori predefiniti e il comportamento dei listati sono osservati eseguendoli, non letti dalla documentazione

Commenti
Caricamento commenti...
Accedi per commentare