Agent가 같은 자리를 맴돌 때, 언제 멈춰야 하는지 어떻게 아는가
← 전체 목차 · 이전: 실행 중 계획이 통째로 무너지면, Agent는 어떻게 스스로 경로를 바꾸는가 · 다음: Agent는 어떤 도구를 호출해야 할지 어떻게 아는가
"같은 도구를 N번 이상 부르면 중단한다"는 판정은 가장 먼저 뚫린다. 도구를 바꿔 가며 제자리를 맴돌면 카운터에 안 잡히고, 매번 파라미터를 살짝 바꾸면 카운터가 영원히 임계값을 넘지 않는다. 순환의 진짜 정의는 **"같은 작업 아래 계획 동작이 종료 상태로 수렴하지 못한 채 자원만 계속 소모하는 것"**이며, 판정 단위를 "호출 횟수"에서 "의미"로 옮겨야 이 정의를 잡아낼 수 있다.
호출 횟수 카운팅이 못 잡는 세 가지
| 회피 방식 | 왜 카운터가 못 잡는가 |
|---|
| 도구를 교대로 호출하며 제자리를 맴돎 | 카운팅 차원(도구별)이 애초에 잘못 잡혔다 |
| 매 계획마다 파라미터를 미세 조정 | 행위가 매번 달라지니 카운터 기준으로는 "다른 시도"다 |
| 모델이 "다음 번엔 될 것"이라는 환각에 빠짐 | 종료권을 환각을 일으키는 당사자에게 맡긴 셈이 된다 |
계수는 행위를 세지만, 순환은 의도의 반복이다. 행위가 바뀌어도 의도가 그대로면 여전히 순환이다.
의미 지문 + 상태 머신 — 데이터베이스 원자 설비에 판정을 얹는다
agent_plan_trace 테이블에 계획 스텝마다 의미 지문을 남긴다.
표: agent_plan_trace
필드: task_id / plan_semantic_hash / step_status / tool_called / result_similarity
(task_id, plan_semantic_hash)에 유일 제약을 건다
매 계획 스텝 생성 → 의미 지문 계산 → 삽입 시도
삽입 성공 → 계속 실행
같은 지문 적중 → 즉시 실패 아니라 "검증" 트리거
상태 머신이 작업 단계를 흐르게 한다.
핵심 제약 세 가지: 매 단계 전환은 현재 상태를 기준으로 검증해야 하고, 데이터베이스 행 잠금으로 상태 전환의 유일성을 보장하며, 같은 의미의 계획이 재생성될 때 영향 행 수가 0이면 이를 순환 후보로 판정한다. 순환 판정이 별도의 if 분기가 아니라 유일 제약과 행 잠금이라는 원자 설비가 자연스럽게 함께 잡아내는 부산물이 되는 셈이다.
5층 방어선 — 원인이 다원적이니 방어도 계층으로
무한 루프의 원인은 하나가 아니다: 도구 결과를 모델이 못 알아듣거나, 작업 자체가 답이 없거나, 목표가 표류하거나, 시스템에 애초에 정지 조건이 없거나. 그래서 해법도 카운터 하나가 아니라 층마다 다른 방어가 필요하다.
| 층 | 방어 대상 | 구체 수단 |
|---|
| 1. Prompt 계약층 | 근원에서 순환 확률을 낮춤 | finish 도구를 명시적 계약으로 등록: "완료 또는 충분한 정보 확보 시 반드시 finish 호출, 다른 도구 계속 호출 금지" / "같은 도구·같은 파라미터 연속 2회 실패 시 방법·파라미터를 반드시 바꿀 것" |
| 2. 편성 통제층 | 모델에게서 종료 결정권을 회수 | 총 라운드 상한(10~15) / 동일 도구+동일 파라미터 연속 2회 초과 시 즉시 차단 / 연속 오류 3회 시 강제 강등 — 개입은 점진적으로: 1회 실패→방법 바꾸라고 제시, 2회 실패→중복 중이라고 시스템 메시지 주입, 3회 실패→종료 후 "부분 결과 + 사유"를 출력 |
| 3. 도구 실행층 | 단일 도구 장애가 전체를 끌고 가지 못하게 격리 | 도구별 타임아웃 + 유한 재시도(지수 백오프) + 서킷 브레이커(연속 5회 실패 시 냉각기 진입, 냉각 후 반개방 탐침 1회) |
| 4. 의미 감지층 | 행위는 변하는데 진전은 없는 경우 식별 | 무진전 감지(연속 N스텝 새 사실/데이터/결론 없음 → 강제 중단) + 목표 표류 감지(매 라운드 현재 하위 목표와 원 질문의 의미 유사도 계산, 낮으면 재계획 트리거) |
| 5. 비용 안전망층 | 앞의 모든 층이 실패해도 지켜지는 최후선 | 단일 작업 토큰 예산 상한 초과 시 강제 종료 / 전역 타임아웃 도달 시 프로세스 강제 종료, 뭉툭한 결과라도 반환 |
가로축: 전 층에서 순환 횟수, 실패 원인, 토큰 소모, 실행 시간을 로그·모니터링에 남긴다. 온라인 장애는 모델을 추측하기 전에 먼저 모니터링으로 위치를 특정한다.
핵심 통찰
- 순환은 의미층에서 정의해야지 호출 횟수층에서 정의하면 안 된다 — 판정을 "같은 도구를 몇 번 불렀는가"로 잡는 순간, 도구를 교대로 부르거나 매번 파라미터를 미세 조정하는 가장 흔한 두 회피 방식이 자연 면제된다. "계획 동작이 종료 상태로 수렴하지 못한다"는 정의라야 검출 가능하다.
- 계수는 뒷단 안전망일 뿐이다. 계량 단위가 행위이지 의도가 아니기 때문이다 — Agent가 파라미터나 도구를 바꾸면 행위는 바뀌지만 의도는 그대로다. 의미 지문은 "의도가 반복되는가"를 낙인·유일 제약이 걸리는 스칼라값으로 바꿔 준다.
- 판정을 응용층의 if문이 아니라 데이터베이스의 원자 설비에 얹을 것 — 유일 제약의 "삽입 실패"와 행 잠금의 "영향 행 수 0"은 그 자체로 강한 일관성의 판정 신호다. 다시 조회해서 비교할 필요가 없고, 동시성과 재시도에 자연히 강하다.
- 종료권을 환각을 일으킬 수 있는 바로 그 당사자에게 맡기면 안 된다 — 대형 모델이 "다음 번엔 될 것"이라고 확신할 때, 모델의 자기 판단에 의존하는 어떤 종료 조건도 실패한다. 강제 중단은 반드시 모델 바깥의 상태 머신에서 나와야 한다.
- 자연어 당부는 대형 모델에 대한 강제력이 없고, 강제 호출 인터페이스로 바꿔야 준수율이 올라간다 —
finish 도구 계약 한 줄로 저급 순환의 상당수를 막을 수 있다는 것은, "모델이 반드시 하길 바라는 일"은 전부 반드시 호출해야 하는 출구를 줘야지 당부만 해서는 안 된다는 일반 원칙을 보여준다.
- 통제권을 통제 대상에게 맡길 수 없다 — 편성층의 하드 카운터가 "중점 중의 중점"인 이유는, 정지 결정을 모델 손에서 코드로 되찾아오기 때문이다. 확률적 컴포넌트는 결정론적 행위를 보증할 수 없다.
- "없다는 것"이 "반복"보다 더 찾기 어렵고 더 비싸다 — 파라미터는 다른데 결론이 늘지 않는 호출은 문자열 비교형 차단을 전부 피해 간다. 판정은 정보 증분(새 사실/새 데이터/새 결론)에 걸어야지 행위가 같은지에 걸면 안 된다.
- 매 자동화 방어선마다 강등 경로가 짝을 이뤄야 한다 — 의미 검증 서비스 자체도 장애가 난다. 그럴 때는 호출 횟수 기반 임시 차단 + 사후 인력 샘플링으로 물러서는 것이, "검증이 안 되니 검증을 아예 안 한다"보다 훨씬 안전하다.
엔지니어링 실전 Tips
- 판정과 차단을 분리할 것: "유사 지문 적중"은 차단이 아니라 검증을 트리거한다. "의심"과 "확정"을 두 단계로 나눠야 정당한 반복 시도를 포용할 수 있다.
- 유일 제약이 가장 저렴한 중복 제거기다: 먼저 조회하고 삽입하지 말 것. 삽입 실패 자체가 신호이며, 조회 한 번을 아끼고 동시성 상황의 경쟁 조건도 같이 해결한다.
- 행 잠금 판정은 "영향 행 수"를 볼 것, 반환값을 볼 것이 아니다: 영향 행 수가 0이면 "이 스텝은 진전이 없었다"는 뜻이며, 이는 업무 반환 코드보다 우회하기 어려운 사실이다.
- 재시도 횟수·서킷 브레이커 임계값·냉각 시간을 별도로 설정할 것: 재시도 2회(초 단위), 서킷 브레이커 5회(분 단위 윈도우), 냉각 60초는 서로 다른 시간 단위다. 하나의 "최대 재시도" 파라미터로 뭉뚱그리면 서킷 브레이커가 무의미해진다.
- 반개방 탐침은 서킷 브레이커에 필수다: 차단만 하고 탐침을 안 하면 해당 도구는 영구 오프라인이 된다. 냉각 후 한 번 시험 요청을 던져 성공하면 복구, 실패하면 계속 차단한다.
- 비용 안전망은 "돈"과 "시계 시간"으로 표현할 것: 라운드는 이미 편성층에서 관리한다. 5층은 정교한 축(금액, 시간)으로 "라운드는 적은데 매 라운드가 몹시 비싼" 누락 케이스를 막는다.
- 모니터링 필드는 첫날부터 심을 것: 순환 횟수, 실패 원인, 토큰 소모, 실행 시간 네 필드가 사후 위치 특정의 최소 집합이다. 나중에 심는 비용이 처음부터 써 넣는 것보다 훨씬 크다.