GPT-5.6 Persisted Reasoning: Memory와 Context를 섞지 않는 장기 Agent 상태 설계

이경규·2026년 7월 28일

GPT-5.6 Persisted Reasoning: Memory와 Context를 섞지 않는 장기 Agent 상태 설계

AI Agent를 몇 턴 사용하다 보면 한 가지 문제가 생긴다.

처음에는 Agent가 작업을 잘 이해하고 있다.

사용자

이 프로젝트의 로그인 문제를 조사해줘.
Architecture는 그대로 유지하고
최소 수정으로 해결해줘.

Agent가 Repository를 조사한다.

AuthManager
LoginViewModel
TokenStore

몇 차례 대화하면서 원인을 좁힌다.

1턴
→ Authentication 구조 확인

2턴
→ Race Condition 후보 발견

3턴
→ Token 갱신 흐름 확인

4턴
→ 수정 방향 결정

그런데 대화가 길어지면 이런 현상이 생긴다.

왜 이 파일을 조사했는지 다시 설명해야 한다.

이미 제외한 가설을 다시 검토한다.

앞에서 합의한 우선순위를 잊는다.

같은 Tool을 다시 호출한다.

이미 했던 판단을 다시 한다.

그래서 많은 Agent 시스템이 모든 것을 Context에 쌓기 시작한다.

System Prompt
+
Conversation
+
Repository 정보
+
Tool 결과
+
Task 상태
+
요약
+
Memory
+
이전 판단

그리고 Context Window가 커진다.

하지만 GPT-5.6에서는 여기서 한 가지 새로운 선택지가 생겼다.

Persisted Reasoning이다.

GPT-5.6은 이전 턴의 reasoning item을 다음 턴에서 다시 활용할 수 있도록 reasoning.context를 제공한다.

그래서 이제 Agent 상태를 최소 세 가지로 구분해서 생각할 필요가 있다.

Memory

Context

Persisted Reasoning

이 셋은 비슷해 보이지만 역할이 전혀 다르다.

이번 글에서는 이 세 가지를 어떻게 분리하고, 장시간 실행되는 Agent Runtime에서 어떻게 관리할지 정리해본다.


1. 먼저 세 가지를 한눈에 구분해보자

가장 간단하게 정리하면 이렇다.

Memory
→ 오래 기억해야 할 사실

Context
→ 지금 작업하는 데 필요한 정보

Persisted Reasoning
→ 앞선 판단을 이어가기 위한 추론 연속성

예를 들어 iOS Agent가 있다고 하자.

Memory

이 프로젝트는 Swift 6을 사용한다.

외부 라이브러리 추가에는 승인이 필요하다.

Generated 디렉터리는 직접 수정하지 않는다.

이런 정보는 여러 Task에서도 계속 유효할 수 있다.


Context

현재 Task가

로그인 실패 시 사용자 메시지를 수정한다.

라면 필요한 Context는

LoginViewModel.swift

AuthErrorMapper.swift

관련 테스트

현재 Git Diff

Task 요구사항

정도다.

Task가 끝나면 대부분 필요 없어진다.


Persisted Reasoning

Agent가 조사하면서 이런 판단을 했다고 하자.

네트워크 계층 문제 가능성은 낮다.

AuthErrorMapper에서 서버 오류가 그대로 전달되고 있다.

Public API를 변경할 필요는 없다.

수정 범위는 ErrorMapper와 Test면 충분하다.

다음 턴에서도 같은 Task를 계속한다면 이런 판단의 연속성이 유용하다.

이 역할에 가까운 것이 Persisted Reasoning이다.


2. Persisted Reasoning은 Memory가 아니다

여기서 가장 많이 헷갈릴 수 있다.

이전 Reasoning을 유지한다.

=

Memory다.

가 아니다.

Memory는 보통 사실이나 장기 상태를 저장한다.

예를 들어

{
  "project": {
    "language": "Swift 6",
    "architecture": "MVVM"
  }
}

또는

{
  "userPreferences": {
    "preferSmallPR": true
  }
}

처럼 명시적인 데이터를 저장할 수 있다.

반면 Persisted Reasoning은 GPT-5.6이 이전 응답에서 생성한 reasoning item을 다음 턴에서 활용하게 하는 기능이다.

중요한 차이가 있다.

Memory

Application이 관리하는 정보
Persisted Reasoning

Model의 이전 reasoning 상태를 이어가는 기능

따라서 Agent의 영구 데이터베이스를 Persisted Reasoning으로 대체해서는 안 된다.


3. Context와도 다르다

Context는 모델에게 현재 요청을 처리하기 위해 제공하는 입력 정보다.

예를 들어

System Prompt

Task

Repository files

Tool results

Previous messages

같은 것들이다.

Context는 쉽게 말해

지금 모델이 보고 있는 작업 공간

이다.

반면 Persisted Reasoning은

이 작업을 이전에 어떻게 이해하고 있었는가

의 연속성에 가깝다.

둘은 서로 보완 관계다.

Context
→ 무엇을 보고 있는가

Reasoning
→ 그것을 어떻게 판단해 왔는가

4. GPT-5.6에서는 reasoning.context를 선택할 수 있다

GPT-5.6 Responses API에는 reasoning.context 설정이 있다.

현재 주요 선택지는 다음처럼 이해하면 된다.

auto

all_turns

current_turn

auto

기본 동작을 모델과 API에 맡긴다.

reasoning.context = auto

특별한 이유가 없다면 시작점으로 사용할 수 있다.


all_turns

앞선 턴의 Reasoning이 현재 작업에도 계속 중요할 때 사용한다.

reasoning.context = all_turns

예를 들어

대규모 Refactoring

