콘텐츠로 이동

에이전트 메모리

메모리를 사용하면 이후 sandbox-agent 실행이 이전 실행에서 학습할 수 있습니다. 이는 메시지 기록을 저장하는 SDK 의 대화형 세션 메모리와는 별개입니다. 메모리는 이전 실행의 교훈을 샌드박스 작업 공간의 파일로 정리하므로, 생성된 메모리 아티팩트는 보관되는 데이터로 취급하고 작업 공간에 적용하는 것과 동일한 민감도 및 보존 정책을 적용하세요.

메모리는 이후 실행에서 세 가지 종류의 비용을 줄일 수 있습니다:

  1. 에이전트 비용: 에이전트가 워크플로를 완료하는 데 오랜 시간이 걸렸다면, 다음 실행에서는 탐색이 덜 필요해야 합니다. 이를 통해 토큰 사용량과 완료 시간을 줄일 수 있습니다.
  2. 사용자 비용: 사용자가 에이전트를 수정했거나 선호를 표현했다면, 이후 실행에서 그 피드백을 기억할 수 있습니다. 이를 통해 사람의 개입을 줄일 수 있습니다.
  3. 컨텍스트 비용: 에이전트가 이전에 작업을 완료했고 사용자가 그 작업을 이어서 진행하려는 경우, 사용자는 이전 스레드를 찾거나 모든 컨텍스트를 다시 입력할 필요가 없어야 합니다. 이렇게 하면 작업 설명이 더 짧아집니다.

샌드박스 에이전트에 capability 로 memory()를 추가합니다.

메모리 활성화
import {
filesystem,
Manifest,
memory,
SandboxAgent,
shell,
} from '@openai/agents/sandbox';
const manifest = new Manifest({
entries: {
'README.md': {
type: 'file',
content: '# Memory demo\n\nA workspace for follow-up runs.\n',
},
},
});
const agent = new SandboxAgent({
name: 'Memory-enabled reviewer',
model: 'gpt-5.5',
instructions:
'Inspect the workspace, verify important claims, and preserve useful lessons for follow-up runs.',
defaultManifest: manifest,
capabilities: [filesystem(), shell(), memory()],
});

읽기가 활성화되어 있으면 memory()에는 shell()이 필요합니다. 이를 통해 주입된 요약만으로 충분하지 않을 때 에이전트가 메모리 파일을 읽고 검색할 수 있습니다. 기본적으로 실시간 메모리 업데이트가 활성화되어 있는 경우에는 filesystem()도 필요하며, 이를 통해 에이전트가 오래된 메모리를 발견하거나 사용자가 메모리 업데이트를 요청했을 때 memories/MEMORY.md를 업데이트할 수 있습니다.

기본적으로 메모리 아티팩트는 샌드박스 작업 공간의 memories/ 아래에 저장됩니다. 이후 실행에서 이를 재사용하려면 동일한 라이브 샌드박스 세션을 유지하거나, 저장된 세션 상태 또는 스냅샷에서 재개하여 구성된 메모리 디렉터리 전체를 보존하고 재사용하세요. 새 빈 샌드박스는 빈 메모리로 시작합니다.

memory()는 메모리 읽기와 생성 둘 다 활성화합니다. 메모리를 읽을 수는 있지만 새 메모리를 생성해서는 안 되는 에이전트에는 memory({ generate: false })를 사용하세요. 예를 들어 내부 에이전트, 서브에이전트, 검사기, 또는 실행이 큰 신호를 추가하지 않는 일회성 도구 에이전트가 이에 해당합니다. 실행이 나중을 위해 메모리를 생성해야 하지만 사용자가 기존 메모리의 영향을 원하지 않는 경우에는 memory({ read: null })을 사용하세요.

읽기 전용 메모리 구성
import { memory } from '@openai/agents/sandbox';
const readOnlyMemory = memory({
read: { liveUpdate: false },
generate: false,
});

메모리 읽기는 점진적 공개를 사용합니다. 실행 시작 시 SDK 는 일반적으로 유용한 팁, 사용자 선호, 사용 가능한 메모리를 담은 작은 요약(memory_summary.md)을 에이전트의 개발자 프롬프트에 주입합니다. 이를 통해 에이전트는 이전 작업이 관련이 있을 수 있는지 판단할 수 있을 만큼의 컨텍스트를 얻습니다.

이전 작업이 관련 있어 보이면, 에이전트는 현재 작업의 키워드로 구성된 메모리 인덱스(memoriesDir 아래의 MEMORY.md)를 검색합니다. 작업에 더 자세한 정보가 필요할 때만 구성된 rollout_summaries/ 디렉터리 아래의 해당 이전 rollout 요약을 엽니다.

메모리는 오래될 수 있습니다. 에이전트는 메모리를 참고용으로만 취급하고 현재 환경을 신뢰하도록 지시받습니다. 기본적으로 메모리 읽기에는 liveUpdate가 활성화되어 있으므로, 에이전트가 오래된 메모리를 발견하면 같은 실행 안에서 구성된 MEMORY.md를 업데이트할 수 있습니다. 예를 들어 실행이 지연 시간에 민감한 경우처럼, 에이전트가 메모리를 읽되 실행 중에는 수정하지 않아야 한다면 실시간 업데이트를 비활성화하세요.

실행이 끝나면 샌드박스 런타임은 해당 실행 구간을 대화 파일에 추가합니다. 누적된 대화 파일은 샌드박스 세션이 닫힐 때 처리됩니다. 이러한 대화 파일에는 사용자 입력, assistant 및 도구 항목, 인터럽션(중단 처리), 최종 출력이 포함될 수 있으므로, 민감한 워크로드에는 적절한 메모리 저장소와 보존 정책을 사용하세요.

