먼저 답부터 말씀드리면: 스트리밍으로 보이는 문장 조각은 진행을 알리는 미리보기일 수 있습니다. CRM·티켓·보고서 같은 업무 기록과 완료 상태는 서버가 식별자, 순서, 최종성, 도구·승인 결과를 확인한 terminal record로만 확정해야 합니다.
긴 답변을 내보내던 에이전트가 연결이 끊긴 뒤, 화면에는 거의 완성된 답이 남았는데 업무 시스템에는 결과가 없었던 경험이 있으신가요? 반대로 화면은 계속 로딩 중인데 이미 외부 티켓이 완료로 바뀌는 경우도 있습니다. 어떤 이벤트는 임시 화면에만 쓰고, 어떤 이벤트를 최종 업무 기록으로 확정해야 할까요?
핵심은 표시·저장·완료를 하나의 신호로 취급하지 않는 것입니다. 아래에서는 재연결, 중단, 도구 승인, 서버 재시작까지 고려해 기록을 맞추는 운영 계약을 정리합니다.

핵심 요약
- 미리보기 delta는 빠르게 보여 주되, 그것만으로 업무 결과를 확정하지 않습니다.
- 영속 이벤트는 재전송·감사·복구에 필요하지만, 모든 저장 이벤트가 완료는 아닙니다.
- 권위 기록은 서버가 순서와 중복을 판정한 기준점입니다.
- terminal event와 결과 검증 전에는 외부 시스템에 완료를 쓰지 않는 편이 안전합니다.
- 재연결은 클라이언트 화면을 믿는 일이 아니라, 마지막 수신 지점 이후 서버 기록과 다시 대조하는 일입니다.
목차
- 보이는 답과 확정 기록이 다른 이유
- 이벤트 4층을 나누는 방법
- 최소 이벤트 스키마와 중복 방지
- 재연결·중단·승인 상태 전이
- 실패 주입 QA
- 완료 확정 체크리스트
- 자주 묻는 질문
화면에 보인 답이 왜 완료가 아닐까요?
스트리밍 API는 응답을 여러 이벤트 조각으로 소비하도록 설계될 수 있습니다. OpenAI의 스트리밍 안내는 응답이 이벤트 흐름으로 전달되는 전송 경계를 설명합니다. Anthropic의 세션 이벤트 문서는 실시간 표시용 delta와 세션의 더 완전한 기록을 구분해 다룹니다. 두 문서는 구현 방식이 같다는 뜻이 아니라, 전송 중인 조각과 업무 확정은 다른 문제라는 점을 확인하는 근거입니다.
예를 들어 고객 문의를 요약해 티켓에 남기는 에이전트를 생각해 보겠습니다. 화면에 요약 문장이 나타났더라도 도구 호출이 아직 승인 대기이거나, 서버가 최종 결과를 검증하지 못했을 수 있습니다. 이때 화면의 마지막 문장을 티켓 완료 신호로 삼으면, 중단된 작업을 완료 처리하거나 재연결 뒤 같은 티켓을 두 번 갱신할 위험이 생깁니다.
이벤트를 네 층으로 나누면 판단이 쉬워집니다
| 구분 | 사용자 화면 | 영속 저장 | 재전송·복원 | 업무 완료 확정 |
|---|---|---|---|---|
| preview | 즉시 표시 | 선택적 | 잃어도 서버 기준으로 복구 | 불가 |
| persisted | 필요 시 표시 | 이벤트 저장소 | 가능 | 단독으로 불가 |
| authoritative | 상태 표시 기준 | 서버 판정 기록 | 가능 | 조건부 |
| terminal | 완료·실패 표시 | 최종 결과와 함께 보존 | 가능 | 검증 뒤 가능 |
이 표는 특정 공급자의 이벤트 이름을 표준으로 만들자는 제안이 아닙니다. 팀이 어떤 SDK나 전송 방식을 쓰더라도 “지금 화면에 보이는 것”, “되돌릴 수 있는 저장”, “서버가 권위 있다고 선언한 것”, “업무 결과를 확정할 수 있는 것”을 구별하자는 운영 언어입니다.