복잡한 Debugging

Research

Migration

장시간 Agent

처럼 여러 턴 동안 같은 목표와 가정이 유지되는 작업이다.


current_turn

과거 Reasoning을 이어갈 필요가 없을 때 사용한다.

reasoning.context = current_turn

새로운 Task로 전환했거나 앞선 판단이 더 이상 의미가 없다면 이쪽이 낫다.


5. 가장 중요한 기준은 Task Continuity다

all_turns를 사용할지 판단하는 가장 좋은 질문은 이것이다.

앞선 턴의 목표와 가정이
지금도 유효한가?

YES라면

all_turns

후보다.

NO라면

current_turn

으로 끊는 편이 좋다.

예를 들어

Task A

로그인 Race Condition 조사

를 계속하고 있다.

Turn 1
Architecture 분석

Turn 2
가능한 원인 후보

Turn 3
로그 확인

Turn 4
수정

Turn 5
Test

같은 Goal이다.

이때는 Reasoning 연속성이 유용하다.


하지만 사용자가 갑자기

이제 로그인 문제는 끝났고
설정 화면 UI를 만들어줘.

라고 한다.

Task가 완전히 달라졌다.

Auth Debugging Reasoning

↓

Settings UI

이전 추론을 계속 유지할 이유가 적다.

이때 Reasoning을 끊는 것이 자연스럽다.


6. 모든 턴을 계속 유지하면 오히려 문제가 될 수 있다

Persisted Reasoning이라는 이름 때문에

항상 all_turns를 쓰면
더 똑똑하지 않을까?

라고 생각할 수 있다.

그렇지 않다.

오래된 판단이 현재 Task와 맞지 않을 수 있다.

예를 들어 Agent가 초기에 이렇게 판단했다.

원인은 TokenStore일 가능성이 가장 높다.

그런데 새로운 로그가 들어왔다.

TokenStore는 정상.

실제 원인은 Session Refresh.

Agent가 오래된 가설에 과도하게 매달리면 문제가 된다.

Reasoning도 Context처럼 수명이 있는 정보로 봐야 한다.


7. 장기 Agent 상태를 네 계층으로 나누자

실전에서는 세 개보다 조금 더 세분화하는 편이 관리하기 좋다.

1. Durable Memory

2. Task Context

3. Execution State

4. Persisted Reasoning

구조로 나눈다.


Durable Memory

Task가 끝나도 남는 정보다.

Repository 규칙

사용자 선호

프로젝트 Architecture

정책

팀 Convention

예:

{
  "repository": {
    "language": "Swift 6",
    "architecture": "MVVM",
    "generatedPath": "Generated/"
  }
}

Task Context

현재 작업에 필요한 자료다.

Issue

관련 코드

현재 Diff

Test

Reference

사용자의 현재 요구사항

예:

{
  "taskId": "PAP-142",
  "title": "Fix login error handling",
  "files": [
    "AuthErrorMapper.swift",
    "LoginViewModel.swift"
  ]
}

Execution State

Agent Runtime 자체의 상태다.

현재 Step

완료한 Tool

생성된 Artifact

Retry 횟수

Budget

Checkpoint

예:

{
  "taskId": "PAP-142",
  "step": "verification",
  "completedSteps": [
    "analysis",
    "implementation"
  ],
  "retryCount": 0
}

Persisted Reasoning

앞선 Model 판단을 이어가는 계층이다.

이건 애플리케이션에서

{
  "reasoning": "..."
}

형태로 직접 저장하는 일반 Memory와 다르다.

Responses API에서 Reasoning Item을 유지하고 다음 턴에 다시 사용할 수 있도록 연결한다.


8. 전체 구조를 그리면 이렇게 된다

                 Agent Runtime
                      │
        ┌─────────────┼─────────────┐
        │             │             │
     Memory        Context       Execution
        │             │             │
        │             │             │
        └───────┬─────┴─────┬───────┘
                │           │
                ▼           ▼
              Model     Reasoning State
                │
                └─────┬─────┘
                      │
                    Result

각 계층은 책임이 다르다.


9. previous_response_id와 함께 사용한다

Responses API에서는 이전 Response를 이어갈 때 previous_response_id를 사용할 수 있다.

개념적으로 첫 요청은 다음과 같다.

const first = await openai.responses.create({
  model: "gpt-5.6-sol",

  reasoning: {
    effort: "high",
    context: "all_turns"
  },

  input: `
    Investigate the login race condition.
    Preserve the existing public API.
  `
});

다음 요청은 앞선 Response를 연결한다.

const second = await openai.responses.create({
  model: "gpt-5.6-sol",

  previous_response_id: first.id,

  reasoning: {
    effort: "high",
    context: "all_turns"
  },

  input: `
    The latest test log is attached.
    Continue the investigation.
  `
});

같은 Task가 계속되기 때문에 앞선 Reasoning을 활용할 수 있다.


10. 새 Task에서는 끊는다

다음 사용자 요청이 완전히 다른 작업이라면

SettingsView를 새 디자인으로 만들어줘.

이전 Auth Reasoning을 끌고 갈 필요가 없다.

const response = await openai.responses.create({
  model: "gpt-5.6-terra",

  reasoning: {
    effort: "medium",
    context: "current_turn"
  },

  input: `
    Implement the new SettingsView.
  `
});

또는 새로운 Agent Run 자체를 시작한다.

핵심은

Conversation이 계속된다

≠

Reasoning도 반드시 계속돼야 한다

는 것이다.


11. Conversation과 Task를 분리하는 것이 중요하다

Chat UI에서는 한 Conversation 안에서 여러 작업을 할 수 있다.

Conversation #123

