Torna alle guide
Configurazione·21 settembre 2026·Aggiornato il 24 settembre 2026·9 min di lettura

Loop infiniti e utilizzo dei token in Nanobot: diagnosi di una run Dream con limite

L'impostazione indicata dal titolo del bug è stata eliminata, la pull request che avrebbe dovuto ripristinarla è stata chiusa senza merge e l'unico limite rimasto è a livello di processo.

Ultima revisione: .

Un'esecuzione nanobot che sembra un ciclo infinito è in realtà limitata: nel codice sorgente distribuito della v0.3.5 ogni turno dell'agente è limitato da agents.defaults.maxToolIterations, il cui valore predefinito è 200, e un manutentore ha dichiarato pubblicamente che non si tratta di un ciclo letteralmente infinito. Il vero problema è l'uso dei token, perché un'esecuzione che raggiunge quel limite registra 201 turni dell'assistente e reinvia ogni volta un prompt sempre più grande. Capire quale dei due casi hai davanti richiede una diagnosi in quattro domande; la correzione supportata dalle prove non è un valore di configurazione.

Inizia eliminando l'ipotesi più ovvia. La segnalazione upstream è il problema #5781, il cui titolo rimanda a dream.maxIterations, mentre PR #5782 si intitola "fix(dream): enforce configured iteration limit". Quella chiave non esiste nella v0.3.5 e la PR è stata chiusa senza merge il 16 settembre 2026. Un tutorial basato su di essa non configura nulla.

Un chiarimento, perché i risultati della ricerca mostrano il tracker sbagliato. Questa pagina riguarda HKUDS/nanobot, MIT, installato come pacchetto PyPI nanobot-ai — 0.3.5, Python 3.11 o successivo, caricato il 15 settembre 2026. obot-platform/nanobot è un progetto Go diverso, il cui README dichiara la modalità di manutenzione con le issue disabilitate; i suoi numeri di issue non costituiscono una prova in questo contesto. Inoltre, pip install nanobot, senza suffisso, installa un pacchetto di navigazione robotica non correlato.

Cosa è stato segnalato e contro quale versione

Dream è l'attività pianificata di consolidamento della memoria di nanobot, eseguita dal gateway come cron job denominato dream. Non è un'attività di embedding o di indice vettoriale: Kunavo non fornisce alcun modello di embedding e Dream non ne ha bisogno, perché la memoria persistente di nanobot è costituita da semplici file nel workspace e un'esecuzione Dream è normale traffico di chat.

Il problema #5781 è stato aperto il 15 settembre 2026 da BrianMwangi21 contro nanobot v0.3.0, su Python 3.12 con un modello di ragionamento raggiunto tramite OpenRouter. Il sintomo: l'attività Dream alternava read_file su memory/history.jsonl con read_file su una singola SKILL.md, per decine di volte, mentre la traccia di ragionamento riconsiderava dove archiviare un unico piccolo fatto. Sette esecuzioni registrate in circa 26 ore duravano da circa 25 minuti a circa 111 minuti; quelle vicine a 200 chiamate agli strumenti raggiungevano il limite globale e un checkpoint della sessione mostrava runtime_checkpoint.iteration: 164, fase tools_completed, sulla stessa chiamata read_file.

Tretti limiti di ambito accompagnano quei numeri. Si tratta dei log del gateway riferiti da un singolo utente, su un solo modello, in v0.3.0 — nessun manutentore li ha riprodotti e nessuno ha ripetuto i test su v0.3.5. Il problema è contrassegnato come enhancement e priority: p2, non come bug, ed è ancora aperto. Inoltre, questa situazione si è già verificata: issue #3073, un ciclo read_file quasi identico su history.jsonl del 12 aprile 2026, è stato chiuso come non pianificato. Nulla di tutto questo dimostra che nanobot sia generalmente costoso; dimostra che conviene verificare se la propria installazione si sta comportando così.

La chiave deprecata e il limite effettivamente attivo

L'intera confusione deriva da una differenza di versione, e la fonte la risolve. Consultare i due tag di release del 21 settembre 2026:

Chiave di configurazioneIn v0.3.0In v0.3.5Cosa fare ora
dream.maxIterationsValore predefinito 15, contrassegnato # Deprecated: no longer usedRimossa dallo schemaNon scriverla; non configura nulla
dream.maxBatchSizeValore predefinito 20, stesso commento di deprecazioneRimossaNon scriverla
dream.annotateLineAgesValore predefinito true, stesso commento di deprecazioneRimossaNon scriverla
dream.enabledValore predefinito trueValore predefinito trueModificabile nelle impostazioni runtime della WebUI
dream.intervalHValore predefinito 2Valore predefinito 2Modificare config.json; non è un elemento foglia della WebUI
dream.cronNull; override legacyNull; override legacyHa precedenza su intervalH quando impostato
dream.modelOverrideDichiarata, commentata in attesa di implementazioneImplementataSolo nomi di preset, mai un model ID grezzo
agents.defaults.maxToolIterations200200L'unico limite, ed è a livello di processo

Due elementi rendono facile interpretare male quella tabella. Il 200 è vero due volte: è il valore nella configurazione del segnalatore e il valore predefinito distribuito alla riga 129 di nanobot/config/schema.py, identico nel tag v0.3.5 e su main, quindi anche chi non lo ha mai impostato ha 200. Inoltre, non è documentato: il recupero della documentazione di riferimento della configurazione 0.3.5 di nanobot stesso il 21 settembre 2026 ha restituito 488.608 byte di HTML con zero occorrenze di maxToolIterations, e nemmeno il file docs/configuration.md del repository a quel tag ne contiene. Il numero è dimostrabile dal codice sorgente e da un commento di un manutentore, non da una pagina di documentazione: quindi qualsiasi tutorial che citi una cifra diversa va considerato con sospetto.

modelOverride è l'unico rimedio con un vincolo di versione. In v0.3.0 il campo esisteva con il commento in attesa di implementazione e senza alcun codice che lo risolvesse; PR #5107, unita il 27 luglio 2026, lo ha implementato per v0.3.5. La pagina ufficiale sulla memoria 0.3.5 afferma che seleziona una voce denominata da model_presets, accetta solo nomi di preset e che gli identificatori di modello grezzi non sono supportati. La pagina documenta tre chiavi Dream e non menziona alcun limite di iterazioni. Ecco la superficie completa attuale, con il blocco providers su cui si basa trattato nella pagina di configurazione di nanobot:

~/.nanobot/config.json — l'intera superficie Dream v0.3.5
{
  "modelPresets": {
    "dream-cheap": {
      "provider": "kunavo",
      "model": "claude-haiku-4-5",
      "maxTokens": 8192
    }
  },
  "agents": {
    "defaults": {
      "maxToolIterations": 200,
      "dream": {
        "enabled": true,
        "intervalH": 2,
        "modelOverride": "dream-cheap"
      }
    }
  }
}

Si noti cosa non è presente in quel file: un modo per limitare solo Dream. AgentLoop viene costruito una volta con max_iterations dai valori predefiniti del processo, e sia il percorso cron di Dream sia il percorso manuale /dream chiamano process_direct(...) senza alcun argomento di iterazione, così come i subagent. Ridurre il limite lo riduce contemporaneamente per chat, Dream, heartbeat e subagent.

Diagnosticare in quest'ordine

Rispondere a queste quattro domande prima di cambiare qualcosa, perché tre sono gratuite e la quarta indica se le prime tre contano. Le stringhe dei log sono il testo letterale in v0.3.5; le parentesi graffe sono valori runtime.

