Voltar aos guias
Configuração·21 de setembro de 2026·Atualizado em 24 de setembro de 2026·9 min de leitura

Loops infinitos e uso de tokens no Nanobot: diagnostique uma execução Dream limitada

A configuração indicada pelo título do bug foi excluída, a pull request que a restauraria foi encerrada sem merge, e o único limite restante é global ao processo.

Última revisão em .

Uma execução do nanobot que parece um loop infinito é limitada: no código-fonte distribuído da v0.3.5, cada turno do agente é limitado por agents.defaults.maxToolIterations, cujo padrão é 200, e um mantenedor afirma oficialmente que não se trata de um loop literalmente infinito. O verdadeiro problema é o uso de tokens, porque uma execução que chega a esse limite registra 201 turnos do assistente e reenvia um prompt cada vez maior. Distinguir qual desses casos você tem exige quatro perguntas, e a correção respaldada por evidências não é um valor de configuração.

Comece eliminando a pista óbvia. O relatório upstream é a issue #5781, cujo título aponta para dream.maxIterations, e o PR #5782 tem o título "fix(dream): enforce configured iteration limit". Essa chave não existe na v0.3.5, e o PR foi encerrado sem incorporação em 16 de setembro de 2026. Um tutorial baseado nele não configura nada.

Uma distinção, porque a consulta mostra o rastreador errado. Esta página trata de HKUDS/nanobot, MIT, instalado como o pacote PyPI nanobot-ai — 0.3.5, Python 3.11 ou posterior, enviado em 15 de setembro de 2026. obot-platform/nanobot é um projeto Go diferente, cujo README declara modo de manutenção com issues desativadas; seus números de issue não são evidências aqui. E pip install nanobot, sem sufixo, instala um pacote não relacionado de navegação de robôs.

O que foi relatado e contra qual versão

Dream é o job agendado de consolidação de memória do nanobot, executado pelo gateway como um job cron chamado dream. Ele não é um job de embeddings nem de índice vetorial: a Kunavo não fornece um modelo de embeddings, e o Dream não precisa de um, porque a memória persistente do nanobot consiste em arquivos simples no workspace e uma execução do Dream é tráfego comum de chat.

A issue #5781 foi aberta em 15 de setembro de 2026 por BrianMwangi21 contra o nanobot v0.3.0, em Python 3.12, com um modelo de raciocínio acessado pelo OpenRouter. O sintoma: o job Dream alternava read_file em memory/history.jsonl com read_file em um único SKILL.md, dezenas de vezes, enquanto o rastreamento de raciocínio reconsiderava onde registrar um único fato pequeno. Sete execuções registradas ao longo de aproximadamente 26 horas variaram de cerca de 25 minutos a cerca de 111 minutos; as que se aproximaram de 200 chamadas de ferramentas atingiram o limite global, e um checkpoint da sessão mostrava runtime_checkpoint.iteration: 164, fase tools_completed, na mesma chamada read_file.

Três limites de escopo devem acompanhar esses números. Eles são logs do gateway autorrelatados por um usuário, em um modelo, na v0.3.0 — nenhum mantenedor os reproduziu e ninguém refez o teste na v0.3.5. A issue está marcada como enhancement e priority: p2, não como bug, e continua aberta. E esse padrão já apareceu antes: a issue #3073, um loop quase idêntico de read_file em history.jsonl de 12 de abril de 2026, foi encerrada como não planejada. Nada disso sustenta tratar o nanobot como geralmente caro; sustenta verificar se a sua própria instalação está fazendo isso.

A chave obsoleta e o limite que está realmente ativo

Toda a confusão é uma diferença de versão, e o código-fonte resolve a questão. Leia as duas tags de lançamento em 21 de setembro de 2026:

Chave de configuraçãoNa v0.3.0Na v0.3.5O que fazer agora
dream.maxIterationsPadrão 15, marcada como # Deprecated: no longer usedRemovida do schemaNão a escreva; ela não configura nada
dream.maxBatchSizePadrão 20, mesmo comentário de obsolescênciaRemovidaNão a escreva
dream.annotateLineAgesPadrão true, mesmo comentário de obsolescênciaRemovidaNão a escreva
dream.enabledPadrão truePadrão trueEditável nas configurações de runtime da WebUI
dream.intervalHPadrão 2Padrão 2Edite config.json; não é um campo da WebUI
dream.cronNulo; substituição legadaNulo; substituição legadaTem precedência sobre intervalH quando definido
dream.modelOverrideDeclarada, comentada como pendente de implementaçãoImplementadaSomente nomes de presets, nunca um ID de modelo bruto
agents.defaults.maxToolIterations200200O único limite, e ele é aplicado a todo o processo