├── 로그인 Bug
├── 설정 화면
├── Push Notification
└── Test 개선

하지만 Agent Runtime에서는 이것을 하나의 Reasoning Session으로 취급하면 좋지 않다.

Task별로 나눈다.

Conversation #123

Task A
Login Bug
Reasoning Session A

Task B
Settings UI
Reasoning Session B

Task C
Push Notification
Reasoning Session C

이 구조가 훨씬 명확하다.


12. Task Run ID를 따로 둔다

예를 들어

type AgentTask = {
  conversationId: string;
  taskId: string;
  runId: string;

  reasoningPolicy:
    | "auto"
    | "all_turns"
    | "current_turn";
};

실제 값은

{
  "conversationId": "conv-71",
  "taskId": "PAP-142",
  "runId": "run-9912",
  "reasoningPolicy": "all_turns"
}

처럼 관리한다.

사용자가 같은 Chat 화면에 있어도 Task가 바뀌면 새로운 Run을 만든다.


13. Reasoning Session을 Runtime에서 관리한다

간단한 구조를 만든다면 다음처럼 할 수 있다.

type ReasoningSession = {
  taskId: string;

  previousResponseId?: string;

  mode:
    | "auto"
    | "all_turns"
    | "current_turn";

  createdAt: number;
  updatedAt: number;
};

Task Store에서 관리한다.

class ReasoningSessionStore {
  private sessions =
    new Map<string, ReasoningSession>();

  get(taskId: string) {
    return this.sessions.get(taskId);
  }

  save(session: ReasoningSession) {
    this.sessions.set(
      session.taskId,
      session
    );
  }

  clear(taskId: string) {
    this.sessions.delete(taskId);
  }
}

14. Agent Runtime에서 연결한다

async function runAgent(
  taskId: string,
  input: string
) {
  const session =
    reasoningStore.get(taskId);

  const response =
    await openai.responses.create({
      model: "gpt-5.6-sol",

      previous_response_id:
        session?.previousResponseId,

      reasoning: {
        effort: "high",
        context:
          session?.mode ?? "auto"
      },

      input
    });

  reasoningStore.save({
    taskId,
    previousResponseId: response.id,
    mode: "all_turns",
    createdAt:
      session?.createdAt ?? Date.now(),
    updatedAt: Date.now()
  });

  return response;
}

핵심은 Agent Runtime이

Task
↔
Response Chain

관계를 알고 있다는 것이다.


15. Reasoning Context를 Prompt에서 결정하지 않는다

이렇게 만드는 것은 좋지 않다.

Agent에게 묻는다.

"이전 추론을 계속 기억할까요?"

Reasoning State 정책은 Runtime이 관리해야 한다.

Model

→ Task 내용 판단

Runtime

→ State Policy 결정

왜냐하면

보존 기간

비용

Task Boundary

Privacy

Retry

Failure Recovery

같은 정책은 Model이 아니라 시스템 책임이기 때문이다.


16. Reasoning Policy Router를 만들 수 있다

앞 글의 Model Router와 비슷하다.

type ReasoningTaskProfile = {
  sameGoal: boolean;
  assumptionsStable: boolean;
  taskChanged: boolean;
  previousReasoningUseful: boolean;
};

function selectReasoningContext(
  task: ReasoningTaskProfile
):
  | "all_turns"
  | "current_turn" {

  if (task.taskChanged) {
    return "current_turn";
  }

  if (
    task.sameGoal &&
    task.assumptionsStable &&
    task.previousReasoningUseful
  ) {
    return "all_turns";
  }

  return "current_turn";
}

처음에는 이 정도 규칙이면 충분하다.


17. "같은 목표"라는 조건이 중요하다

예를 들어 다음은 Reasoning을 이어가기 좋다.

Turn 1

AuthManager 분석
Turn 2

관련 Test 확인
Turn 3

실패 로그 추가
Turn 4

수정 구현
Turn 5

Test 실패 원인 분석

계속 같은 Goal이다.

Login Race Condition 해결

Reasoning Continuity의 가치가 높다.


18. 가정이 바뀌었을 때 Reset을 고려한다

같은 Task여도 중요한 가정이 바뀔 수 있다.

예를 들어 처음 Task는

NetworkClient를 수정할 수 있다.

였다.

그런데 사용자가 중간에 말한다.

NetworkClient는 공용 SDK라 수정하면 안 돼.

큰 제약이 바뀌었다.

이럴 때는 이전 Reasoning이 오히려 방해가 될 수 있다.

Reasoning Context를 Reset하고 새 제약으로 다시 판단하게 하는 것이 안전할 수 있다.

Critical Constraint Changed

→ Reasoning Reset

19. 새로운 Evidence가 기존 가설을 깨뜨리는 경우도 있다

예:

Agent 초기 판단

TokenStore 문제

그런데 새로운 Evidence가 들어왔다.

Trace

TokenStore 정상

SessionManager에서 Race 발생

이때 두 가지 전략이 있다.

계속 Reasoning 유지

기존 가설
+
새 Evidence

→ 기존 판단 수정

Reasoning Reset

새 Evidence

→ 처음부터 재평가

어느 쪽이 좋은지는 Task 성격에 따라 다르다.

그래서 Runtime에 Reset 조건을 둘 수 있다.


20. Reset Policy를 만든다

type ReasoningResetReason =
  | "new_task"
  | "critical_constraint_changed"
  | "goal_changed"
  | "invalidated_assumption"
  | "manual_reset";

그리고

function shouldResetReasoning(
  reason: ReasoningResetReason
): boolean {
  return [
    "new_task",
    "critical_constraint_changed",
    "goal_changed",
    "invalidated_assumption",
    "manual_reset"
  ].includes(reason);
}