DomandaDove cercareCosa significa la risposta
1. L'esecuzione si è fermata da sola o ha raggiunto il limite?Log del gateway: Max iterations (200) reached, da agent/loop.pyLa presenza indica un'esecuzione limitata, con circa 201 turni dell'assistente. L'assenza indica che l'esecuzione è terminata prima del limite: il modello ha raggiunto la convergenza oppure l'esecuzione è fallita del tutto e ha registrato Dream cron job failed
2. Il cursore Dream è avanzato?Tre righe distinte in cli/gateway_runtime.py: Dream cron job completed, cursor advanced to …; … completed with no memory changes; cursor advanced to …; Dream cron job did not complete (…); cursor remains at …La terza riga indica che il fail-safe di v0.3.5 sta funzionando: un'esecuzione incompleta lascia il batch da ritentare. Significa anche che lo stesso batch ritorna al tick successivo
3. Lo stesso strumento con gli stessi argomenti si ripete?Le righe Tool call: comprese tra quei due marcatoriStrumento e argomenti identici ripetuti continuamente indicano la non convergenza del modello, che è la conclusione raggiunta upstream. L'unica protezione contro le ripetizioni in v0.3.5 corrisponde a web_fetch e web_search; una ripetizione di read_file non viene intercettata
4. Quanto è costato?llm_usage.sqlite3 nella directory di configurazione, aggregato per data e origine; lato gateway, per chiave e per giorno in usageDream è contrassegnato dream. L'heartbeat è contrassegnato cron, quindi filtrare per "heartbeat" non restituisce nulla

Non è necessario attendere due ore il tick del cron per riprodurlo. Il comando /dream esegue lo stesso job su richiesta e riporta la stessa distinzione nella chat: Dream completed in Ns. o Dream completed in Ns; no memory changes. in caso di successo, rispetto a Dream did not complete after Ns (reason); memory cursor was not advanced. quando non termina. Un'altra modifica di v0.3.5 è importante mentre si cercano prove: i file JSONL delle sessioni sono stati spostati nell'albero sessions/<workspace-id>/ della directory di configurazione, quindi i percorsi di v0.3.0 citati nel thread dell'issue non sono quelli in cui si trova il checkpoint.

Cinque leve e ciò che ciascuna supporta realmente

LevaProve a sostegnoVantaggioso quandoCosto
Aggiornare da v0.3.0 a v0.3.5Il commit 4e2640f, presente in v0.3.5 ma non in v0.3.0, fa avanzare il cursore solo quando il motivo di arresto è completedIl sintomo è il salto della memoria, non la spesaNon accorcia un ciclo non convergente e nessuno ha ripetuto i test su #5781 in 0.3.5
Cambiare il modello per DreamL'unico rimedio con un confronto prima/dopo: nell'audit del segnalatore, un batch su cui un modello ha speso 91 minuti senza terminare è stato completato dall'esecuzione successiva con un modello diverso in circa un minuto, con 6 chiamate agli strumenti, stesso prompt, stessa cronologia, stessi strumentiLa qualità della chat deve restare sul modello costosoRichiede v0.3.5 e un preset definito; in v0.3.0 il campo non risolve nulla
Ridurre maxToolIterationsModificabile nelle impostazioni runtime della WebUI, minimo 1, per webui/settings_runtime.pySi desidera un limite massimo nel caso peggiore durante la diagnosiUn'unica manopola per chat, Dream, heartbeat e subagent; inoltre un'esecuzione limitata non fa avanzare il cursore, quindi lo stesso batch viene ritentato al tick successivo
Rallentare o disabilitare DreamintervalH, oppure dream.enabled nella WebUI; il PR #5407 unito ritira il job persistente quando viene disabilitatoIl consolidamento non vale il suo costo per il proprio carico di lavoroSi perde il consolidamento della memoria, che è la funzionalità
Instradare in modo che il reinvio costi menoIn v0.3.5 esattamente due specifiche dei provider impostano supports_prompt_caching: anthropic e openrouter; il campo ha valore predefinito falseSi accettano esecuzioni lunghe e si vuole che costino menoDipende dal percorso del protocollo configurato e dalla verifica autonoma dell'usage restituito

I due model ID del segnalatore erano deepseek/deepseek-v4-flash-0731 e openai/gpt-5.6-luna come scritti tramite OpenRouter; qui tali ID e i relativi prezzi non sono stati verificati, quindi il confronto va letto come prova del fatto che il modello determina la convergenza, non come raccomandazione dell'uno o dell'altro. Upstream è giunto alla stessa conclusione: annunciando la chiusura del PR #5782 nell'issue #5781, chengyongru ha scritto che un limite fisso alle iterazioni di Dream non risolve il problema di fondo della convergenza dipendente dal modello e può causare il ritento ripetuto di esecuzioni altrimenti valide.

