본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 05. 26. 21:58

재개 가능한 에이전트 워커(Agent Workers)를 위한 작은 런타임을 구축했습니다

요약

에이전트의 지속 가능한 실행을 지원하기 위해 설계된 경량 런타임 레이어인 Roost를 소개합니다. 기존의 거대한 프레임워크와 달리, 작업의 상태 유지, 재시도 안전성, 리소스 점유 등 운영적 측면에 집중하여 에이전트 워커의 안정성을 높입니다.

핵심 포인트

  • 에이전트를 지속 가능한 단계 머신(durable step machine)으로 취급
  • 작업별 리스 및 스냅샷을 통한 장애 복구 지원
  • 프롬프트나 모델 라우팅이 아닌 운영적 안정성에 특화
  • 최소 한 번 실행 및 재시도 안전한 진행 보장

얼마 전 저는 재개 가능한 (resumable) 에이전트 런타임 (runtime)이 필요했습니다.

저는 Temporal만큼 거대한 것을 원하지 않았고, LangChain과 같은 또 다른 에이전트 프레임워크 (agent framework)도 원하지 않았습니다. 제가 이해할 수 있을 만큼 충분히 작으면서도, 제가 구축하고 있는 다양한 수직 계열 (verticals) 전반에 걸쳐 적응할 수 있을 만큼 견고한 것을 원했습니다.

이것은 몇 가지 기본적인 질문에서 시작되었습니다.

에이전트가 노트북 (notebook), 스크립트 (script), 또는 채팅 세션 (chat session)을 벗어나는 순간, 어려운 문제들이 바뀝니다:

  • 어떤 작업이 존재하는가?
  • 현재 어떤 워커 (worker)가 그 작업을 소유하고 있는가?
  • 마지막으로 수행된 지속 가능한 단계 (durable step)는 무엇인가?
  • 충돌 (crash) 발생 후 다른 워커가 재개할 수 있는가?
  • 어떤 리소스 (resources)가 잠겨 있는가?
  • 에이전트가 무엇을 생성했는가?
  • 운영자 (operators)가 발생한 일을 검사할 수 있는가?

그 결과물로, 해당 문제를 해결하기 위한 작은 런타임 레이어 (runtime layer)인 Roost가 탄생했습니다.

GitHub: https://github.com/mczaykowski/Roost

기본 개념

Roost는 에이전트를 지속 가능한 단계 머신 (durable step machine)으로 취급합니다.

엔진 (engine)은 두 가지 메서드를 구현합니다:

class Engine:
    engine_id: str

...

엔진은 도메인 특화 전이 (domain-specific transition)를 소유합니다.

Roost는 운영 기질 (operational substrate)을 소유합니다:

Queue
  -> lease 획득 (acquire lease)
  -> 최신 스냅샷 (Snapshot) 로드
...

이를 통해 다음과 같은 기능을 얻을 수 있습니다:

  • 지속 가능한 스냅샷 (durable snapshots)
  • 작업별 리스 (per-work leases)
  • 최소 한 번 실행 (at-least-once execution)
  • 재시도에 안전한 진행 (retry-safe progress)
  • 지연된 계속 (delayed continuation)
  • 리소스 점유 (resource claims)
  • 이벤트 히스토리 (event history)
  • 콘텐츠 주소 지정된 아티팩트 (content-addressed artifacts)
  • 실패한 작업 검사 (failed-work inspection)

이것은 의도적으로 작게 설계되었습니다. 프롬프트 프레임워크 (prompt framework), 모델 라우터 (model router), 워크플로 DSL (workflow DSL), 또는 호스팅된 에이전트 플랫폼 (hosted agent platform)이 되려고 시도하지 않습니다.

Roost는 에이전트가 생각하는 것을 돕지 않습니다.

Roost는 에이전트가 계속 나아가는 것을 돕습니다.

이것을 구축한 이유

많은 에이전트 도구들이 사고 루프 (thinking loop)에 집중합니다: 프롬프트 (prompts), 도구 (tools), 검색 (retrieval), 계획 (planning), 메모리 (memory), 모델 라우팅 (model routing).

그것은 유용하지만, 에이전트가 워커 (workers)로서 몇 분, 몇 시간, 또는 며칠 동안 실행되면, 병목 현상은 더 지루하고 더 운영적인 (operational) 문제가 됩니다.

