Cloudflare 기반 AI Agent SaaS에 Pi Durable을 도입한 경험
요약
Cloudflare 기반 AI Agent SaaS 개발자가 Pi Durable 도입 경험을 공유합니다. Pi Durable은 Model Turn이나 Tool Call 같은 실행 중간 상태를 저장하여, 프로세스 중단 시에도 작업의 재개를 가능하게 하는 핵심 메커니즘입니다. 이를 통해 기존에는 복원할 수 없었던 에이전트의 실행 중간 상태까지 영속화하는 데 성공했습니다.
핵심 포인트
- Pi Durable은 Agent의 실행 중간 상태(Model Call, Tool Call 등)를 저장합니다.
- 프로세스 중단 시에도 작업 진행 상황을 정확히 파악하고 재개할 수 있습니다.
- 기존 Cloudflare Workflows/PostgreSQL 방식으로는 에이전트의 '실행' 상태 복원이 어려웠습니다.
제가 직접 개발하는 AI Agent SaaS는 처음부터 Cloudflare를 실행 기반으로 사용하고 있으며, Agent Runtime에는 Pi를 채택하고 있습니다.
2026년 10월 1일에 Pi가 1.0으로 업데이트되었고, 이와 동시에 @earendil-works/pi-durable 1.0.0이 등장했습니다. 게다가 10월 2일에는 Cloudflare 측에서도 Agents SDK를 통해 Pi Durable을 사용할 수 있는 PiHarness가 발표되었습니다.
Pi Durable에 대해 조사해 보니, Model Turn이나 Tool Call 같은 실행 상태를 Storage에 저장하여 Process가 도중에 중단되어도 저장된 상태부터 처리를 재개할 수 있는 메커니즘이었습니다.
이는 마침 제 SaaS에 부족했던 기능이었습니다.
지금까지는 Cloudflare Workflows나 PostgreSQL을 사용하여 장시간 처리나 Business Data 자체는 영속화하고 있었습니다. 하지만 Agent가 하나의 지시를 처리하는 도중에 Process가 다운될 경우, '어떤 Model Call까지 완료했는지', '어떤 Tool을 이미 실행했는지'와 같은 실행 중간 상태까지는 복원할 수 없었습니다.
그래서 Pi를 0.85.1에서 1.0.0으로 업그레이드한 후, 기존의 Cloudflare Workflows, Durable Objects, PostgreSQL 구성을 유지하면서 Pi Durable을 도입했습니다.
이 글에서는 Pi 1.0으로의 마이그레이션은 간단히 언급하고, Pi Durable을 기존 SaaS에 어떻게 통합하여 중단된 Agent를 어디서부터 재개할 수 있게 했는지에 초점을 맞춰 작성하겠습니다.
Pi 1.0으로의 마이그레이션 준비 단계
먼저 Pi 관련 의존성을 1.0.0으로 업데이트했습니다.
- "@earendil-works/pi-agent-core": "0.85.1",
- "@earendil-works/pi-ai": "0.85.1",
+ "@earendil-works/pi-agent-core": "1.0.0",
...
다음으로 Durable Execution을 위해 pi-durable과 그 기반이 되는 chord를 추가했습니다.
"@earendil-works/chord": "1.0.0",
"@earendil-works/pi-durable": "1.0.0"
이번에 사용한 Pi 관련 Package의 역할을 정리하면 다음과 같습니다.
| Package | 역할 |
|---|---|
pi-agent-core | Agent Loop, Tool 실행, Message나 Event 등, Agent Runtime의 기본 기능 |
pi-ai | Model Provider와의 연결 및 Model 호출을 다루는 계층 |
pi-durable | Conversation, Task, Tool Execution 등의 실행 상태를 영속화하고, 중단 후 Recovery를 가능하게 하는 계층 |
chord | Pi Durable 아래에서 State, Context, Service / Extension의 조합을 지탱하는 기반 |
대략적으로 보면 다음과 같은 관계입니다.
pi-agent-core
└─ Agent Loop / Tool / Message
pi-ai
...
Pi 1.0으로 마이그레이션하면서 System Prompt나 Tool을 Transcript Context에서 가져오는 형태로 맞추는 등, 주로 Context Contract 준수에 중점을 두었습니다.
실제 Qwen을 사용한 Tool Task에서도 Model Request → Tool Call → Tool Result → 최종 답변까지 기존의 Tool Loop가 정상적으로 작동하는 것을 확인했습니다.
여기까지의 변경은 기존 Agent Runtime을 Pi 1.0에 맞추기 위한 준비 과정입니다. 기능 면에서 크게 바뀐 부분은 이 다음에 Pi Durable을 실제 Execution Path에 통합한 부분이었습니다.
'Run이 남아있다'와 '실행을 재개할 수 있다'는 다르다
원래 PostgreSQL에는 Conversation이나 Agent Run, usage, Business Data를 저장했고, Cloudflare Workflows로 장시간 처리도 실행했습니다.
하지만 그럼에도 불구하고 Agent의 실행 중간까지는 복원할 수 없었습니다.
프로세스가 도중에 멈췄을 때, 새로운 Executor가 알고 싶어 하는 정보는 다음과 같습니다.
어떤 Model Call까지 완료했는지
어떤 Tool Call이 완료했는지
다음부터 어디서 재개해야 하는지
기존에는 실행할 때마다 프로세스 내에 Agent State를 구축했기 때문에, 프로세스가 손실되면 미완료된 Turn 상태도 함께 손실되었습니다.
DB에 Run = running이라고 남아 있어도, 그것만으로는 실행 현장을 복원할 수 없습니다.
Pi Durable을 도입한 목적은 이 Execution State를 영속화하는 것입니다.
기존 Cloudflare 구성에 Pi Durable 결합하기
Cloudflare가 제공하는 PiHarness는 Pi Durable을 Agents SDK의 Lifecycle에 통합하여, Durable Object 위에서 장시간 실행되는 Agent의 Execution State를 관리하는 구성입니다.
공식 예제에서는 PiHarness를 Agent의 Lifecycle에 등록합니다.
harness = new PiHarness({
harness: ({ storage, context }) =>
Harness.open(
...
하지만 이번에는 이 구성을 그대로 채택하지 않았습니다.
제 SaaS에는 이미 Cloudflare Workflows를 통한 실행 관리, Durable Objects를 통한 Run 단위 조정, PostgreSQL을 통한 Business Data 및 usage 관리가 있었고, 각각이 기존의 역할을 가지고 있었기 때문입니다.
그래서 Lifecycle 전체를 대체하는 것이 아니라, 기존 Architecture를 유지한 채 Pi Durable을 Execution State의 영속화 레이어로 결합했습니다.

(기존 Cloudflare 구성에 Pi Durable을 결합한 실행 / 복구 흐름)
도에서는 실행 플로우를 4개의 Layer로 나누고 있습니다.
- Web Client:
Submit Task로 User Input과 선택된 Context를 전달하고, 완료 후는
재시도(Retry)의 책임 범위도 정리했습니다. Pi 내부와 Model Stream 쪽의 재시는 무효화하고, Cloudflare Workflow 측으로 통합했습니다.
- retries: { limit: 0, delay: "5 seconds", backoff: "exponential" },
+ retries: { limit: 2, delay: "5 seconds", backoff: "exponential" },
Checkpoint가 없는 상태에서 재시도하더라도 처음부터 처리를 다시 하는 것일 뿐입니다.
Pi Durable을 통해 Execution State를 복원할 수 있게 되면서, Workflow Retry를 저장된 상태를 열어 미완료 부분부터 처리를 계속하는 진입점(entry point)으로 사용할 수 있게 되었습니다.
Tool 실행 직후에 다운되면 어떻게 할까
Pi Durable을 도입할 때 가장 어려웠던 점은 Tool의 부작용이었습니다.
예를 들어, 다음 타이밍에서 Process가 다운되었다고 가정해 봅시다.
Tool이 Business Data를 업데이트
↓
DB Transaction은 commit됨
...
새로운 Process의 관점에서 보면, Pi 상에서는 Tool이 아직 완료되지 않은 상태입니다.
그대로 Tool을 재실행하면 같은 Business Data를 두 번 업데이트할 가능성이 있습니다.
그래서 Pi의 Task ID에서 안정적인 Tool 실행 ID를 만들도록 했습니다.
const taskId = `${input.turnId ?? "turn"}:${api.taskId}`;
나아가, Business Operation과 Tool Receipt를 같은 PostgreSQL Transaction으로 저장합니다.
Tool Task
↓
저장된 Receipt를 검색
...
이를 통해 Process 재시작 후에도 동일한 Tool Handler에 다시 진입하더라도 이미 완료된 경우라면 저장된 Result를 반환할 수 있습니다.
설계 원칙은 Tool Handler의 재실행 자체를 금지하는 것이 아니라, 재실행되어도 Business Effect가 중복되지 않도록 하는 것입니다.
다만, 이 보장은 Transaction 내에 포함되는 PostgreSQL 작업으로 한정됩니다.
외부 HTTP API 등 임의의 부작용까지 global한 exactly-once를 보장하는 것은 아닙니다.
정말로 SIGKILL을 해봤다
Recovery가 실제로 작동하는지 확인하기 위해 실제 Qwen, Production용 Engine, PostgreSQL을 사용한 Integration Test를 만들었습니다.
Recovery Test는 다음의 여러 단계(multiple Step) Task를 실행시켰습니다.
Data를 읽는다
↓
Tool로 업데이트를 스테이징한다
...
Tool에 의한 업데이트가 PostgreSQL에 commit된 직후, Pi 측에서는 아직 해당 Tool Task의 완료 상태가 완전히 저장되지 않은 타이밍에 Node Process를 SIGKILL (후처리할 여지 없이 Process를 강제 종료하는 Signal)로 중단시켰습니다.
Model Request #1 완료
↓
Model Request #2 완료
...
새로운 Process에서 동일한 Run을 다시 열면, 이미 완료된 2번의 Model Request는 재실행되지 않았고, 아직 시작되지 않은 최종 답변만 새로 실행되었습니다.
Tool Handler 자체는 Recovery 시에 다시 진입하지만, 저장된 Receipt를 이용하기 때문에 Business Data 업데이트도 중복 없이 한 번만 이루어졌습니다.
이 테스트를 통해 Pi Durable이 단순히 Run을 재개하는 것뿐만 아니라, 완료된 Model Step과 Tool Result를 재활용하면서 미완료 부분부터 처리를 계속할 수 있음을 확인할 수 있었습니다.
Streaming 중에 다운된 경우
최종 답변을 스트리밍(Streaming)하는 도중에도 Process를 다운시켜 보았습니다.
이 경우, 이미 시작한 Remote Model Request 자체를 중간부터 복원하는 것은 불가능합니다. 완료된 Tool 처리는 재활용되지만, 중단된 최종 답변만 새로운 Model Request로 다시 생성하게 됩니다.
Pi Durable이 제공하는 것은, 저장된 Execution State를 기반으로 완료된 처리를 재활용하면서 미완료 부분부터 실행을 재개하는 메커니즘입니다.
스트리밍 중에 중단된 Model Request의 경우, Provider로부터 완전한 usage가 반환되지 않을 때도 있습니다. 이번에는 해당 usage를 추측하지 않고 anomaly로 저장하고, Recovery 후의 Request는 별도의 Request로 측정하도록 했습니다.
요약
이번에 다시 느낀 것은, 새로운 Runtime이나 공식 Integration이 나와도 그 메커니즘을 전부 그대로 도입할 필요는 없다는 것입니다.
Cloudflare에는 PiHarness라는 선택지도 있지만, 저희의 SaaS에서는 이미 Workflows, Durable Objects, PostgreSQL이 각각 역할을 가지고 있었습니다. 그래서 기존 구성을 대체하기보다는, 부족했던 Execution Recovery 부분만 Pi Durable로 보완하는 형태로 했습니다.
새로운 기술을 도입할 때는 기능의 많음보다, 현재 Architecture의 어느 부분이 부족하며 그 기능을 어디에 두는 것이 자연스러운지를 생각하는 것이 중요하다는 것을 느꼈습니다.
논의

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