상주형 AI 챗 에이전트의 무중단 업데이트 배포 설계
요약
Slack/Teams 등 상주형 AI 에이전트는 배치 처리와 달리 구조적인 '배포 창' 확보가 어렵습니다. 따라서 업데이트 시 프로세스 중단, 상태 읽기 실패, 행동 방식 변경 등의 문제를 방지하기 위한 설계 원칙을 제시합니다. 핵심은 종료 과정에서 현재 진행 중인 작업을 완료하고, 대화 상태는 신구 버전 모두를 지원하는 방식으로 점진적 마이그레이션을 수행하는 것입니다.
핵심 포인트
- 상주 에이전트는 구조적인 배포 창 확보가 불가능하다.
- 업데이트 시 '처리 도중 멈춤' 방지를 위해 종료 과정을 설계해야 한다.
- 대화 중간 상태는 신구 버전 모두를 읽을 수 있도록 점진적으로 이전해야 한다.
Slack / Teams / Chatwork 등에 상주하며 계속 작동하는 AI 에이전트는 배치 처리와 달리 '사용되지 않는 시간대'가 없습니다. 심야에 업데이트를 시도하더라도 그 시간에 실행되는 정기 처리가 있고, 아침 시간에는 이용이 집중됩니다. 즉, 배포 창(deployment window)을 구조적으로 확보하기 어렵습니다.
여기서 '사용자가 적은 시간을 노린다'는 운영으로 임시방편을 쓰게 되면, 업데이트할 때마다 식은땀을 흘리게 됩니다. 상주 에이전트 특유의, 업데이트 시에 망가지는 부분과 설계상의 방지 방법을 정리합니다.
상주 에이전트 업데이트로 인해 망가지는 3가지 지점
웹 앱의 로링 업데이트는 '요청을 받고 응답하면 끝'이라는 전제가 되므로, 한 대씩 교체하는 것만으로도 대체로 성립합니다. 상주 에이전트는 여기가 다릅니다.
- 처리 도중에 멈춤 — 발언을 받은 후 LLM 추론(inference)이나 외부 API 호출, 응답까지 몇 초에서 수십 초가 걸립니다. 이 과정 중에 프로세스가 종료되면 사용자 입장에서는 '말했는데 무시당했다'고 느낍니다.
- 대화 중간 상태를 읽지 못함 — 확인 대기나 다단계 요청 등, 중간 상태를 영속화(persist)하고 있을 때, 새 버전이 구 형식(format)을 읽지 못하면 대화가 공중에 떠 있게 됩니다.
- 행동 방식이 조용히 바뀜 — 프롬프트나 판단 기준을 변경하면, 어제와 똑같이 질문한 사용자가 다른 답변을 받게 됩니다. 버그는 아니지만, 신뢰도는 여기서 떨어집니다.
1번은 인프라(Infrastructure), 2번은 데이터(Data), 3번은 경험(Experience)의 문제입니다. 각각 별도의 대책이 필요합니다.
대책 1: 수신을 멈춘 후, 처리를 완료하고, 종료하기
종료 시그널을 받았다고 즉시 종료하지 않고, '새로운 수신 중단 → 처리 중인 것 완료 대기 → 종료' 순서로 진행합니다.
let accepting = true;
const inFlight = new Set<Promise<void>>();
async function onEvent(event: ChatEvent) {
...
핵심은, 수신을 멈춘 시간 동안의 이벤트를 누락으로 간주하지 않는 것입니다. Webhook은 at-least-once로 재전송되므로, 응답하지 않으면 새로운 인스턴스에 다시 배포됩니다. 억지로 자체적으로 큐(queue)에 보관하는 것보다 플랫폼의 재전송에 맡기는 것이 구조가 단순합니다(대신, 재전송을 전제로 한 Idempotency 구현이 필수입니다).
드레인(Drain) 대기 시간은 실제 처리 시간 분포를 기반으로 결정해야 합니다. 상한선을 무한대로 하면 멈추지 않는 인스턴스가 남아있고, 너무 짧으면 1번 문제가 재발합니다.
대책 2: 상태는 '신구 둘 다 읽을 수 있는 기간'을 만든 후 이전하기
중간 상태에 스키마(Schema) 버전을 부여하고, 쓰기를 새 형식으로 전환하기 전에, 읽기는 양쪽 모두 대응하는 버전을 먼저 배포하는 2단계로 이전을 진행합니다.
type ConversationState =
|
{ v: 1; pendingConfirm: string }
|
{ v: 2; pending: { kind:
사용자 측에서 바라본 'AI가 사용하지 못하는 시간이 있을 것 같다'는 불안감에 대해서는, AI 서비스가 중단되었을 때의 업무 영향도(業務影響)를 업무 관점에서 정리했습니다.
## 요약
- 상주 에이전트에는 배포 창(デプロイ窓)이 없습니다. '비어 있는 시간을 노린다'는 것은 설계가 아니라 운영상의 임시방편입니다.
- 종료 과정은 '접수 중단 → 처리 완료 대기 → 종료' 순서입니다. 접수하지 못한 이벤트는 재전송에 맡깁니다.
- 중간 상태(途中状態)는 버전과 유효기간을 부여하고, 읽기 전용(読み取り)와 쓰기(書き込み)를 모두 지원하는 것을 먼저 배포한 후 쓰기를 전환합니다.
- 동작 변경은 배포와 분리하여 테넌트 단위로 단계적으로 활성화합니다.
'무정지 배포(無停止デプロイ)'라고 하면 인프라 이야기로 흐르기 쉽지만, 상주 에이전트에서 실제로 효과를 보는 것은 상태의 호환성(状態の互換性)과 동작 변경을 구현하는 방식이라는 **애플리케이션 측 설계**입니다. 이 부분을 확실히 다지면, 업데이트할 때마다 긴장해야 하는 운영 방식에서 벗어날 수 있습니다.
저는 Slack / Teams / Chatwork에 상주하며 매일 아침 보고서 형태로 정보를 전달하는 AI 에이전트 HACH를 개발하고 있으며, 가동을 멈추지 않으면서 기능을 계속 추가해 나가면서 이러한 설계 판단들을 거듭했습니다. 이와 유사한 에이전트를 개발하거나 운영하시는 분들께 도움이 되기를 바랍니다.
### 토론

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