예를 들어:

  • 워커가 작업 중간에 종료됨
  • 동일한 작업이 두 번 전달됨
  • 장기 실행 작업 (long-running task)이 다음 단계로 넘어가기 전에 대기해야 함
  • 두 명의 워커가 동시에 동일한 리소스에 접근해서는 안 됨
  • 운영자 (operator)가 무슨 일이 일어났는지 알아야 함
  • 나중에 출력물을 검사할 수 있어야 함

워크플로 엔진 (workflow engine), 커스텀 큐 (custom queue), 데이터베이스 테이블 (database table), 또는 일련의 스크립트 뭉치로 이를 해결할 수 있습니다.

Roost는 이러한 계층을 에이전트 형태에 맞게 작게 구현해 보려는 저의 시도입니다.

간단한 데모: 충돌 방지(crash-safe) URL 감시 목록

데모 엔진은 URL 감시 목록 (watchlist) 워커입니다.

이 워커는 여러 단계에 걸쳐 URL을 가져오고, 각 관찰 결과(observation)를 스냅샷 (snapshot)에 저장하며, 체크 사이에 대기한 후, 최종 JSON 아티팩트 (artifact)를 작성합니다.

작업 중간에 워커를 강제 종료하고 다시 시작하더라도, Roost는 가장 최근에 저장된 스냅샷부터 재개합니다.

uv sync --extra redis --extra dev
docker run --rm -p 6379:6379 redis:7

한쪽 터미널에서:

uv run roost worker --engines watchlist

다른 터미널에서:

WORK_ID=$(uv run roost enqueue \
  --engine watchlist \
  --resource domain:example.com \
...

그 다음 Ctrl-C로 워커를 종료하고, 다시 시작한 뒤, 동일한 작업 항목을 검사해 보세요.

uv run roost worker --engines watchlist
uv run roost status "$WORK_ID"

로컬 엔드 투 엔드 (end-to-end) 스크립트도 있습니다:

scripts/e2e_watchlist.sh

LLM 키는 필요하지 않습니다. 이 데모는 모델의 동작이 아니라 런타임 (runtime) 동작에 관한 것입니다.

로컬 콘솔

Roost에는 작은 로컬 콘솔이 포함되어 있습니다:

uv run roost ui

실시간 작업, 저장된 상태, 이벤트, 실패한 작업 및 아티팩트를 보여줍니다.

Roost Console Work View

상세 보기 (detail view)를 통해 페이로드 (payload), 스냅샷, 그리고 출력물을 검사할 수 있습니다:

Roost Console Detail

이것이 위치하는 곳

Roost는 LangChain, LlamaIndex, CrewAI, AutoGen, Temporal, Celery 또는 여러분의 자체 에이전트 루프 (agent loop)를 대체하는 것이 아닙니다.

Roost는 다른 계층 (layer)에 위치합니다.

LangChain은 에이전트가 무엇을 해야 할지 결정하는 것을 돕습니다.
Temporal은 워크플로 (workflows)를 조정하는 것을 돕습니다.
Celery는 작업 (jobs)을 실행합니다.
...

현재 백엔드 (backend)는 Redis + SAQ입니다. 실행은 최소 한 번 (at-least-once) 보장되므로, 엔진은 동일한 스냅샷 (snapshot)으로부터 step()이 재시도 안전 (retry-safe)하도록 만들어야 합니다.

이러한 트레이드오프 (tradeoff)는 의도된 것입니다. 저는 정확히 한 번 (exactly-once) 실행이 존재하는 것처럼 가장하기보다는 의미론 (semantics)을 명확하게 드러내는 쪽을 택하겠습니다.

피드백을 받고 싶은 부분

저는 특히 추상화 경계 (abstraction boundary)에 대한 피드백에 관심이 많습니다.

이것이 에이전트 루프 (agent loops) 하단의 작은 런타임 (runtime)으로서 유용할까요?

여러분은 Temporal, Celery 또는 커스텀 큐 (custom queue) 중 무엇을 더 선호하시나요?

init_snapshot() / step() 모델이 너무 작게 느껴지나요, 아니면 딱 적당한 크기인가요?

GitHub: https://github.com/mczaykowski/Roost

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0