무한 반복 감지 및 중단
최대 반복 횟수 보호, 반복 작업 감지, 반복 회로 차단기를 다룹니다.
무한 반복 감지 및 중단은(는) CoddyKit의 무료 AI Agents 강의입니다. 이것은 4개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 AI Agents 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. AI Agents 강의에는 총 4개의 강의가 포함되어 있습니다.
무한 루프의 위협
무한 루프에 빠진 에이전트는 토큰을 소모하고 리소스를 차단하며 유용한 출력을 생성하지 못합니다. 운영 환경에서는 이것이 곧 낭비되는 비용과 사용자의 불만으로 이어집니다.
무한 루프를 방지하는 세 가지 방법이 함께 작동합니다. 최대 반복 횟수 제한, 반복 동작 감지, 시간 제한입니다.
보호 장치 1: 최대 반복 횟수 제한
가장 단순하면서도 중요한 보호 장치는 엄격한 단계 제한입니다. 모든 에이전트 루프에는 이 제한이 있어야 합니다. 제한에 도달하면 에이전트는 현재 얻은 최선의 답변이나 명시적인 실패 메시지를 반환합니다.
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
}보호 장치 2: 반복 동작 감지하기
반복 동작은 무한 루프의 대표적인 징후입니다. (도구 이름, 인수) 쌍의 이력을 추적합니다. 같은 쌍이 N번보다 많이 나타나면 에이전트가 멈춘 것이므로 루프를 중단하고 오류 메시지를 주입합니다.
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}범위 내에서 반복 동작 추적하기
전체 기간의 횟수를 추적하는 대신 최근 N단계로 이루어진 슬라이딩 범위에서 반복을 감지합니다. 이렇게 하면 조금씩 다르지만 짧은 주기로 순환하는 루프를 포착할 수 있습니다.
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 detectedsignal.alarm을 사용한 실제 시간 제한
Unix 시스템에서는 signal.alarm()이 지정된 시간이 지나면 SIGALRM을 발생시킵니다. 따라서 에이전트 루프가 느린 도구 호출에서 차단된 경우에도 엄격한 시간 제한을 적용할 수 있습니다.
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)threading.Timer를 사용한 시간 제한(플랫폼 간 지원)
threading.Timer는 Windows를 포함한 모든 플랫폼에서 작동합니다. 시간 제한이 지나면 플래그를 설정하고, 에이전트 루프는 플래그가 설정되었는지 확인하여 설정되어 있으면 종료합니다.
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}asyncio.wait_for를 사용한 비동기 시간 제한
비동기 에이전트 아키텍처에서는 asyncio.wait_for(coroutine, timeout=N)을 사용합니다. 코루틴이 지정된 시간(초) 안에 완료되지 않으면 asyncio.TimeoutError를 발생시킵니다.
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))이력에 탈출 지침 주입하기
루프가 감지되었을 때 조용히 중단하기만 해서는 안 됩니다. 대화 이력에 무슨 일이 발생했는지 설명하고 에이전트에 결론을 내리도록 요청하는 시스템 메시지를 주입합니다. 이렇게 하면 강제로 중단되기 전에 LLM이 최종 답변을 생성할 기회를 얻습니다.
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'])
루프가 중단될 때 기록하기
루프 보호 장치가 작동할 때는 항상 기록하십시오. 이를 통해 에이전트가 얼마나 자주, 어떤 이유로 멈추는지 파악할 수 있습니다. 프롬프트와 도구 구현을 개선하는 데 매우 중요한 데이터입니다.
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"}')
세 가지 보호 장치 모두 결합하기
운영 환경용 에이전트는 세 가지 보호 장치를 모두 결합해야 합니다. 최대 반복 횟수 제한은 필수이고, 반복 감지는 순환을 포착하며, 시간 제한은 도구 호출로 인한 차단을 포착합니다. 이들이 함께 작동하면 루프가 매우 견고해집니다.
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'}단위 테스트로 루프 보호 장치 테스트하기
루프 보호 장치를 위한 전용 단위 테스트를 작성합니다. 항상 같은 도구를 호출하는 모의 에이전트를 만들고, 보호 장치가 예상된 단계 수 이내에 이를 감지하는지 검증합니다.
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')지식 확인: 무한 루프 감지하기
무한 루프를 감지하고 중단하는 기법에 대한 이해도를 확인합니다.
복습: 무한 루프 감지 및 중단하기
이제 서로 보완하는 세 가지 보호 장치로 에이전트를 무한 루프로부터 보호할 수 있습니다.
- 최대 반복 횟수: 엄격한 단계 제한이며 모든 에이전트 루프에 필수입니다
- 반복 감지: (도구, 인수) 쌍을 해시하고 N번보다 많이 나타나면 중단합니다
- 시간 제한: Unix에서는
signal.alarm(), 플랫폼 간에는threading.Timer, 비동기 작업에는asyncio.wait_for()를 사용합니다 - 탈출 지침 주입: 강제로 중단하기 전에 에이전트가 결론을 내릴 기회를 제공합니다
- 보호 장치가 작동할 때는 항상 기록하십시오. 프롬프트 개선에 유용한 데이터입니다
AI 튜터와 함께 AI Agents을(를) 배우세요 — 무료
브라우저에서 실제 코드를 작성하고 실행하며, 24/7 AI 튜터로부터 즉각적인 도움을 받고, 웹이나 앱에서 중단한 부분부터 계속 학습하세요.
- 코스
- 60
- 레슨
- 239
자주 묻는 질문
“무한 반복 감지 및 중단” 강의는 무료인가요?
네 — “무한 반복 감지 및 중단” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 AI Agents 강의 전체를 잠금 해제할 수 있습니다. AI Agents 강의에는 총 4개의 강의가 포함되어 있습니다.
“무한 반복 감지 및 중단”에서 뭘 배우나요?
최대 반복 횟수 보호, 반복 작업 감지, 반복 회로 차단기를 다룹니다. 브라우저에서 직접 실행하는 실습 코드로 AI Agents을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
AI Agents을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 AI Agents은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 3번째 강의입니다.
“무한 반복 감지 및 중단” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 AI Agents 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 AI Agents 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- 일반적인 에이전트 반복 과정 실패
- 에이전트 단계 추적 로깅
- 무한 반복 감지 및 중단
- 단계별 디버깅 기법