0Pricing
AI Agents · 강의

일반적인 에이전트 반복 과정 실패

무한 반복, 동일한 도구 호출의 반복, 최종 답변에 도달하지 못하는 문제를 다룹니다.

일반적인 에이전트 반복 과정 실패은(는) CoddyKit의 무료 AI Agents 강의입니다. 이것은 4개 중 1번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 AI Agents 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. AI Agents 강의에는 총 4개의 강의가 포함되어 있습니다.

에이전트 루프와 실패 유형

에이전트 루프는 추론 → 도구 호출 → 결과 관찰 → 다시 추론하는 과정을 반복해서 실행합니다. 이 루프는 강력하지만 취약합니다. 잘 알려진 여러 실패 유형으로 인해 에이전트가 멈추고, 토큰을 낭비하며, 유용한 출력을 생성하지 못할 수 있습니다.

이러한 실패를 이해하는 것이 이에 대응하는 첫 단계입니다.

실패 1: 무한 루프

에이전트가 진전 없이 같은 인수로 같은 도구를 반복해서 호출하면 무한 루프가 발생합니다. 도구가 도움이 되지 않는 결과를 반환하고 에이전트가 추론만으로 그 상황에서 벗어나지 못할 때 이런 일이 발생할 수 있습니다.

# Example of an agent in an infinite loop:
# Step 1: reasoning='Need to search for Python docs'
#         tool='search_web', args={'query': 'Python documentation'}
# Step 2: reasoning='Search result was unhelpful, try again'
#         tool='search_web', args={'query': 'Python documentation'}
# Step 3: reasoning='Search result was unhelpful, try again'
#         tool='search_web', args={'query': 'Python documentation'}
# ... repeats until max_iterations or token budget is exhausted

print('Symptom: same tool + same arguments appearing repeatedly in steps')
print('Fix: detect repeated (tool, args) pairs and break the loop')

실패 2: 멈춘 상태

멈춘 상태는 무한 루프보다 미묘한 형태입니다. 에이전트가 계속 추론하고 서로 다른 도구를 호출하지만 최종 답변에 도달하지 못합니다. 진전 없이 여러 접근 방식 사이를 오갑니다.

# Example of a stuck agent:
# Step 1: tool='search_web', args={'query': 'topic A'}
# Step 2: tool='search_web', args={'query': 'topic B'}  # different args
# Step 3: tool='search_web', args={'query': 'topic A'}  # back to first
# Step 4: tool='read_document', args={'url': '...'}
# Step 5: tool='search_web', args={'query': 'topic A'}
# ... no FINAL_ANSWER ever produced

print('Symptom: agent takes many steps but never calls FINAL_ANSWER')
print('Fix: max_iterations guard + force final answer if limit is near')

실패 3: 최종 답변 누락

일부 에이전트는 작업이 완료되었다고 판단하지 못한 채 계속 반복합니다. 정보를 수집하기만 하고 이를 종합하여 반환하기 위해 멈추지 않습니다. 이로 인해 토큰과 시간이 낭비됩니다.

# An agent that never concludes:
def run_agent_bad(query: str, max_steps: int = 20) -> str:
    for step in range(max_steps):
        action = llm_decide_action(query, history)

        if action['type'] == 'tool':
            result = execute_tool(action)
            history.append(result)
        # BUG: No check for 'final_answer' type!
        # The agent loops until max_steps, returning None

    return None  # never actually returns an answer

# Fix: explicitly check for final_answer signal
def run_agent_good(query: str, max_steps: int = 20) -> str:
    for step in range(max_steps):
        action = llm_decide_action(query, history)
        if action['type'] == 'final_answer':
            return action['answer']  # exit cleanly
        execute_tool(action)
    return 'Reached step limit without a conclusion.'

실패 4: 도구 호출 구문 분석 오류

LLM이 함수 호출을 위한 형식이 잘못된 JSON을 생성하면 도구 실행기가 이를 구문 분석하지 못합니다. 제대로 작성되지 않은 에이전트는 충돌하거나 해당 단계를 조용히 건너뜁니다. 견고한 에이전트는 구문 분석 오류를 포착하고 그 오류를 LLM에 다시 전달합니다.

import json