최소 이벤트 스키마: 복구할 수 있게 남기세요
재연결과 중복 전달을 다루려면 내용만 저장해서는 부족합니다. 다음 필드는 구현 언어와 무관하게 유용한 최소 출발점입니다.
run_id: 한 번의 장기 작업을 묶는 식별자event_id: 동일 이벤트의 중복을 무해하게 만드는 식별자sequence: 같은 실행 안에서 서버가 판정한 순서event_type와emitted_at: 어떤 상태가 언제 발생했는지 설명하는 정보finality: 미리보기인지, 권위 기록인지, 최종 결과인지 나타내는 값payload_hash: 결과 내용이 바뀌었는지 대조하는 값supersedes_event_id: 이전 잠정 기록을 교체하는 경우의 연결고리
실무에서는 event_id 또는 별도 멱등 키를 기준으로 외부 갱신을 한 번만 적용하는 규칙이 중요합니다. 같은 terminal event가 네트워크 재시도 때문에 두 번 들어와도 CRM에 두 번 메모를 남기지 않아야 합니다. 반대로 이벤트가 순서 없이 도착했을 때는 클라이언트가 임의로 합치기보다 서버의 sequence와 권위 상태를 다시 조회하게 만드세요.
재연결은 화면 복원이 아니라 기록 대조입니다
SSE는 Last-Event-ID와 재시도 동작을 제공할 수 있으며, MDN 문서는 이를 포함한 재연결 방식을 설명합니다. 그러나 SSE만이 답은 아닙니다. WebSocket이나 polling fallback에서도 동일하게 마지막으로 확인한 지점 이후의 서버 기록을 가져와 클라이언트 버퍼와 대조해야 합니다.