처럼 단순하게 시작할 수 있다.


21. Memory에는 검증된 사실만 저장한다

Persisted Reasoning과 Memory를 분리하는 가장 중요한 이유 중 하나다.

Reasoning에는 임시 가설이 있을 수 있다.

TokenStore가 문제일 가능성이 높다.

이걸 Memory에 저장하면 위험하다.

Memory에는 검증된 결과를 저장한다.

Confirmed:

AuthErrorMapper is the production error mapping path.

Reasoning

가설
판단
탐색
우선순위

Memory

확정된 사실
지속되는 규칙
사용자 선호
정책

을 구분해야 한다.


22. Memory Promotion 단계를 둔다

Agent가 알아낸 모든 정보를 바로 Memory로 보내지 않는다.

Reasoning

↓

Finding

↓

Validation

↓

Memory Candidate

↓

Policy

↓

Durable Memory

예를 들어 Agent가 알아냈다.

LegacyAuthService는 이름과 달리
현재 Production에서 사용 중이다.

코드와 배포 설정으로 확인됐다.

이건 Memory Candidate가 될 수 있다.

반면

Token Refresh가 가끔 느린 것 같다.

정도는 Memory에 넣으면 안 된다.


23. Memory Record에 Provenance를 둔다

type MemoryRecord = {
  key: string;
  value: string;

  source:
    | "repository"
    | "user"
    | "tool"
    | "verified_agent";

  confidence:
    | "confirmed"
    | "probable";

  createdAt: number;
};

예:

{
  "key": "auth.productionMapper",
  "value": "AppErrorMapper",
  "source": "repository",
  "confidence": "confirmed",
  "createdAt": 1785200000
}

Reasoning의 임시 판단과 구분하기 쉬워진다.


24. Context는 매 Turn 다시 조립한다

Context를 DB에 하나의 거대한 문자열로 저장할 필요도 없다.

Task마다 필요한 정보를 조립한다.

Context Builder

├── Task
├── Relevant Memory
├── Repository Files
├── Current Diff
├── Relevant Tool Results
└── Policy

예를 들어

type AgentContext = {
  task: Task;
  memories: MemoryRecord[];
  files: string[];
  artifacts: Artifact[];
  policies: Policy[];
};

처럼 관리한다.

그리고 각 턴에 필요한 것만 선택한다.


25. Context Retrieval과 Reasoning Persistence는 별개다

이 부분이 중요하다.

관련 파일을 다시 찾는다

≠

이전 Reasoning을 다시 사용한다

Context Retrieval은

현재 Task에 필요한 자료는 무엇인가?

를 해결한다.

Persisted Reasoning은

앞선 판단을 계속 이어갈 필요가 있는가?

를 해결한다.

두 기능을 하나로 만들지 않는다.


26. Tool Result도 Context에 영구 저장하지 않는다

장시간 Agent에서는 Tool Result가 계속 쌓인다.

git diff

test logs

search result

build output

database query

API response

전부 Conversation에 계속 넣으면 Context가 커진다.

Tool Result는 보통 Artifact Store에 보관한다.

Artifact Store

run-9912/
├── git-diff.patch
├── test-result.json
├── build.log
└── investigation.json

모델 Context에는 필요한 요약과 Reference만 넣는다.


27. Artifact와 Memory도 다르다

Artifact는 작업의 결과물이다.

Patch

Test Report

Screenshot

Log

Review Result

Memory는 이후 판단에 사용할 지속 정보다.

예를 들어

test-result.json

은 Artifact다.

하지만

이 Repository에서 Integration Test는
Simulator iPhone 17 Pro에서 실행해야 한다.

같은 지속 규칙은 Memory가 될 수 있다.


28. 전체 Agent State 모델을 만들어보자

type AgentRunState = {
  task: {
    taskId: string;
    goal: string;
    status: string;
  };

  reasoning: {
    previousResponseId?: string;
    context:
      | "auto"
      | "all_turns"
      | "current_turn";
  };

  execution: {
    step: string;
    retryCount: number;
    toolCalls: number;
  };

  context: {
    memoryIds: string[];
    artifactIds: string[];
    filePaths: string[];
  };
};

이 구조만 봐도 역할이 구분된다.


29. 폴더 구조도 분리한다

실제 Agent Runtime이라면 다음처럼 나눌 수 있다.

src/
├── runtime/
│   ├── AgentRuntime.ts
│   └── AgentRunState.ts
│
├── reasoning/
│   ├── ReasoningSession.ts
│   ├── ReasoningPolicy.ts
│   └── ReasoningResetPolicy.ts
│
├── memory/
│   ├── MemoryStore.ts
│   ├── MemoryRecord.ts
│   └── MemoryPromotion.ts
│
├── context/
│   ├── ContextBuilder.ts
│   └── ContextRetriever.ts
│
├── artifacts/
│   ├── ArtifactStore.ts
│   └── Artifact.ts
│
└── tasks/
    ├── TaskStore.ts
    └── Task.ts

Reasoning, Memory, Context가 서로 다른 Module이다.


30. Persisted Reasoning과 Checkpoint도 다르다

장시간 Agent에서는 Checkpoint가 필요하다.

예를 들어

Step 1
Repository 분석

Step 2
Plan

Step 3
Code 변경

Step 4
Test

Step 3에서 Process가 죽었다.

Agent가 다시 실행될 때

어디까지 했는가?

를 알아야 한다.

이것은 Persisted Reasoning보다 Execution Checkpoint 문제다.

{
  "taskId": "PAP-142",
  "completedSteps": [
    "repository_analysis",
    "implementation"
  ],
  "nextStep": "verification"
}

