백엔드

백엔드 (Backends)

Deep Agents를 위한 파일시스템 백엔드를 선택하고 구성하세요. 서로 다른 백엔드에 라우트를 지정하고, 가상 파일시스템을 구현하고, 정책을 적용할 수 있어요.

Deep Agents는 ls, read_file, write_file, edit_file, glob, grep 같은 도구를 통해 에이전트에게 파일시스템 표면을 노출합니다. 이 도구들은 플러그 가능한 백엔드를 통해 작동합니다. read_file 도구는 모든 백엔드에서 바이너리 파일(이미지, PDF, 오디오, 비디오)을 네이티브로 지원하며, 타입이 있는 contentmimeType을 가진 ReadResult를 반환합니다.

샌드박스와 LocalShellBackendexecute 도구도 제공합니다.

이 페이지는 다음 방법을 설명합니다:

출처: 문서

본문

[LangSmith Deployment](/langsmith/deployment)에 배포하면 스토어가 자동으로 프로비저닝됩니다. [LangSmith](/langsmith/observability) 트레이싱으로 파일 경로, 권한 거부, 스레드 간 스토리지를 디버깅하세요. [관측성 빠른 시작](/langsmith/observability-quickstart)을 따라 설정하세요.

LangSmith Engine도 설정하는 것을 권장합니다. 트레이스를 모니터링하고, 문제를 감지하며, 수정을 제안합니다.

에이전트가 파일시스템 도구를 통해 읽을 수 있는 내구성 있는 저장소 위키를 생성하려면 [OpenWiki](/oss/openwiki/overview)를 참고하세요.

빠른 시작 (Quickstart)

딥 에이전트와 함께 빠르게 사용할 수 있는 사전 구축된 파일시스템 백엔드:

내장 백엔드 설명
기본값 (StateBackend) agent = create_deep_agent(model=\"google_genai:gemini-3.6-flash\") — 스레드 범위. 에이전트의 기본 파일시스템 백엔드는 langgraph state에 저장됩니다. 파일은 스레드 내에서 턴을 걸쳐(체크포인터 통해) 유지되며 스레드 간에 공유되지 않습니다.
로컬 파일시스템 영속성 (FilesystemBackend) agent = create_deep_agent(model=\"google_genai:gemini-3.6-flash\", backend=FilesystemBackend(root_dir=\"/Users/nh/Desktop/\")) — 딥 에이전트에게 로컬 머신 파일시스템 접근을 줍니다. 에이전트가 접근할 루트 디렉터리를 지정할 수 있어요. 제공된 root_dir은 절대 경로여야 합니다. 일반적으로 내부 에이전트 데이터(오프로드된 도구 결과, 대화 기록)를 프로젝트 파일과 분리하기 위해 CompositeBackend로 감쌉니다.
내구성 스토어 (LangGraph store) agent = create_deep_agent(model=\"google_genai:gemini-3.6-flash\", backend=StoreBackend())스레드 간에 영속되는 장기 스토리지 접근을 에이전트에게 줍니다. 여러 실행에 걸쳐 에이전트에 적용되는 장기 메모리나 지침을 저장하는 데 좋습니다.
Context Hub agent = create_deep_agent(model=\"google_genai:gemini-3.6-flash\", backend=ContextHubBackend(\"my-agent\")) — 별도의 LangGraph 스토어를 프로비저닝하지 않고 LangSmith Hub 저장소에 파일을 내구성 있게 저장합니다.
샌드박스 agent = create_deep_agent(model=\"google_genai:gemini-3.6-flash\", backend=sandbox) — 격리된 환경에서 코드 실행. 샌드박스는 파일시스템 도구와 셸 명령 실행용 execute 도구를 제공합니다. LangSmith, AgentCore, Daytona 또는 다른 샌드박스 통합 중에서 선택하세요.
로컬 셸 (LocalShellBackend) agent = create_deep_agent(model=\"google_genai:gemini-3.6-flash\", backend=LocalShellBackend(root_dir=\".\", env={\"PATH\": \"/usr/bin:/bin\"})) — 호스트에서 직접 파일시스템과 셸 실행. 격리 없음 — 통제된 개발 환경에서만 사용하세요. 아래 보안 고려 사항 참고.
복합 (CompositeBackend) 기본적으로 스레드 범위, /memories/는 스레드 간 영속. Composite 백엔드는 최대한 유연합니다. 파일시스템의 서로 다른 라우트를 서로 다른 백엔드로 지정할 수 있어요. 붙여 바로 사용할 수 있는 예시는 아래 Composite 라우팅을 참고하세요.

내장 백엔드 (Built-in backends)

StateBackend

import { createDeepAgent, StateBackend } from "deepagents";

// By default we provide a StateBackend
const agent = createDeepAgent();

// Under the hood, it looks like
const agent2 = createDeepAgent({
  backend: new StateBackend(),
});

작동 방식:

  • StateBackend를 통해 현재 스레드의 LangGraph 에이전트 state에 파일을 저장합니다.
  • 체크포인트를 통해 같은 스레드의 여러 에이전트 턴에 걸쳐 유지됩니다. 파일은 스레드 간에 공유되지 않습니다.
그래프 안에서 사용하도록 설계되었습니다. 그래프 실행 밖에서 백엔드 메서드(예: `state_backend.upload_files(...)`)를 호출하면 그래프가 실행될 때까지 효과가 없습니다.

최적의 경우:

  • 에이전트가 중간 결과를 쓰는 스크래치 패드.
  • 에이전트가 나중에 조각조각 다시 읽을 수 있는 대용량 도구 출력의 자동 퇴거.

이 백엔드는 슈퍼바이저 에이전트와 서브에이전트 사이에 공유되며, 서브에이전트가 쓴 파일은 그 서브에이전트의 실행이 끝난 후에도 LangGraph 에이전트 state에 남습니다. 그 파일들은 슈퍼바이저 에이전트와 다른 서브에이전트가 계속 사용할 수 있습니다.

FilesystemBackend (로컬 디스크)

FilesystemBackend는 구성 가능한 루트 디렉터리 아래에서 실제 파일을 읽고 씁니다.

이 백엔드는 에이전트에게 직접 파일시스템 읽기/쓰기 접근을 부여합니다. 주의해서 적절한 환경에서만 사용하세요.

적절한 사용 사례:

  • 로컬 개발 CLI (코딩 어시스턴트, 개발 도구)
  • CI/CD 파이프라인 (아래 보안 고려 사항 참고)

부적절한 사용 사례:

보안 위험:

  • 에이전트가 접근 가능한 모든 파일(비밀, API 키, 자격 증명, .env 파일 포함)을 읽을 수 있음
  • 네트워크 도구와 결합하면 SSRF 공격을 통해 비밀이 유출될 수 있음
  • 파일 수정은 영구적이고 되돌릴 수 없음

권장 보호 장치:

  1. 민감한 작업을 검토하도록 휴먼 인 더 루프 (HITL) 미들웨어 활성화

  2. 접근 가능한 파일시스템 경로에서 비밀 제외 (특히 CI/CD에서)

  3. 파일시스템 상호작용이 필요한 프로덕션 환경에는 샌드박스 백엔드 사용

  4. 경로 기반 접근 제한을 활성화하려면 root_dir과 함께 virtual_mode=True항상 사용 (루트 밖의 .., ~, 절대 경로 차단)

    기본값(virtual_mode=False)은 root_dir이 설정되어도 보안을 제공하지 않습니다.

import { createDeepAgent, FilesystemBackend } from "deepagents";

const agent = createDeepAgent({
  model: "google-genai:gemini-3.6-flash",
  backend: new FilesystemBackend({ rootDir: ".", virtualMode: true }),
});
import { createDeepAgent, FilesystemBackend } from "deepagents";

const agent = createDeepAgent({
  model: "openai:gpt-5.5",
  backend: new FilesystemBackend({ rootDir: ".", virtualMode: true }),
});
import { createDeepAgent, FilesystemBackend } from "deepagents";

const agent = createDeepAgent({
  model: "anthropic:claude-sonnet-5",
  backend: new FilesystemBackend({ rootDir: ".", virtualMode: true }),
});
import { createDeepAgent, FilesystemBackend } from "deepagents";

const agent = createDeepAgent({
  model: "openrouter:z-ai/glm-5.2",
  backend: new FilesystemBackend({ rootDir: ".", virtualMode: true }),
});
import { createDeepAgent, FilesystemBackend } from "deepagents";

const agent = createDeepAgent({
  model: "fireworks:accounts/fireworks/models/glm-5p2",
  backend: new FilesystemBackend({ rootDir: ".", virtualMode: true }),
});
import { createDeepAgent, FilesystemBackend } from "deepagents";

const agent = createDeepAgent({
  model: "baseten:zai-org/GLM-5.2",
  backend: new FilesystemBackend({ rootDir: ".", virtualMode: true }),
});
import { createDeepAgent, FilesystemBackend } from "deepagents";

const agent = createDeepAgent({
  model: "ollama:north-mini-code-1.0",
  backend: new FilesystemBackend({ rootDir: ".", virtualMode: true }),
});

작동 방식:

  • 구성 가능한 root_dir 아래에서 실제 파일을 읽고/씁니다.
  • 선택적으로 virtual_mode=Trueroot_dir 아래 경로를 샌드박싱하고 정규화할 수 있습니다.
  • 안전한 경로 해석을 사용하고, 가능하면 안전하지 않은 심링크 탐색을 방지하며, 빠른 grep을 위해 ripgrep을 사용할 수 있습니다.

최적의 경우:

  • 머신의 로컬 프로젝트
  • CI 샌드박스
  • 마운트된 영구 볼륨

에이전트가 이 파일시스템 도구로 읽을 수 있는 내구성 있는 저장소 위키(openwiki/에서)는 OpenWiki를 참고하세요.

대부분의 사용 사례에서 `FilesystemBackend`를 `CompositeBackend`로 **감싸세요**. Deep Agents는 오프로드된 대용량 도구 결과(`/large_tool_results/`)와 대화 기록(`/conversation_history/`)을 포함한 내부 데이터를 백엔드에 자동으로 씁니다. `FilesystemBackend`만 사용하면 이 내부 파일들이 `root_dir` 아래 실제 디스크에 기록되어 에이전트 산출물과 프로젝트 파일이 섞입니다.

CompositeBackend를 사용해 내부 경로는 일시적인 StateBackend 스토리지에 두면서 프로젝트 디렉터리를 FilesystemBackend로 라우팅하세요:

import { createDeepAgent, CompositeBackend, FilesystemBackend, StateBackend } from "deepagents";

const agent = createDeepAgent({
  backend: new CompositeBackend(
    new StateBackend(),
    {
      "/workspace/": new FilesystemBackend({ rootDir: "/path/to/project", virtualMode: true }),
    },
  ),
});

이렇게 하면 /workspace/ 아래의 에이전트 읽기/쓰기는 실제 디스크로 가고, 오프로드된 도구 결과와 기타 내부 데이터는 일시적인 state에 남습니다. 더 많은 라우팅 패턴은 다른 백엔드로 라우팅을 참고하세요.

LocalShellBackend (로컬 셸)

이 백엔드는 에이전트에게 직접 파일시스템 읽기/쓰기 접근 **및** 호스트에서 제한 없는 셸 실행을 부여합니다. 극도의 주의를 기울여 적절한 환경에서만 사용하세요.

적절한 사용 사례:

  • 로컬 개발 CLI (코딩 어시스턴트, 개발 도구)
  • 에이전트의 코드를 신뢰하는 개인 개발 환경
  • 적절한 비밀 관리가 있는 CI/CD 파이프라인

부적절한 사용 사례:

  • 프로덕션 환경 (웹 서버, API, 멀티테넌트 시스템 등)
  • 신뢰할 수 없는 사용자 입력 처리 또는 신뢰할 수 없는 코드 실행

보안 위험:

  • 에이전트가 여러분의 사용자 권한으로 임의 셸 명령을 실행할 수 있음
  • 에이전트가 접근 가능한 모든 파일(비밀, API 키, 자격 증명, .env 파일 포함)을 읽을 수 있음
  • 비밀이 노출될 수 있음
  • 파일 수정과 명령 실행은 영구적이고 되돌릴 수 없음
  • 명령이 호스트 시스템에서 직접 실행됨
  • 명령이 무제한 CPU, 메모리, 디스크를 소비할 수 있음

권장 보호 장치:

  1. 실행 전에 작업을 검토하고 승인하도록 휴먼 인 더 루프 (HITL) 미들웨어 활성화. 강력히 권장됩니다.
  2. 전용 개발 환경에서만 실행. 공유 또는 프로덕션 시스템에서는 절대 사용 금지.
  3. 셸 실행이 필요한 프로덕션 환경에는 샌드박스 백엔드 사용.

참고: 셸 접근이 활성화되면 명령이 시스템의 어떤 경로에든 접근할 수 있으므로 virtual_mode=True는 보안을 제공하지 않습니다.

import { createDeepAgent, LocalShellBackend } from "deepagents";

const backend = new LocalShellBackend({ workingDirectory: "." });

const agent = createDeepAgent({
  model: "google-genai:gemini-3.6-flash",
  backend,
});
import { createDeepAgent, LocalShellBackend } from "deepagents";

const backend = new LocalShellBackend({ workingDirectory: "." });

const agent = createDeepAgent({
  model: "openai:gpt-5.5",
  backend,
});
import { createDeepAgent, LocalShellBackend } from "deepagents";

const backend = new LocalShellBackend({ workingDirectory: "." });

const agent = createDeepAgent({
  model: "anthropic:claude-sonnet-5",
  backend,
});
import { createDeepAgent, LocalShellBackend } from "deepagents";

const backend = new LocalShellBackend({ workingDirectory: "." });

const agent = createDeepAgent({
  model: "openrouter:z-ai/glm-5.2",
  backend,
});
import { createDeepAgent, LocalShellBackend } from "deepagents";

const backend = new LocalShellBackend({ workingDirectory: "." });

const agent = createDeepAgent({
  model: "fireworks:accounts/fireworks/models/glm-5p2",
  backend,
});
import { createDeepAgent, LocalShellBackend } from "deepagents";

const backend = new LocalShellBackend({ workingDirectory: "." });

const agent = createDeepAgent({
  model: "baseten:zai-org/GLM-5.2",
  backend,
});
import { createDeepAgent, LocalShellBackend } from "deepagents";

const backend = new LocalShellBackend({ workingDirectory: "." });

const agent = createDeepAgent({
  model: "ollama:north-mini-code-1.0",
  backend,
});

작동 방식:

  • 호스트에서 셸 명령을 실행하는 execute 도구로 FilesystemBackend를 확장합니다.
  • 명령은 샌드박싱 없이 subprocess.run(shell=True)를 사용해 머신에서 직접 실행됩니다.
  • 환경 변수용 timeout(기본 120초), max_output_bytes(기본 100,000), env, inherit_env를 지원합니다.
  • 셸 명령은 root_dir을 작업 디렉터리로 사용하지만 시스템의 어떤 경로에든 접근할 수 있습니다.

최적의 경우:

  • 로컬 코딩 어시스턴트 및 개발 도구
  • 에이전트를 신뢰할 때 개발 중 빠른 반복

StoreBackend (LangGraph store)

import { createDeepAgent, StoreBackend } from "deepagents";
import { InMemoryStore } from "@langchain/langgraph";

const store = new InMemoryStore(); // Good for local dev; omit for LangSmith Deployment

const agent = createDeepAgent({
  model: "google-genai:gemini-3.6-flash",
  backend: new StoreBackend({
    namespace: (rt) => [rt.serverInfo.user.identity],
  }),
  store,
});
import { createDeepAgent, StoreBackend } from "deepagents";
import { InMemoryStore } from "@langchain/langgraph";

const store = new InMemoryStore(); // Good for local dev; omit for LangSmith Deployment

const agent = createDeepAgent({
  model: "openai:gpt-5.5",
  backend: new StoreBackend({
    namespace: (rt) => [rt.serverInfo.user.identity],
  }),
  store,
});
import { createDeepAgent, StoreBackend } from "deepagents";
import { InMemoryStore } from "@langchain/langgraph";

const store = new InMemoryStore(); // Good for local dev; omit for LangSmith Deployment

const agent = createDeepAgent({
  model: "anthropic:claude-sonnet-5",
  backend: new StoreBackend({
    namespace: (rt) => [rt.serverInfo.user.identity],
  }),
  store,
});
import { createDeepAgent, StoreBackend } from "deepagents";
import { InMemoryStore } from "@langchain/langgraph";

const store = new InMemoryStore(); // Good for local dev; omit for LangSmith Deployment

const agent = createDeepAgent({
  model: "openrouter:z-ai/glm-5.2",
  backend: new StoreBackend({
    namespace: (rt) => [rt.serverInfo.user.identity],
  }),
  store,
});
import { createDeepAgent, StoreBackend } from "deepagents";
import { InMemoryStore } from "@langchain/langgraph";

const store = new InMemoryStore(); // Good for local dev; omit for LangSmith Deployment

const agent = createDeepAgent({
  model: "fireworks:accounts/fireworks/models/glm-5p2",
  backend: new StoreBackend({
    namespace: (rt) => [rt.serverInfo.user.identity],
  }),
  store,
});
import { createDeepAgent, StoreBackend } from "deepagents";
import { InMemoryStore } from "@langchain/langgraph";

const store = new InMemoryStore(); // Good for local dev; omit for LangSmith Deployment

const agent = createDeepAgent({
  model: "baseten:zai-org/GLM-5.2",
  backend: new StoreBackend({
    namespace: (rt) => [rt.serverInfo.user.identity],
  }),
  store,
});
import { createDeepAgent, StoreBackend } from "deepagents";
import { InMemoryStore } from "@langchain/langgraph";

const store = new InMemoryStore(); // Good for local dev; omit for LangSmith Deployment

const agent = createDeepAgent({
  model: "ollama:north-mini-code-1.0",
  backend: new StoreBackend({
    namespace: (rt) => [rt.serverInfo.user.identity],
  }),
  store,
});
[LangSmith Deployment](/langsmith/deployment)에 배포할 때는 `store` 파라미터를 생략하세요. 플랫폼이 에이전트를 위한 스토어를 자동으로 프로비저닝합니다. `namespace` 파라미터는 데이터 격리를 제어합니다. 멀티유저 배포에서는 항상 [네임스페이스 팩토리](/oss/javascript/deepagents/backends#namespace-factories)를 설정해 사용자 또는 테넌트별로 데이터를 격리하세요.

작동 방식:

  • StoreBackend는 런타임이 제공하는 LangGraph BaseStore에 파일을 저장하여 스레드 간 내구성 스토리지를 가능하게 합니다.

최적의 경우:

  • 이미 구성된 LangGraph 스토어(BaseStore 뒤의 Redis, Postgres, 클라우드 구현 등)로 실행 중일 때.
  • LangSmith Deployment로 에이전트를 배포할 때 (에이전트를 위한 스토어가 자동으로 프로비저닝됨).
네임스페이스 팩토리 (Namespace factories)

네임스페이스 팩토리는 StoreBackend가 데이터를 읽고 쓰는 위치를 제어합니다. LangGraph Runtime을 받아 스토어 네임스페이스로 사용되는 문자열 튜플을 반환합니다. 사용자, 테넌트, 어시스턴트 간에 데이터를 격리하려면 네임스페이스 팩토리를 사용하세요.

StoreBackend를 구성할 때 namespace 파라미터에 네임스페이스 팩토리를 전달하세요:

NamespaceFactory = Callable[[Runtime], tuple[str, ...]]

Runtime은 다음을 제공합니다:

  • rt.context — LangGraph의 컨텍스트 스키마를 통해 전달된 사용자 제공 컨텍스트 (예: user_id)
  • rt.serverInfo — LangGraph Server에서 실행할 때의 서버별 메타데이터 (어시스턴트 ID, 그래프 ID, 인증된 사용자)
  • rt.executionInfo — 실행 식별 정보 (스레드 ID, 실행 ID, 체크포인트 ID)
`Runtime` 인자는 `deepagents>=1.9.1`에서 사용할 수 있습니다. 이전 1.9.x 릴리스는 대신 `BackendContext`를 전달했습END — 아래 [BackendContext에서 마이그레이션](#migrating-from-backendcontext) 참고. `rt.serverInfo`와 `rt.executionInfo`는 `deepagents>=1.9.0`이 필요합니다.

일반적인 네임스페이스 패턴:

import { StoreBackend } from "deepagents";

// Per-user: each user gets their own isolated storage
const backend = new StoreBackend({
  namespace: (rt) => [rt.serverInfo.user.identity],  // [!code highlight]
});

// Per-assistant: all users of the same assistant share storage
const backend = new StoreBackend({
  namespace: (rt) => [rt.serverInfo.assistantId],  // [!code highlight]
});

// Per-thread: storage scoped to a single conversation
const backend = new StoreBackend({
  namespace: (rt) => [rt.executionInfo.threadId],  // [!code highlight]
});

더 구체적인 범위를 위해 여러 컴포넌트를 결합할 수 있습니다 — 예: 사용자별·대화별 격리의 (user_id, thread_id), 또는 같은 범위가 여러 스토어 네임스페이스를 사용할 때 "filesystem" 같은 접미사를 붙여 구별할 수 있습니다.

네임스페이스 컴포넌트는 영숫자 문자, 하이픈, 밑줄, 점, @, +, 콜론, 물결표만 포함해야 합니다. 와일드카드(*, ?)는 glob 주입을 방지하기 위해 거부됩니다.

`namespace` 파라미터는 v1.9.0에서 **필수가** 됩니다. 새 코드에서는 항상 명시적으로 설정하세요. 네임스페이스 팩토리를 제공하지 않으면 레거시 기본값은 LangGraph 구성 메타데이터의 `assistant_id`를 사용합니다. 이는 같은 [어시스턴트](/langsmith/assistants)의 모든 사용자가 같은 스토리지를 공유한다는 뜻입니다. 멀티유저 [프로덕션 출시](/oss/javascript/deepagents/going-to-production)의 경우 항상 네임스페이스 팩토리를 제공하세요.

ContextHubBackend

**시작하기 전에:** `ContextHubBackend`는 LangSmith에 설정된 Context Hub 저장소가 필요합니다. 에이전트 저장소와 스킬 저장소에 익숙하지 않다면 먼저 [Context Hub 개념](/langsmith/context-engineering-concepts) 페이지를 읽어보세요.

ContextHubBackend는 에이전트의 파일시스템을 LangSmith Context Hub 저장소에 저장합니다. 독립형 저장소 또는 스킬 저장소로 링크되는 에이전트 저장소를 사용할 수 있습니다.

저장소 구조: Context Hub에서 에이전트 저장소는 에이전트의 최상위 지침과 설정(예: AGENTS.md, tools.json)을 보유합니다. 하나 이상의 스킬 저장소로 링크할 수 있으며, 각 스킬 저장소는 재사용 가능한 능력(예: 이메일 포맷팅이나 코드 리뷰 지침이 있는 SKILL.md)으로 패키징됩니다. ContextHubBackend("my-agent")를 전달하면 백엔드가 에이전트 저장소를 파일시스템 루트에 마운트하고, 링크된 스킬 저장소는 /skills/ 아래 하위 디렉터리로 나타납니다.

이는 에이전트의 컨텍스트가 의도적으로 여러 저장소에 걸쳐 있다는 뜻입니다: 에이전트당 하나의 저장소, 스킬별 별도 저장소. 그 분리는 스킬이 여러 에이전트에서 독립적으로 버전 관리, 공유, 재사용될 수 있게 합니다. 분산되어 보인다면 연결된 저장소에서 그 근거를 확인하세요.

owner/name 또는 name 형식의 저장소 식별자로 구성하세요.

`ContextHubBackend`를 사용하기 전에 `LANGSMITH_API_KEY`를 설정하세요.

작동 방식:

  • 첫 사용 시 Hub 저장소 트리를 지연적으로 가져오고, 이후 읽기는 인메모리 캐시에서 제공합니다.
  • 쓰기와 편집을 Hub 커밋으로 영속화하고 성공적인 커밋 후 캐시를 업데이트합니다.
  • 낙관적 부모 커밋 쓰기(parent_commit)를 사용합니다: 각 푸시는 가장 최근에 알려진 커밋 해시를 대상으로 합니다.

동작 및 제한:

  • 저장소가 존재하지 않으면 첫 가져오기는 빈 것으로 처리됩니다; 첫 성공적인 쓰기가 저장소를 만들 수 있습니다.
  • 다른 작성자가 먼저 저장소를 진행하면, 오래된 부모 커밋 쓰기가 실패할 수 있습니다. 충돌 시 다시 가져와 재시도하세요.
  • upload_files()는 UTF-8 텍스트를 수용합니다. 비-UTF-8 파일은 경로별로 invalid_path로 거부됩니다.

최적의 경우:

  • LangGraph BaseStore를 별도로 연결하지 않는 LangSmith 네이티브 내구성 파일시스템 영속성.
  • 파일시스템 변경에 Hub 커밋 기록의 이점을 활용하는 워크플로.

CompositeBackend (라우터)

import {
  createDeepAgent,
  CompositeBackend,
  StateBackend,
  StoreBackend,
} from "deepagents";
import { InMemoryStore } from "@langchain/langgraph";

const store = new InMemoryStore();

const agent = createDeepAgent({
  model: "google-genai:gemini-3.6-flash",
  backend: new CompositeBackend(new StateBackend(), {
    "/memories/": new StoreBackend({
      namespace: () => ["memories"],
    }),
  }),
  store,
});
import {
  createDeepAgent,
  CompositeBackend,
  StateBackend,
  StoreBackend,
} from "deepagents";
import { InMemoryStore } from "@langchain/langgraph";

const store = new InMemoryStore();

const agent = createDeepAgent({
  model: "openai:gpt-5.5",
  backend: new CompositeBackend(new StateBackend(), {
    "/memories/": new StoreBackend({
      namespace: () => ["memories"],
    }),
  }),
  store,
});
import {
  createDeepAgent,
  CompositeBackend,
  StateBackend,
  StoreBackend,
} from "deepagents";
import { InMemoryStore } from "@langchain/langgraph";

const store = new InMemoryStore();

const agent = createDeepAgent({
  model: "anthropic:claude-sonnet-5",
  backend: new CompositeBackend(new StateBackend(), {
    "/memories/": new StoreBackend({
      namespace: () => ["memories"],
    }),
  }),
  store,
});
import {
  createDeepAgent,
  CompositeBackend,
  StateBackend,
  StoreBackend,
} from "deepagents";
import { InMemoryStore } from "@langchain/langgraph";

const store = new InMemoryStore();

const agent = createDeepAgent({
  model: "openrouter:z-ai/glm-5.2",
  backend: new CompositeBackend(new StateBackend(), {
    "/memories/": new StoreBackend({
      namespace: () => ["memories"],
    }),
  }),
  store,
});
import {
  createDeepAgent,
  CompositeBackend,
  StateBackend,
  StoreBackend,
} from "deepagents";
import { InMemoryStore } from "@langchain/langgraph";

const store = new InMemoryStore();

const agent = createDeepAgent({
  model: "fireworks:accounts/fireworks/models/glm-5p2",
  backend: new CompositeBackend(new StateBackend(), {
    "/memories/": new StoreBackend({
      namespace: () => ["memories"],
    }),
  }),
  store,
});
import {
  createDeepAgent,
  CompositeBackend,
  StateBackend,
  StoreBackend,
} from "deepagents";
import { InMemoryStore } from "@langchain/langgraph";

const store = new InMemoryStore();

const agent = createDeepAgent({
  model: "baseten:zai-org/GLM-5.2",
  backend: new CompositeBackend(new StateBackend(), {
    "/memories/": new StoreBackend({
      namespace: () => ["memories"],
    }),
  }),
  store,
});
import {
  createDeepAgent,
  CompositeBackend,
  StateBackend,
  StoreBackend,
} from "deepagents";
import { InMemoryStore } from "@langchain/langgraph";

const store = new InMemoryStore();

const agent = createDeepAgent({
  model: "ollama:north-mini-code-1.0",
  backend: new CompositeBackend(new StateBackend(), {
    "/memories/": new StoreBackend({
      namespace: () => ["memories"],
    }),
  }),
  store,
});

작동 방식:

  • CompositeBackend는 경로 접두사에 따라 파일 연산을 서로 다른 백엔드로 라우팅합니다.
  • 목록과 검색 결과에서 원래 경로 접두사를 보존합니다.

최적의 경우:

  • 에이전트에게 스레드 범위와 스레드 간 스토리지를 모두 주고 싶을 때, CompositeBackendStateBackendStoreBackend를 모두 제공할 수 있습니다.
  • 에이전트에게 단일 파일시스템의 일부로 제공하려는 여러 정보 소스가 있을 때.
    • 예: 한 Store의 /memories/ 아래에 장기 메모리를 저장하고, /docs/에서 접근할 수 있는 문서를 가진 커스텀 백엔드도 있을 때.

백엔드 지정하기 (Specify a backend)

  • 백엔드 인스턴스를 createDeepAgent({ backend: ... })에 전달하세요. 파일시스템 미들웨어가 모든 도구에 이를 사용합니다.
  • 백엔드는 AnyBackendProtocol(BackendProtocolV1 또는 BackendProtocolV2)을 구현해야 합니다 — 예: new StateBackend(), new FilesystemBackend({ rootDir: "." }), new StoreBackend().
  • 생략하면 기본값은 new StateBackend()입니다.
1.9.0 이전에는 `BackendProtocolV1`인 `BackendProtocol`만 지원되었습니다. V1 백엔드는 `adaptBackendProtocol()`로 런타임에 자동으로 V2로 적응됩니다. 기존 V1 백엔드를 계속 사용하는 데 코드 변경이 필요 없습니다. v2로 업데이트하려면 [기존 백엔드를 v2로 업데이트](#update-existing-backends-to-v2)를 참고하세요.

다른 백엔드로 라우팅 (Route to different backends)

네임스페이스의 일부를 다른 백엔드로 라우팅합니다. 일반적으로 /memories/*를 스레드 간에 영속시키고 나머지는 스레드 범위로 유지하는 데 사용합니다.

import { createDeepAgent, CompositeBackend, FilesystemBackend, StateBackend } from "deepagents";

const agent = createDeepAgent({
  backend: new CompositeBackend(
    new StateBackend(),
    {
      "/memories/": new FilesystemBackend({ rootDir: "/deepagents/myagent", virtualMode: true }),
    },
  ),
});

동작:

  • /workspace/plan.mdStateBackend (스레드 범위)
  • /memories/agent.md/deepagents/myagent 아래 FilesystemBackend
  • ls, glob, grep는 결과를 집계하고 원래 경로 접두사를 보여줍니다.

참고:

  • 더 긴 접두사가 우선합니다 (예: "/memories/projects/""/memories/"를 덮어쓸 수 있음).
  • StoreBackend 라우팅의 경우 create_deep_agent(model=..., store=...)로 스토어를 제공하거나 플랫폼이 프로비저닝했는지 확인하세요.
  • Deep Agents는 내부 데이터(오프로드된 도구 결과, 대화 기록)를 기본 백엔드에 씁니다. 기본값으로 StateBackend를 사용해 이 산출물을 일시적으로 유지하고 디스크나 영구 스토어에 쓰지 않게 하세요. 완전한 예시는 FilesystemBackend 팁을 참고하세요.

커스텀 백엔드 (Custom backends)

데이터베이스, 객체 스토어, 원격 파일시스템 같은 스토리지 시스템에 Deep Agents를 연결하려면 커스텀 백엔드를 구현하세요. 예시는 커뮤니티 구축 백엔드를 참고하세요.

백엔드 프로토콜 구현 (Implement the backend protocol)

BackendProtocol(BackendProtocolV2)을 구현하고 다음 메서드를 제공하세요:

메서드 시그니처 하는 일
ls (path: string) => Promise<LsResult> 주어진 경로의 파일과 디렉터리 나열.
read (filePath: string, offset?, limit?) => Promise<ReadResult> 파일 내용 반환, 선택적으로 페이지네이션. 바이너리 파일은 mimeType과 함께 Uint8Array 콘텐츠를 반환.
readRaw (filePath: string) => Promise<ReadRawResult> 원시 FileData 반환 (프레임워크가 내부적으로 사용).
write (filePath: string, content: string) => Promise<WriteResult> 파일 만들기 또는 덮어쓰기.
edit (filePath: string, oldString: string, newString: string, replaceAll?: boolean) => Promise<EditResult> 기존 파일 내에서 찾아 바꾸기.
glob (pattern: string, path?: string) => Promise<GlobResult> glob 패턴과 일치하는 경로 반환.
grep (pattern: string, path?, glob?) => Promise<GrepResult> 리터럴 문자열에 대한 파일 내용 검색.

execute 도구(셸 명령 실행)도 지원하려면 BackendProtocolV2를 확장해 execute 메서드를 추가한 SandboxBackendProtocol을 대신 구현하세요.

모든 메서드는 선택적 error 필드가 있는 구조화된 Result 객체를 반환해야 합니다 — 누락된 파일이나 유효하지 않은 패턴에서 throw하지 마세요.

예시: S3 스타일 백엔드 스켈레톤 이 스켈레톤은 파일시스템 경로를 객체 키에 매핑합니다. 각 메서드를 스토리지 클라이언트의 list, read, search, upload, read-modify-write 연산으로 채우세요.

import {
  type BackendProtocolV2,
  type EditResult,
  type GlobResult,
  type GrepResult,
  type LsResult,
  type ReadRawResult,
  type ReadResult,
  type WriteResult,
} from "deepagents";

class S3Backend implements BackendProtocolV2 {
  constructor(private bucket: string, private prefix: string = "") {
    this.prefix = prefix.replace(/\/$/, "");
  }

  private key(path: string): string {
    return `${this.prefix}${path}`;
  }

  async ls(path: string): Promise<LsResult> {
    ...
  }

  async read(filePath: string, offset?: number, limit?: number): Promise<ReadResult> {
    ...
  }

  async readRaw(filePath: string): Promise<ReadRawResult> {
    ...
  }

  async grep(pattern: string, path?: string | null, glob?: string | null): Promise<GrepResult> {
    ...
  }

  async glob(pattern: string, path = "/"): Promise<GlobResult> {
    ...
  }

  async write(filePath: string, content: string): Promise<WriteResult> {
    ...
  }

  async edit(filePath: string, oldString: string, newString: string, replaceAll?: boolean): Promise<EditResult> {
    ...
  }
}

권한 (Permissions)

권한으로 에이전트가 읽거나 쓸 수 있는 파일과 디렉터리를 선언적으로 제어하세요. 권한은 내장 파일시스템 도구에 적용되며 백엔드가 호출되기 전에 평가됩니다.

규칙 순서, 서브에이전트 권한, 컴포지트 백엔드 상호작용을 포함한 전체 옵션은 권한 가이드를 참고하세요.

정책 훅 추가 (Add policy hooks)

경로 기반 허용/거부 규칙(속도 제한, 감사 로깅, 콘텐츠 검사)을 넘어서는 커스텀 검증 로직의 경우, 백엔드를 서브클래싱하거나 래핑해 엔터프라이즈 규칙을 시행하세요.

선택된 접두사 아래의 쓰기/편집 차단 (서브클래스):

import { FilesystemBackend, type WriteResult, type EditResult } from "deepagents";

class GuardedBackend extends FilesystemBackend {
  private denyPrefixes: string[];

  constructor({ denyPrefixes, ...options }: { denyPrefixes: string[]; rootDir?: string }) {
    super(options);
    this.denyPrefixes = denyPrefixes.map(p => p.endsWith("/") ? p : p + "/");
  }

  async write(filePath: string, content: string): Promise<WriteResult> {
    if (this.denyPrefixes.some(p => filePath.startsWith(p))) {
      return { error: `Writes are not allowed under ${filePath}` };
    }
    return super.write(filePath, content);
  }

  async edit(filePath: string, oldString: string, newString: string, replaceAll = false): Promise<EditResult> {
    if (this.denyPrefixes.some(p => filePath.startsWith(p))) {
      return { error: `Edits are not allowed under ${filePath}` };
    }
    return super.edit(filePath, oldString, newString, replaceAll);
  }
}

일반 래퍼 (모든 백엔드에서 작동):

import {
  type BackendProtocolV2,
  type LsResult,
  type ReadResult,
  type ReadRawResult,
  type GrepResult,
  type GlobResult,
  type WriteResult,
  type EditResult,
} from "deepagents";

class PolicyWrapper implements BackendProtocolV2 {
  private denyPrefixes: string[];

  constructor(private inner: BackendProtocolV2, denyPrefixes: string[] = []) {
    this.denyPrefixes = denyPrefixes.map(p => p.endsWith("/") ? p : p + "/");
  }

  private isDenied(path: string): boolean {
    return this.denyPrefixes.some(p => path.startsWith(p));
  }

  ls(path: string): Promise<LsResult> { return this.inner.ls(path); }
  read(filePath: string, offset?: number, limit?: number): Promise<ReadResult> { return this.inner.read(filePath, offset, limit); }
  readRaw(filePath: string): Promise<ReadRawResult> { return this.inner.readRaw(filePath); }
  grep(pattern: string, path?: string | null, glob?: string | null): Promise<GrepResult> { return this.inner.grep(pattern, path, glob); }
  glob(pattern: string, path?: string): Promise<GlobResult> { return this.inner.glob(pattern, path); }

  async write(filePath: string, content: string): Promise<WriteResult> {
    if (this.isDenied(filePath)) return { error: `Writes are not allowed under ${filePath}` };
    return this.inner.write(filePath, content);
  }

  async edit(filePath: string, oldString: string, newString: string, replaceAll = false): Promise<EditResult> {
    if (this.isDenied(filePath)) return { error: `Edits are not allowed under ${filePath}` };
    return this.inner.edit(filePath, oldString, newString, replaceAll);
  }
}

멀티모달 및 바이너리 파일 (Multimodal and binary files)

멀티모달 파일 지원(PDF, 오디오, 비디오)은 `deepagents>=1.9.0`이 필요합니다.

V2 백엔드는 바이너리 파일을 네이티브로 지원합니다. read()가 바이너리 파일(파일 확장자의 MIME 유형으로 결정)을 만나면 Uint8Array 콘텐츠와 해당 mimeType을 가진 ReadResult를 반환합니다. 텍스트 파일은 string 콘텐츠를 반환합니다.

지원 MIME 유형

카테고리 확장자 MIME 유형
이미지 .png, .jpg/.jpeg, .gif, .webp, .svg, .heic, .heif image/png, image/jpeg, image/gif, image/webp, image/svg+xml, image/heic, image/heif
오디오 .mp3, .wav, .aiff, .aac, .ogg, .flac audio/mpeg, audio/wav, audio/aiff, audio/aac, audio/ogg, audio/flac
비디오 .mp4, .webm, .mpeg/.mpg, .mov, .avi, .flv, .wmv, .3gpp video/mp4, video/webm, video/mpeg, video/quicktime, video/x-msvideo, video/x-flv, video/x-ms-wmv, video/3gpp
문서 .pdf, .ppt, .pptx application/pdf, application/vnd.ms-powerpoint, application/vnd.openxmlformats-officedocument.presentationml.presentation
텍스트 .txt, .html, .json, .js, .ts, .py text/plain, text/html, application/json

바이너리 파일 읽기

const result = await backend.read("/workspace/screenshot.png");

if (result.error) {
  console.error(result.error);
} else if (result.content instanceof Uint8Array) {
  // Binary file — content is Uint8Array, mimeType is set
  console.log(`Binary file: ${result.mimeType}`); // "image/png"
} else {
  // Text file — content is string
  console.log(`Text file: ${result.mimeType}`); // "text/plain"
}

FileData 형식

FileData는 state 및 store 백엔드에서 파일 콘텐츠를 저장하는 데 사용되는 유형입니다.

type FileData =
  // Current format (v2)
  | {
      content: string | Uint8Array; // string for text, Uint8Array for binary
      mimeType: string;             // e.g. "text/plain", "image/png"
      created_at: string;           // ISO 8601 timestamp
      modified_at: string;          // ISO 8601 timestamp
    }
  // Legacy format (v1)
  | {
      content: string[];            // array of lines
      created_at: string;           // ISO 8601 timestamp
      modified_at: string;          // ISO 8601 timestamp
    };

백엔드는 state 또는 store에서 읽을 때 두 형식 모두를 만날 수 있습니다. 프레임워크는 둘 다 투명하게 처리합니다. 새 쓰기는 기본적으로 v2 형식입니다. 이전 독자가 레거시 형식을 필요로 하는 롤링 배포 중에는 백엔드 생성자에 fileFormat: "v1"을 전달하세요 (예: new StoreBackend({ fileFormat: "v1" })).

백엔드 팩토리에서 마이그레이션 (Migrate from backend factories)

백엔드 팩토리 패턴은 `deepagents` 1.9.0부터 **deprecated**입니다. 팩토리 함수 대신 미리 구성된 백엔드 인스턴스를 직접 전달하세요.

이전에는 StateBackendStoreBackend 같은 백엔드가 작동하려면 런타임 컨텍스트(state, store)가 필요했기 때문에, 런타임 객체를 받는 팩토리 함수가 필요했습니다. 백엔드는 이제 LangGraph의 get_config(), get_store(), get_runtime() 헬퍼를 통해 이 컨텍스트를 내부적으로 해결하므로 인스턴스를 직접 전달할 수 있습니다.

무엇이 바뀌었나 (What changed)

Before (deprecated) After
backend=lambda rt: StateBackend(rt) backend=StateBackend()
backend=lambda rt: StoreBackend(rt) backend=StoreBackend()
backend=lambda rt: CompositeBackend(default=StateBackend(rt), ...) backend=CompositeBackend(default=StateBackend(), ...)
backend: (config) => new StateBackend(config) backend: new StateBackend()
backend: (config) => new StoreBackend(config) backend: new StoreBackend()

Deprecated API

Deprecated 대체
BackendFactory 유형 백엔드 인스턴스를 직접 전달
BackendRuntime 인터페이스 백엔드가 컨텍스트를 내부적으로 해결
StateBackend(runtime, options?) 생성자 오버로드 new StateBackend(options?)
StoreBackend(stateAndStore, options?) 생성자 오버로드 new StoreBackend(options?)
WriteResultEditResultfilesUpdate 필드 state 쓰기는 이제 백엔드가 내부적으로 처리
팩토리 패턴은 런타임에서 여전히 작동하며 deprecation 경고를 방출합니다. 다음 메이저 버전 전에 직접 인스턴스를 사용하도록 코드를 업데이트하세요.

마이그레이션 예시

// Before (deprecated)
import { createDeepAgent, CompositeBackend, StateBackend, StoreBackend } from "deepagents";

const agent = createDeepAgent({
  backend: (config) => new CompositeBackend(
    new StateBackend(config),
    { "/memories/": new StoreBackend(config, {
      namespace: (rt) => [rt.serverInfo.user.identity],
    }) },
  ),
});

// After
const agent = createDeepAgent({
  backend: new CompositeBackend(
    new StateBackend(),
    { "/memories/": new StoreBackend({
      namespace: (rt) => [rt.serverInfo.user.identity],
    }) },
  ),
});

BackendContext에서 마이그레이션

deepagents>=0.5.2(Python) 및 deepagents>=1.9.1(TypeScript)에서 네임스페이스 팩토리는 BackendContext 래퍼 대신 LangGraph Runtime을 직접 받습니다. 이전 BackendContext 형식은 하위 호환 .runtime.state 접근자를 통해 여전히 작동하지만, 이 접근자는 deprecation 경고를 방출하며 deepagents>=0.7에서 제거될 것입니다.

바뀐 것:

  • 팩토리 인자는 이제 BackendContext가 아닌 Runtime입니다.
  • .runtime 접근자를 제거하세요 — 예: ctx.runtime.context.user_idrt.server_info.user.identity가 됩니다.
  • ctx.state에 대한 직접적인 대체는 없습니다. 네임스페이스 정보는 실행 수명 동안 읽기 전용이고 안정적이어야 하지만, state는 변경 가능하며 단계마다 바뀝니다 — state에서 네임스페이스를 파생하면 데이터가 일관되지 않은 키 아래에 들어갈 위험이 있습니다. 에이전트 state를 읽어야 하는 사용 사례가 있으면 이슈를 열어주세요.
// Before (deprecated, removed in v0.7)
new StoreBackend({
  namespace: (ctx) => [ctx.runtime.context.userId],  // [!code --]
});

// After
new StoreBackend({
  namespace: (rt) => [rt.serverInfo.user.identity],  // [!code ++]
});

프로토콜 레퍼런스 (Protocol reference)

백엔드는 BackendProtocol를 구현해야 합니다.

필수 메서드:

  • ls(path: string) → LsResult — 최소 path가 있는 항목을 반환. 가능하면 is_dir, size, modified_at 포함. 결정적인 출력을 위해 path로 정렬.
  • read(filePath: string, offset?: number, limit?: number) → ReadResult — 성공 시 파일 데이터를 반환. 파일 누락 시 { error: "File '/x' not found" } 반환.
  • readRaw(filePath: string) → ReadRawResult — 파일 콘텐츠를 원시 FileData로 읽기. 타임스탬프를 포함한 전체 파일 데이터를 반환.
  • grep(pattern: string, path?: string | null, glob?: string | null) → GrepResult — 리터럴 텍스트 패턴에 대한 파일 내용 검색. MIME 유형으로 판별된 바이너리 파일은 건너뜀. 실패 시 { error: "..." } 반환.
  • glob(pattern: string, path?: string) → GlobResult — glob 패턴과 일치하는 파일을 FileInfo 항목으로 반환.
  • write(filePath: string, content: string) → WriteResult — 생성 전용 의미. 충돌 시 { error: "..." } 반환. 성공 시 path를 설정하고 state 백엔드의 경우 filesUpdate={...} 설정; 외부 백엔드는 filesUpdate=null 사용.
  • edit(filePath: string, oldString: string, newString: string, replaceAll?: boolean) → EditResultreplaceAll=true가 아니면 oldString의 고유성을 강제. 없다면 오류 반환. 성공 시 occurrences 포함.

선택 메서드:

  • uploadFiles(files: Array<[string, Uint8Array]>) → FileUploadResponse[] — 여러 파일 업로드 (샌드박스 백엔드용).
  • downloadFiles(paths: string[]) → FileDownloadResponse[] — 여러 파일 다운로드 (샌드박스 백엔드용).

결과 유형:

유형 성공 필드 오류 필드
ReadResult content?: string | Uint8Array, mimeType?: string error
ReadRawResult data?: FileData error
LsResult files?: FileInfo[] error
GlobResult files?: FileInfo[] error
GrepResult matches?: GrepMatch[] error
WriteResult path?: string error
EditResult path?: string, occurrences?: number error

지원 유형:

  • FileInfopath (필수), 선택적으로 is_dir, size, modified_at.
  • GrepMatchpath, line (1-인덱스), text.
  • FileData — 타임스탬프가 있는 파일 콘텐츠. FileData 형식 참고.

샌드박스 확장:

SandboxBackendProtocolV2BackendProtocolV2를 확장합니다:

  • execute(command: string) → ExecuteResponse — 샌드박스에서 셸 명령 실행.
  • readonly id: string — 샌드박스 인스턴스의 고유 식별자.

기존 백엔드를 V2로 업데이트 (Update existing backends to V2)

메서드 이름 변경:

V1 메서드 V2 메서드 반환 유형 변경
lsInfo(path) ls(path) FileInfo[]LsResult
read(filePath, offset, limit) read(filePath, offset, limit) stringReadResult
readRaw(filePath) readRaw(filePath) FileDataReadRawResult
grepRaw(pattern, path, glob) grep(pattern, path, glob) GrepMatch[] | stringGrepResult
globInfo(pattern, path) glob(pattern, path) FileInfo[]GlobResult
write(...) write(...) 변경 없음 (WriteResult)
edit(...) edit(...) 변경 없음 (EditResult)

유형 이름 변경:

V1 유형 V2 유형
BackendProtocol BackendProtocolV2
SandboxBackendProtocol SandboxBackendProtocolV2

적응 유틸리티:

V2 전용 코드와 함께 사용해야 하는 기존 V1 백엔드가 있다면 적응 함수를 사용하세요:

import { adaptBackendProtocol, adaptSandboxProtocol } from "deepagents";

// Adapt a V1 backend to V2
const v2Backend = adaptBackendProtocol(v1Backend);

// Adapt a V1 sandbox to V2
const v2Sandbox = adaptSandboxProtocol(v1Sandbox);
프레임워크는 `createDeepAgent()`에 전달된 V1 백엔드를 자동으로 적응시킵니다. 수동 적응은 프로토콜 메서드를 직접 호출할 때만 필요합니다.

더 알아보기

  • OpenWiki: 에이전트가 파일시스템 도구로 읽는 내구성 있는 저장소 Markdown 생성
  • 메모리: 파일시스템 기반 장기 메모리
  • 샌드박스: 격리된 파일시스템 및 셸 실행