Agent Mentor Learn
상태 관리와 지속화: 긴 작업이 중단을 견디게 만들기 · 1 / 6강

레슨 1: 메모리 너머에 있는 상태

학습 목표:

  • '메모리'(모델에게 주는 컨텍스트)와 '실행 상태'(하네스가 붙들고 있는 실행 중인 장면)를 한 문장으로 가려내고, 각각의 예를 들기
  • '긴 작업에 크래시가 유독 치명적이다'라는 근거를 적어도 세 가지 구체적으로 대고, 각각이 실행의 어느 부분을 가리키는지 말하기
  • 실행 중인 하네스가 떠안고 있는 것들의 목록을 받았을 때, 각각이 메모리인지 실행 상태인지 디스크 출력물인지 판정하고, 프로세스가 죽어도 남는지 판정하기

전제: 이 시리즈의 앞선 코스들을 마쳤고, "에이전트 하네스 기초: 루프와 통제"의 stop_reason 구동 하네스 루프와 "Context Engineering: Spending Finite Attention Where It Counts"의 컨텍스트 관리를 이해하고 있어야 합니다 | 다음: 레슨 2 >>

23턴째, 프로세스가 죽습니다

"에이전트 하네스 기초: 루프와 통제"에서 직접 쓴 하네스가 40턴이 걸리는 긴 작업을 돌리고 있다고 상상해 보십시오. 파일을 한 묶음 읽어 들이고, 하나씩 분석하고, 결론을 그때그때 리포트에 덧붙여 가는 작업입니다. 23턴째에 프로세스가 죽습니다. 배포 업데이트였을 수도 있고, 서버 전원이 나갔을 수도 있고, 여러분이 Ctrl+C를 잘못 눌렀을 수도 있습니다.

디스크를 확인해 봅니다. 앞선 22턴이 만든 리포트 파일은 전부 그대로 있습니다. NOTES.md("Context Engineering: Spending Finite Attention Where It Counts"에서 마련해 둔 그 작업 진척 요약)에도 '어느 파일까지 분석했고 결론은 무엇이었는지'가 여전히 기록되어 있습니다. 크게 잃은 것은 없어 보입니다. 프로세스를 다시 띄우고 멈춘 자리에서 이어 가면 될 것 같습니다.

그런데 다시 띄워 보면 runAgentmessages 배열이 비어 있습니다. [{ role: "user", content: userInput }]부터 다시 쌓아야 합니다. turns 카운터는 0으로 돌아가 있습니다. tokensUsed도 0입니다. 그리고 크래시가 23턴째의 '모델이 도구를 지명했다'와 '도구 결과가 messages에 밀려 들어갔다' 사이에 정확히 떨어졌다면, 그 도구 호출은 — 막 실행을 시작했든 이미 끝나 있었든 — 이제 아무 흔적도 남기지 않습니다.

작업은 23턴째에서 재개되지 않습니다. 1턴째부터 다시 시작합니다. 디스크의 파일은 전부 그대로인데, '내가 어디까지 갔는가'에 대한 하네스 자신의 기록만 아무것도 남기지 못한 것입니다.

메모리란 무엇이고, 상태란 무엇인가

이 코스가 가르치려는 것을 가르치기 전에, 흐려지기 쉬운 개념 하나와 선을 그어야 합니다.

메모리는 모델에게 주는 컨텍스트입니다. 코스 5 "에이전트 메모리와 상태"는 그것을 세션을 넘어 지속시키는 방법을 다루고, 코스 8 "Context Engineering: Spending Finite Attention Where It Counts"는 매 턴 모델에게 정확히 무엇을 보여 줄지를 다룹니다. 메모리가 답하는 질문은 '모델은 무엇을 보았는가?'입니다. NOTES.md는 메모리를 실어 나르는 수단 중 하나입니다. 이미 디스크에 쓰여 있고, 다음 턴이나 다음 세션이 그것을 읽어 들여 프롬프트에 넣을 수 있습니다.

실행 상태는 하네스 프로세스 자신이 붙들고 있는 실행 중인 장면입니다. messages 배열, turnstokensUsed 같은 카운터, 아직 기록되지 않은 도구 호출이 그것입니다. 실행 상태가 답하는 질문은 '하네스는 자기가 어디까지 갔는지 기억하는가?'입니다.