이 데이터는 반드시 Runtime이 명시적으로 저장해야 한다.

Reasoning State만 믿으면 안 된다.


31. 이유는 간단하다

Agent가 Crash됐을 때 시스템이 알아야 하는 것은

무슨 생각을 하고 있었는가?

뿐만 아니다.

더 중요한 것은

무슨 작업이 실제로 완료됐는가?

다.

그래서

Reasoning
→ 판단 연속성

Checkpoint
→ 실행 연속성

으로 분리한다.


32. 장기 Agent에는 다섯 개의 State가 생긴다

조금 더 확장하면 다음 다섯 가지가 된다.

Memory

Context

Reasoning

Execution

Artifact

Memory

장기 사실

Context

현재 필요한 정보

Reasoning

앞선 판단의 연속성

Execution

작업 진행 상태

Artifact

실제 만들어진 결과

이 다섯 가지를 분리하면 Agent Runtime이 훨씬 안정적이다.


33. 실제 Coding Agent 흐름으로 보자

Task:

FramePublisher의 Race Condition을 수정한다.

Agent가 시작한다.

Memory

Swift 6

Actor isolation 사용

외부 라이브러리 추가 금지

Context

FramePublisher.swift

CameraSession.swift

관련 Test

Reasoning

Race는 callback queue와 actor boundary 사이에서 발생할 가능성이 높다.

Execution

analysis completed

implementation pending

Artifact

아직 없음.


Agent가 코드를 수정한다.

Execution

analysis completed

implementation completed

verification pending

Artifact

frame-publisher-fix.patch

테스트를 실행한다.

Artifact

test-result.json

작업이 끝난다.

이제 Reasoning Session은 종료할 수 있다.

하지만 일부 사실은 Memory 후보가 될 수 있다.


34. Task 종료 시 Reasoning을 닫는다

Task가 완료됐다고 해서 모든 State를 남길 필요가 없다.

Task Done

↓

Reasoning Session Close

Durable Memory만 필요한 내용을 승격한다.

Artifact는 보관 정책에 따라 저장한다.

Execution State는 완료 상태로 고정한다.

Reasoning
→ 종료

Context
→ 폐기

Execution
→ completed

Artifact
→ 보존

Memory
→ 필요한 것만 Promotion

이 흐름이 깔끔하다.


35. Reasoning Session에 TTL을 둘 수 있다

사용자가 작업을 중단했다가 일주일 뒤 돌아올 수도 있다.

그때 이전 Reasoning을 그대로 이어가는 것이 항상 좋은 것은 아니다.

그래서 Session TTL을 둔다.

type ReasoningPolicy = {
  maxIdleMs: number;
};

예:

const policy = {
  maxIdleMs:
    1000 * 60 * 60 * 4
};

4시간 이상 작업이 중단됐다면 새 Context를 만들고 Reasoning도 재검토한다.

TTL 값은 서비스 특성에 따라 다르게 설정한다.


36. Repository가 바뀌었을 때도 Reset을 고려한다

예를 들어 Agent가 Branch A를 기준으로 Reasoning했다.

그 사이 대규모 Merge가 발생했다.

Reasoning

기준 SHA
abc123

현재 Repository

SHA
xyz981

코드 상태가 크게 달라졌다.

이전 Reasoning이 현재 Repository에 맞지 않을 수 있다.

그래서 Reasoning Session에 Base Revision을 기록하는 것도 방법이다.

type ReasoningSession = {
  taskId: string;
  previousResponseId?: string;
  baseRevision?: string;
};

Revision 변화가 크면 Reasoning Reset을 검토한다.


37. Branch와 Reasoning Session을 연결할 수도 있다

Coding Agent에서는

Task

↔

Git Branch

↔

Reasoning Session

관계를 만들 수 있다.

예:

{
  "taskId": "PAP-142",
  "branch": "fix/PAP-142-auth-race",
  "reasoningSession": "rs-291"
}

다른 Branch로 이동하면 새로운 Session을 만들 수 있다.


38. Multi-Agent에서는 Reasoning을 공유하지 않는 편이 기본이다

Planner와 Developer Agent가 있다고 하자.

Planner

→ Developer

Planner의 Reasoning 전체를 Developer에게 그대로 전달하고 싶어질 수 있다.

하지만 두 Agent의 역할은 다르다.

Planner Reasoning

Architecture 후보
Trade-off
Task 분해

Developer에게 필요한 것은 보통

Plan

Constraints

Acceptance Criteria

다.

Reasoning 자체를 공유하기보다 Artifact를 공유한다.

Planner

Reasoning
↓
Plan Artifact
↓
Developer

이 구조가 Agent 간 결합도를 낮춘다.


39. Agent 간에는 Typed Artifact를 사용한다

예:

type ImplementationPlan = {
  goal: string;

  files: string[];

  constraints: string[];

  steps: Array<{
    id: string;
    description: string;
  }>;

  acceptanceCriteria: string[];
};

Planner가 생성한다.

{
  "goal": "Fix auth race condition",
  "files": [
    "FramePublisher.swift"
  ],
  "constraints": [
    "Do not change public API"
  ],
  "steps": [
    {
      "id": "1",
      "description": "Move state mutation into actor isolation"
    }
  ],
  "acceptanceCriteria": [
    "Existing tests pass",
    "Race regression test passes"
  ]
}

Developer는 이 Artifact를 Context로 사용한다.

Planner의 Persisted Reasoning을 공유할 필요가 없다.


40. Multi-Agent에서 Reasoning Isolation이 중요하다

Agent A가 잘못된 가설을 가질 수 있다.

그 Reasoning을 Agent B가 그대로 물려받으면 Bias도 전달된다.

예:

Agent A

"Network 문제다."

