Agent memory

Agent memory (에이전트 메모리)

메모리는 이후 샌드박스 에이전트 실행이 이전 실행에서 배울 수 있게 해줘요. 메시지 기록을 저장하는 SDK의 대화형 Session 메모리와는 별개예요. 메모리는 이전 실행의 교훈을 샌드박스 작업 공간의 파일로 증류해요.

베타 기능: 샌드박스 에이전트는 베타 상태예요. GA 전에 API·기본값·지원 기능의 세부 사항이 바뀔 수 있고, 시간이 지나 더 많은 고급 기능이 추가될 거예요.

메모리는 향후 실행의 세 가지 비용을 줄일 수 있어요.

  • 에이전트 비용: 에이전트가 워크플로를 완료하는 데 오래 걸렸다면 다음 실행은 탐색을 덜 해도 돼요. 이건 토큰 사용량과 완료 시간을 줄일 수 있어요.
  • 사용자 비용: 사용자가 에이전트를 교정하거나 선호를 표현했다면 미래 실행이 그 피드백을 기억할 수 있어요. 인간 개입을 줄일 수 있어요.
  • 컨텍스트 비용: 에이전트가 이전에 작업을 완료했고 사용자가 그 작업을 바탕으로 확장하려 한다면, 사용자가 이전 스레드를 찾거나 모든 컨텍스트를 다시 타이핑할 필요가 없어요. 작업 설명을 더 짧게 만들어요.

버그를 고치고 메모리를 생성하고 스냅샷을 재개하고 후속 검증 실행에서 그 메모리를 사용하는 완전한 두 실행 예제는 examples/sandbox/memory.py를 참고하세요. 별도 메모리 레이아웃을 가진 다중 턴·다중 에이전트 예제는 examples/sandbox/memory_multi_agent_multiturn.py를 참고하세요.

출처: 문서

본문

메모리 켜기

샌드박스 에이전트에 capability로 Memory()를 추가하세요.

from pathlib import Path
import tempfile

from agents.sandbox import LocalSnapshotSpec, SandboxAgent
from agents.sandbox.capabilities import Filesystem, Memory, Shell

agent = SandboxAgent(
    name="Memory-enabled reviewer",
    instructions="Inspect the workspace and preserve useful lessons for follow-up runs.",
    capabilities=[Memory(), Filesystem(), Shell()],
)

with tempfile.TemporaryDirectory(prefix="sandbox-memory-example-") as snapshot_dir:
    sandbox = await client.create(
        manifest=manifest,
        snapshot=LocalSnapshotSpec(base_path=Path(snapshot_dir)),
    )

read가 켜져 있으면 Memory()Shell()을 요구해요. 주입된 요약만으론 부족할 때 에이전트가 메모리 파일을 읽고 검색하게 해주거든요. 라이브 메모리 업데이트가 켜져 있으면(기본값) Filesystem()도 요구하는데, 에이전트가 오래된 메모리를 발견하거나 사용자가 메모리 업데이트를 요청하면 memories/MEMORY.md를 갱신하게 해줘요.

기본적으로 메모리 산출물은 샌드박스 작업 공간의 memories/ 아래에 저장돼요. 나중 실행에서 재사용하려면 같은 라이브 샌드박스 세션을 유지하거나 영속된 세션 상태·스냅샷에서 재개해서 구성된 memories 디렉터리 전체를 보존·재사용하세요. 새 빈 샌드박스는 빈 메모리로 시작해요.

Memory()는 메모리 읽기와 생성을 둘 다 켜요. 메모리는 읽되 새 메모리는 생성하지 말아야 하는 에이전트에는 Memory(generate=None)을 쓰세요. 예를 들어 내부 에이전트·서브에이전트·체커·일회성 도구 에이전트의 실행이 큰 신호를 추가하지 않을 때요. 실행이 나중을 위해 메모리를 생성해야 하지만 기존 메모리의 영향을 받지 않길 원할 때는 Memory(read=None)을 쓰세요.

메모리 읽기

메모리 읽기는 점진적 공개(progressive disclosure)를 사용해요. 실행 시작 시 SDK는 일반적으로 유용한 팁·사용자 선호·사용 가능한 메모리 요약(memory_summary.md)을 에이전트의 developer 프롬프트에 주입해요. 이것은 이전 작업이 관련될 수 있는지 결정할 충분한 컨텍스트를 에이전트에게 줘요.

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

메모리는 오래될 수 있어요. 에이전트는 메모리를 안내로만 취급하고 현재 환경을 신뢰하도록 지시받아요. 기본적으로 메모리 읽기는 live_update가 켜져 있어, 에이전트가 오래된 메모리를 발견하면 같은 실행에서 구성된 MEMORY.md를 갱신할 수 있어요. 실행 중 에이전트가 메모리를 읽되 수정하지 않아야 할 때(예: 실행이 지연에 민감한 경우) 라이브 업데이트를 끄세요.

메모리 생성

실행이 끝나면 샌드박스 런타임은 그 실행 세그먼트를 대화 파일에 추가해요. 누적된 대화 파일은 샌드박스 세션이 닫힐 때 처리돼요.

메모리 생성은 두 단계가 있어요.

  • 1단계: 대화 추출. 메모리 생성 모델이 누적된 대화 파일 하나를 처리하고 대화 요약을 생성해요. System·developer·reasoning 콘텐츠는 생략돼요. 대화가 너무 길면 컨텍스트 창에 맞게 잘리고, 시작과 끝은 보존돼요. 또 원시 메모리 추출(raw memory extract)도 생성해요. 2단계가 통합할 수 있는 대화의 간결한 메모입니다.
  • 2단계: 레이아웃 통합. 통합 에이전트가 한 메모리 레이아웃의 원시 메모리를 읽고, 더 많은 증거가 필요하면 대화 요약을 열며, MEMORY.mdmemory_summary.md로 패턴을 추출해요.