메모리 생성은 두 단계로 이루어집니다:

  1. 1단계: 대화 추출. 메모리를 생성하는 모델이 누적된 대화 파일 하나를 처리해 대화 요약을 생성합니다. system, developer, reasoning 콘텐츠는 제외됩니다. 대화가 너무 길면 컨텍스트 윈도에 맞도록 잘리며, 시작과 끝은 보존됩니다. 또한 2단계에서 통합할 수 있도록 대화에서 추린 간결한 메모인 원문 메모리 추출도 생성합니다.
  2. 2단계: 레이아웃 통합. 통합 에이전트가 하나의 메모리 레이아웃에 대한 원문 메모리를 읽고, 더 많은 근거가 필요할 때 대화 요약을 열어 패턴을 MEMORY.mdmemory_summary.md로 추출합니다.

기본 작업 공간 레이아웃은 다음과 같습니다:

workspace/
├── sessions/
│ └── <rollout-id>.jsonl
└── memories/
├── memory_summary.md
├── MEMORY.md
├── raw_memories.md
├── raw_memories/
└── rollout_summaries/

memory({ generate: ... })로 메모리 생성을 구성할 수 있습니다:

메모리 생성 구성
import { memory } from '@openai/agents/sandbox';
const memoryCapability = memory({
generate: {
maxRawMemoriesForConsolidation: 128,
phaseOneModel: 'gpt-5.4-mini',
phaseTwoModel: 'gpt-5.4',
extraPrompt:
'Prioritize workflow corrections, verification commands, and user preferences.',
},
});

extraPrompt를 사용해 GTM 에이전트의 고객 및 회사 세부 정보처럼, 메모리 생성기에서 어떤 신호를 가장 중요하게 볼지 사용 사례에 맞게 알려주세요.

최근 원문 메모리가 maxRawMemoriesForConsolidation를 초과하면, 2단계는 가장 최신 대화의 메모리만 유지하고 오래된 메모리는 제거합니다. 최신성은 대화가 마지막으로 업데이트된 시간을 기준으로 합니다. 이 망각 메커니즘은 메모리가 가장 최신 환경을 반영하도록 돕습니다.

멀티턴 샌드박스 채팅에는 동일한 라이브 샌드박스 세션과 함께 일반 SDK Session을 사용하세요:

하나의 샌드박스 세션에 하나의 SDK 세션 사용
import { MemorySession, run } from '@openai/agents';
import {
filesystem,
Manifest,
memory,
SandboxAgent,
shell,
} from '@openai/agents/sandbox';
import { UnixLocalSandboxClient } from '@openai/agents/sandbox/local';
const manifest = new Manifest();
const agent = new SandboxAgent({
name: 'Memory-enabled reviewer',
model: 'gpt-5.5',
instructions: 'Inspect the workspace before answering.',
capabilities: [filesystem(), shell(), memory()],
});
const conversation = new MemorySession({ sessionId: 'workspace-review' });
const sandbox = await new UnixLocalSandboxClient().create({ manifest });
try {
await run(agent, 'Analyze data/leads.csv.', {
session: conversation,
sandbox: { session: sandbox },
});
await run(agent, 'Write a follow-up recommendation.', {
session: conversation,
sandbox: { session: sandbox },
});
} finally {
await sandbox.close?.();
}

두 실행은 동일한 SDK 대화 세션을 전달하므로 같은 세션 id 를 공유하고, 따라서 하나의 메모리 대화 파일에 추가됩니다. 이는 라이브 작업 공간을 식별하지만 메모리 대화 ID 로는 사용되지 않는 샌드박스와는 다릅니다. 1단계는 샌드박스 세션이 닫힐 때 누적된 대화를 보므로, 서로 분리된 두 턴이 아니라 전체 교환에서 메모리를 추출할 수 있습니다.

여러 run(...) 호출을 하나의 메모리 대화로 만들고 싶다면, 해당 호출들에 걸쳐 안정적인 식별자를 전달하세요. 메모리가 실행을 대화와 연결할 때는 다음 순서로 확인합니다:

  1. run(...)에 전달한 conversationId
  2. SDK Session을 전달한 경우의 SDK session id
  3. 위 둘 다 없을 경우 groupId
  4. 안정적인 식별자가 없을 경우 실행별로 생성된 ID

서로 다른 에이전트의 메모리를 분리하기 위한 서로 다른 레이아웃 사용

섹션 제목: “서로 다른 에이전트의 메모리를 분리하기 위한 서로 다른 레이아웃 사용”

메모리 분리는 에이전트 이름이 아니라 MemoryLayoutConfig를 기준으로 합니다. 동일한 레이아웃과 동일한 메모리 대화 ID 를 가진 에이전트는 하나의 메모리 대화와 하나의 통합 메모리를 공유합니다. 서로 다른 레이아웃을 가진 에이전트는 같은 샌드박스 작업 공간을 공유하더라도 별도의 rollout 파일, 원문 메모리, MEMORY.md, memory_summary.md를 유지합니다.

여러 에이전트가 하나의 샌드박스를 공유하지만 메모리는 공유하지 않아야 한다면 별도의 레이아웃을 사용하세요:

별도 메모리 레이아웃 사용
import { memory } from '@openai/agents/sandbox';
const engineeringMemory = memory({
layout: {
memoriesDir: 'memories/engineering',
sessionsDir: 'sessions/engineering',
},
});
const financeMemory = memory({
layout: {
memoriesDir: 'memories/finance',
sessionsDir: 'sessions/finance',
},
});

이렇게 하면 한 도메인의 분석이 다른 도메인의 메모리에 통합되는 일과 그 반대의 경우를 방지할 수 있습니다.