Quanto costa un'esecuzione limitata: calcolo illustrativo

Si tratta di un calcolo illustrativo dei token, non del costo misurato di un'attività e non di un limite di fatturazione. nanobot non pubblica alcun numero di token per esecuzione di Dream, quindi ogni dato qui è un'ipotesi da sostituire con la propria misurazione. Si supponga un'esecuzione che raggiunge il limite a 201 turni dell'assistente, il conteggio dell'audit del segnalatore, ciascuno dei quali reinvia un prompt mantenuto costante a 25.000 token, la sua caratterizzazione del proprio workspace, non un dato pubblicato. Sono 5,03M token di input. I token di output sono esclusi, e un prompt reale cresce con ogni risultato degli strumenti, quindi questa stima sottovaluta un'esecuzione reale in due direzioni contemporaneamente. Le tariffe sono i prezzi attuali del catalogo Kunavo.

ModelloInput per 1MLettura dalla cache per 1MUna sola esecuzione limitata, senza cacheStessa esecuzione, reinvii letti dalla cache
Claude Haiku 4.5$0,70$0,07$3,52$0,37
GPT-5.6 Terra$0,70$0,07$3,52$0,37
Claude Sonnet 5$1,40$0,14$7,04$0,74

L'ultima colonna presuppone il caso migliore, che qui non è stato verificato: il primo invio alla tariffa normale di input e tutti i reinvii 200 serviti come letture dalla cache. Una scrittura nella cache viene fatturata alla propria tariffa, che per alcuni modelli è superiore alla tariffa normale di input; una voce della cache scade; e un prompt che cresce viene riscritto anziché riletto: quindi la differenza tra le ultime due colonne indica l'entità del vantaggio, non un preventivo. Il punto è solo che, in un'esecuzione lunga e ripetitiva, è il reinvio, non il modello, a determinare la spesa.

La presenza dei marcatori della cache sul filo è determinata dalla configurazione di nanobot ed è visibile nel codice sorgente distribuito. Una chiave provider inventata sotto providers viene trattata come un provider compatibile con OpenAI semplice e lascia supports_prompt_caching al valore predefinito false, quindi il client di nanobot non invia marcatori cache_control su quel percorso nemmeno per un model ID con forma Claude. Mantenere il preset sul provider integrato anthropic e sovrascrivere providers.anthropic.apiBase li mantiene attivi. Questa è un'affermazione su ciò che invia il client di nanobot, non su ciò che fa autonomamente un endpoint, e Kunavo non ha testato nanobot in runtime. Prima di mettere a budget un job ricorrente come memorizzato nella cache, leggere l'usage restituito da una chiamata reale: la documentazione sulla cache mostra l'aspetto di una cache funzionante e il riferimento al base URL fornisce entrambe le convenzioni degli endpoint.

L'importo del catalogo Kunavo è un minimo di fatturazione, non un limite: quando l'upstream comunica il proprio addebito, la fattura è il maggiore tra il costo del catalogo e il costo upstream moltiplicato per il markup applicabile. Il ricarico minimo è $10 di credito prepagato: un minimo di finanziamento, non una tariffa per attività né un abbonamento. Consultare i dettagli di fatturazione e l'ottimizzazione dei costi per il metodo di misurazione che sostituisce le ipotesi precedenti.

Verificare la correzione su un'esecuzione

Cambiare una sola cosa, quindi eseguire una volta /dream invece di attendere la pianificazione e controllare i tre marcatori nell'ordine: nessun avviso Max iterations (200) reached, una riga cursor advanced to … anziché cursor remains at …, e un numero plausibile di chiamate agli strumenti nel mezzo. Poi leggere l'addebito registrato dal proprio account per quella finestra, per chiave e per giorno, in usage; lo store di nanobot conta i token, non il denaro. Se si configura l'endpoint per la prima volta, la guida rapida e la pagina di configurazione di nanobot coprono entrambi i percorsi del protocollo, e la creazione di un account Kunavo è il passaggio precedente al finanziamento di una chiave. Si stanno invece confrontando i runtime? nanobot vs OpenClaw affianca le due cadenze in background, e la directory delle API agent indicizza i client per protocollo wire.

