Lesson 8 of 30 ~15 min
Course progress
0%

When Model Gets Stuck in a Loop

Diagnostika a řešení situací kdy model opakuje sám sebe nebo se zasekne.

Někdy se model zasekne v neproduktivní smyčce. Naučte se to rozpoznat a řešit.

Typy loop problémů

1. Repetitive Output Loop

Model opakuje stejný text:

Assistant: Let me think about this...
Let me think about this...
Let me think about this...
Let me think about this...

Příčina: Temperature příliš nízká nebo corrupted context.

Řešení:

# Zvyšte temperature
response = client.messages.create(
    model="claude-opus-4-5-20250101",
    temperature=0.7,  # Increase from 0
    messages=[...]
)

2. Thinking Loop

Model v extended thinking krouží bez závěru:

<thinking>
Option A might work...
But option B is also good...
Actually, let me reconsider A...
But B has advantages...
Let me think about A again...
</thinking>

Příčina: Ambiguní zadání bez jasného kritéria pro rozhodnutí.

Řešení:

# Přidejte decision criteria
prompt = """
Choose between A and B.
Decision criteria (in priority order):
1. Performance > 100ms
2. Cost < $1
3. Simplicity

Make a definitive choice based on these criteria.
"""

3. Tool Calling Loop

Agent volá stejný nástroj opakovaně:

Tool: search_database("user")
Tool: search_database("user")
Tool: search_database("user")

Příčina: Tool vrací nedostatečný výsledek, model zkouší znovu.

Řešení:

class LoopDetector:
    def __init__(self, max_same_calls=3):
        self.history = []
        self.max_same_calls = max_same_calls
    
    def check(self, tool_name: str, tool_input: dict) -> bool:
        call = (tool_name, str(tool_input))
        self.history.append(call)
        
        # Count same calls
        same_count = sum(1 for c in self.history if c == call)
        
        if same_count >= self.max_same_calls:
            return False  # Don't execute
        return True
    
    def get_suggestion(self) -> str:
        return "I notice I'm repeating the same action. Let me try a different approach."

# V agent loop
if not loop_detector.check(tool.name, tool.input):
    # Force different approach
    messages.append({
        "role": "user",
        "content": loop_detector.get_suggestion()
    })

Diagnostika

Detekce loop patterns

import re
from collections import Counter

def detect_repetition(text: str, min_length: int = 20) -> bool:
    """Detect if text contains repetitive patterns"""
    
    # Split into chunks
    chunks = [text[i:i+min_length] for i in range(0, len(text)-min_length, 10)]
    
    # Count occurrences
    counter = Counter(chunks)
    
    # If any chunk appears >3 times, it's likely a loop
    most_common = counter.most_common(1)
    if most_common and most_common[0][1] > 3:
        return True
    
    return False

def detect_thinking_loop(thinking_text: str) -> bool:
    """Detect circular reasoning in thinking"""
    
    patterns = [
        r"let me (think|consider|reconsider)",
        r"on (the other|second) hand",
        r"but (wait|actually|however)"
    ]
    
    total_backtracks = 0
    for pattern in patterns:
        matches = re.findall(pattern, thinking_text.lower())
        total_backtracks += len(matches)
    
    # Too many backtracks indicates circular reasoning
    return total_backtracks > 10

Monitoring v reálném čase

class StreamingLoopDetector:
    def __init__(self):
        self.buffer = ""
        self.chunk_hashes = []
    
    def on_chunk(self, chunk: str):
        self.buffer += chunk
        
        # Hash each 50 char segment
        if len(self.buffer) >= 50:
            segment = self.buffer[-50:]
            segment_hash = hash(segment)
            
            if segment_hash in self.chunk_hashes[-10:]:
                return "LOOP_DETECTED"
            
            self.chunk_hashes.append(segment_hash)
        
        return "OK"

Recovery strategie

Strategy 1: Hard Reset

async def recover_from_loop(original_prompt: str):
    """Start fresh with modified prompt"""
    
    reset_prompt = f"""
{original_prompt}

IMPORTANT: 
- Be direct and decisive
- Don't overthink or reconsider excessively
- Make a choice and commit to it
- If unsure, state your best guess with confidence level
"""
    
    return await client.messages.create(
        model="claude-opus-4-5-20250101",
        messages=[{"role": "user", "content": reset_prompt}]
    )

Strategy 2: Decomposition

async def break_down_task(stuck_prompt: str):
    """Break complex task into smaller steps"""
    
    breakdown_prompt = f"""
I was trying to do this but got stuck:
{stuck_prompt}

Please break this down into 3-5 smaller, concrete steps.
For each step, give a specific action I can take.
"""
    
    steps = await get_steps(breakdown_prompt)
    
    results = []
    for step in steps:
        result = await client.messages.create(
            messages=[{"role": "user", "content": step}]
        )
        results.append(result)
    
    return combine_results(results)

Strategy 3: Timeout + Retry

import asyncio

async def with_timeout_retry(prompt: str, timeout: int = 30, retries: int = 3):
    for attempt in range(retries):
        try:
            result = await asyncio.wait_for(
                call_claude(prompt),
                timeout=timeout
            )
            
            if not detect_repetition(result):
                return result
            
            # Retry with modified prompt
            prompt += "\n\n(Note: Please provide a direct, non-repetitive response)"
            
        except asyncio.TimeoutError:
            print(f"Attempt {attempt + 1} timed out")
            continue
    
    raise LoopError("Failed to get non-looping response")

Rozpoznání a recovery z loop je klíčová skill pro práci s AI.