본문으로 건너뛰기

© 2026 Molayo

Qiita헤드라인2026. 06. 19. 13:41

Cloudflare Agents SDK, 부작용(Side Effect)을 승인 게이트로 중단하고 재개하는 메커니즘

요약

Cloudflare Agents SDK v0.16.1은 에이전트의 부작용(Side Effect)이 있는 작업을 인간이 승인할 수 있는 메커니즘을 제공합니다. 이벤트 소싱 방식을 통해 작업 중단 시에도 로그를 기반으로 상태를 복구하고 이어서 실행할 수 있는 내구성을 갖췄습니다.

핵심 포인트

  • 인간의 승인을 거치는 '승인 게이트' 메커니즘 도입
  • 이벤트 소싱 기반의 내구 로그를 통한 중단 및 재개 지원
  • Code Mode를 활용해 대규모 API 호출 시 토큰 소비 99.9% 절감
  • V8 샌드박스 환경을 통한 보안 및 격리 강화

에이전트에게 "GitHub 이슈를 만들어 둬"라고 부탁했다고 가정하자. 모델이 폭주하여 엉뚱한 이슈를 5개나 만들어 버리면 곤란하므로, 실제로 만들기 전에 사람이 한 번 확인하고 싶다. 게다가 확인하는 도중에 서버가 재배포되거나, Durable Object가 퇴피(evacuate)되더라도 처음부터 다시 시작하고 싶지는 않다. 이 "부작용(Side Effect)이 있는 작업에만 인간의 승인을 거치게 하고, 도중에 중단되어도 이어서 재개하는 것"을 프레임워크 측에서 관리하려고 하는 것이 6월 16일에 출시된 Cloudflare Agents SDK v0.16.1이다.

먼저 토대가 되고 있는 Code Mode를 한마디로 설명하자면. 통상적인 도구 호출(Tool Call)에서는 사용할 수 있는 API의 개수만큼 도구 정의(이름·설명·인자 스키마)를 프롬프트에 나열한다. API가 거대하면 이것이 효과를 발휘하지 못한다. Cloudflare의 측정에 따르면, 자사 API를 그대로 MCP 서버로 만들면 입력만으로 117만 토큰을 소비한다고 한다 (Code Mode 해설 기사).

For a large API like the Cloudflare API, Code Mode reduces the number of input tokens used by 99.9%.

Code Mode는 이를 역전시킨다. 모델에는 대량의 도구 정의 대신 codemode라는 단일 도구만을 보여주며, 모델은 하고 싶은 일을 JavaScript 코드로 작성한다. 그 코드는 search()로 API 사양을 탐색하고, execute()로 실제로 호출한다. 여러 API 호출을 하나의 코드로 묶을 수 있으므로 왕복 횟수도 줄어든다. 코드는 파일 시스템도 환경 변수도 가지지 않는 V8의 일회용 샌드박스(Dynamic Worker isolate) 안에서 동작한다. 프롬프트 인젝션(Prompt Injection)으로 키를 탈취당하지 않기 위한 격리다.

여기까지는 기존의 발상이며, 이번의 핵심은 실행을 **내구화(durable)**하여 중단 및 재개가 가능하도록 만들었다는 점에 있다. 메커니즘은 이벤트 소싱(Event Sourcing)이나 워크플로 엔진(Workflow Engine)과 유사하다. 커넥터(외부 서비스의 래퍼)의 각 호출은 반드시 런타임(Runtime)을 경유하며, 그 결과가 내구 로그(Durable Log)에 기록된다. 로그가 항상 "진실의 원천(Source of Truth)"이 된다.

승인이 필요한 작업에 부딪히면, 런타임은 거기서 실행을 중단하고 다음과 같은 값을 반환한다.

{
  status: "paused";
  executionId: string;
  ...
}