Domande frequenti

nanobot è davvero bloccato in un ciclo infinito?

No, e un manutentore lo ha dichiarato pubblicamente. Commentando il problema #5324 il 10 agosto 2026, chengyongru ha scritto che l'agent runner di nanobot è limitato da agents.defaults.maxToolIterations, 200 per impostazione predefinita; quindi non si tratta di un ciclo letteralmente infinito — aggiungendo che un ciclo lungo ma limitato può comunque causare un uso cumulativo molto elevato dei token, perciò l'impatto pratico è reale. Il codice sorgente distribuito della v0.3.5 concorda: max_tool_iterations ha valore predefinito 200 in nanobot/config/schema.py e agent/loop.py registra l'avviso "Max iterations (200) reached" quando un'esecuzione lo raggiunge. Quello che viene chiamato ciclo infinito è un'esecuzione che raggiunge quel limite, che nei log di un segnalatore significava 201 turni dell'assistente rileggendo gli stessi due file.

Perché impostare dream.maxIterations non produce alcun effetto?

Perché il campo non esiste più. In nanobot v0.3.0 la configurazione Dream conteneva max_iterations, max_batch_size e annotate_line_ages, ciascuno contrassegnato nel codice sorgente con il commento "Deprecated: no longer used"; nel tag v0.3.5 tutti e tre sono scomparsi e la classe definisce solo enabled, intervalH, cron e modelOverride. Il manutentore chengyongru ha dichiarato il 15 settembre 2026 che dream.maxIterations era stato intenzionalmente contrassegnato come deprecato e inutilizzato quando Dream è stato spostato sul normale agent loop, e da allora è stato rimosso da main. La pull request che avrebbe dovuto ripristinarlo, #5782, è stata chiusa senza merge il giorno successivo. Scrivere quella chiave in una configurazione v0.3.5 significa scrivere una chiave che lo schema non definisce.

Come posso limitare i token solo per l'attività Dream di nanobot?

Non come budget cumulativo, in nanobot v0.3.5. Nel codice distribuito nulla somma i token di un'esecuzione e la interrompe al raggiungimento di una cifra, e agents.defaults.maxToolIterations è l'unico limite alle iterazioni: è globale al processo e si applica contemporaneamente ai normali turni di chat, a Dream, all'heartbeat e ai sottagenti. Tramite agents.defaults.dream.modelOverride puoi circoscrivere a Dream due elementi: il modello e i limiti per chiamata propri di quel preset, perché ModelPresetConfig contiene maxTokens e contextWindowTokens e dream_runtime() risolve il preset nominato nell'ambiente di runtime in cui viene eseguita l'attività Dream. Questi limiti valgono per ogni singola chiamata, non per il totale dell'esecuzione; quindi 200 chiamate con un maxTokens basso restano 200 chiamate. Anche la pianificazione può essere circoscritta, tramite intervalH. Un budget cumulativo è ciò che l'upstream ha rifiutato di aggiungere per ora: nel problema #5781 del 16 settembre 2026, lo stesso giorno in cui ha chiuso la PR #5782, chengyongru ha scritto che un budget di token o risorse per le attività in background richiede una progettazione più dettagliata che copra unità e ambito del budget, semantica della terminazione, comportamento di retry e cursore, osservabilità e interazione con modelli diversi, e che per ora non intendono portare avanti il lavoro.

Come interrompo un'esecuzione Dream di nanobot già in corso?