def safe_parse_tool_call(arguments_str: str) -> dict:
    try:
        return json.loads(arguments_str)
    except json.JSONDecodeError as e:
        print(f'Failed to parse tool arguments: {e}')
        print(f'Raw: {arguments_str}')
        return None

def execute_step(tool_call) -> str:
    args = safe_parse_tool_call(tool_call.function.arguments)
    if args is None:
        # Feed the error back to the LLM in the next step
        return f'ERROR: Could not parse tool arguments. Raw: {tool_call.function.arguments}'
    return run_tool(tool_call.function.name, args)

실패 5: 도구가 유용한 데이터를 반환하지 않음

도구가 기술적으로는 성공하더라도(예외가 발생하지 않더라도) 비어 있거나 쓸모없는 데이터를 반환할 수 있습니다. 모든 도구 호출이 실행에 활용할 수 있는 정보를 반환한다고 가정하지 말고 이 경우를 처리해야 합니다.

def run_agent_with_empty_result_handling(query: str) -> str:
    for step in range(20):
        action = decide_next_action(query, history)

        if action['type'] == 'final_answer':
            return action['answer']

        result = execute_tool(action['tool'], action['args'])

        # Detect empty results and provide context
        if not result or result.strip() == '':
            observation = f'Tool {action["tool"]} returned no data. Try a different approach or different arguments.'
        elif 'error' in result.lower():
            observation = f'Tool error: {result}. Consider a different tool or query.'
        else:
            observation = result

        history.append({'tool': action['tool'], 'result': observation})

    return 'Could not complete task within step limit.'

실패 6: 환각으로 생성된 도구 이름

LLM이 존재하지 않는 도구 이름을 생성하는 경우가 있습니다. 도구를 호출하기 전에 항상 등록된 도구 목록과 대조하여 도구 이름을 검증합니다. 이런 일이 발생하면 에이전트에 유용한 오류를 반환합니다.

REGISTERED_TOOLS = {
    'search_web': search_web_function,
    'get_weather': get_weather_function,
    'calculate': calculate_function
}

def dispatch_tool(tool_name: str, args: dict) -> str:
    if tool_name not in REGISTERED_TOOLS:
        available = ', '.join(REGISTERED_TOOLS.keys())
        return (
            f'ERROR: Unknown tool "{tool_name}". '
            f'Available tools: {available}. '
            f'Please use one of the available tools.'
        )

    tool_fn = REGISTERED_TOOLS[tool_name]
    return tool_fn(**args)

실패 7: 토큰 예산 소진

전체 도구 결과를 컨텍스트에 저장하는 장시간 실행 에이전트는 LLM의 문맥 창 제한에 도달할 수 있습니다. 결과를 이력에 추가하기 전에 큰 도구 결과를 요약하거나 잘라 내십시오.

def truncate_tool_result(result: str, max_chars: int = 2000) -> str:
    if len(result) <= max_chars:
        return result
    truncated = result[:max_chars]
    return f'{truncated}\n... [result truncated to {max_chars} chars]'

def add_observation_to_history(history: list, tool_name: str, result: str):
    safe_result = truncate_tool_result(result, max_chars=2000)
    history.append({
        'role': 'tool',
        'content': safe_result,
        'tool_name': tool_name
    })
    print(f'[Step] Tool={tool_name}, Result length={len(result)} (stored {len(safe_result)})')

if __name__ == '__main__':
    demo_history = []
    add_observation_to_history(demo_history, 'search_web', 'x' * 3000)

실패 유형을 프로그래밍 방식으로 감지하기

에이전트의 단계 이력을 분석하여 어떤 실패 유형이 발생했는지 식별하는 진단 함수를 작성합니다. 이는 디버깅 중에 매우 유용합니다.

def diagnose_agent_failure(steps: list) -> str:
    if not steps:
        return 'No steps recorded'

    # Check for infinite loop: same (tool, args) repeated
    seen = {}
    for s in steps:
        key = (s.get('tool'), str(s.get('args')))
        seen[key] = seen.get(key, 0) + 1
    repeated = {k: v for k, v in seen.items() if v > 2}
    if repeated:
        return f'INFINITE_LOOP: repeated actions: {repeated}'

    # Check for missing final answer
    has_answer = any(s.get('type') == 'final_answer' for s in steps)
    if not has_answer and len(steps) >= 15:
        return 'STUCK_STATE: many steps taken but no final answer'

    # Check for parse errors
    errors = [s for s in steps if 'ERROR' in str(s.get('result', ''))]
    if len(errors) > 2:
        return f'TOOL_ERROR: {len(errors)} tool errors in pipeline'

    return 'OK'

