Codex를 통해 '하드 스톱(Hard Stop)'의 가치를 깨닫기 전까지는 지속형 AI 에이전트에게 더 많은 자율성이 필요하다고 생각했습니다
요약
AI 에이전트 운영 시 무조건적인 자율성보다 실행을 즉시 중단할 수 있는 '하드 스톱(Hard Stop)' 기능의 중요성을 강조합니다. 에이전트가 도구를 사용해 상태를 변경할 때, 부분 실행으로 인한 사이드 이펙트를 방지하기 위한 설계 전략을 다룹니다.
핵심 포인트
- 에이전트의 중단 기능은 단순 UX가 아닌 필수적인 런타임 운영 기능임
- 부분 실행(Partial execution)은 상태 불일치와 중복 사이드 이펙트를 유발함
- 비용이 발생하거나 되돌릴 수 없는 작업 전 중단 전략이 반드시 필요함
- OpenAI API의 취소 기능처럼 설계 단계부터 중단 가능성을 고려해야 함
저는 에이전트 운영(Agent Ops)의 주요 역할이 모델이 계속해서 작동할 수 있도록 돕는 것이라고 생각하곤 했습니다.
더 긴 실행 시간. 더 많은 자율성. 더 적은 인간의 체크포인트.
그러다 실제 운영 환경에서 에이전트를 실행하는 사람들의 실패 보고서를 읽기 시작했고, 명확한 패턴을 발견했습니다. 비용이 많이 드는 부분은 대개 에이전트가 멈추는 것이 아니었습니다.
에이전트가 충분히 빨리 멈추지 않는 것이 문제였습니다.
만약 당신의 에이전트가 도구(Tools)를 호출하고, 파일을 편집하며, GitHub에 쓰거나, 웹훅(Webhooks)을 호출하거나, 운영 상태(Production state)를 변경할 수 있다면, 중단(Interruption) 기능은 있으면 좋은 기능이 아닙니다. 그것은 사전에 설계해야 하는 런타임(Runtime) 기능입니다.
OpenClaw에서 Codex를 사용하여 에이전트의 턴(Turn)을 중단하는 것에 관한 Reddit 스레드를 읽으면서 이 점이 명확해졌습니다. 언뜻 보기에는 지엽적인 UX 문제처럼 들릴 수 있지만, 그렇지 않습니다. 에이전트가 턴의 중간 단계에 있고 사이드 이펙트(Side effects)가 이미 발생하고 있다면, "그냥 끝날 때까지 두자"는 방식은 잘못된 운영 모델이 됩니다.
진짜 실패 모드는 부분 실행(Partial execution)입니다
가장 명확한 사례 중 하나는 2026.7.1 릴리스 이후 설치를 망가뜨린 OpenClaw 불만 스레드에서 나왔습니다.
한 사용자가 다음과 같은 경고를 보았습니다:
에이전트가 응답을 생성할 수 없습니다. 참고: 일부 도구 작업이 이미 실행되었을 수 있습니다 — 재시도하기 전에 확인하십시오.
이 문장이 문제의 핵심입니다.
그 문구가 극적이라서가 아닙니다. 그것이 정상적인 상황이기 때문입니다.
현실 세계에서 에이전트의 실패는 다음과 같은 모습으로 나타납니다:
- 모델이 턴의 중간 단계까지 진행됨
- 일부 도구가 이미 실행됨
- 상태(State)가 현재 절반만 변경됨
- 재시도 시 사이드 이펙트(Side effects)가 중복될 수 있음
- 무슨 일이 일어났는지 아무도 완전히 확신하지 못함
많은 에이전트 관련 논의들이 여전히 중단을 단순한 UI 기능처럼 취급합니다.
저는 그것이 거꾸로 되었다고 생각합니다.
중단은 운영의 기본 요소(Ops primitive)입니다.
만약 당신의 에이전트가 다음 중 하나라도 수행할 수 있다면, 중단 전략(Stop strategy)이 필요합니다:
- 이메일 전송
- Slack 또는 Discord에 게시
- 코드 병합(Merge)
- 파일 편집
- Jira 티켓 생성
- n8n 웹훅 트리거
- Make 시나리오 실행
- 데이터베이스에 쓰기
질문은 "이 에이전트가 얼마나 자율적인가?"가 아닙니다.
질문은 이것입니다: "비용이 많이 들거나 되돌릴 수 없게 되기 전에 어디에서 중단할 수 있는가?"
OpenAI의 취소(cancellation)는 이를 계획했을 때만 작동합니다
OpenAI의 Responses API는 장시간 실행되는 작업에 대해 실제 취소 경로(cancellation path)를 제공합니다.
이는 유용합니다.
하지만 함정이 있습니다: background=true로 생성된 응답만 취소할 수 있다는 점입니다.
따라서 중단(interruption)은 나중에 덧붙이는(bolt on) 것이 아닙니다. 실행(run)이 중단 가능하도록 설계되었거나, 그렇지 않거나 둘 중 하나입니다.
백그라운드 모드로 실행 시작
curl https://api.openai.com/v1/responses \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
...
그 다음 응답이 여전히 실행 중인 동안 상태를 폴링(poll)합니다.
curl https://api.openai.com/v1/responses/$RESPONSE_ID \
-H "Authorization: Bearer $OPENAI_API_KEY"
만약 턴(turn)이 멈춰 있거나, 루프를 돌거나, 너무 오래 걸린다면 취소하십시오.
curl -X POST https://api.openai.com/v1/responses/$RESPONSE_ID/cancel \
-H "Authorization: Bearer $OPENAI_API_KEY"
Python을 사용한 최소한의 폴링 예시
import os
import time
import requests
...
많은 에이전트 러너(agent runners)들은 여전히 모든 턴이 동기적(synchronous)이어야 한다고 가정합니다.
그 결과, 팀들은 영원히 기다리기만 하고 이를 깔끔하게 중단할 방법이 없는 프로세스를 갖게 됩니다.
취소는 부수 효과(side effects)를 되돌리지 않습니다
이 부분은 사람들이 흔히 간과하는 지점입니다.
모델을 중단한다고 해서 이미 발생한 일을 롤백(roll back)하지는 않습니다.
만약 에이전트가 이미 다음과 같은 행동을 했다면:
- Slack에 게시
- Jira 이슈 생성
- 파일 작성
- 웹훅(webhook) 호출
- 레코드 업데이트
응답을 취소하더라도 이 중 그 어떤 것도 되돌릴 수 없습니다.
따라서 여전히 다음 요소들이 필요합니다:
- 멱등성(idempotent) 도구
- 재시도 전 검증
- 보상 작업(compensating actions)
- 감사 로그(audit logs)
- 상태 검사(state inspection)
취소는 출혈을 멈추게 할 뿐입니다. 피를 닦아내지는 않습니다.
LangGraph는 대부분의 프레임워크보다 중단을 더 올바르게 처리합니다
LangGraph의 중단(interrupt) 모델은 프로덕션 시스템이 필요로 하는 것에 훨씬 더 가깝습니다.
적절한 순간에 턴을 죽일 수 있기를 바라는 대신, 그래프 내에 정확한 일시 중지 지점(pause points)을 정의합니다.
from langgraph.types import interrupt
def approval_node(state):
...
나중에, 동일한 thread_id를 사용하여 그래프를 재개합니다.
from langgraph.types import Command
graph.invoke(
...
이는 무모한 재시도 (blind retries)보다 훨씬 더 나은 모델입니다.
실행이 어디서 멈췄는지 추측하는 것이 아닙니다. 어디서 일시 중단되었는지 정확히 알 수 있습니다.
지속 가능한 상태 (Durable state)는 데모와 시스템을 가르는 차이점입니다
이 지점이 바로 많은 에이전트 데모들이 속임수를 쓰는 부분입니다.
일시 중단/재개 (Pause/resume) 기능은 프로세스가 재시작되기 전까지는 인메모리 상태 (in-memory state)로도 훌륭해 보입니다.
복구 가능한 인터럽트 (recoverable interrupts)를 원한다면, 실제 체크포인터 (checkpointer)가 필요합니다.
LangGraph의 경우, 이는 보통 다음과 같은 것을 의미합니다:
PostgresSaverSqliteSaver
재시작 시 사라져 버리는 인메모리 체크포인터가 아닙니다.
실제적인 스케치는 다음과 같습니다:
from langgraph.checkpoint.sqlite import SqliteSaver
checkpointer = SqliteSaver.from_conn_string("state.db")
...
이를 통해 워커 (worker)가 충돌하거나 프로세스가 재배포(redeployed)되더라도 실제적인 복구 경로를 확보할 수 있습니다.
만약 당신의 에이전트가 일시 중단은 할 수 있지만 재시작 후 결정론적으로 (deterministically) 재개할 수 없다면, 그것은 인터럽트가 아니라 연극 (theater)에 불과합니다.
실제로 인터럽트 지점을 배치할 곳
모든 워크플로 (workflow)에 인간의 승인이 필요한 것은 아닙니다.
로그를 요약하거나, 티켓을 분류하거나, PDF에서 필드를 추출하거나, 지원 메시지를 라우팅하는 경우, 너무 많은 승인 게이트 (approval gates)는 처리량 (throughput)을 저하시킬 뿐입니다.
하지만 인터럽트가 마찰을 감수할 만큼 가치 있는 명확한 지점들이 있습니다.
1. 되돌릴 수 없는 부작용 (irreversible side effects)이 발생하기 전
다음 작업 전에 일시 중단을 배치하세요:
- 이메일 전송
- PR (Pull Requests) 병합
- 레코드 삭제
- 외부 게시
- 운영 시스템 (production systems)에 쓰기 작업
2. 턴 (turn)이 정상적인 실행 시간을 초과할 때
GPT-5, Claude Opus, 또는 Grok이 예상 범위를 훨씬 벗어나 계속해서 연산을 수행하고 있다면, 무언가 잘못되었을 가능성이 높습니다.
시간 예산 (time budgets)을 사용하세요.
MAX_RUNTIME_SECONDS = 90
실행이 임계값을 넘으면, 검토를 위해 라우팅하거나 취소하세요.
3. 도구 출력 (tool output)이 일관되지 않을 때
예시:
- 잘못된 형식의 JSON
- 반복되는 재시도
- 빈 페이로드 (empty payloads)
- 모순되는 도구 결과
- 필수 필드 누락
그것은 에이전트가 실수를 누적하기 전에 일시 중지해야 한다는 강력한 신호입니다.
4. 에이전트가 루프(looping)를 시작할 때
이 현상은 실제 환경에서 끊임없이 나타납니다.
에이전트가 동일한 패턴을 계속 재시도하거나, 동일한 도구(tool)를 계속 호출하거나, 결코 얻을 수 없는 형식을 계속 요청하는 경우입니다.
그것은 자율성(autonomy)이 아닙니다.
그것은 중단 조건(stop condition)이 누락된 것입니다.
5. 비용과 큐(queue) 압박이 눈덩이처럼 불어나기 전에
장시간 실행되는 턴(turns)에 재시도와 도구 소모(tool churn)가 더해지면, 팀들이 사용량 기반 AI 과금(usage-based AI billing)에서 싫어하는 고질적인 문제가 발생합니다. 즉, 시스템이 멍청한 짓을 하는 동안 계량기가 돌아가는 것을 실시간으로 느끼게 되는 것입니다.
이것이 에이전트 워크로드에서 예측 가능한 컴퓨팅(predictable compute)이 매우 중요한 이유 중 하나입니다. 만약 n8n, Make, Zapier, OpenClaw 또는 커스텀 워커(custom workers)에서 하루 종일 자동화(automations)를 실행하고 있다면, 토큰당 과금(per-token billing) 방식은 모든 잘못된 루프를 재무적인 문제로 변질시킵니다.
고정 월정액 모델(flat monthly model)은 에이전트 운영(agent ops)에 훨씬 더 적합합니다. 왜냐하면 하루 종일 지출 대시보드를 감시하는 대신 런타임 제어(runtime controls)에 집중할 수 있게 해주기 때문입니다.
빠른 비교: 각 접근 방식이 실제로 잘하는 것
| 접근 방식 | 강점 |
|---|---|
| OpenAI Responses 백그라운드 모드 | background=true로 시작할 때, 장시간 실행되는 모델 작업을 위한 비동기 실행(Async execution), 폴링(polling) 및 취소(cancellation) |
| ... |
주관적인 버전:
- OpenAI Responses는 취소 가능한 장시간 모델 호출에 좋습니다.
- LangGraph는 정밀한 일시 중지/재개(pause/resume) 의미론(semantics)이 필요할 때 더 좋습니다.
- 자유롭게 실행되는 에이전트 루프(Free-running agent loops)는 복구 없는 중단이 설계의 절반에 불과하다는 것을 팀들이 깨닫게 되는 지점입니다.
이것을 하나의 규칙으로 압축해야 한다면, 다음과 같습니다:
검사(inspect), 일시 중지(pause) 또는 복구(repair)할 수 없는 부수 효과(side effect)를 에이전트에게 절대 부여하지 마세요.
더 안전한 에이전트를 위한 실용적인 패턴
만약 제가 오늘 지속형 에이전트(persistent agent)를 구축한다면, 다음과 같은 패턴을 사용할 것입니다:
- 위험한 실행(risky runs)을 비동기(asynchronously)로 시작하십시오.
- Postgres 또는 SQLite에 상태(state)를 유지(persist)하십시오.
- 되돌릴 수 없는 작업(irreversible actions) 전에 명시적인 중단 지점(interrupt points)을 추가하십시오.
- 단계별(per step) 및 실행별(per run) 런타임 제한(runtime limits)을 추가하십시오.
- 가능한 경우 도구 호출(tool calls)을 멱등(idempotent)하게 만드십시오.
- 나중에 검증하거나 보상(compensate)할 수 있도록 충분한 메타데이터와 함께 모든 부작용(side effect)을 로그(log)로 남기십시오.
- 의심스러운 실행은 맹목적으로 재시도하는 대신 검토(review) 단계로 라우팅하십시오.
의사코드(pseudocode)로 표현하면 다음과 같습니다:
def run_agent(task):
state = load_state(task.thread_id)
...
이것은 “완전 자율 소프트웨어 엔지니어(fully autonomous software engineer)”라는 말보다 덜 화려합니다.
하지만 실제 운영 환경(production)에서 살아남는 방식에는 훨씬 더 가깝습니다.
에이전트 운영(agent ops)에서 과소평가된 기술
사람들은 에이전트가 아무런 관리 없이 14단계의 워크플로우(workflows)를 수행하는 스크린샷을 올리는 것을 좋아합니다.
하지만 그들이 올리지 않는 것은 9단계의 상황입니다:
- 하나의 API가 타임아웃(timed out)됨
- 하나의 도구가 이미 실행됨
- 모델이 맥락(thread)을 놓침
- 큐(queue)가 쌓이고 있음
- 이제 누군가가 실행을 재개할지, 재시도할지, 보상할지, 아니면 종료할지 결정해야 함
그것이 실제 업무입니다.
단순히 프롬프팅(prompting)만 하는 것이 아닙니다.
단순히 GPT-5, Claude Opus, Grok, Qwen 또는 Llama 중에서 선택하는 것도 아닙니다.
과소평가된 기술은 턴(turn)을 끝까지 마치게 두는 대신, 언제 중단(interrupt)해야 하는지를 아는 것입니다.
그 사실을 받아들이고 나면, 많은 아키텍처(architecture) 결정이 쉬워집니다:
- 위험한 실행을 처음부터 비동기(async)로 만들기
- 조기에 중단 조건(stop conditions) 추가하기
- 실제 어딘가에 상태(state)를 유지(persist)하기
- 재시도(retries)를 고려하여 도구 설계하기
- 부분적 실행(partial execution)을 위한 보상 작업(compensating actions) 구축하기
이것은 자율성(autonomy)에 반대하는 것이 아닙니다.
이것이 바로 자율성을 생존 가능하게 만드는 방법입니다.
그리고 에이전트를 대규모(scale)로 운영하고 있다면, 이것이 바로 가격 모델(pricing model)이 중요한 이유이기도 합니다. OpenAI 호환 API를 기반으로 자동화(automations)를 구축하는 팀들은 토큰당 과금(per-token billing)으로 인한 지속적인 비용 불안감 없이 현대적 모델의 제어 표면(control surface)을 원하곤 합니다. 이것이 바로 Standard Compute와 같은 서비스가 흥미로운 이유입니다. 동일한 OpenAI 호환 워크플로우를 제공하면서도, 상시 가동되는(always-on) 에이전트에 훨씬 더 적합한 월정액 요금제를 제공하기 때문입니다.
가장 똑똑한 에이전트는 결코 멈추지 않는 에이전트가 아닙니다.
당신이 의도적으로 멈출 수 있는 에이전트입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기