Non con /stop, secondo una lettura del codice sorgente v0.3.5. /stop è documentato come annullamento del turno attivo dell'agente per questa chat ed è implementato come annullamento delle attività registrate sotto la chiave di sessione della chat, mentre un'esecuzione Dream viene creata con una propria chiave effimera nel formato dream:YYYYMMDD-HHMMSS. Questa è una lettura del percorso del codice, non un risultato testato: qui /stop non è stato eseguito contro un'esecuzione Dream attiva. Le leve documentate sono /restart, disattivare agents.defaults.dream.enabled oppure arrestare il processo gateway. La PR unita #5407 nella v0.3.5 è ciò che fa sì che la disattivazione ritiri effettivamente l'attività di sistema persistita invece di lasciarla pianificata.

Come posso vedere quanti token hanno utilizzato le attività in background di nanobot?

Leggi l'archivio locale dell'utilizzo, non un comando slash. nanobot v0.3.5 registra ogni chiamata al modello con un campo source di tipo user, api, cron, dream o system e le scrive in llm_usage.sqlite3 nella directory di configurazione — ~/.nanobot per impostazione predefinita — con colonne per i token di input, output, lettura dalla cache e scrittura nella cache; inoltre le aggrega per data e origine. Due trappole. Non esiste alcun comando /insights o /cost: entrambe le pull request che ne proponevano uno, #3735 e #3921, sono state chiuse senza merge e l'elenco integrato della v0.3.5 è /new, /compact, /stop, /restart, /status, /model, /history, /goal, /trigger, /dream, /dream-log, /dream-restore, /dream-prompt, /evaluator-prompt, /skill, /help e /pairing. Inoltre, le etichette sono asimmetriche: la spesa Dream è contrassegnata come dream, mentre quella dell'heartbeat è contrassegnata come cron, perché la chiave di sessione dell'heartbeat è letteralmente "heartbeat". Si tratta di conteggi di token, non di denaro; riconciliali con il registro del tuo provider.

L'aggiornamento a nanobot v0.3.5 risolve il ciclo?

Nessuno ha affermato che lo faccia e nemmeno questa pagina lo farà. Il problema #5781 è stato aperto contro la v0.3.0 ed è ancora aperto, con le etichette enhancement e priority p2; il segnalatore non ha ripetuto il test dopo l'aggiornamento e nessun manutentore lo ha riprodotto. La v0.3.5 risolve invece aspetti più circoscritti, comunque utili: il commit 4e2640f impedisce a un'esecuzione incompleta di far avanzare il cursore Dream e saltare silenziosamente la cronologia, la PR unita #5442 fa segnalare perché un'esecuzione incompleta non è stata completata e la PR unita #5325 fa restituire a edit_file "Error: new_text must be different from old_text." invece di segnalare il successo di una modifica senza effetto. Quest'ultima correzione riguarda il ciclo lettura-poi-modifica del problema #5324, non il ciclo di sola lettura del problema #5781. Anche nella v0.3.5 non viene fornita alcuna protezione generale contro chiamate identiche ripetute agli strumenti. L'unica protezione per le ripetizioni nel codice distribuito, repeated_external_lookup_error in nanobot/utils/runtime.py, blocca una chiamata web_fetch o web_search identica dopo due tentativi e non corrisponde ad alcun altro nome di strumento; quindi una read_file ripetuta continua fino al limite di iterazioni. Le cinque pull request che proponevano una protezione generale — #3077, #4522, #5344, #3701 e #4154 — non sono state unite.

Verificato il 21 settembre 2026: l'API GitHub per HKUDS/nanobot, per le issue #5781, #5324 e #3073 e per le pull request #5782, #5107, #5325, #5442, #5407, #3077, #4522, #5344, #3701, #4154, #3735, #3921 e #4622; il record PyPI per nanobot-ai 0.3.5; la documentazione sulla memoria e sulla configurazione di nanobot 0.3.5; e il codice sorgente distribuito al tag v0.3.5 per ogni valore predefinito, stringa di log e percorso del codice citati sopra, confrontato con v0.3.0 dove differiscono. Kunavo non ha installato né eseguito nanobot, nessun comportamento qui descritto è stato testato da Kunavo e il ciclo dell'issue #5781 non è stato nuovamente testato su v0.3.5 da nessuno. Le tariffe dei token provengono dal catalogo attuale e ogni cifra in dollari è un calcolo illustrativo basato sulle ipotesi indicate.