승인 후 코드는 다시 처음부터 실행되지만, 이미 완료된 호출은 내구 로그로부터 리플레이(Replay, 재실행하지 않고 결과만 반환)되며, 승인 대기 중이었던 작업만이 실제로 실행되어 그대로 이어진다. 도중에 Durable Object가 중단되어도 로그가 있기 때문에 동일한 방식으로 복구할 수 있다.

승인을 거치고 싶은 작업은 커넥터 측에서 requiresApproval: true를 선언한다. 원래대로 되돌리는 revert도 작성할 수 있으므로, 나중에 롤백(Rollback)할 수 있다.

export class MyConnector extends CodemodeConnector<Env> {
  protected tools() {
    return {
      ...
    }
  }
}

런타임은 createCodemodeRuntime으로 조립한다. 샌드박스를 구동하는 DynamicWorkerExecutor와 사용하게 할 커넥터를 전달한다.

import {
  createCodemodeRuntime,
  DynamicWorkerExecutor,
  ...
}

반환된 runtime이 제어반 역할을 하며, 모델용과 운영용으로 역할이 나뉘어 있다.

메서드역할
runtime.tool()모델에게 보여줄 단일 도구 생성
runtime.pending()승인 대기 중인 작업 목록 확인
runtime.approve({ executionId })리플레이를 통해 계속 진행
runtime.reject({ seq, executionId })실행 중단
runtime.rollback({ executionId })revert로 취소
runtime.executions()감사 로그 (최신순)
runtime.snippets() / saveSnippet()성공한 실행을 스니펫(Snippet)으로 재사용

pending()으로 무엇이 멈춰 있는지 확인하고, 사람이 UI에서 approve()를...

버튼을 누르는 Human-in-the-loop (인간 참여형) 루프를 자체적인 pause/resume 구현 없이 구축할 수 있다는 뜻이다. 동일한 v0.16.1 버전에서는 브라우저 조작을 담당하는 browser_execute 또한 마찬가지로 중간 정지 및 재개가 가능한 내구형 도구 (Durable tool)가 되며, Think 서브 에이전트 (Sub-agent)가 부모의 clientTools를 호출할 수 있도록 되어 있다.

에이전트에게 부작용 (Side Effect)이 있는 작업을 수행하게 하는 현장에서는, 승인 플로우와 "중단되어도 망가지지 않음"을 어떻게 양립시킬지가 은근히 무거운 과제다. 많은 팀이 도구마다 pause/resume을 수동으로 작성하고 있을 텐데, 이를 로그 리플레이 (Log replay)라는 하나의 모델로 통합한 것은 매우 영리한 접근이다.

다만 리플레이를 전제로 하므로, 커넥터 (Connector)를 통하지 않은 부작용 (예: 코드 내에서 직접 외부 fetch를 수행하여 무언가를 쓰는 등)을 섞으면 정합성이 깨진다. 상태 변화는 반드시 커넥터를 통하게 하고, 커넥터 호출 이외의 부분은 결정론적 (Deterministic)으로 작성해야 한다는 규율이 필요하다. 이 지점은 Workflows나 Temporal 같은 기존의 워크플로우 엔진 (Workflow engine)을 다뤄본 사람이라면 더욱 깊이 공감할 것이다.

또 다른 현실적인 제약은 이것이 Durable Object와 Worker Loader라는 Cloudflare 고유의 기반에 강하게 의존하고 있다는 점이다. 내구 로그 (Durable log)의 저장소가 Durable Object이므로, 다른 환경으로 그대로 이식할 수는 없다. Cloudflare 위에서 에이전트를 구동하는 것을 전제로 한다면, 승인과 복귀 기능이 SDK에 내장되어 있다는 점은 매우 큰 가치를 지닌다. 반대로 멀티 클라우드 (Multi-cloud) 환경에서 구동하고 싶다면, 이 설계 사상(상태 변화는 로그에 집약하고, 재개는 리플레이로 한다)만 가져와 자체적인 기반에 구현하는 것이 현실적인 해답이 될 것이다.

AI 자동 생성 콘텐츠

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

원문 바로가기
0

댓글

0