튜토리얼
AI Agent State란 무엇인가? 2026 상태 관리, JSON State, Memory, Workflow와 작업 실행 완전 가이드
채팅 기록은 상태가 아니다. Agent가 일시 정지, 재개, 다음 홉으로 넘길 수 있는 이유는 검증 가능한 JSON이 있기 때문이다. 목표, 단계, 도구 회신, 기억 포인터, 작업 봉투.
2026년에 Agent를 프로덕션에 넣을 때 막히는 지점은 「모델이 충분히 똑똑한가」가 아니다. 중단, 재시도, 사람 확인 뒤에 자신이 몇 홉에 있었는지를 기억하는가다. 이전 글은 Agent를 관찰–결정–도구 호출 루프로 접었다. AI Agent란을 보라. 이 글은 루프 바깥 층을 더한다. State. State는 대화 전체를 문맥에 넣는 것도, 벡터 저장소의 한 조각도 아니다. 런타임 현재 기위의 구조화 스냅샷이며 거의 항상 JSON이다. JSON State, Memory, Workflow, 작업 실행으로 가른 뒤 Stateless MCP, A2A, Structured Output, 1M 컨텍스트 글로 잇는다.
Agent State란: 채팅 기록·Session과의 차이
최소 정의는 한 문장이다. Agent State는 한 run을 일시 정지·재개·재생할 수 있게 하는 구조화 스냅샷이다. 적어도 넷에 답한다. 목표는 무엇인가, 지금 어느 홉인가, 이미 확정된 작업 결과는 무엇인가, 다음을 누가 막고 있는가(도구, 사람, maxSteps). 행동은 모델이 현재 관찰에서 고르고, 실행과 기위 기록은 런타임이 한다. 검증 가능한 기위가 없으면 루프는 「채팅 전체를 다시 붙이는」수밖에 없다. 그것은 채팅이지 상태 관리가 아니다.
채팅 기록은 모델이 보는 메시지 목록이다. user / assistant / tool. Session(OpenAI Conversations, previous_response_id, 옛 Assistants Thread)은 벤더가 보는 세션 핸들이다. 다음 요청이 가져가야 할 모델 측 항목. State는 당신 런타임이 보는 기위다. 청구서 대사 진도, 확인 대기 금액, 현재 그래프 노드, checkpoint id. 공존은 된다. 서로 사칭하면 안 된다. messages[]를 유일한 진실로 두면 재시도가 이중 청구·이중 메일을 만든다. Conversation id를 업무 상태로 두면 벤더를 바꾸는 순간 기위가 사라진다. Assistants가 Responses로 옮긴 뒤 세션 원어가 바뀌었다. 업무 스냅샷을 플랫폼 객체에 묶을 이유는 더 적다. Assistants → Responses 이전.
2026년 흔한 사고는 층이 섞인 것이다. 도구 arguments를 State에 쓰고, State 통째를 다음 프롬프트에 넣고, 장기 기억을 checkpoint로 재생한다. 나눈 뒤에야 디버그에 손잡이가 생긴다. 모델이 읽기를 틀린 것은 관찰, 기위를 잘못 쓴 것은 reducer / Schema, 취향을 잘못 꺼낸 것은 Memory. 대조는 아래와 같다.
| 개념 | 누가 읽는가 | 잃으면 어떻게 되는가 |
|---|---|---|
| 채팅 / messages | 모델(이번 턴 문맥) | 동문서답. 대개 checkpoint에서 다시 투영할 수 있다 |
| Session / Conversation | 모델 벤더 | 추론 항목이 어긋남. 업무 기위는 독립해야 한다 |
| Agent State / checkpoint | 당신 런타임과 오케스트레이터 | 안전하게 재개 불가. 재시도가 하류에 이중 기록 |
| Memory | run을 넘는 검색과 취향 | 습관을 잊음. 현재 단계의 진실이 되어서는 안 됨 |
JSON State: 계약은 checkpoint
State를 JSON으로 쓰는 것은 보기 위해서가 아니라 검증, Diff, 재생을 위해서다. LangGraph 계열 오케스트레이터는 super-step마다 checkpoint를 남기고 thread_id로 한 줄을 이으며 checkpoint_id로 한 장을 가리킨다. 프로덕션은 프로세스 안 MemorySaver가 아니라 Postgres / SQLite saver. 이름은 바뀐다. 모양은 바꾸면 안 된다. parse 가능한 객체에 schemaVersion, status 열거, step, working, memoryRefs. 직렬화는 JsonPlus나 확장 JSON이어도 되지만 로그, 공개, 연동에 내놓는 층은 평범한 JSON object여야 한다. 아니면 Schema 검증과 브라우저 Diff를 쓸 수 없다.
아래 스냅샷은 기위만 적는다. messages[]나 하류 HTTP 원문을 넣지 않는다. 업무 필드는 working. 도구 호출은 name과 callId. 기억은 포인터. 전체 대화는 checkpoint에서 모델 문맥으로 다시 투영한다. 반대로 문맥을 State로 쓰지 마라.
{
"schemaVersion": "1.0",
"runId": "run_7c2a",
"threadId": "thr_invoice_42",
"goal": "Reconcile January 2026 paid invoices",
"status": "awaiting_tool",
"step": 3,
"maxSteps": 12,
"node": "call_tools",
"plan": ["searchInvoices", "sumTotals", "askConfirm"],
"working": {
"invoiceCount": 2,
"currency": "USD"
},
"pendingTool": {
"name": "searchInvoices",
"callId": "call_8f3a"
},
"memoryRefs": ["mem_user_prefs", "mem_last_reconcile"],
"checkpointId": "ckpt_3"
}
두 방식 모두 성립한다. 매번 전체 스냅샷, 또는 JSON Patch / reducer. 전체는 Diff와 재생이 쉽다. 패치는 저장을 아끼고 패치 자체를 검증할 수 있어야 한다. 어느 쪽이든 Draft 2020-12 Schema를 먼저 정한다. status는 열거(running / awaiting_tool / awaiting_human / succeeded / failed / cancelled), step은 정수, working 키는 업무에서, additionalProperties는 금지해 도구 쓰레기가 새지 않게 한다. 사용자나 하류에 줄 최종 답은 별도 Structured Output 파일. checkpoint와 공유하지 마라. AI Structured Output.
Memory: 회상은 기위가 아니다
Memory는 「시간을 넘어 무엇을 알아야 하는가」, State는 「이 한 장이 어디에 멈췄는가」. 2026년 흔한 세 층: 작업 기억(이번 턴 메시지와 최근 tool_result), 단기 / 스레드 기억(같은 thread_id의 checkpoint 사슬, LangGraph의 short-term memory), 장기 기억(스레드를 넘는 Store: 취향, 사실, 절차). 셋을 거대한 JSON에 넣으면 싸 보인다. 재생과 망각 정책이 함께 망가진다.
내용으로도 가른다. 에피소드(이번 대사에서 무슨 일이 있었는가), 의미(사용자는 달러 합계를 선호), 절차(「먼저 청구서를 찾고 다음에 합산」). 현재 run이 인용한 기억만 State의 memoryRefs에 넣는다. 컨텍스트 창이 백만 토큰이 되어도 이 포인터 층은 은퇴하지 않는다. 창은 예산이지 진실이 아니다. 1M Token 컨텍스트.
| 층 | 전형 매체 | 넣으면 안 되는 것 |
|---|---|---|
| 작업 기억 | 이번 턴 messages / tool_result | 세션을 넘는 취향 전문 |
| 단기 / checkpoint | thread_id 위의 State 스냅샷 | 벡터 저장소 원문, 자르지 않은 로그 |
| 장기 Store | userId / namespace 항목 | 현재 step, pendingTool, 멱등 키 |
| 모델 측 Session | Conversation / previous_response_id | 업무 working 객체 |
장기 항목은 봉투를 고정한다. id, kind, scope, text 또는 data, source, updatedAt. source는 사용자 명시, 도구 회신, 모델 요약 중 무엇인지 적는다. 뒤 둘은 폐기할 수 있어야 한다. 검색 히트 뒤에는 State에 id만 쓰고 본문은 필요할 때 문맥에 넣는다. 예:
{
"id": "mem_user_prefs",
"kind": "semantic",
"scope": "user",
"userId": "u_1042",
"text": "Prefers USD totals and weekday email summaries",
"source": "explicit_setting",
"updatedAt": "2026-09-01T09:00:00Z"
}
Workflow와 Agent: 누가 간선을 긋고 누가 State를 쓰는가
고전 워크플로(n8n, Temporal, 자체 상태 기계)의 다음 홉은 사람이 미리 잇는다. State는 워크플로 변수다. 주문 id, 재시도 횟수, 보상을 냈는지. Agent의 다음 홉은 모델이 현재 JSON 관찰에서 고른다. State는 plan, node, pendingTool도 적는다. 2026년 프로덕션은 순종이 드물다. 「그래프 + 여러 Agent 노드」가 흔하다. 간선은 워크플로, 노드 안은 도구 루프. 하나의 JSON State가 두 독자를 섬긴다. 오케스트레이터는 status / node를 읽고, 모델은 투영한 관찰 부분집합만 본다.
MCP는 이 층을 갖지 않는다. 2026-07-28 전후 원격 MCP는 무상태 JSON-RPC다. 요청마다 메타를 실어 나르고 Server는 업무 기위를 기억하지 않는다. 그것은 전송의 올바른 선택이지 「Agent는 상태를 가질 수 없다」가 아니다. 애플리케이션 상태는 여전히 당신 checkpoint에 있다. 세부: Stateless MCP. 도구 arguments Schema와 State Schema는 파일을 나눈다. 전자는 이 홉 입력, 후자는 기위. MCP와 JSON Schema.
다중 Agent 가로 위임은 A2A. 상대는 불투명한 Agent. 작업은 자체 수명 주기(submitted / working / completed / failed)와 artifacts를 가진다. 그것은 다른 상태 기계다. 로컬 checkpoint와 객체를 공유하지 마라. 오케스트레이터는 parentRunId로 고정한다. 대조: A2A vs MCP. 모델 게이트웨이(로컬 /v1 등)는 추론 공급만 바꾸고 State 모양은 바꾸지 않는다. 계약이 안정해야 폴백에 의미가 있다.
작업 실행: run, step, 멱등과 재시도
실행 층은 State를 「사진」에서 「복구 가능한 기계」로 바꾼다. 사용자 목표마다 runId. 루프의 각 도구 hop이 step. 하류 쓰기(청구, 메일, 티켓)에는 idempotencyKey가 필수다. 충돌 뒤에는 최신 checkpoint에서 재개하고 이미 성공한 step의 부작용을 다시 실행하지 않는다. pending writes(일부 성공, 일부 실패)는 스냅샷에 남긴다. 운영자의 추측에 맡기지 마라.
사람 확인은 일등 상태이지 특수 분기가 아니다. status=awaiting_human, 확인 대상은 working, 재개 시 합법 전이만 허용한다(승인→계속, 거부→실패 또는 plan 변경). 「모델에게 다시 묻기」로 상태 전이를 대체하지 마라. 관찰에 쓰지 않은 클릭은 모델이 보지 못한다. maxSteps, 사용자 취소, Schema 실패도 정지 조건이다. status에 쓰고 로그만 남기지 마라.
플랫폼 세션과 당신 실행 기록 중 역사의 주인을 하나로 고른다. OpenAI Responses는 Conversation 또는 previous_response_id로 추론 항목을 이어갈 수 있다. 그것은 모델 측 테이프이지 청구서 대사 기위가 아니다. 권장: checkpoint와 작업 봉투는 당신이 갖고, 플랫폼은 재생을 요구하는 reasoning 항목만 갖는다(tool_calls가 있을 때 reasoning_content를 원문 그대로 되돌려 달라고 하는 벤더가 있다). 작업 봉투 예:
{
"taskId": "task_a2a_91",
"parentRunId": "run_7c2a",
"kind": "delegate",
"status": "working",
"idempotencyKey": "inv-jan-2026-reconcile",
"steps": [
{ "id": "s1", "name": "searchInvoices", "ok": true },
{ "id": "s2", "name": "sumTotals", "ok": null }
],
"artifacts": []
}
자식 Agent에 위임할 때는 원격 taskId를 로컬 working 또는 steps에 쓴다. 상대 artifacts를 같은 checkpoint에 펼치지 마라. 중간 산물은 새로운 JSON 가족이다. 최종 Structured Output과도 MCP arguments와도 파일을 공유하지 마라. 지금부터 각 도구 로그에 correlationId / runId를 찍어라. 이후 대사가 맞는다. DevDay 식 관측도 같은 키로 맞춘다. OpenAI DevDay 2026 예측.
현장 검증과 JSONVue
checkpoint를 떨어뜨리기 전 세 단계. parse → Schema → 업무 규칙. 똑똑한 모델도 이 셋을 대체하지 않는다. State가 깨지는 것은 arguments가 깨지는 것보다 위험하다. 후자는 한 홉, 전자는 run 전체의 진실이다.
- checkpoint를 JSON.parse. 실패면 쓰기를 거부하고 이전 ckpt_id를 남긴다.
- State Schema(Draft 2020-12)로 status / step / working을 검증. path와 keyword를 낸다.
- 업무 게이트: step은 단조, 멱등 키는 안정, memoryRefs는 모두 존재, 불법 status 전이는 실패로 닫는다.
연동 때 세 JSON을 나란히 둔다. ckpt_n, ckpt_n+1, 모델에 투영한 관찰. 모양 점프는 거의 reducer. 브라우저에서 JSON 포맷터로 스냅샷 나무를 보고, JSON Schema 검증으로 State와 Memory 봉투를 고정하고, JSON Diff로 인접 checkpoint를 비교한다. valid / step 누락 / 불법 status 픽스처를 CI와 수동이 공유한다.
더 읽기: AI Agent란, Structured Output, Stateless MCP, A2A vs MCP, 1M Token 컨텍스트.
자주 묻는 질문
State와 Memory는 같은가?
아니다. State는 현재 run의 기위(안전하게 재개할 수 있는가). Memory는 시간을 넘는 회상(취향, 사실, 옛 에피소드). checkpoint 사슬은 단기 기억이 될 수 있다. 장기 Store에 step / pendingTool을 쓰면 안 된다. 재생은 State, 검색은 Memory.
컨텍스트 창이 1M가 됐다. 그래도 checkpoint가 필요한가?
필요하다. 창은 「이번 턴에 관찰을 얼마나 넣을 수 있는가」를 정한다. 「충돌 후 어느 홉에서 이어갈 것인가」와 「재시도가 이중 기록할 것인가」는 정하지 않는다. 이력 전체를 State로 두면 요금과 고장면이 함께 나빠진다. 1M는 예산 도구, checkpoint는 실행 도구.
OpenAI Conversation을 쓴다. 그래도 JSON State를 직접 저장해야 하나?
해야 한다. Conversation / previous_response_id가 이어 주는 것은 모델 측 항목이지 업무 기위가 아니다. 쿼터, 리전, 게이트웨이가 바뀌면 플랫폼 세션이 어긋날 수 있다. working, 멱등 키, 사람 확인 상태는 당신이 통제하는 JSON에 둔다.
Stateless MCP면 상태 있는 Agent를 만들 수 없나?
만들 수 있다. 프로토콜이 무상태라는 것은 매 tools/call이 자기 인자를 가진다는 뜻이다. Server는 대사 진도를 저장하지 않는다. 애플리케이션 상태는 당신 checkpoint에 있다. MCP는 발견과 전송으로 남는다. inputSchema와 State Schema는 두 파일로 나눈다.
요약과 다음 단계
2026 Agent State는 한 줄이다. 런타임은 검증 가능한 JSON 스냅샷으로 기위를 기억하고, Memory는 인용된 회상만 공급하며, Workflow는 간선을 긋거나 모델에 넘기고, 작업 실행은 run / step / 멱등 키로 스냅샷을 복구 가능한 기계로 만든다. 채팅 기록과 플랫폼 Session은 이 스냅샷을 대체하지 않는다.
다음은 구체적이다. State Schema와 valid checkpoint 하나를 쓰고, JSONVue에서 인접 스냅샷을 Diff하고, 필드 누락과 불법 status 픽스처를 더한다. 루프 정의는 Agent 글, 최종 모양은 Structured Output, 프로토콜은 MCP / A2A.