Duas coisas tornam essa tabela fácil de interpretar errado. O 200 é duplamente verdadeiro — é o valor na configuração do autor e o padrão distribuído na linha 129 de nanobot/config/schema.py, idêntico na tag v0.3.5 e em main, portanto um leitor que nunca o definiu ainda tem 200. E ele não é documentado: uma consulta à própria referência de configuração 0.3.5 do nanobot em 21 de setembro de 2026 retornou 488.608 bytes de HTML com zero ocorrências de maxToolIterations, e o docs/configuration.md do repositório nessa tag também não contém nenhuma. O número pode ser comprovado pelo código-fonte e por um comentário de mantenedor, não por uma página de documentação — portanto, trate com desconfiança qualquer tutorial que cite um valor diferente.

modelOverride é o único recurso com uma condição de versão. Na v0.3.0, o campo existia com o comentário pendente de implementação e sem nenhum código que o resolvesse; o PR #5107, incorporado em 27 de julho de 2026, o implementou na v0.3.5. A página oficial de memória da 0.3.5 afirma que ele seleciona uma entrada nomeada de model_presets para o Dream, aceita somente nomes de presets e não oferece suporte a identificadores brutos de modelos. Essa página documenta três chaves do Dream e não menciona nenhum limite de iterações. Eis a superfície completa atual, com o bloco providers em que ela se apoia coberto na página de configuração do nanobot:

~/.nanobot/config.json — toda a superfície Dream do 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"
      }
    }
  }
}

Observe o que não está nesse arquivo: qualquer forma de limitar apenas o Dream. AgentLoop é construído uma vez com max_iterations a partir dos padrões do processo, e tanto o caminho cron do Dream quanto o caminho manual /dream chamam process_direct(...) sem um argumento de iteração, assim como os subagentes. Reduzir o limite o reduz para chat, Dream, heartbeat e subagentes em conjunto.

Diagnostique nesta ordem

Responda a estas quatro perguntas antes de alterar qualquer coisa, porque três não custam nada e a quarta informa se as três primeiras importam. As strings dos logs são o texto literal na v0.3.5; as chaves representam valores de runtime.

PerguntaOnde procurarO que a resposta significa
1. A execução parou sozinha ou atingiu o limite?Log do gateway: Max iterations (200) reached, de agent/loop.pyPresente significa uma execução limitada, com aproximadamente 201 turnos do assistente. Ausente significa que a execução terminou antes do limite — o modelo convergiu ou a execução falhou diretamente e registrou Dream cron job failed
2. O cursor do Dream avançou?Três linhas distintas em 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 …A terceira linha é o mecanismo de segurança da v0.3.5 funcionando: uma execução incompleta deixa o lote para ser tentado novamente. Isso também significa que o mesmo lote volta no próximo tick
3. A mesma ferramenta com os mesmos argumentos está se repetindo?As linhas Tool call: entre esses dois marcadoresA repetição contínua da ferramenta e dos argumentos idênticos é não convergência do modelo, que foi a conclusão do upstream. A única proteção contra repetição na v0.3.5 corresponde a web_fetch e web_search; uma repetição de read_file não é capturada
4. Qual foi o custo?llm_usage.sqlite3 no diretório de configuração, agregado por data e origem; no lado do gateway, por chave e por dia em usageO Dream recebe a etiqueta dream. O heartbeat recebe a etiqueta cron, portanto filtrar por "heartbeat" não encontra nada

Você não precisa esperar duas horas pelo tick do cron para reproduzi-lo. O comando /dream executa o mesmo job sob demanda e informa a mesma distinção no chat: Dream completed in Ns. ou Dream completed in Ns; no memory changes. em caso de sucesso, contra Dream did not complete after Ns (reason); memory cursor was not advanced. quando não termina. Outra mudança da v0.3.5 importa enquanto você procura evidências: os arquivos JSONL de sessão foram movidos para a árvore sessions/<workspace-id>/ do diretório de configuração, portanto os caminhos da v0.3.0 citados na thread da issue não são onde seu checkpoint está.

Cinco recursos e o que realmente respalda cada um