Agent B까지

Network 문제라고 가정하고 조사

하게 만들 수 있다.

대신

Evidence

Artifact

Contract

를 공유한다.

각 Agent는 자신의 Reasoning Session을 갖는다.


41. Reviewer Agent는 더더욱 독립적인 Reasoning이 좋다

Developer가

이 구현이 가장 안전하다.

라고 판단했다고 해서 Reviewer도 같은 Reasoning을 이어받을 필요는 없다.

오히려 독립적으로 보는 것이 좋다.

Developer Reasoning

X

Reviewer Reasoning

공유하는 것은

Task

Diff

Test Result

Acceptance Criteria

정도다.

Reviewer가 독립적으로 판단한다.


42. Persisted Reasoning을 Audit Log로 착각하지 않는다

Reasoning State는 감사 로그를 대체하지 않는다.

운영에서는 반드시 별도의 기록이 필요하다.

누가

언제

어떤 Tool을

어떤 입력으로

어떤 결과를 만들었는가

예:

{
  "runId": "run-9912",
  "events": [
    {
      "type": "tool_call",
      "tool": "run_tests",
      "status": "completed"
    }
  ]
}

이런 정보가 Audit Log다.

Persisted Reasoning과 역할이 다르다.


43. Reasoning을 사용자에게 그대로 보여주는 기능도 아니다

여기서 중요한 점이 하나 있다.

Persisted Reasoning은

모델의 내부 생각을
사용자에게 그대로 공개한다.

는 기능이 아니다.

Responses API의 Reasoning Item을 모델의 다음 턴에서 재사용하는 기능으로 이해해야 한다.

UI에서 사용자에게 보여줄 필요가 있는 정보는 별도의 Summary나 Artifact로 만든다.

예:

{
  "investigationSummary": {
    "confirmed": [
      "Race occurs during session refresh"
    ],
    "excluded": [
      "TokenStore"
    ],
    "nextAction": "Patch SessionManager"
  }
}

이런 형태가 더 안전하고 운영하기 쉽다.


44. Human-readable Decision Log를 따로 두자

장기 Agent라면

왜 이런 결정을 했지?

를 사람이 확인해야 할 때가 있다.

Reasoning State를 직접 쓰지 말고 Decision Log를 만든다.

type DecisionRecord = {
  decision: string;
  evidence: string[];
  alternatives?: string[];
  timestamp: number;
};

예:

{
  "decision": "Modify SessionManager instead of TokenStore",
  "evidence": [
    "race-test-18.log",
    "SessionManager.swift:142"
  ],
  "alternatives": [
    "TokenStore modification"
  ],
  "timestamp": 1785200012
}

이건 사람이 읽고 검토할 수 있는 Artifact다.


45. 장기 Agent에서는 Reasoning Summary도 유용하다

Task가 매우 길다면 중간 Checkpoint마다 사람이 읽을 수 있는 Summary를 생성할 수 있다.

Checkpoint 1

Investigated
- AuthManager
- TokenStore

Excluded
- NetworkClient

Current hypothesis
- Session refresh race

Next
- Reproduce with concurrent refresh test

이 Summary는 Persisted Reasoning과 별개다.

Persisted Reasoning
→ Model Continuity

Reasoning Summary
→ Human / Runtime Visibility

역할을 나눈다.


46. store: false 환경에서는 더 신경 써야 한다

OpenAI 공식 가이드에서는 직접 History를 관리하거나 store: false, Zero Data Retention 환경에서 동작할 때 이전 입력과 Response Output Item을 다시 제공하는 흐름을 설명한다.

GPT-5.6에서는 이런 경우 API가 반환하는 encrypted reasoning item을 재전달하는 방식도 고려해야 한다.

Server-managed continuation

vs

Application-managed continuation

두 구조가 있다.


47. Server-managed 구조

가장 간단한 흐름은

Response 1

↓

previous_response_id

↓

Response 2

↓

previous_response_id

↓

Response 3

이다.

Application은 Response ID 체인을 관리한다.

Task
→ latestResponseId

정도만 저장하면 된다.


48. Application-managed History

일부 시스템에서는 모든 History를 직접 저장한다.

User Input

Response Output Items

Tool Calls

Tool Results

Reasoning Items

을 Application Store에 보관하고 다음 요청에 재구성한다.

장점은

State 관리가 명확함

재현 가능성

Custom Retention

Migration

이다.

대신 구현이 복잡하다.


49. 어떤 방식을 선택할까

작은 Agent라면

previous_response_id

방식부터 시작하는 것이 단순하다.

큰 Agent Platform에서는

Task Store

Artifact Store

Memory Store

Execution Store

Response State

를 애플리케이션에서 관리하는 방향을 고려할 수 있다.

특히

장기 실행

Multi-Agent

Resume

Replay

Audit

ZDR

요구가 커질수록 Application State가 중요해진다.


50. Retry에서도 Reasoning State를 조심한다

Tool Timeout으로 요청이 실패했다고 하자.

Runtime이 Retry한다.

여기서 잘못하면 같은 작업을 중복 실행할 수 있다.

Turn

Tool Call

Timeout

Retry

같은 Tool Call

그래서 Reasoning 연속성뿐 아니라 Tool의 Idempotency도 함께 관리해야 한다.

Reasoning State

+

Execution Checkpoint

+

Tool requestId

가 같이 필요하다.


51. Failure Recovery 구조

장시간 Agent라면 이런 구조가 좋다.

Agent Run

↓

Checkpoint

↓

Model Reasoning

↓

Tool

↓

Artifact

↓

Checkpoint

Crash가 나면

Checkpoint Load

↓

Execution State 확인

↓

