Snapshots와 Interrupts
롤백, 분기 탐색, Human-in-the-loop
Snapshots와 Interrupts
롤백, 분기 탐색, Human-in-the-loop
에이전트의 기억을 설계한다
세션 영속화부터 컨텍스트 자동 관리까지 — 상태의 4계층
Context Management
지키기 — 압축·오프로드 · 멈추기 — Checkpoint·HITL
Context Management
매 호출의 모델 입력을 한도 안에 지키는 자동 방어, 그리고 실행을 멈췄다 이어가는 제어
Context Management
컨텍스트 한도 방어 2가지 · 실행 정지·재개 제어 2가지
- context_manager
- ContextOffloader
- Checkpoint
- Interrupts
지키기(방어 → 오프로드), 그다음 멈추기(체크포인트 → 승인) 순서로 살펴봅니다.
지키기 vs 멈추기
지키기 = 컨텍스트가 한도를 넘지 않게 유지 · 멈추기 = 실행을 멈췄다 다시 잇는 재개
지키기
한도 안에서 컨텍스트를 보호
- context_manager — 임계치 감지 후 선제 요약 (초과 지속 시 재요약)
- ContextOffloader — 큰 도구 결과는 저장소로
- 다루는 것: 매 호출의 모델 입력 (토큰)
- 얻는 것: 비용 절감 · 윈도우 초과 방지
대화가 아무리 길어져도 호출이 실패하지 않게 — 설정만 하면 자동으로 동작합니다.
멈추기
실행을 정지했다가 이어가기
- Checkpoint — 시스템이 계획적으로 정지
- Interrupts — 사람의 승인 때문에 정지
- 다루는 것: 에이전트의 실행 흐름
- 얻는 것: 장기 작업 분할 · HITL 안전장치
멈췄다가 이어서 재개 — 둘의 차이는 뒤에서 자세히 비교합니다.
지키기는 설정만 하면 자동으로 개입, 멈추기는 멈춘 지점을 코드로 재개 — 성격이 달라 넷을 함께 쓸 수 있습니다.
context_manager 자동 방어
지키기 ① — 한도 접근 감지 시 선제 요약 + 대용량 도구 결과 오프로딩 개입
-
1
임계치 감지
현재 컨텍스트 토큰 수가 모델 한도의 85%를 초과하면 자동 트리거.
-
2
선제 요약
오래된 대화를 LLM이 요약으로 압축. 핵심 정보(결정, 사실, 작업 상태)를 보존.
-
3
오프로딩·재요약
대용량 도구 결과는 ContextOffloader가 스토리지로 오프로드. 요약 후에도 초과가 지속되면 반응적으로 재요약.
-
4
모델 호출
압축된 컨텍스트로 정상 추론 진행. 사용자에게 투명하게 동작.
- None
- 기본값 — 자동 개입 없음, ConversationManager 정책만 동작
- 'auto'
- 요약 + 오프로딩을 자동 적용 — 대부분의 프로덕션 권장
- 'agentic'
- 모델이 스스로 압축·오프로딩 시점을 판단 (토큰↔정확도 트레이드오프)
감지·요약·오프로딩 전부 자동 — 개발자 코드는 context_manager='auto' 한 줄입니다.
큰 도구 결과는 밖으로 — ContextOffloader
지키기 ② — "큰 도구 결과도 매번 다시 전송"되는 비용을 오프로딩으로 차단
핵심 포인트
- max_result_tokens
- 이 크기를 넘는 도구 결과를 외부 저장소로 이동 (기본 2500)
- preview_tokens
- 컨텍스트에는 미리보기만 남김 (기본 1000)
- storage
- InMemory · File · S3 저장소 선택
- Unified Storage
- 스토리지 백엔드 통합 인터페이스 — 오프로더 저장소에 자동 네임스페이스(auto-namespace) 적용
- retrieve_offloaded_content
- 원본이 필요하면 자동 등록된 도구로 에이전트가 직접 조회
코드
from strands import Agent
from strands.vended_plugins.context_offloader.plugin import ContextOffloader
from strands.vended_plugins.context_offloader.storage import S3Storage
# 2500토큰 초과 도구 결과를 S3로 — 컨텍스트에는 미리보기만
agent = Agent(
model="us.anthropic.claude-sonnet-4-6",
plugins=[ContextOffloader(
max_result_tokens=2500,
preview_tokens=1000,
storage=S3Storage(bucket="ctx-offload"),
)],
)
# 원본이 필요하면 retrieve_offloaded_content 도구로 자동 조회
지키기 두 도구의 분담 — context_manager + ContextOffloader
고르는 것이 아니라 함께 켜는 조합 — 지키는 대상이 다름
context_manager
쌓여가는 대화 이력을 지킨다
- 대상: 대화 이력 전체 (토큰 합계)
- 방식: 임계치 감지 → 선제 요약 (초과 시 재요약)
- 시점: 한도에 접근할 때만 개입
- 결과: 이력이 압축되어 한도 안으로
설정은 context_manager='auto' 한 줄 — 평소에는 개입하지 않다가 한도 접근 시에만 동작합니다.
ContextOffloader
큰 도구 결과 하나를 격리한다
- 대상: 임계치를 넘는 개별 도구 결과
- 방식: 저장소로 오프로드 + 미리보기만 유지
- 시점: 큰 결과가 생기는 즉시
- 결과: 원본은 밖에, 필요하면 도구로 조회
플러그인으로 장착 — 대화가 짧아도 도구 결과 하나가 크면 이쪽이 막습니다.
발표자 노트
두 도구는 경쟁 관계가 아니라 분담 관계입니다. context_manager는 대화가 길어져서 생기는 문제를, ContextOffloader는 도구 결과 하나가 커서 생기는 문제를 각각 막아요. 그래서 실무에서는 보통 둘 다 켭니다. 가운데가 VS가 아니라 플러스인 이유입니다.
멈추기 두 방식 — Checkpoint vs Interrupts
둘 다 "멈췄다 이어가기" — 차이는 멈추는 주체와 이유
Checkpoint
시스템이 멈춘다
- 도구 사이클 경계에서 계획적 일시 정지
- 장기 작업 분할, 재배포·중단 대비
- stop_reason="checkpoint"로 반환
- 재개: checkpointResume를 담아 재호출
실행을 쪼개 두었다가 이어 붙이는 용도 — 사람의 개입 없이도 돌아갑니다.
Interrupts
사람 때문에 멈춘다
- 고위험 도구 직전 승인 대기 (HITL)
- BeforeToolCallEvent에서 event.interrupt()
- stop_reason="interrupt"로 반환
- 재개: interruptResponse를 담아 재호출
사람의 승인/거부가 곧 재개 조건 — 프로덕션 안전벨트입니다.
Checkpoint — 일시 정지와 재개
멈추기 ① — 도구 사이클 경계에서 멈췄다가 이어서 재개 (experimental, 상태 캡처는 take_snapshot()이 별도)
핵심 포인트
- checkpointing=True
- 체크포인트 활성화 — experimental 기능
- stop_reason="checkpoint"
- 도구 사이클 경계에서 일시 정지하며 반환
- to_dict / from_dict
- 직렬화해 외부 저장소에 보관, checkpointResume로 재개
- 주의
- 대화 이력은 캡처하지 않음 — 영속화는 SessionManager 병행
코드
from strands import Agent
# 체크포인트 활성화 — tool_use 사이클 경계에서 일시 정지 (experimental)
agent = Agent(model="us.anthropic.claude-sonnet-4-6", checkpointing=True)
# 실행 — 사이클 경계에 도달하면 stop_reason="checkpoint"로 반환
result = agent("프로젝트 구조를 분석해줘")
# 직렬화 — 체크포인트를 dict로 변환해 외부 저장소에 보관
saved = result.checkpoint.to_dict()
# 재개 — 저장한 dict를 checkpointResume로 그대로 되돌려 전달
agent({"checkpointResume": {"checkpoint": saved}})
Interrupts — 멈추고, 묻고, 재개하는 절차
멈추기 ② — 고위험 동작 앞에서 사람의 승인을 기다리는 HITL 4단계
-
1
트리거
BeforeToolCallEvent에서 event.interrupt(name, reason) 호출 — 고위험 동작(파일 삭제, 결제) 전에 발동.
-
2
일시 정지
stop_reason="interrupt"로 반환 — 재개에 필요한 정보는 result.interrupts에 담김.
-
3
사용자 확인
외부 시스템(UI, Slack, API)이 사용자에게 승인/거부를 요청.
-
4
재개 또는 중단
응답을 interruptResponse로 담아 재호출하면 이어서 실행 — 거부 응답이면 에이전트가 대안 탐색.
- HumanInTheLoop
- 내장 HITL — from strands.vended_interventions.hitl, Agent(interventions=[...])로 장착
- allowed_tools
- 승인 없이 통과시킬 도구 목록 — 나머지는 사람에게 묻습니다.
- ask='stdio'
- 기본은 콘솔 승인 — 콜백을 넘기면 Slack·웹 UI로 연동
고위험 도구 앞에서 멈추고, 사람의 승인으로만 지나갑니다 — 프로덕션 에이전트의 안전벨트
Session · Conversation · Memory · Context — 4계층으로 기억을 설계