← 모든 글

Tool Use Loop 가 멈추지 않을 때 — 안전장치 설계

LLM 에이전트가 도구 호출 루프를 빠져나오지 못하는 상황을 어떻게 감지하고 제어할 것인가에 대해 팀이 고민한 내용을 공유한다.

에이전트 워크플로우를 처음 만들 때 우리가 예상하지 못했던 문제가 있었다. 모델이 도구를 호출하고, 결과를 받아 다음 도구를 호출하는 루프가 멈추지 않는 상황이었다. 에러도 없고, 정상적인 흐름처럼 보이는데 같은 도구를 계속 반복하거나 아무 진전 없이 돌기만 했다.

루프가 멈추지 않는 원인들

우리가 경험한 원인은 크게 두 가지였다.

첫째는 목표 불명확이다. “필요한 정보를 모두 모아라”처럼 종료 조건이 모호한 목표를 주면 모델이 언제 멈춰야 하는지 스스로 판단하기 어렵다. 정보를 더 찾을 수 있는 도구가 남아있는 한 계속 호출하려는 경향이 있다.

둘째는 도구 결과 해석 실패다. 어떤 도구가 “결과 없음”을 반환했을 때 모델이 이를 다르게 해석하고 같은 도구를 다른 인자로 다시 호출하는 경우가 있었다. 빈 결과 처리를 명시적으로 프롬프트에 정의해두지 않으면 반복이 발생한다.

우리가 도입한 안전장치

가장 기본적인 것은 호출 횟수 제한이다.

MAX_TOOL_CALLS = 20

def agent_loop(task, tools):
    call_count = 0
    while True:
        response = model.generate(task)
        if response.is_final:
            return response
        if call_count >= MAX_TOOL_CALLS:
            return error_response("최대 호출 횟수 초과")
        result = tools.execute(response.tool_call)
        task = task.append_result(result)
        call_count += 1

단순하지만 효과적이다. 제한에 걸리면 에러를 명시적으로 반환하고 로그를 남긴다. 이 로그를 분석하면 어떤 상황에서 루프가 발생하는지 패턴을 파악할 수 있다.

두 번째는 중복 호출 감지다. 같은 도구에 같은 인자로 연속 호출이 발생하면 무한 루프의 신호로 본다. 직전 호출 기록을 비교해서 동일하면 루프를 강제 종료하고 이유를 반환한다.

세 번째는 명시적 종료 도구다. 모델이 “작업이 완료됐다”고 판단했을 때 호출할 수 있는 별도 도구를 제공한다. 이 도구를 호출하면 루프가 종료된다. 이렇게 하면 모델이 “언제 멈춰야 하는가”를 도구 선택으로 표현할 수 있다.

설계 원칙으로서의 교훈

에이전트 루프를 설계할 때 “어떻게 하면 모델이 더 많이 할 수 있을까”만큼 “어떻게 멈출 것인가”도 처음부터 고려해야 한다. 종료 조건이 명확하고, 루프에 상한이 있고, 비정상 상태를 감지하는 장치가 있어야 안심하고 에이전트를 프로덕션에 올릴 수 있다.

셋이서 이 문제를 겪고 나서 “에이전트 루프의 설계는 알고리즘보다 운영 관점이 더 중요하다”는 말이 자주 나온다. 이상적인 흐름을 만드는 것보다 비정상 상황을 안전하게 처리하는 것이 실무에서 더 중요하다.

— by slecs