Reasoning Session 복원 또는 Reset 판단

↓

다음 Step 진행

한다.

Reasoning State 하나만 복원하는 것이 아니다.


52. Reasoning Context를 Budget와 연결할 수도 있다

앞선 글에서 Model Router와 Budget을 다뤘다.

Reasoning도 비용과 연결된다.

장기간 계속 all_turns를 유지하는 것이 모든 작업에 적합한 것은 아니다.

Runtime Policy에 이런 값을 둘 수 있다.

type ReasoningBudget = {
  maxTurns: number;
  maxIdleMinutes: number;
  resetOnTaskChange: boolean;
};

예:

{
  "maxTurns": 20,
  "maxIdleMinutes": 240,
  "resetOnTaskChange": true
}

20턴이 넘어가면 Summary와 Task State를 확인하고 새로운 Reasoning Session으로 넘어가는 식이다.

이 숫자가 정답이라는 의미는 아니다.

자신의 Eval을 기준으로 조정한다.


53. Context Budget과 Reasoning Budget을 따로 본다

Context Budget

무엇을 얼마나 모델에게 보여줄까
Reasoning Budget

얼마나 오래 앞선 판단을 이어갈까

둘은 다른 문제다.

대규모 Context가 필요하지만 Reasoning 연속성은 짧을 수 있다.

반대도 가능하다.

작은 코드 몇 개

+

매우 복잡한 Debugging

+

10턴 동안 같은 가설 검증

에서는 Context는 작아도 Reasoning Continuity가 중요할 수 있다.


54. Persisted Reasoning Eval도 필요하다

새 기능이라고 무조건 켜면 안 된다.

대표 Task를 준비한다.

.ai/
└── evals/
    └── reasoning/
        ├── multi-turn-debugging.json
        ├── architecture-migration.json
        ├── research-task.json
        └── task-switch.json

그리고 비교한다.

current_turn

vs

all_turns

측정 항목은

Task Success

Repeated Tool Calls

Turns to Completion

Total Tokens

Latency

Cost

Contradictions

Stale Assumption Rate

정도가 좋다.


55. 특히 반복 행동을 측정한다

Persisted Reasoning의 효과를 볼 때 유용한 지표가 있다.

같은 파일 재검색 횟수

같은 Tool 중복 호출

이미 제외한 가설 재검토

같은 질문 반복

동일 Plan 재생성

예를 들어

current_turn

평균 Tool Call
32회

중복 호출
8회
all_turns

평균 Tool Call
24회

중복 호출
2회

처럼 차이가 나타날 수 있다.

하지만 이것은 실제 프로젝트에서 측정해야 한다.


56. 반대로 Stale Reasoning도 측정한다

Persisted Reasoning의 부작용도 확인한다.

새 Evidence를 무시했는가

오래된 가설을 계속 유지했는가

변경된 Constraint를 놓쳤는가

Task 전환 후 이전 목표를 끌고 왔는가

이걸

Stale Assumption

지표로 볼 수 있다.

Reasoning Continuity가 높다고 항상 좋은 것은 아니다.


57. Reasoning Policy를 Eval로 조정한다

처음에는 간단하게

같은 Task
→ all_turns

새 Task
→ current_turn

으로 시작한다.

운영 데이터가 쌓이면 더 세분화한다.

Debugging
→ all_turns

일회성 Q&A
→ current_turn

Repository Migration
→ all_turns

Independent Review
→ current_turn

Reviewer Agent
→ 새 Reasoning Session

서비스에 맞게 최적화한다.


58. Model Router와 Reasoning Router를 연결한다

앞에서 만든 Model Router를 기억해보자.

Task

↓

Model Router

↓

Sol / Terra / Luna

이제 Reasoning Router가 추가된다.

Task

↓

Task Profiler

├── Model Router
│
│   Sol / Terra / Luna
│
└── Reasoning Router
    │
    auto
    all_turns
    current_turn

예를 들어

Simple Formatting

→ Luna
→ current_turn
일반 Bug Fix

→ Terra
→ all_turns
Complex Debugging

→ Sol high
→ all_turns
새로운 Independent Review

→ Sol
→ current_turn

처럼 구성할 수 있다.


59. Tool Strategy까지 붙이면 Agent Runtime이 완성되기 시작한다

지금까지 세 글의 내용을 합치면 구조가 보인다.

첫 번째 글:

Model Router

두 번째:

Tool Strategy Router

이번 글:

Reasoning State Router

전체는

Task

↓

Task Profiler

↓

┌─────────────────────┐
│ Model Router        │
│                     │
│ Sol / Terra / Luna  │
└─────────────────────┘

↓

┌─────────────────────┐
│ Tool Strategy       │
│                     │
│ Direct              │
│ Programmatic        │
│ Hybrid              │
└─────────────────────┘

↓

┌─────────────────────┐
│ Reasoning Policy    │
│                     │
│ auto                │
│ all_turns           │
│ current_turn        │
└─────────────────────┘

↓

Agent Runtime

이제 Agent가 단순히

모델 하나 + Prompt 하나

가 아니다.


60. 제가 실제 Coding Agent를 만든다면

Task를 처음 받으면 다음 Profile을 만든다.

type AgentTaskProfile = {
  taskId: string;

  complexity:
    | "simple"
    | "standard"
    | "complex";

  horizon:
    | "short"
    | "long";

  continuity:
    | "new"
    | "continuing";

  toolStrategy:
    | "direct"
    | "programmatic"
    | "hybrid";

  risk:
    | "low"
    | "medium"
    | "high";
};

예:

{
  "taskId": "PAP-142",
  "complexity": "complex",
  "horizon": "long",
  "continuity": "continuing",
  "toolStrategy": "hybrid",
  "risk": "medium"
}