| 상태 | 화면 행동 | 서버 확인 | 다음 전이 조건 |
|---|---|---|---|
| connecting | 연결 준비 표시 | run_id 유효성 확인 | 스트림 수립 |
| previewing | 조각을 임시 표시 | 이벤트 순서 기록 | 도구·승인·최종 결과 |
| awaiting_action | 승인 대기임을 명시 | 권한·요청 상태 확인 | 승인 또는 거절 |
| reconnecting | 완료처럼 보이지 않게 표시 | 마지막 확인 지점 이후 조회 | 대조 완료 |
| reconciled | 서버 기준으로 화면 교정 | 중복·누락·교체 확인 | terminal 또는 계속 실행 |
| completed/failed | 검증된 결과만 표시 | finality·결과·도구 상태 확인 | 업무 후속 처리 |
실패 주입 QA: 정상 흐름만 통과시키지 마세요
정합성은 문서에서 보장되지 않습니다. 다음 상황을 의도적으로 만들고, 화면과 서버 기록과 외부 시스템 결과가 모두 맞는지 확인해 보세요.
| 상황 | 기대 화면 | 서버 권위 기록 | 차단할 오류 | 통과 기준 |
|---|---|---|---|---|
| delta 유실 | 재연결 중 표시 | 누락 구간 조회 가능 | 보이는 문장만 저장 | 복원 뒤 서버 순서와 일치 |
| final 지연 | 완료 대신 처리 중 표시 | terminal 전 상태 유지 | 조기 완료 갱신 | 최종 기록 뒤 한 번만 처리 |
| 중복 전달 | 변화 없음 | 같은 event_id 식별 | 이중 티켓·알림 | 외부 부작용 한 번 |
| 승인 대기 | 권한 대기 표시 | 승인 결과 분리 저장 | 도구 성공을 완료로 오인 | 승인 뒤에만 후속 실행 |
| 서버 재시작 | 복구 중 표시 | run_id별 상태 재구성 | 새 실행으로 중복 생성 | 동일 실행을 재개·실패로 판정 |
완료를 확정하기 전, 이 체크리스트를 통과하세요
- terminal finality가 서버 기록에 있는가?
- 최종 결과의 해시 또는 버전이 예상한 값과 맞는가?
- 필수 도구 실행 결과가 성공·실패·보류 중 무엇인지 명확한가?
- 사람 승인이 필요한 작업이라면 승인 결과가 연결돼 있는가?
- 같은 run_id와 멱등 키로 이미 외부 갱신을 적용하지 않았는가?
- 감사 로그에는 어떤 입력·도구·결과가 이 결론을 만들었는지 추적할 수 있는가?
도입 순서: 큰 재설계보다 경계부터 만드세요
- 현재 이벤트를 화면용과 업무 기록용으로 표시해 봅니다.
- 한 작업의 run_id와 외부 갱신의 멱등 키를 먼저 도입합니다.
- 완료를 쓰는 지점을 terminal 검증 뒤로 옮깁니다.
- 재연결 시 마지막 확인 지점 이후를 서버에서 조회하게 합니다.
- 위 실패 주입 표를 배포 전 점검 항목으로 반복합니다.
자주 묻는 질문
delta를 데이터베이스에 저장하면 곧 최종 기록이 되나요?
그렇지 않습니다. 복구와 분석을 위해 저장할 수는 있지만, 저장 여부와 업무 완료 가능 여부는 별도 규칙으로 두는 편이 좋습니다. finality와 순서, 결과 검증을 함께 확인하세요.
SSE를 쓰지 않으면 이 설계가 필요 없나요?
필요합니다. SSE의 재연결 기능은 한 구현 예시일 뿐입니다. WebSocket·polling 등 어떤 전송 방식이든 클라이언트가 잃을 수 있는 진행 표시와 서버의 권위 기록을 구분해야 합니다.
terminal event가 오면 항상 바로 외부 시스템을 갱신해도 되나요?
필수 도구 결과, 승인 결과, 결과 버전이 그 terminal record와 연결돼 있는지 먼저 확인하는 편이 안전합니다. 특히 사람 승인이 필요한 작업은 도구 호출 성공만으로 끝나지 않을 수 있습니다.
모든 이벤트를 영구 보관해야 하나요?
그럴 필요는 없습니다. 복구·감사·분쟁 대응에 필요한 범위와 보존 기간을 정하면 됩니다. 다만 최종 판정의 근거와 외부 변경의 멱등 키는 나중에 대조할 수 있어야 합니다.
이 구조가 과한 경우도 있나요?
수 초 안에 끝나고 외부 부작용이 없는 단순 질의라면 가벼운 구현으로 시작할 수 있습니다. 다만 장기 실행, 도구 권한, 사람 승인, 고객 기록이 결합되면 초기에 경계를 정해 두는 편이 운영 비용을 줄입니다.
참고 자료
- Anthropic — Session event stream: 세션 이벤트, 실시간 표시, 상태 경계를 살펴볼 수 있는 공식 문서입니다.
- OpenAI — Streaming API responses: 응답을 이벤트 흐름으로 소비하는 전송 경계를 확인할 수 있는 공식 안내입니다.
- MDN — Using server-sent events: Last-Event-ID와 재시도를 포함한 SSE 재연결 동작을 설명합니다.
이 글이 마음에 드세요?
FLOWIT on YouTube
영상으로도 FLOWIT을 이어서 보세요
AI 자동화, Claude Code, n8n, 데이터 분석 흐름을 블로그와 영상으로 함께 정리하고 있습니다.
AI 에이전트가 내 Android 앱을 조작하게 할까? AppFunctions 공개 전 6칸 capability 카드
AI 데이터 분석 에이전트에 테이블을 다 보여주면 안 되는 이유: 검증된 질의 표면 계약 5단계
AI 데이터 분석 답변, 숫자만 믿어도 될까? 근거 패킷 6단계
“AI 에이전트가 ‘거의 끝난 답’을 보여줄 때 저장하면 안 되는 이유: 스트리밍 미리보기·최종 기록 정합성 체크리스트”에 대한 1개의 생각