둘의 결정적인 차이는 '내용이 무엇인가'가 아니라 '지금 어디에 살고 있는가'입니다. 메모리는 이미 디스크에 있을 수 있습니다(NOTES.md는 파일 시스템에 놓여 있고, 프로세스가 살든 죽든 그것이 거기 있다는 사실은 달라지지 않습니다). 반면 실행 상태는 기본적으로 프로세스의 메모리에만 삽니다. let messages = [...]라는 한 줄이 만들어 낸 그것은, 누군가 의도적으로 디스크에 쓰지 않는 한, 프로세스가 끝나는 순간 메모리와 함께 회수됩니다. 앞 절에 나온 것 중 어느 하나도 — messages, turns, tokensUsed, 허공에 뜬 도구 호출 — 저절로 디스크에 쓰이지 않습니다.

state야말로 이 코스가 '디스크에 쓰고 되살릴 수 있는 것'으로 바꾸는 법을 가르칠 대상입니다.

긴 작업에서는 이것이 성패를 가릅니다

먼저 셈부터 해 봅시다. "Agents can run for long periods of time, maintaining state across many tool calls."1(에이전트는 오랜 시간 동안 돌면서 수많은 도구 호출에 걸쳐 상태를 유지할 수 있다) 23턴째의 messages 배열이 계속 불어나는 것은 바로 그 때문입니다. 그런데 같은 사실이 이런 뜻이기도 합니다. "Agents are stateful and errors compound."1(에이전트는 상태를 가지며 에러는 누적된다) 상태가 쌓일수록, 사슬의 어딘가가 어긋나는 순간 그 비용은 선형으로 늘지 않고 겹쳐서 옵니다.

여기에 하나를 더 얹습니다. "Without effective mitigations, minor system failures can be catastrophic for agents."1(효과적인 완화책이 없으면 사소한 시스템 장애도 에이전트에게 파국이 될 수 있다) '사소한'과 '파국'을 나란히 놓은 이 문장이 23턴째의 상황을 그대로 묘사합니다. 프로세스가 죽는 것 자체는 그저 흔한 운영 이벤트이지만, 그것이 22턴 분량의 실행 상태를 단번에 지워 버리고, 바로 그 점이 비용을 증폭시킵니다.

에러가 난 뒤에는 "When errors occur, we can't just restart from the beginning: restarts are expensive and frustrating for users."1(에러가 발생했을 때 우리는 그냥 처음부터 다시 시작할 수 없다. 재시작은 비싸고 사용자를 좌절시킨다) 그래서 만들어야 하는 것은 이런 시스템입니다. "Instead, we built systems that can resume from where the agent was when the errors occurred."1(대신 우리는 에러가 발생했을 때 에이전트가 있던 지점에서 재개할 수 있는 시스템을 만들었다) '메모리 너머에 상태가 있다'가 학술적인 구분이 아니라 긴 작업이 중단을 견뎌 낼 수 있는지를 가르는 토대인 이유가 여기에 있습니다.

작업이 길수록 이 청구서는 무거워집니다. "The LLM will potentially operate for many turns, and you must have some level of trust in its decision-making."2(LLM은 잠재적으로 여러 턴에 걸쳐 동작하게 되며, 여러분은 그 의사 결정을 어느 정도 신뢰해야만 한다), 그리고 "The autonomous nature of agents means higher costs, and the potential for compounding errors."2(에이전트의 자율적인 성질은 더 높은 비용과, 에러가 누적될 가능성을 의미한다). 더 많은 턴을 돌수록 쌓이는 실행 상태는 두꺼워지고, 한 번의 중단이 지울 수 있는 것도 커집니다.

크래시는 드문 일이 아닙니다

23턴째의 그 '프로세스가 죽었다'는 확률 낮은 사고처럼 들리지만, 수십 턴을 도는 긴 작업에서 도중에 중단되는 일은 전혀 드물지 않습니다. 가장 일상적인 배포 업데이트조차 돌아가는 중인 에이전트와 부딪힐 수 있습니다. 그래서 팀들은 의도적으로 "use rainbow deployments to avoid disrupting running agents, by gradually shifting traffic from old to new versions"1(레인보우 배포를 사용해, 트래픽을 옛 버전에서 새 버전으로 점진적으로 옮김으로써 돌아가는 중인 에이전트를 방해하지 않도록 한다) 하며, 그 이유는 "whenever we deploy updates, agents might be anywhere in their process."1(업데이트를 배포할 때마다 에이전트는 자기 프로세스의 어느 지점에 있어도 이상하지 않다)이기 때문입니다.