Runtime이 이를 이용한다.

Model

GPT-5.6 Sol

Reasoning

all_turns

Tool

Hybrid

Memory

Repository Policy만 Retrieval

Execution

Checkpoint 활성화

이런 식이다.


61. 가장 피해야 할 구조

다음과 같은 Agent를 만들지 않는 것이 좋다.

하나의 Conversation

↓

모든 Task

↓

모든 Memory

↓

모든 Tool Result

↓

모든 Reasoning

↓

끝없이 이어지는 Context

처음에는 편하다.

시간이 지나면 다음 문제가 생긴다.

Context 증가

오래된 정보

상충하는 규칙

잘못된 가설

Tool 중복 호출

Task 경계 붕괴

비용 증가

디버깅 어려움

62. 대신 Task를 State Boundary로 사용한다

가장 실용적인 기준 중 하나다.

Task Start
↓
Reasoning Session Start

Task Continue
↓
Reasoning Continue

Major Constraint Change
↓
Reasoning Reset 검토

Task Complete
↓
Reasoning Session Close

New Task
↓
New Reasoning Session

Task가 Reasoning의 Lifecycle을 결정한다.


63. 장기 Agent에서 "기억"이라는 단어를 하나로 쓰지 말자

실무에서

Agent가 기억해야 한다.

라고 말하면 너무 모호하다.

정확히 구분해야 한다.

사용자 선호를 기억한다.

→ Memory
현재 Diff를 알아야 한다.

→ Context
이전 Debugging 가설을 이어가야 한다.

→ Persisted Reasoning
Test까지 완료했다는 것을 알아야 한다.

→ Execution State
Test 결과 파일을 남겨야 한다.

→ Artifact

이 구분만 해도 Agent Architecture가 훨씬 명확해진다.


64. 마무리

GPT-5.6의 Persisted Reasoning은 장기 Agent를 만들 때 꽤 중요한 변화다.

하지만

Reasoning을 오래 유지하면
Agent가 모든 것을 기억한다.

라고 이해하면 안 된다.

장기 Agent 상태는 최소한 다음처럼 분리하는 것이 좋다.

Memory
→ 오래 유지할 사실

Context
→ 현재 작업 자료

Persisted Reasoning
→ 앞선 판단의 연속성

Execution State
→ 실제 작업 진행 상태

Artifact
→ 작업으로 만들어진 결과

그리고 Reasoning에는 Lifecycle이 있어야 한다.

Task Start

→ Reasoning Start

Task Continue

→ all_turns

Goal / Constraint 변경

→ Reset 검토

Task Complete

→ Reasoning Close

New Task

→ current_turn / New Session

특히 중요한 것은 Conversation과 Task를 같은 것으로 보지 않는 것이다.

한 Conversation 안에서도 여러 Task가 존재할 수 있다.

Conversation

├── Task A
│   └── Reasoning Session A
│
├── Task B
│   └── Reasoning Session B
│
└── Task C
    └── Reasoning Session C

Reasoning은 Conversation 전체의 영구 Memory가 아니라 Task에 종속된 작업 상태에 가깝게 다루는 편이 안전하다.

그리고 Agent 간에는 Reasoning 자체보다

Plan

Artifact

Evidence

Contract

Decision Log

를 전달한다.

한 줄로 정리하면 이렇다.

Memory는 무엇을 기억할지 결정하고,

Context는 지금 무엇을 볼지 결정하며,

Persisted Reasoning은
앞선 판단을 계속 이어갈지 결정한다.

장기 Agent가 안정적으로 동작하려면 많이 기억하는 것보다

무엇을 오래 보존하고, 무엇을 현재 작업에만 사용하며, 어떤 판단은 언제 끊을지를 명확하게 나누는 것이 더 중요하다.


참고 자료

  • OpenAI — GPT-5.6 Model Guidance
    GPT-5.6에서 새롭게 제공되는 Persisted Reasoning과 reasoning.contextauto, all_turns, current_turn 사용 기준을 확인할 수 있는 공식 문서.

  • OpenAI Responses API Documentation
    previous_response_id를 이용한 Multi-turn Response 연결과 Response Item을 직접 관리하는 방식을 확인할 수 있는 공식 API 문서.

  • OpenAI — GPT-5.6 Models
    GPT-5.6 Sol·Terra·Luna의 Reasoning 지원 범위와 Responses API 지원 여부를 확인할 수 있는 공식 모델 문서.

핵심 참고 포인트

GPT-5.6의 Persisted Reasoning은 이전 턴의 reasoning item을 다음 턴에서 다시 활용할 수 있도록 하는 기능이다.

같은 목표·가정·우선순위가 여러 턴 동안 유지되는 작업에서는 reasoning.context: "all_turns"previous_response_id를 이용해 이전 Reasoning을 이어갈 수 있다.

반대로 이전 판단이 더 이상 관련 없거나 Task 자체가 달라졌다면 current_turn을 사용해 과거 Reasoning의 영향을 끊을 수 있다.

OpenAI는 직접 History를 관리할 경우 이전 User Input뿐 아니라 Response Output Item도 보존해 다시 전달하도록 안내하고 있으며, store: false 또는 Zero Data Retention 환경에서는 API가 반환하는 encrypted reasoning item을 재전달하는 방식도 지원한다.

따라서 Persisted Reasoning은 일반적인 사용자 Memory나 데이터베이스 상태를 대체하는 기능이 아니라 여러 턴에 걸쳐 동일 작업의 Reasoning Continuity를 유지하기 위한 별도의 Agent State 계층으로 보는 것이 적절하다.

profile
iOS 앱 개발자

0개의 댓글