내 에이전트는 결코 불안정한 것이 아니었다 — 실제로 준비되기 전 30~60초 동안 부팅 중이었을 뿐이다
요약
에이전트의 불안정성 문제는 모델의 결함이 아니라 인프라의 부팅 및 준비 상태(readiness) 문제인 경우가 많습니다. 컨테이너가 실행 중이라도 Redis나 Postgres 같은 의존 서비스가 완전히 준비되기 전 작업을 할당하면 오류가 발생하므로, 헬스 체크를 통한 오케스트레이션이 필수적입니다.
핵심 포인트
- 에이전트의 무작위 오류는 모델 품질이 아닌 인프라 부팅 시간 문제일 가능성이 높음
- '컨테이너 시작'과 '서비스 준비 완료'를 구분하여 설계해야 함
- Docker Compose의 healthcheck와 condition: service_healthy를 활용해 의존성 제어
- Redis 등 데이터 레이어에 대한 명시적인 프로브(probe) 도입 권장
에이전트를 24시간 내내 실행하는 사람들로부터 똑같은 불평을 계속 듣고 있습니다:
“불안정해요 (It's flaky).”
죽은 것도 아니고, 지속적으로 고장 난 것도 아닙니다. 그저 첫 번째 턴, 재연결 후, 또는 재시작 직후에 무작위로 성능이 나빠질 뿐입니다.
OpenClaw가 도구 (tool)를 잊어버립니다.
n8n 워커 (workers)가 상태 (state)를 놓칩니다.
커스텀 FastAPI 도구 서버가 올라왔지만, 첫 번째 호출이 실패합니다.
그러면 누군가는 재시도하면 마법처럼 해결되기 때문에 GPT-5나 Claude를 탓합니다.
그러한 패턴은 대개 모델의 품질과는 아무런 상관이 없습니다.
대부분의 경우, 진짜 버그는 부팅 후 첫 30~60초 사이에 존재합니다.
Redis, Postgres, OpenClaw Gateway 또는 생성된 설정 파일 (config file)이 단순히 실행 중일 뿐, 실제로 준비(ready)된 상태가 아니라면, 에이전트는 너무 일찍 작업을 할당받고 제대로 작동하지 못하고 넘어집니다.
그것은 불안정한 AI가 아닙니다. 잘못된 스타트업 오케스트레이션 (startup orchestration)입니다.
실수: "컨테이너 시작됨" != "서비스 준비됨"
이것이 많은 가짜 LLM 버그의 근원입니다.
많은 에이전트 스택은 다음과 같은 순서가 안전하다고 가정합니다:
- 컨테이너 시작
- 에이전트 시작
- 작업 전송
그렇지 않습니다.
실행 중인 Postgres 컨테이너는 여전히 쿼리를 거부할 수 있습니다.
실행 중인 Redis 컨테이너는 여전히 워밍업 (warming) 중일 수 있습니다.
실행 중인 OpenClaw Gateway는 여전히 프로필이나 채널 상태를 놓치고 있을 수 있습니다.
설정 파일은 디스크에 존재하지만 여전히 작성 중일 수 있습니다.
그 결과 다음과 같은 현상이 발생합니다:
- 첫 번째 턴의 도구 (tool) 실패
- 재연결 시 메모리 (memory) 누락
- 재시도 시 사라지는 무작위 스타트업 오류
- 실제로는 인프라 버그임에도 "Claude가 이상했다"라고 보고되는 현상
에이전트 워크플로우 (agent workflows)를 셀프 호스팅 (self-hosting)하고 있다면, 부팅 경로 (boot path)는 사람들이 생각하는 것보다 훨씬 중요합니다.
Docker Compose는 이미 이를 알려주고 있습니다
Compose는 "실행 중 (running)"을 "준비됨 (ready)"으로 취급하지 않습니다.
만약 에이전트가 Postgres에 의존한다면, 헬스 체크 (health check)로 이를 제어하세요.
services:
agent:
build: .
...
여기서 두 가지 중요한 세부 사항이 있습니다:
condition: service_healthy는 에이전트가 실제 준비 상태가 될 때까지 기다린다는 의미입니다.restart: true는 명시적인 의존성 재시작 후 의존 항목이 올바르게 재연결되도록 돕습니다.
두 번째 사항은 과소평가되어 있습니다.
많은 "세션 리셋 (session reset)" 버그는 그저 더 그럴듯한 이름이 붙은 재연결 버그일 뿐입니다.
Redis를 사용 중이라면, Redis를 조사(probe)하세요
동일한 규칙이 적용됩니다.
프로세스가 존재한다고 해서 Redis를 사용할 수 있다고 가정하지 마세요.
헬스 체크 (health check) 예시:
services:
redis:
image: redis:7
...
메모리 레이어 (memory layer), 큐 워커 (queue worker), 또는 에이전트 세션 캐시 (agent session cache)가 Redis에 의존한다면, 이 한 가지 체크만으로도 시작 단계의 놀라운 혼란을 제거할 수 있습니다.
Kubernetes는 수년 전에 이미 이를 올바르게 처리했습니다
Kubernetes에서 에이전트를 실행한다면, liveness probe를 만능 망치처럼 사용하는 것을 멈추세요.
세 가지 개념이 서로 다른 데에는 이유가 있습니다:
startupProbe: 앱이 아직 초기화 중임readinessProbe: 앱이 이제 트래픽을 받을 수 있음livenessProbe: 앱이 비정상 상태이며 재시작되어야 함
이것들은 서로 대체될 수 없습니다.
만약 귀하의 OpenClaw 워커 (worker)나 툴 서버 (tool server)가 다음을 위해 시간이 필요하다면:
- Postgres 연결
- Redis 연결
- 임베딩 (embeddings) 로드
- 볼륨 마운트 (mount volumes)
- 생성된 파일 읽기
- 캐시 하이드레이션 (hydrate caches)
그렇다면 먼저 startup 및 readiness 체크를 수행해야 합니다.
liveness probe를 너무 공격적으로 사용하면, 재부팅 루프 (reboot loop)를 만들고 이를 "자가 치유 (self-healing)"라고 부르게 될 수 있습니다.
그것은 회복 탄력성 (resilience)이 아닙니다. 그것은 귀하가 직접 작성한 서비스 거부 공격 (denial-of-service attack)입니다.
간단한 경험칙 (rule of thumb)
| Probe | 용도 |
|---|---|
| startupProbe | 재시작을 유발해서는 안 되는 느린 초기화 |
| ... |
일부 시작 버그는 네트워크 버그가 전혀 아닙니다
이 부분부터는 상황이 더 짜증 나게 변합니다.
때로는 의존성이 Postgres나 Redis가 아닐 때가 있습니다.
때로는 파일인 경우도 있습니다.
예시:
- 생성된 설정 파일 (config file)
- 플러그인 번들 (plugin bundle)
- 소켓 파일 (socket file)
- 메모리 인덱스 (memory index)
- 다른 프로세스에 의해 작성된 자격 증명 파일 (credentials file)
그리고 네, 이것들은 에이전트 시작을 확실히 망가뜨릴 수 있습니다.
가장 끔찍한 상황은 다음과 같습니다:
- 파일이 나타남
- 시작 스크립트가 이를 감지함
- 에이전트가 부팅됨
- 파일이 여전히 쓰기 작업 중이었음
- 첫 번째 요청이 실패함
- 재시도하면 성공함
- 모두가 모델을 탓함
이것이 파일 준비 상태 (file readiness) 체크가 중요한 이유입니다.
파일 상태가 의존성일 때는 와처 (watcher)를 사용하세요
Node.js의 경우, 저는 Chokidar를 선호합니다.
이는 fs.watch의 여러 가지 기이한 동작들을 매끄럽게 해결해주며, 다음과 같은 실용적인 옵션들을 제공합니다:
awaitWriteFinishatomicready
예시:
import chokidar from 'chokidar';
const watcher = chokidar.watch('./runtime/config.json', {
...
여기서 ready 이벤트가 유용한 부분입니다.
이 이벤트는 추측하는 대신, 초기 파일 탐색(file discovery)이 완료되었다는 실제 신호를 제공합니다.
만약 당신의 에이전트가 생성된 아티팩트 (artifact)에 의존한다면, 이는 단순히 10초 동안 잠을 자며(sleep) 운에 맡기는 것보다 훨씬 나은 방법입니다.
Python의 경우, watchdog를 사용하세요.
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
import time
...
정말로 필요한 경우가 아니라면 저장소 (repo) 전체를 감시하지 마세요.
준비 상태를 증명할 수 있는 단 하나의 파일이나 디렉토리만 감시하세요.
그것이 비결입니다.
OpenClaw는 올바른 디버깅 경로를 제공합니다
OpenClaw에서 제가 좋아하는 점 중 하나는, 문제 해결 흐름이 신비로운 프롬프트 수정 (prompt tweaking) 대신 런타임 (runtime) 상태를 향한다는 것입니다.
만약 어시스턴트 (assistant)가 고장 난 것처럼 느껴진다면, 여기서부터 시작하세요:
openclaw status
openclaw status --all
openclaw gateway probe
...
이것이 정확히 올바른 사고방식입니다.
모델이 왜 나쁘게 행동했는지 묻기 전에, 컨트롤 플레인 (control plane)이 실제로 활성화(warm)되어 있고 연결되어 있었는지 먼저 물으세요.
만약 게이트웨이 (Gateway)가 잘못된 프로필, 오래된 세션 상태 (stale session state), 또는 누락된 도구 (tools)와 함께 실행되었다면, 어시스턴트는 추론 (reasoning)과는 전혀 상관없는 이유로 멍청해 보일 것입니다.
특히 프로필을 전환하거나 특정 도구 노출 (tool exposure)에 의존하고 있다면 더욱 그렇습니다.
만약 어시스턴트가 갑자기 "제한적"인 것처럼 보인다면, 프롬프트를 건드리기 전에 런타임 상태를 확인하세요.
이는 n8n 및 커스텀 워크플로 스택에서도 나타납니다
스택은 다르지만 이야기는 같습니다.
만약 워커 (workers), 큐 (queues), Redis, Postgres, 그리고 커스텀 AI 노드와 함께 n8n을 실행한다면, 당신의 신뢰성 문제는 모델의 문제로 넘어가기 전에 대부분 오케스트레이션 (orchestration)의 문제입니다.
취약점은 지루할 정도로 뻔합니다:
- Redis에 도달하기 전에 워커 (workers)가 시작됨
- 노드 간 암호화 키 (encryption key) 불일치
- 재시작 후 오래된 큐 (queue) 연결
- 작업이 시작될 때 툴 서버 (tool servers)가 준비되지 않음
- 생성된 환경/설정 (env/config) 아티팩트가 늦게 배치됨
이것들은 전형적인 시작 (startup) 및 재연결 (reconnect) 버그입니다.
단지 가시적인 실패가 LLM 기반 워크플로우 (LLM-powered workflow) 내부에서 발생하기 때문에 오진될 뿐입니다.
내가 내일 아침 실제로 할 일
에이전트를 24시간 내내 실행하고 있다면, 다음 체크리스트를 확인하세요.
1) 실제 준비 상태 신호 (readiness signal)로 모든 의존성 (dependency)을 제어하세요
예시:
- Postgres:
pg_isready - Redis:
redis-cli ping - HTTP 툴 서버:
/health또는/readyz - OpenClaw Gateway:
openclaw gateway probe
2) 시작 (startup)과 활성 상태 (liveness)를 분리하세요
느린 웜업 (warm-up)은 프로세스가 죽은 것과는 다릅니다.
초기화 (initialization)에 시간이 걸린다는 이유만으로 정상적인 서비스를 재시작하지 마세요.
3) 시작이 생성된 아티팩트에 의존한다면 하나의 좁은 파일 와처 (file watcher)를 추가하세요
좋은 대상:
- 설정 파일 (config file)
- 플러그인 출력 디렉토리 (plugin output directory)
- 소켓 파일 (socket file)
- 메모리 인덱스 (memory index)
나쁜 대상:
- "거기에 뭔가 중요한 게 있을지도 몰라"라는 이유로 모노레포 (monorepo) 전체를 지정하는 것
4) 재연결 (reconnect) 동작을 명시적으로 만드세요
Postgres, Redis, 또는 OpenClaw Gateway가 재시작되면, 에이전트는 깔끔하게 재연결되어야 합니다.
라이브러리가 당신이 원하는 방식으로 이를 처리할 것이라고 가정하지 마세요.
테스트하세요.
실제로 의존성을 재시작하고 어떤 일이 일어나는지 지켜보세요.
5) 첫 1분을 매우 중요한 것처럼 로그를 남기세요
왜냐하면 실제로 중요하기 때문입니다.
부팅, 재연결, 또는 세션 리셋 (session reset) 후의 첫 30~60초는 수많은 "무작위" 실패가 탄생하는 지점입니다.
로그 기록 대상:
- 의존성 프로브 (dependency probe) 결과
- 설정 로드 (config load) 타이밍
- 툴 등록 (tool registration) 타이밍
- 재연결 시도 (reconnect attempts)
- Postgres/Redis에 대한 첫 번째 성공적인 쿼리
- 첫 번째 성공적인 Gateway 프로브
아주 작은 쉘 게이트 (shell gate)만으로도 충분한 경우가 많습니다
매우 단순한 시작 가드 (startup guard)를 원한다면, 에이전트를 실행하기 전에 다음과 같은 스크립트를 사용하세요:
#!/usr/bin/env bash
set -e
...
화려하지는 않습니다.
하지만 "모든 것을 시작하고 기도하기"보다는 극적으로 더 낫습니다.
토큰당 비용을 지불할 때 이것이 더욱 중요한 이유
사람들이 충분히 이야기하지 않는 부분이 여기 있습니다:
잘못된 스타트업 오케스트레이션 (startup orchestration)은 토큰을 낭비합니다.
만약 에이전트가 준비가 덜 된 의존성 (dependencies) 때문에 충돌하고, 동일한 단계를 세 번이나 재시도하며, 잘못된 재연결을 수행하고, 컨텍스트 (context)를 다시 재생한다면, 당신은 단순히 신뢰성 문제만 겪는 것이 아닙니다. 피할 수 있었던 실수에 대해 비용을 지불하고 있는 것입니다.
이것이 예측 가능한 AI 인프라 (AI infrastructure)가 중요한 이유 중 하나입니다.
지속적으로 실행되는 자동화 (automations)를 구축하고 있다면, 다음 두 가지가 필요합니다:
- 스택 (stack)이 실제로 준비되었을 때만 에이전트가 실행되도록 하는 스타트업 규율 (startup discipline)
- 재시도와 장기 실행 워크플로우 (long-running workflows)가 결제 불안으로 이어지지 않도록 하는 예측 가능한 가격 책정 (predictable pricing)
이것이 이러한 종류의 워크로드 (workload)에 있어 Standard Compute가 매력적인 이유입니다.
Standard Compute는 고정된 월간 가격으로 OpenAI 호환 API를 제공하므로, 하루 종일 토큰 소모량을 노려보지 않고도 에이전트, 자동화, 재시도를 실행할 수 있습니다. 이미 OpenAI SDK, n8n 플로우, 또는 커스텀 에이전트 러너 (agent runners)를 연결하여 사용 중이라면, 그대로 가져다 쓸 수 있는 (drop-in) 점이 핵심입니다.
하지만 고정 요금제 컴퓨팅을 사용하더라도 엔지니어링 교훈은 동일합니다:
부팅 시퀀스 (boot sequence)가 허술하다면, 당신의 에이전트는 여전히 불안정해 보일 것입니다.
단지 당신이 잘못된 계층 (layer)에서 디버깅을 하고 있을 뿐입니다.
던져야 할 더 나은 질문
에이전트가 첫 번째 턴에서 실패했을 때, 다음과 같이 시작하지 마세요:
"왜 GPT-5가 그렇게 행동했을까?"
대신 이렇게 시작하세요:
"모델이 작업을 받았을 때 환경 (environment)의 상태가 정확히 어떠했는가?"
Postgres가 준비되었는가?
Redis에 접속 가능했는가?
OpenClaw Gateway가 워밍업 (warm) 상태였는가?
올바른 툴 프로필 (tool profile)이 로드되었는가?
설정 파일 (config file)이 완전했는가?
라이브니스 프로브 (liveness probe)가 아직 워밍업 중인 프로세스를 종료시키지는 않았는가?
그 지점에서 많은 미스터리가 사라집니다.
그리고 솔직히 말해서, 이것은 좋은 소식입니다.
당신의 "불안정한" 에이전트가 대개 단지 잘못 설계된 스타트업 시퀀스 때문이라는 것을 깨닫는 순간, 문제는 다시 일반적인 엔지니어링의 영역으로 돌아오기 때문입니다.
일반적인 엔지니어링은 해결 가능합니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기