if __name__ == '__main__':
    demo_steps = [{'tool': 'search_web', 'args': {'q': 'weather'}} for _ in range(3)]
    print('Diagnosis:', diagnose_agent_failure(demo_steps))

간단한 단계 예산 구현하기

모든 운영 환경용 에이전트 루프에는 엄격한 단계 제한이 있어야 합니다. 이는 가장 중요한 안전장치입니다. LLM이 무엇을 결정하든 루프가 종료되도록 보장하기 때문입니다.

def run_agent_with_budget(query: str, max_steps: int = 15) -> dict:
    history = []
    for step in range(1, max_steps + 1):
        print(f'[Step {step}/{max_steps}]')

        action = decide_next_action(query, history)

        if action['type'] == 'final_answer':
            return {
                'status': 'success',
                'answer': action['answer'],
                'steps_taken': step
            }

        result = execute_tool(action['tool'], action['args'])
        history.append({'step': step, 'tool': action['tool'], 'result': result})

        if step == max_steps - 1:
            # Warn the agent it must conclude
            history.append({'role': 'system',
                            'content': 'You must provide a FINAL_ANSWER on the next step.'})

    return {'status': 'timeout', 'answer': None, 'steps_taken': max_steps}

빠른 참고: 실패 유형과 해결 방법

에이전트 루프의 일곱 가지 실패 유형과 해결 방법을 요약하면 다음과 같습니다.

  • 무한 루프: 반복되는 (도구, 인수) 쌍을 감지하고 오류 피드백과 함께 중단합니다
  • 멈춘 상태: 최대 반복 횟수 보호 장치를 사용하고, 제한에 가까워지면 최종 답변을 강제합니다
  • 최종 답변 누락: 동작에 최종 답변 신호가 있는지 명시적으로 확인합니다
  • 구문 분석 오류: JSON 구문 분석을 예외 처리로 감싸고 오류를 LLM에 다시 전달합니다
  • 빈 도구 결과: 빈 문자열을 감지하고 '데이터 없음' 피드백을 제공합니다
  • 환각으로 생성된 도구 이름: 등록된 도구와 대조하여 검증하고 오류 메시지를 반환합니다

지식 확인: 에이전트 루프의 실패

일반적인 에이전트 루프 실패 유형에 대한 이해도를 확인합니다.

복습: 일반적인 에이전트 루프 실패

이제 주요 에이전트 루프 실패 유형을 식별하고 이에 대응할 수 있습니다.

  • 무한 루프, 멈춘 상태, 최종 답변 누락에는 모두 최대 반복 횟수 보호 장치가 필요합니다
  • 도구 호출 구문 분석 오류에는 JSON 구문 분석을 예외 처리로 감싸야 합니다
  • 빈 도구 결과는 감지하고 LLM에 유용한 피드백을 제공해야 합니다
  • 환각으로 생성된 도구 이름은 등록된 도구 목록과 대조하여 검증해야 합니다
  • 토큰 예산 소진에는 결과 잘라 내기가 필요합니다

견고한 에이전트 루프는 이러한 모든 실패 유형을 예상하고 적절하게 처리합니다.

자주 묻는 질문

“일반적인 에이전트 반복 과정 실패” 강의는 무료인가요?

네 — “일반적인 에이전트 반복 과정 실패” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 AI Agents 강의 전체를 잠금 해제할 수 있습니다. AI Agents 강의에는 총 4개의 강의가 포함되어 있습니다.

“일반적인 에이전트 반복 과정 실패”에서 뭘 배우나요?

무한 반복, 동일한 도구 호출의 반복, 최종 답변에 도달하지 못하는 문제를 다룹니다. 브라우저에서 직접 실행하는 실습 코드로 AI Agents을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

AI Agents을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 AI Agents은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 1번째 강의입니다.

“일반적인 에이전트 반복 과정 실패” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 AI Agents 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 AI Agents 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 일반적인 에이전트 반복 과정 실패
  2. 에이전트 단계 추적 로깅
  3. 무한 반복 감지 및 중단
  4. 단계별 디버깅 기법
← AI Agents(으)로 돌아가기