Detectando e interrompendo ciclos infinitos
Proteções contra excesso de iterações, detecção de ações repetidas e interruptores de circuito para ciclos.
Detectando e interrompendo ciclos infinitos é uma aula grátis de AI Agents no CoddyKit. Esta é a aula 3 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de AI Agents, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de AI Agents inclui 4 aulas no total.
A Ameaça dos Ciclos Infinitos
Um agente em um ciclo infinito consome tokens, bloqueia recursos e não produz nenhuma saída útil. Em produção, isso se traduz diretamente em dinheiro desperdiçado e frustração do usuário.
Três mecanismos trabalham em conjunto para impedir ciclos infinitos: limites máximos de iterações, detecção de ações repetidas e tempos limite.
Proteção 1: Limite Máximo de Iterações
A proteção mais simples e importante é um limite rígido de etapas. Todo ciclo de agente deve ter um. Quando o limite é atingido, o agente retorna sua melhor resposta atual ou uma mensagem explícita de falha.
MAX_ITERATIONS = 20
def run_agent(query: str) -> dict:
history = []
for step in range(1, MAX_ITERATIONS + 1):
action = decide_action(query, history)
if action['type'] == 'final_answer':
return {'status': 'ok', 'answer': action['answer'], 'steps': step}
result = execute_tool(action['tool'], action['args'])
history.append({'step': step, 'tool': action['tool'], 'result': result})
# Hard stop — max iterations reached
return {
'status': 'max_iterations_reached',
'answer': None,
'steps': MAX_ITERATIONS
}Proteção 2: Detectando Ações Repetidas
Ações repetidas são a marca registrada de um ciclo infinito. Acompanhe um histórico de pares (nome da ferramenta, argumentos). Se o mesmo par aparecer mais de N vezes, o agente está travado — interrompa o ciclo e injete uma mensagem de erro.
import hashlib
import json
def action_hash(tool_name: str, args: dict) -> str:
payload = json.dumps({'tool': tool_name, 'args': args}, sort_keys=True)
return hashlib.md5(payload.encode()).hexdigest()
def run_agent_with_repeat_detection(query: str) -> dict:
history = []
action_counts = {}
for step in range(1, 21):
action = decide_action(query, history)
if action['type'] == 'final_answer':
return {'status': 'ok', 'answer': action['answer']}
key = action_hash(action['tool'], action['args'])
action_counts[key] = action_counts.get(key, 0) + 1
if action_counts[key] > 2: # seen this exact action more than twice
history.append({
'role': 'system',
'content': f'You have called {action["tool"]} with the same arguments {action_counts[key]} times. '
f'This approach is not working. Try a completely different strategy or state what you know so far.'
})
continue
result = execute_tool(action['tool'], action['args'])
history.append({'tool': action['tool'], 'result': result})
return {'status': 'loop_detected', 'answer': None}Rastreando Ações Repetidas em uma Janela
Em vez de acompanhar contagens de todo o histórico, detecte repetições em uma janela deslizante das últimas N etapas. Isso captura ciclos que variam ligeiramente, mas se repetem ao longo de um período curto.
from collections import deque
def is_cycling(recent_actions: deque, window: int = 6) -> bool:
if len(recent_actions) < window:
return False
# Check if the last window/2 actions repeat the first window/2
half = window // 2
first_half = list(recent_actions)[:half]
second_half = list(recent_actions)[half:window]
return first_half == second_half
# In the agent loop:
# recent_actions = deque(maxlen=6)
# recent_actions.append(action_hash(tool, args))
# if is_cycling(recent_actions):
# print('Cycling detected — breaking loop')
# break
recent = deque(['a', 'b', 'a', 'b'], maxlen=6)
print(is_cycling(recent, window=4)) # True — cycling detectedProteção 3: Tempo Limite de Relógio com signal.alarm
Em sistemas Unix, signal.alarm() lança um SIGALRM após uma quantidade especificada de segundos. Isso fornece um tempo limite rígido, mesmo que o ciclo do agente esteja bloqueado em uma chamada lenta de ferramenta.
import signal
class AgentTimeout(Exception):
pass
def timeout_handler(signum, frame):
raise AgentTimeout('Agent exceeded time limit')
def run_agent_with_signal_timeout(query: str, timeout_seconds: int = 60) -> dict:
signal.signal(signal.SIGALRM, timeout_handler)
signal.alarm(timeout_seconds) # set the alarm
try:
result = run_core_agent_loop(query)
signal.alarm(0) # cancel the alarm on success
return result
except AgentTimeout:
signal.alarm(0)
return {'status': 'timeout', 'answer': None}
except Exception as e:
signal.alarm(0)
raise
# Note: signal.alarm is Unix-only (Linux/Mac)Tempo Limite com threading.Timer (Multiplataforma)
threading.Timer funciona em todas as plataformas, incluindo Windows. Defina um sinalizador após o período do tempo limite — o ciclo do agente verifica o sinalizador e sai quando ele está definido.
import threading
def run_agent_with_timer_timeout(query: str, timeout_seconds: int = 60) -> dict:
timed_out = threading.Event()
def set_timeout():
timed_out.set()
timer = threading.Timer(timeout_seconds, set_timeout)
timer.start()
history = []
try:
for step in range(1, 21):
if timed_out.is_set():
return {'status': 'timeout', 'answer': None, 'steps': step}
action = decide_action(query, history)
if action['type'] == 'final_answer':
return {'status': 'ok', 'answer': action['answer']}
result = execute_tool(action['tool'], action['args'])
history.append({'tool': action['tool'], 'result': result})
finally:
timer.cancel() # always cancel if done before timeout
return {'status': 'max_steps', 'answer': None}Tempo Limite Assíncrono com asyncio.wait_for
Em arquiteturas de agentes assíncronos, use asyncio.wait_for(coroutine, timeout=N). Ele lança asyncio.TimeoutError se a corrotina não for concluída dentro do número de segundos especificado.
import asyncio
async def run_async_agent(query: str) -> dict:
history = []
for step in range(1, 21):
action = await async_decide_action(query, history)
if action['type'] == 'final_answer':
return {'status': 'ok', 'answer': action['answer']}
result = await async_execute_tool(action['tool'], action['args'])
history.append({'tool': action['tool'], 'result': result})
return {'status': 'max_steps', 'answer': None}
async def run_with_timeout(query: str, timeout: float = 60.0) -> dict:
try:
return await asyncio.wait_for(run_async_agent(query), timeout=timeout)
except asyncio.TimeoutError:
return {'status': 'timeout', 'answer': None}
# asyncio.run(run_with_timeout('What is Python?', timeout=30.0))Injetando Instruções de Escape no Histórico
Quando um ciclo é detectado, não o interrompa simplesmente em silêncio. Injete uma mensagem do sistema no histórico da conversa explicando o que aconteceu e pedindo ao agente que conclua. Isso dá ao LLM a chance de produzir uma resposta final antes de ser interrompido.
def inject_loop_escape(history: list, step: int, reason: str):
message = (
f'[SYSTEM] You have been running for {step} steps. Reason: {reason}. '
f'You MUST now provide a FINAL_ANSWER based on what you have found so far, '
f'even if the information is incomplete. Do not call any more tools.'
)
history.append({'role': 'system', 'content': message})
# In the agent loop, when approaching the limit:
# if step >= MAX_ITERATIONS - 2:
# inject_loop_escape(history, step, 'approaching max iteration limit')
# Or when a repeat is detected:
# if action_counts[key] > 2:
# inject_loop_escape(history, step, 'repeated action detected')
if __name__ == '__main__':
demo_history = []
inject_loop_escape(demo_history, step=18, reason='approaching max iteration limit')
print(demo_history[-1]['content'])
Registrando Quando um Ciclo é Interrompido
Sempre registre quando uma proteção de ciclo é acionada. Isso cria um histórico da frequência e dos motivos pelos quais os agentes ficam travados — dados inestimáveis para melhorar suas instruções e implementações de ferramentas.
import logging
logger = logging.getLogger('agent_guard')
def check_and_break_loop(step: int, action_counts: dict, current_key: str) -> bool:
count = action_counts.get(current_key, 0)
if count > 2:
logger.warning(
f'Infinite loop detected at step {step}. '
f'Action hash {current_key[:8]} seen {count} times. '
f'Breaking loop.'
)
return True # signal to break
if step >= 18: # approaching limit
logger.warning(
f'Approaching max iterations at step {step}. '
f'Injecting escape prompt.'
)
return False
if __name__ == '__main__':
import sys
logging.basicConfig(level=logging.WARNING, format='%(message)s', stream=sys.stdout)
demo_counts = {'search:{"q": "weather"}': 3}
check_and_break_loop(step=10, action_counts=demo_counts, current_key='search:{"q": "weather"}')
Combinando as Três Proteções
Os agentes de produção devem combinar as três proteções: máximo de iterações (obrigatório), detecção de repetições (captura ciclos) e tempo limite (captura chamadas de ferramentas bloqueadas). Juntas, elas tornam o ciclo à prova de falhas.
import threading
import hashlib
import json
def run_production_agent(query: str) -> dict:
MAX_STEPS = 20
TIMEOUT_SEC = 120
timed_out = threading.Event()
timer = threading.Timer(TIMEOUT_SEC, timed_out.set)
timer.start()
history = []
action_counts = {}
try:
for step in range(1, MAX_STEPS + 1):
if timed_out.is_set():
return {'status': 'timeout'}
action = decide_action(query, history)
if action['type'] == 'final_answer':
return {'status': 'ok', 'answer': action['answer']}
key = hashlib.md5(json.dumps(action, sort_keys=True).encode()).hexdigest()
action_counts[key] = action_counts.get(key, 0) + 1
if action_counts[key] > 2:
inject_loop_escape(history, step, 'repeat detected')
continue
result = execute_tool(action['tool'], action['args'])
history.append({'tool': action['tool'], 'result': result})
finally:
timer.cancel()
return {'status': 'max_steps'}Testando Proteções de Ciclos com Testes Unitários
Escreva testes unitários específicos para suas proteções de ciclos. Crie um agente simulado que sempre chame a mesma ferramenta e verifique se a proteção a detecta dentro do número esperado de etapas.
from unittest.mock import MagicMock
def test_repeat_detection_breaks_loop():
# Create a mock that always returns the same action
always_same_action = MagicMock(return_value={
'type': 'tool',
'tool': 'search_web',
'args': {'query': 'same query'}
})
always_success = MagicMock(return_value='some result')
result = run_agent_with_repeat_detection(
query='test',
decide_action=always_same_action,
execute_tool=always_success
)
# Should stop due to loop detection, not run all 20 steps
assert result['status'] in ('loop_detected', 'max_iterations_reached')
# Should not have run all 20 steps (loop should be detected by step 6-7)
print('Loop guard test passed')Verificação de Conhecimento: Detectando Ciclos Infinitos
Teste sua compreensão das técnicas de detecção e interrupção de ciclos infinitos.
Recapitulação: Detectando e Interrompendo Ciclos Infinitos
Agora você pode proteger seus agentes contra ciclos infinitos com três proteções complementares:
- Máximo de iterações: limite rígido de etapas, obrigatório em todo ciclo de agente
- Detecção de repetições: gere o hash de pares (ferramenta, argumentos) e interrompa quando eles forem vistos mais de N vezes
- Tempo limite:
signal.alarm()no Unix,threading.Timermultiplataforma,asyncio.wait_for()para operações assíncronas - Injeção de escape: dê ao agente a chance de concluir antes da interrupção forçada
- Sempre registre quando uma proteção é acionada — esses são dados valiosos para melhorar as instruções
Aprenda AI Agents com um tutor de IA — grátis
Escreva e execute código real no seu navegador, obtenha ajuda instantânea de um tutor de IA 24/7 e continue de onde parou na web ou no app.
- Cursos
- 60
- Aulas
- 239
Perguntas Frequentes
A aula “Detectando e interrompendo ciclos infinitos” é grátis?
Sim — o texto completo de “Detectando e interrompendo ciclos infinitos” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de AI Agents, atualize para CoddyKit PRO. O curso de AI Agents inclui 4 aulas no total.
O que vou aprender em “Detectando e interrompendo ciclos infinitos”?
Proteções contra excesso de iterações, detecção de ações repetidas e interruptores de circuito para ciclos. Você pratica AI Agents com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar AI Agents?
Nenhuma experiência prévia é necessária. AI Agents no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 3 de 4.
Quanto tempo leva a aula “Detectando e interrompendo ciclos infinitos”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de AI Agents?
Sim. Cada aula de AI Agents inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Falhas comuns em ciclos de agentes
- Registro de rastreamento das etapas do agente
- Detectando e interrompendo ciclos infinitos
- Técnicas de depuração passo a passo