AlavancaEvidência por trás deleVantagensO que isso custa
Atualizar da v0.3.0 para a v0.3.5O commit 4e2640f, na v0.3.5 e não na v0.3.0, faz o cursor avançar somente quando o motivo da parada é completedSeu sintoma é memória ignorada, não gastoEle não encurta um loop não convergente, e ninguém refez o teste da #5781 na 0.3.5
Mudar o modelo do DreamO único recurso com comparação antes e depois: na auditoria do autor, um lote no qual um modelo gastou 91 minutos sem concluir foi concluído na execução seguinte por outro modelo em cerca de um minuto, com 6 chamadas de ferramentas, mesmo prompt, mesmo histórico e mesmas ferramentasA qualidade do chat precisa permanecer no seu modelo mais caroRequer a v0.3.5 e um preset definido; na v0.3.0, o campo não resolve para nada
Reduzir maxToolIterationsEditável nas configurações de runtime da WebUI, mínimo 1, por webui/settings_runtime.pyVocê quer um limite máximo para diagnósticoUm único controle para chat, Dream, heartbeat e subagentes; e uma execução limitada não avança o cursor, portanto o mesmo lote é tentado novamente no próximo tick
Desacelerar ou desativar o DreamintervalH, ou dream.enabled na WebUI; o PR #5407, incorporado, retira o job persistido quando desativadoA consolidação não vale o custo na sua carga de trabalhoVocê perde a consolidação de memória, que é justamente o recurso
Roteie para que o reenvio seja mais baratoNa v0.3.5, exatamente duas especificações de provedor definem supports_prompt_caching: anthropic e openrouter; o campo tem false como padrãoVocê aceita que ocorram execuções longas e quer que custem menosDepende de qual caminho de protocolo você configurou e da verificação do uso retornado por você mesmo

Os dois IDs de modelo do autor eram deepseek/deepseek-v4-flash-0731 e openai/gpt-5.6-luna, conforme ele os escreveu via OpenRouter; esses IDs e seus preços não foram verificados aqui, portanto interprete a comparação como evidência de que o modelo decide a convergência, não como recomendação de nenhum dos dois. O upstream chegou à mesma conclusão: ao anunciar o encerramento do PR #5782 na issue #5781, chengyongru escreveu que um limite fixo de iterações do Dream não aborda o problema subjacente de convergência dependente do modelo e pode fazer com que execuções que poderiam funcionar sejam repetidamente tentadas de novo.

Quanto custa uma execução limitada: cálculo ilustrativo

Estas são contas ilustrativas de tokens, não o custo medido de uma tarefa nem um limite de cobrança. O nanobot não publica um valor de tokens por execução do Dream, portanto toda entrada aqui é uma suposição que você deve substituir pela sua própria medição. Suponha uma execução que atinge o limite em 201 turnos do assistente — a contagem da auditoria do autor — cada um reenviando um prompt mantido constante em 25,000 tokens, caracterização que ele fez do próprio workspace, não um valor publicado. Isso representa 5.03M tokens de entrada. Os tokens de saída são excluídos, e um prompt real cresce a cada resultado de ferramenta, portanto isso subestima uma execução real em duas direções simultaneamente. As tarifas são os preços atuais do catálogo da Kunavo.

ModeloEntrada por 1MLeitura de cache por 1MUma execução limitada, sem cacheMesma execução, reenvios lidos do 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

A última coluna pressupõe um caso ideal que nada aqui testou: o primeiro envio à tarifa de entrada simples e todos os 200 reenvios atendidos como leituras de cache. Uma gravação de cache é cobrada pela própria tarifa, que em alguns modelos fica acima da tarifa de entrada simples; uma entrada de cache expira; e um prompt que cresce é regravado, não relido — portanto, trate a diferença entre as duas últimas colunas como o tamanho do benefício, não como uma cotação. O ponto é apenas que, em uma execução longa e repetitiva, é o reenvio, não o modelo, que consome o dinheiro.

A decisão sobre se os marcadores de cache chegam efetivamente à rede ocorre na configuração do seu nanobot, e é visível no código-fonte distribuído. Um provedor inventado em providers é tratado como um provedor compatível com OpenAI simples e deixa supports_prompt_caching com seu padrão false, portanto o cliente do nanobot não envia marcadores cache_control nesse caminho, mesmo para um ID de modelo no formato Claude. Manter o preset no provedor integrado anthropic e substituir providers.anthropic.apiBase os mantém ativos. Isso descreve o que o cliente do nanobot envia, não o que qualquer endpoint faz do próprio lado, e a Kunavo não testou o nanobot em runtime. Leia o uso retornado de uma chamada real antes de orçar um job recorrente como armazenado em cache — a documentação de cache mostra como é um cache funcionando e a referência da URL base fornece as duas convenções de endpoint.