바꿔 말하면, 운영을 돌리는 사람들조차 '에이전트는 언제든 중단될 수 있다'를 일어날 일로 전제하고, 그것을 피하기 위한 장치를 따로 설계합니다. 여러분의 하네스가 그들보다 운이 좋으리라 가정할 근거는 없습니다.

처방 미리보기: 이 코스의 지도

23턴째에 잃어버린 실행 상태에는 다섯 단계짜리 처방이 있고, 그것이 곧 다음 다섯 레슨의 순서입니다.

  1. 체크포인트(레슨 2) — messages, turns, tokensUsed, 허공에 뜬 도구 호출 같은 실행 상태를 주기적으로 직렬화해 디스크의 체크포인트 파일에 씁니다.
  2. 체크포인트에서 재개하기(레슨 3) — 프로세스를 다시 띄운 뒤 그 상태를 체크포인트 파일에서 읽어 내고, messages를 다시 세우고, 루프가 1턴째부터 다시 시작하는 대신 끊긴 자리에서 이어 가게 합니다.
  3. 부수 효과와 멱등성(레슨 4) — 재개에서 가장 어려운 부분은 '상태가 사라졌다'가 아니라 '어떤 도구 호출은 이미 실제로 실행되었을 수 있다'입니다. 어떤 도구가 다시 실행해도 안전하고, 어떤 도구는 두 번 실행되지 않도록 막아야 하는가.
  4. 되감기와 분기(레슨 5) — 체크포인트는 재해 복구만을 위한 것이 아닙니다. 앞선 장면으로 되감아 다시 시도하게 해 주고, 어떤 노드에서 또 다른 시도를 갈라 내게도 해 줍니다.
  5. 직접 만들기(레슨 6) — 앞선 레슨들의 장치를 "에이전트 하네스 기초: 루프와 통제"의 하네스에 끼워 넣고, 긴 작업을 '도중에 죽이고, 다시 띄우고, 끝까지 완주시키기'까지 직접 돌려 봅니다.

'하네스 엔지니어링'을 축으로 삼은 어느 커뮤니티 오픈소스 로드맵은 이것을 한 줄로 압축합니다. "Checkpoint state every node so you can resume, rewind, fork."3(모든 노드에서 상태를 체크포인트해, 재개하고 되감고 분기할 수 있게 하라) 이것은 지속성 컴포넌트가 무엇을 책임지는지에 대한 커뮤니티 문서의 틀 잡기일 뿐 이 코스가 그대로 베끼는 사양은 아니지만, 그것이 가리키는 순서는 위의 다섯 단계와 맞아떨어집니다.

균형 감각: 모든 작업에 이것이 필요하지는 않습니다

모든 에이전트가 체크포인트 장치를 짊어져야 하는 것은 아닙니다. 복잡도를 더하는 일에 대해서는 "you should consider adding complexity only when it demonstrably improves outcomes."2(결과를 눈에 띄게 개선함이 증명될 때에만 복잡도를 더하는 것을 고려해야 한다)라는 원칙이 있습니다. 도구 호출 몇 턴이면 끝나는 작업은 messages에 담긴 항목도 몇 개뿐이고, 프로세스가 죽으면 그냥 다시 돌리면 됩니다. 비용은 한 번 더 묻는 것뿐이고, 저장과 복원 장치를 통째로 설계할 만한 일이 아닙니다.

이 코스의 장치가 실제로 필요한 것은 첫머리의 23턴째 같은 장면입니다. 수십 턴을 돌고, 몇 분에서 몇 시간이 걸릴 수 있으며, 그동안 지속되지 않은 실행 상태를 잔뜩 쌓아 가는 작업입니다. 체크포인트를 들일지 판단하려면 먼저 스스로에게 한 가지를 물으십시오. 지금 당장 죽는다면, 다시 돌리는 비용을 감당할 수 있는가? 감당할 수 없다면, 그때가 다음 레슨들이 필요한 순간입니다.

