Stop-on-Non-JSON: 자율 에이전트를 신뢰할 수 있게 만드는 안전 패턴

발행: (2026년 2월 1일 오전 11:32 GMT+9)
7 min read
원문: Dev.to

I’m happy to translate the article for you, but I’ll need the text you’d like translated. Could you please paste the content (excluding the source line you already provided) here? Once I have the article’s body, I’ll translate it into Korean while preserving the original formatting, markdown syntax, and technical terms.

Introduction

에이전트를 일정(크론)대로 실행하고 실제 시스템—API, 소셜 네트워크, 온‑체인 액션—에 접근하게 하면, 잔인한 진실을 빨리 깨닫게 됩니다: 대부분의 “에이전트 실패”는 모델 실패나 운영 실패가 아닙니다. 에이전트가 필요하지 않은 경우에도 계속 엔드포인트를 호출합니다.

비‑JSON 응답이 위험한 이유

많은 위험한 엣지 케이스가 비‑JSON 페이로드 형태로 나타납니다:

  • WAF / 봇‑보호 페이지 (HTML)
  • 인증/로그인 리다이렉트 (HTML)
  • 게이트웨이 타임아웃 시 HTML 반환
  • “잘못된 요청” 페이지
  • 벤더 유지보수 화면
  • 부분 응답 / 빈 본문

이를 안전하지 않은 것으로 처리하면 우발적인 스팸 및 부작용을 방지할 수 있습니다.

실제 상황에서의 상태 코드 특이점

엔지니어들은 종종 상태 코드를 기준으로 동작합니다:

  • 200 OK → 진행
  • 429 Too Many Requests → 대기
  • 401 Unauthorized → 토큰 재발급

하지만 플랫폼이 항상 깔끔하게 동작하는 것은 아닙니다. 다음과 같은 경우를 마주할 수 있습니다:

  • 체크포인트 HTML 페이지와 함께 오는 HTTP 200
  • HTML 본문을 포함한 HTTP 404
  • 본문이 잘려 나온 200
  • JSON처럼 보이지만 파싱할 수 없는 응답

에이전트가 이를 오해하면, 하위 시스템의 동작이 치명적일 수 있습니다:

  • 쓰레기 데이터를 파싱해 항목이 0개라고 판단
  • 대기해야 할 때 바로 전송
  • 과도한 재시도
  • 초안 중복 생성

The “Stop‑on‑Non‑JSON” pattern

안전하지 않은 세상에서 안전한 기본값은 JSON을 반환해야 하는 요청이 다른 형태의 응답을 반환하면 즉시 실행을 중단하는 것입니다. 단계는 다음과 같습니다:

  1. 단일 저비용 “세상이 정상인가?” 요청을 수행합니다.
  2. 응답이 유효한 JSON이며 기대하는 형태와 일치하는지 검증합니다.
  3. 검증에 실패하면 해당 크론 실행을 강제로 중단합니다(재시도 없음).

검사가 통과된 경우에만 쓰기 작업을 진행합니다. 이는 부분적인 장애 동안 에이전트가 서비스를 과도하게 호출하는 것을 방지하고 차단 위험을 줄여줍니다.

구현 (툴에 구애받지 않는 의사코드)

import json

class UnsafeResponse(Exception):
    """Raised when a response is deemed unsafe."""
    pass

def safe_json(response_text: str) -> dict:
    # 1) Hard stop on empty body
    if not response_text or not response_text.strip():
        raise UnsafeResponse("empty response")

    # 2) Hard stop on HTML‑ish payloads
    lower = response_text.lstrip().lower()
    if lower.startswith("<!doctype") or lower.startswith("<html"):
        raise UnsafeResponse("html response")

    # 3) Hard stop on parse failure
    try:
        data = json.loads(response_text)
    except Exception:
        raise UnsafeResponse("invalid json")

    # 4) Optional: shape check (e.g., require expected keys)
    # if "posts" not in data:
    #     raise UnsafeResponse("unexpected shape")

    return data

def cron_run():
    # One‑check request
    body = http_get("/feed?limit=10")
    feed = safe_json(body)

    # Proceed with write actions only if the check passed
    if should_engage(feed):
        http_post("/upvote", {"id": pick_post(feed)})

참고

  • HTML 감지는 완벽하지 않지만 대부분의 봇‑게이트 페이지를 잡아냅니다.
  • 형태 검사는 과소평가됩니다; 유효한 JSON 오류 페이로드라도 실패로 간주해야 합니다.

백오프 전략

시스템을 신뢰성 있게 유지하면서 과도한 알림을 방지하려면, 세 가지 유형의 백오프를 추적하세요:

  1. 쓰기 백오프 – 자동화 또는 속도 제한으로 인해 게시물/답글이 실패하면, 몇 시간 동안 쓰기를 일시 중지합니다.
  2. 엔드포인트 백오프 – API가 체크포인트 HTML을 반환하면, 잠시 동안 해당 API 호출을 중단합니다.
  3. 인간 개입 백오프 – 중요한 작업의 경우 자동 재시도 대신 인간에게 에스컬레이션합니다.

10분마다 실행되는 크론 작업이 매 10분마다 통신할 필요는 없습니다. 최적의 조합은:

  • 자주 실행
  • 드물게 행동
  • 항상 로그 기록

결론

에이전트가 실제 시스템에 접근하도록 허용한다면, 오늘 바로 시도해 보세요:

  • Stop‑on‑Non‑JSON 구현: 단일 체크 요청을 게이트키퍼로 만들기.
  • 실패 후 쓰기 백오프 추가.

이것이 에이전트를 더 똑똑하게 만들지는 않지만, 배포하기에 충분히 안전하게 만들어 줍니다. OpenClaw(또는 다른 에이전트 스택) 위에서 개발하고 있다면, 자유롭게 공유해 주세요: 에이전트가 “JSON API”에서 받은 가장 이상한 응답은 무엇인가요?

Back to Blog

관련 글

더 보기 »

Ignacia 포트폴리오 엔진 V!

새해, 새로운 당신 포트폴리오 챌린지 – Google AI 제출물, 새해, 새로운 당신 포트폴리오 챌린지 (Google AI 제공) https://dev.to/challenges/new-...

Anaconda Distribution 개발 중

!Anaconda Distribution https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amaz...