O valor do catálogo da Kunavo é um piso de cobrança, não um teto: quando o upstream informa seu custo, a cobrança é o maior entre o custo do catálogo e o custo do upstream multiplicado pela margem aplicável. O recarregamento mínimo é $10 em crédito pré-pago — um mínimo de financiamento, não uma taxa por tarefa nem uma assinatura. Consulte detalhes de cobrança e otimização de custos para conhecer o método de medição que substitui as suposições acima.

Verifique a correção em uma execução

Altere uma coisa, execute /dream uma vez em vez de esperar pelo agendamento e verifique os três marcadores na ordem: nenhum aviso Max iterations (200) reached, uma linha cursor advanced to … em vez de cursor remains at …, e uma quantidade plausível de chamadas de ferramentas entre eles. Depois leia a cobrança registrada pela sua própria conta nessa janela, por chave e por dia, em usage; o armazenamento do nanobot conta tokens, não dinheiro. Se você estiver configurando o endpoint pela primeira vez, o quickstart e a página de configuração do nanobot cobrem os dois caminhos de protocolo, e criar uma conta Kunavo é a etapa anterior ao financiamento de uma chave. Comparando tempos de execução? nanobot vs OpenClaw coloca as duas cadências em segundo plano lado a lado, e o diretório de APIs de agentes indexa os clientes por protocolo de rede.

Perguntas frequentes

O nanobot está realmente preso em um loop infinito?

Não, e um mantenedor afirmou isso publicamente. Ao comentar a issue #5324 em 10 de agosto de 2026, chengyongru escreveu que o executor de agentes do nanobot é limitado por agents.defaults.maxToolIterations, 200 por padrão; portanto, não se trata literalmente de um loop infinito — acrescentando que um loop longo, embora limitado, ainda pode causar um uso acumulado muito alto de tokens, de modo que o impacto prático é real. O código-fonte distribuído do v0.3.5 confirma: max_tool_iterations tem padrão 200 em nanobot/config/schema.py, e agent/loop.py registra o aviso "Max iterations (200) reached" quando uma execução atinge esse limite. O que as pessoas chamam de loop infinito é uma execução que alcança esse teto; nos logs de um relato, isso significou 201 turnos do assistente relendo os mesmos dois arquivos.

Por que definir dream.maxIterations não faz nada?

Porque o campo não existe mais. No nanobot v0.3.0, a configuração Dream continha max_iterations, max_batch_size e annotate_line_ages, cada um marcado no código-fonte com o comentário "Deprecated: no longer used"; na tag v0.3.5, os três desapareceram, e a classe define apenas enabled, intervalH, cron e modelOverride. O mantenedor chengyongru afirmou em 15 de setembro de 2026 que dream.maxIterations foi intencionalmente marcado como obsoleto e não utilizado quando o Dream foi movido para o loop normal de agentes, e desde então foi removido da branch main. O pull request que o restauraria, #5782, foi fechado sem merge no dia seguinte. Escrever essa chave em uma configuração v0.3.5 grava uma chave que o esquema não define.

Como limito tokens apenas para a tarefa Dream do nanobot?

Não como um orçamento acumulado, no nanobot v0.3.5. Nada no código distribuído soma os tokens de uma execução e a interrompe quando um valor é atingido, e agents.defaults.maxToolIterations é o único limite de iterações — ele vale para todo o processo, aplicando-se simultaneamente a turnos comuns de chat, ao Dream, ao heartbeat e aos subagentes. Duas coisas podem ser configuradas exclusivamente para o Dream por meio de agents.defaults.dream.modelOverride: o modelo e os limites por chamada do próprio preset, porque ModelPresetConfig contém maxTokens e contextWindowTokens, e dream_runtime() resolve o preset nomeado no runtime sob o qual a execução do Dream ocorre. Esses limites se aplicam a cada chamada individual, não ao total da execução; portanto, 200 chamadas com um maxTokens baixo ainda são 200 chamadas. O agendamento também pode ser definido separadamente, por meio de intervalH. Um orçamento acumulado é algo que o upstream decidiu não adicionar por enquanto: na issue #5781, em 16 de setembro de 2026, no dia em que fechou o PR #5782, chengyongru escreveu que um orçamento de tokens ou recursos para tarefas em segundo plano exige um design mais detalhado que cubra a unidade e o escopo do orçamento, a semântica de encerramento, o comportamento de novas tentativas e cursores, a observabilidade e a interação com diferentes modelos, e que não planeja levar isso adiante por enquanto.