정리

  • 에이전트는 오랜 시간 돌면서 수많은 도구 호출에 걸쳐 상태를 유지할 수 있고, 바로 그렇기 때문에 상태를 가지며 에러가 누적된다1. 상태가 쌓일수록 한 번의 장애가 지울 수 있는 것도 커진다.
  • 효과적인 완화책이 없으면 사소한 시스템 장애도 에이전트에게 파국이 될 수 있다1. 에러가 난 뒤에는 처음부터 다시 시작할 수 없는데, 재시작은 비싸고 사용자를 좌절시키기 때문이며, 그래서 에러가 난 지점에서 재개하는 시스템을 만든다1.
  • 크래시는 드문 일이 아니다. 일상적인 배포 업데이트조차 돌아가는 중인 에이전트를 방해하지 않으려고 레인보우 배포를 필요로 하는데, 배포 시점에 에이전트는 자기 프로세스의 어느 지점에 있어도 이상하지 않기 때문이다1.
  • 자율적인 실행에는 본래 더 높은 비용과 에러가 누적될 위험이 따른다2. 작업이 길수록 이 청구서는 무거워지고, 중단을 견뎌 내는 장치가 그만큼 더 필요해진다.
  • 모든 작업이 이 장치를 짊어져야 하는 것은 아니다. 복잡도는 결과를 눈에 띄게 개선함이 증명될 때에만 더하며2, 몇 턴이면 끝나는 작업은 그냥 다시 돌리는 비용이 대체로 감당할 만하다.
  • 메모리(모델에게 주는 컨텍스트)와 실행 상태(하네스가 붙들고 있는 실행 중인 장면)는 서로 다른 것이다. 메모리는 이미 지속되어 있을 수 있지만 실행 상태는 기본적으로 프로세스 메모리에만 산다. 다음 몇 레슨은 그 실행 상태 역시 디스크에 쓰고 되살릴 수 있는 것으로 바꾸는 이야기다.

>> 레슨 2: 체크포인트: 실행 장면을 디스크에 쓰기

Footnotes

  1. How we built our multi-agent research system — Anthropic Engineering — https://www.anthropic.com/engineering/multi-agent-research-system 2 3 4 5 6 7 8 9 10 11

  2. Building Effective AI Agents — Anthropic Engineering — https://www.anthropic.com/engineering/building-effective-agents 2 3 4 5

  3. The 2026 Agent Engineering Roadmap — GitHub (codejunkie99/agent-roadmap-2026) — https://github.com/codejunkie99/agent-roadmap-2026

연습

01

아래는 실행 중인 하네스에 관여하는 여섯 가지 '것'입니다. 각각을 '메모리', '실행 상태', '디스크 출력물' 중 하나로 분류하고, 이 순간 프로세스가 죽는다면 그것이 남아 있는지 말하십시오.

레벨 1: 실행 중인 여섯 가지 '것'을 분류하기
  1. 이미 NOTES.md에 쓰인 작업 진척 요약("Context Engineering: Spending Finite Attention Where It Counts"에서 마련한 그것)
  2. 메모리 위의 messages 배열
  3. 이미 디스크에 쓰인 리포트 파일 report.md
  4. turns 카운터(지금 몇 턴째인가)
  5. 모델이 이번 턴에 방금 생성한 응답 텍스트 안의, 프로젝트 구조에 대한 분석 한 대목 — 아직 NOTES.md에 쓰이지 않음
  6. 모델이 이미 지명했지만 도구 실행이 끝나지 않았고 결과도 messages에 밀려 들어가지 않은 tool_use 블록
완료 기준 · 로컬에서 확인
02

첫머리의 장면으로 돌아갑니다. "에이전트 하네스 기초: 루프와 통제"의 runAgent(messages, turns, tokensUsed라는 변수를 stop_reason 루프로 돌리는 그것)가 40턴짜리 작업을 돌리다가 23턴째에 프로세스가 죽었습니다. 게다가 크래시는 '모델이 도구를 지명했다'와 '도구 결과가 messages에 밀려 들어갔다'의 정확히 사이에 떨어졌습니다. 코드를 쓰지 말고 말로 두 가지를 하십시오.

레벨 2: "에이전트 하네스 기초"의 하네스에 크래시 손실 목록을 쓰기
  1. 크래시 손실 목록: 이번 크래시가 정확히 무엇을 잃었습니까? 영향받지 않고 그대로 남은 것은 무엇입니까?
  2. 체크포인트가 담아야 할 것: 이 하네스에 체크포인트 장치가 있었다면, 이 손실을 최대한 줄이기 위해 체크포인트 파일이 최소한 어떤 필드를 담아야 한다고 보십니까? 필드 이름을 나열하고, 각각을 왜 저장해야 하는지 말하십시오.
완료 기준 · 로컬에서 확인