기본 작업 공간 레이아웃:

workspace/
├── sessions/
│   └── <rollout-id>.jsonl
└── memories/
    ├── memory_summary.md
    ├── MEMORY.md
    ├── raw_memories.md (intermediate)
    ├── phase_two_selection.json (intermediate)
    ├── raw_memories/ (intermediate)
    │   └── <rollout-id>.md
    ├── rollout_summaries/
    │   └── <rollout-id>_<slug>.md
    └── skills/

MemoryGenerateConfig로 메모리 생성을 구성할 수 있어요.

from agents.sandbox import MemoryGenerateConfig
from agents.sandbox.capabilities import Memory

memory = Memory(
    generate=MemoryGenerateConfig(
        max_raw_memories_for_consolidation=128,
        extra_prompt="Pay extra attention to what made the customer more satisfied or annoyed",
    ),
)

extra_prompt을 사용해 메모리 생성기에 어떤 신호가 당신의 유스케이스에 가장 중요한지 알려주세요. GTM 에이전트의 고객·회사 세부 정보 같은 걸요.

최근 원시 메모리가 max_raw_memories_for_consolidation(기본 256)을 넘으면 2단계는 가장 최신 대화의 메모리만 유지하고 더 오래된 것을 제거해요. 최신성은 대화가 마지막으로 갱신된 시간을 기준으로 해요. 이 망각 메커니즘은 메모리가 가장 새로운 환경을 반영하게 해줘요.

다중 턴 대화

다중 턴 샌드박스 채팅에는 같은 라이브 샌드박스 세션과 함께 일반 SDK Session을 쓰세요.

from agents import Runner, SQLiteSession
from agents.run import RunConfig
from agents.sandbox import SandboxRunConfig

conversation_session = SQLiteSession("gtm-q2-pipeline-review")
sandbox = await client.create(manifest=agent.default_manifest)

async with sandbox:
    run_config = RunConfig(
        sandbox=SandboxRunConfig(session=sandbox),
        workflow_name="GTM memory example",
    )
    await Runner.run(
        agent,
        "Analyze data/leads.csv and identify one promising GTM segment.",
        session=conversation_session,
        run_config=run_config,
    )
    await Runner.run(
        agent,
        "Using that analysis, write a short outreach hypothesis.",
        session=conversation_session,
        run_config=run_config,
    )

두 실행 모두 같은 SDK 대화 세션(session=conversation_session)을 넘기므로 같은 session.session_id를 공유해요. 결과적으로 두 실행이 하나의 메모리 대화 파일에 추가돼요. 이것은 라이브 작업 공간을 식별하고 메모리 대화 ID로 쓰이지 않는 샌드박스(sandbox)와는 달라요. 샌드박스 세션이 닫힐 때 1단계는 누적된 대화를 보므로, 두 개의 격리된 턴 대신 전체 교환에서 메모리를 추출할 수 있어요.

여러 Runner.run(...) 호출이 하나의 메모리 대화가 되길 원한다면 그 호출들에 안정적인 식별자를 넘기세요. 메모리가 실행을 대화와 연관지을 때 이 순서로 해석해요.

  • Runner.run(...)에 전달한 conversation_id
  • SQLiteSession 같은 SDK Session을 넘길 때의 session.session_id
  • 둘 다 없으면 RunConfig.group_id
  • 안정적인 식별자가 없으면 생성된 실행별 ID

다른 레이아웃으로 여러 에이전트의 메모리 격리

메모리 격리는 에이전트 이름이 아니라 MemoryLayoutConfig에 기반해요. 같은 레이아웃과 같은 메모리 대화 ID를 가진 에이전트는 하나의 메모리 대화와 하나의 통합 메모리를 공유해요. 레이아웃이 다른 에이전트는 같은 샌드박스 작업 공간을 공유해도 rollout 파일·원시 메모리·MEMORY.md·memory_summary.md를 분리해 유지해요.

여러 에이전트가 샌드박스 하나를 공유하는데 메모리를 공유하면 안 될 때 별도 레이아웃을 쓰세요.

from agents import SQLiteSession
from agents.sandbox import MemoryLayoutConfig, SandboxAgent
from agents.sandbox.capabilities import Filesystem, Memory, Shell

gtm_agent = SandboxAgent(
    name="GTM reviewer",
    instructions="Analyze GTM workspace data and write concise recommendations.",
    capabilities=[
        Memory(
            layout=MemoryLayoutConfig(
                memories_dir="memories/gtm",
                sessions_dir="sessions/gtm",
            )
        ),
        Filesystem(),
        Shell(),
    ],
)

engineering_agent = SandboxAgent(
    name="Engineering reviewer",
    instructions="Inspect engineering workspaces and summarize fixes and risks.",
    capabilities=[
        Memory(
            layout=MemoryLayoutConfig(
                memories_dir="memories/engineering",
                sessions_dir="sessions/engineering",
            )
        ),
        Filesystem(),
        Shell(),
    ],
)

gtm_session = SQLiteSession("gtm-q2-pipeline-review")
engineering_session = SQLiteSession("eng-invoice-test-fix")

이렇게 하면 GTM 분석이 엔지니어링 버그 수정 메모리로 통합되는 것을 막고, 그 반대도 막아요.

더 알아보기 (Learn more)