Como interrompo uma execução do Dream do nanobot que já está em andamento?

Não com /stop, segundo uma leitura do código-fonte da v0.3.5. /stop é documentado como o cancelamento do turno ativo do agente neste chat e implementado como um cancelamento das tarefas registradas sob a chave de sessão desse chat, enquanto uma execução do Dream é criada sob sua própria chave efêmera no formato dream:YYYYMMDD-HHMMSS. Essa é uma leitura do caminho do código, não um resultado testado — /stop não foi executado contra uma execução ativa do Dream aqui. Os mecanismos documentados são /restart, desativar agents.defaults.dream.enabled ou interromper o processo do gateway. O PR #5407, incorporado na v0.3.5, é o que faz a desativação realmente retirar o job persistido do sistema, em vez de deixá-lo agendado.

Como vejo quantos tokens os jobs em segundo plano do nanobot usaram?

Leia o armazenamento local de uso, não um comando de barra. O nanobot v0.3.5 registra cada chamada de modelo com um campo source tipado como user, api, cron, dream ou system, grava-as em llm_usage.sqlite3 no diretório de configuração — ~/.nanobot por padrão — com colunas de tokens de entrada, saída, leitura de cache e gravação de cache, e agrega os dados agrupados por data e origem. Duas armadilhas. Não existe o comando /insights nem /cost: os dois pull requests que propunham um, #3735 e #3921, foram encerrados sem incorporação, e a lista integrada da 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. E os rótulos são assimétricos: o gasto do Dream recebe a etiqueta dream, mas o gasto do heartbeat recebe a etiqueta cron, porque a chave de sessão do heartbeat é literalmente "heartbeat". Essas são contagens de tokens, não valores monetários, portanto reconcilie-as com o próprio registro do seu provedor.

Atualizar para o nanobot v0.3.5 corrige o loop?

Ninguém disse que sim, e esta página também não dirá. A issue #5781 foi aberta contra a v0.3.0 e continua aberta, marcada como enhancement e priority p2; o autor nunca fez um novo teste após a atualização e nenhum mantenedor a reproduziu. O que a v0.3.5 corrige é mais específico e ainda assim vale a atualização: o commit 4e2640f impede que uma execução incompleta avance o cursor do Dream e pule o histórico silenciosamente, o PR #5442, incorporado, faz uma execução incompleta informar por que não foi concluída, e o PR #5325, incorporado, faz edit_file retornar "Error: new_text must be different from old_text." em vez de informar sucesso em uma edição sem efeito. Este último trata do loop de leitura e edição da issue #5324, não do loop somente de leitura da #5781. A v0.3.5 também não inclui uma proteção geral contra chamadas idênticas repetidas de ferramentas. A única proteção contra repetição no código-fonte distribuído, repeated_external_lookup_error em nanobot/utils/runtime.py, bloqueia um web_fetch ou web_search idêntico após duas tentativas e não corresponde a nenhum outro nome de ferramenta; portanto, uma execução repetida de read_file continua até o limite de iterações. Os cinco pull requests que propõem uma proteção geral — #3077, #4522, #5344, #3701 e #4154 — continuam sem incorporação.

Verificado em 21 de setembro de 2026: a API do GitHub para HKUDS/nanobot e para as issues #5781, #5324 e #3073 e os pull requests #5782, #5107, #5325, #5442, #5407, #3077, #4522, #5344, #3701, #4154, #3735, #3921 e #4622; o registro PyPI do nanobot-ai 0.3.5; a documentação de memória e configuração 0.3.5 do nanobot; e o código-fonte distribuído na tag v0.3.5 para cada padrão, string de log e caminho de código citado acima, comparado com a v0.3.0 onde diferem. A Kunavo não instalou nem executou o nanobot, nenhum comportamento aqui foi testado pela Kunavo e o loop da issue #5781 não foi testado novamente na v0.3.5 por ninguém. As tarifas de tokens vêm do catálogo atual e todos os valores em dólares são cálculos ilustrativos segundo as suposições declaradas.