create_deep_agent has the following core configuration options:
- Model
- Tools
- System Prompt
- Middleware, including prebuilt middleware and custom middleware
- Interpreters
- Subagents
- Backends (virtual filesystems)
- Human-in-the-loop
- Skills
- Memory
- Profiles
create_deep_agent(
model: str | BaseChatModel | None = None,
tools: Sequence[BaseTool | Callable | dict[str, Any]] | None = None,
*,
system_prompt: str | SystemMessage | None = None,
middleware: Sequence[AgentMiddleware] = (),
subagents: Sequence[SubAgent | CompiledSubAgent | AsyncSubAgent] | None = None,
skills: list[str] | None = None,
memory: list[str] | None = None,
permissions: list[FilesystemPermission] | None = None,
backend: BackendProtocol | BackendFactory | None = None,
interrupt_on: dict[str, bool | InterruptOnConfig] | None = None,
response_format: ResponseFormat[ResponseT] | type[ResponseT] | dict[str, Any] | None = None,
context_schema: type[ContextT] | None = None,
checkpointer: Checkpointer | None = None,
store: BaseStore | None = None,
debug: bool = False,
name: str | None = None,
cache: BaseCache | None = None
) -> CompiledStateGraph[AgentState[ResponseT], ContextT, _InputAgentState, _OutputAgentState[ResponseT]]
create_deep_agent API reference.
Model
Pass amodel string in provider:model format, or an initialized model instance. See supported models for all providers and suggested models for tested recommendations.
Use the
provider:model format (for example openai:gpt-5.4) to quickly switch between models.- OpenAI
- Anthropic
- Azure
- Google Gemini
- AWS Bedrock
- HuggingFace
- Other
👉 Read the OpenAI chat model integration docs
pip install -U "langchain[openai]"
import os
from deepagents import create_deep_agent
os.environ["OPENAI_API_KEY"] = "sk-..."
agent = create_deep_agent(model="openai:gpt-5.4")
# this calls init_chat_model for the specified model with default parameters
# to use specific model parameters, use init_chat_model directly
import os
from langchain.chat_models import init_chat_model
from deepagents import create_deep_agent
os.environ["OPENAI_API_KEY"] = "sk-..."
model = init_chat_model(model="openai:gpt-5.4")
agent = create_deep_agent(model=model)
import os
from langchain_openai import ChatOpenAI
from deepagents import create_deep_agent
os.environ["OPENAI_API_KEY"] = "sk-..."
model = ChatOpenAI(model="gpt-5.4")
agent = create_deep_agent(model=model)
👉 Read the Anthropic chat model integration docs
pip install -U "langchain[anthropic]"
import os
from deepagents import create_deep_agent
os.environ["ANTHROPIC_API_KEY"] = "sk-..."
agent = create_deep_agent(model="anthropic:claude-sonnet-4-6")
# this calls init_chat_model for the specified model with default parameters
# to use specific model parameters, use init_chat_model directly
import os
from langchain.chat_models import init_chat_model
from deepagents import create_deep_agent
os.environ["ANTHROPIC_API_KEY"] = "sk-..."
model = init_chat_model(model="claude-sonnet-4-6")
agent = create_deep_agent(model=model)
import os
from langchain_anthropic import ChatAnthropic
from deepagents import create_deep_agent
os.environ["ANTHROPIC_API_KEY"] = "sk-..."
model = ChatAnthropic(model="claude-sonnet-4-6")
agent = create_deep_agent(model=model)
👉 Read the Azure chat model integration docs
pip install -U "langchain[openai]"
import os
from deepagents import create_deep_agent
os.environ["AZURE_OPENAI_API_KEY"] = "..."
os.environ["AZURE_OPENAI_ENDPOINT"] = "..."
os.environ["OPENAI_API_VERSION"] = "2025-03-01-preview"
agent = create_deep_agent(model="azure_openai:gpt-5.4")
# this calls init_chat_model for the specified model with default parameters
# to use specific model parameters, use init_chat_model directly
import os
from langchain.chat_models import init_chat_model
from deepagents import create_deep_agent
os.environ["AZURE_OPENAI_API_KEY"] = "..."
os.environ["AZURE_OPENAI_ENDPOINT"] = "..."
os.environ["OPENAI_API_VERSION"] = "2025-03-01-preview"
model = init_chat_model(
model="azure_openai:gpt-5.4",
azure_deployment=os.environ["AZURE_OPENAI_DEPLOYMENT_NAME"],
)
agent = create_deep_agent(model=model)
import os
from langchain_openai import AzureChatOpenAI
from deepagents import create_deep_agent
os.environ["AZURE_OPENAI_API_KEY"] = "..."
os.environ["AZURE_OPENAI_ENDPOINT"] = "..."
os.environ["OPENAI_API_VERSION"] = "2025-03-01-preview"
model = AzureChatOpenAI(
model="gpt-5.4",
azure_deployment=os.environ["AZURE_OPENAI_DEPLOYMENT_NAME"],
)
agent = create_deep_agent(model=model)
👉 Read the Google GenAI chat model integration docs
pip install -U "langchain[google-genai]"
import os
from deepagents import create_deep_agent
os.environ["GOOGLE_API_KEY"] = "..."
agent = create_deep_agent(model="google_genai:gemini-3.1-pro-preview")
# this calls init_chat_model for the specified model with default parameters
# to use specific model parameters, use init_chat_model directly
import os
from langchain.chat_models import init_chat_model
from deepagents import create_deep_agent
os.environ["GOOGLE_API_KEY"] = "..."
model = init_chat_model(model="google_genai:gemini-3.1-pro-preview")
agent = create_deep_agent(model=model)
import os
from langchain_google_genai import ChatGoogleGenerativeAI
from deepagents import create_deep_agent
os.environ["GOOGLE_API_KEY"] = "..."
model = ChatGoogleGenerativeAI(model="gemini-3.1-pro-preview")
agent = create_deep_agent(model=model)
👉 Read the AWS Bedrock chat model integration docs
pip install -U "langchain[aws]"
from deepagents import create_deep_agent
# Follow the steps here to configure your credentials:
# https://docs.aws.amazon.com/bedrock/latest/userguide/getting-started.html
agent = create_deep_agent(
model="anthropic.claude-sonnet-4-6",
model_provider="bedrock_converse",
)
# this calls init_chat_model for the specified model with default parameters
# to use specific model parameters, use init_chat_model directly
from langchain.chat_models import init_chat_model
from deepagents import create_deep_agent
# Follow the steps here to configure your credentials:
# https://docs.aws.amazon.com/bedrock/latest/userguide/getting-started.html
model = init_chat_model(
model="anthropic.claude-sonnet-4-6",
model_provider="bedrock_converse",
)
agent = create_deep_agent(model=model)
from langchain_aws import ChatBedrock
from deepagents import create_deep_agent
# Follow the steps here to configure your credentials:
# https://docs.aws.amazon.com/bedrock/latest/userguide/getting-started.html
model = ChatBedrock(model="anthropic.claude-sonnet-4-6")
agent = create_deep_agent(model=model)
👉 Read the HuggingFace chat model integration docs
pip install -U "langchain[huggingface]"
import os
from deepagents import create_deep_agent
os.environ["HUGGINGFACEHUB_API_TOKEN"] = "hf_..."
agent = create_deep_agent(
model="microsoft/Phi-3-mini-4k-instruct",
model_provider="huggingface",
temperature=0.7,
max_tokens=1024,
)
# this calls init_chat_model for the specified model with default parameters
# to use specific model parameters, use init_chat_model directly
import os
from langchain.chat_models import init_chat_model
from deepagents import create_deep_agent
os.environ["HUGGINGFACEHUB_API_TOKEN"] = "hf_..."
model = init_chat_model(
model="microsoft/Phi-3-mini-4k-instruct",
model_provider="huggingface",
temperature=0.7,
max_tokens=1024,
)
agent = create_deep_agent(model=model)
import os
from langchain_huggingface import ChatHuggingFace, HuggingFaceEndpoint
from deepagents import create_deep_agent
os.environ["HUGGINGFACEHUB_API_TOKEN"] = "hf_..."
llm = HuggingFaceEndpoint(
repo_id="microsoft/Phi-3-mini-4k-instruct",
temperature=0.7,
max_length=1024,
)
model = ChatHuggingFace(llm=llm)
agent = create_deep_agent(model=model)
Pass any supported model string, or an initialized model instance:
from deepagents import create_deep_agent
agent = create_deep_agent(model="provider:model-name")
from deepagents import create_deep_agent
from langchain.chat_models import init_chat_model
model = init_chat_model("provider:model-name")
agent = create_deep_agent(model=model)
from langchain_<provider> import Chat<Provider>
from deepagents import create_deep_agent
model = Chat<Provider>(model="model-name")
agent = create_deep_agent(model=model)
Chat models automatically retry transient API failures (with exponential backoff). For defaults, limits, and code samples for tuning
max_retries / timeout live on the LangChain Models page.Tools
In addition to built-in tools for planning, file management, and subagent spawning, you can provide custom tools:import os
from typing import Literal
from tavily import TavilyClient
from deepagents import create_deep_agent
tavily_client = TavilyClient(api_key=os.environ["TAVILY_API_KEY"])
def internet_search(
query: str,
max_results: int = 5,
topic: Literal["general", "news", "finance"] = "general",
include_raw_content: bool = False,
):
"""Run a web search"""
return tavily_client.search(
query,
max_results=max_results,
include_raw_content=include_raw_content,
topic=topic,
)
agent = create_deep_agent(
model="google_genai:gemini-3.1-pro-preview",
tools=[internet_search],
)
import os
from typing import Literal
from tavily import TavilyClient
from deepagents import create_deep_agent
tavily_client = TavilyClient(api_key=os.environ["TAVILY_API_KEY"])
def internet_search(
query: str,
max_results: int = 5,
topic: Literal["general", "news", "finance"] = "general",
include_raw_content: bool = False,
):
"""Run a web search"""
return tavily_client.search(
query,
max_results=max_results,
include_raw_content=include_raw_content,
topic=topic,
)
agent = create_deep_agent(
model="openai:gpt-5.4",
tools=[internet_search],
)
import os
from typing import Literal
from tavily import TavilyClient
from deepagents import create_deep_agent
tavily_client = TavilyClient(api_key=os.environ["TAVILY_API_KEY"])
def internet_search(
query: str,
max_results: int = 5,
topic: Literal["general", "news", "finance"] = "general",
include_raw_content: bool = False,
):
"""Run a web search"""
return tavily_client.search(
query,
max_results=max_results,
include_raw_content=include_raw_content,
topic=topic,
)
agent = create_deep_agent(
model="anthropic:claude-sonnet-4-6",
tools=[internet_search],
)
import os
from typing import Literal
from tavily import TavilyClient
from deepagents import create_deep_agent
tavily_client = TavilyClient(api_key=os.environ["TAVILY_API_KEY"])
def internet_search(
query: str,
max_results: int = 5,
topic: Literal["general", "news", "finance"] = "general",
include_raw_content: bool = False,
):
"""Run a web search"""
return tavily_client.search(
query,
max_results=max_results,
include_raw_content=include_raw_content,
topic=topic,
)
agent = create_deep_agent(
model="openrouter:anthropic/claude-sonnet-4-6",
tools=[internet_search],
)
import os
from typing import Literal
from tavily import TavilyClient
from deepagents import create_deep_agent
tavily_client = TavilyClient(api_key=os.environ["TAVILY_API_KEY"])
def internet_search(
query: str,
max_results: int = 5,
topic: Literal["general", "news", "finance"] = "general",
include_raw_content: bool = False,
):
"""Run a web search"""
return tavily_client.search(
query,
max_results=max_results,
include_raw_content=include_raw_content,
topic=topic,
)
agent = create_deep_agent(
model="fireworks:accounts/fireworks/models/qwen3p5-397b-a17b",
tools=[internet_search],
)
import os
from typing import Literal
from tavily import TavilyClient
from deepagents import create_deep_agent
tavily_client = TavilyClient(api_key=os.environ["TAVILY_API_KEY"])
def internet_search(
query: str,
max_results: int = 5,
topic: Literal["general", "news", "finance"] = "general",
include_raw_content: bool = False,
):
"""Run a web search"""
return tavily_client.search(
query,
max_results=max_results,
include_raw_content=include_raw_content,
topic=topic,
)
agent = create_deep_agent(
model="baseten:zai-org/GLM-5",
tools=[internet_search],
)
import os
from typing import Literal
from tavily import TavilyClient
from deepagents import create_deep_agent
tavily_client = TavilyClient(api_key=os.environ["TAVILY_API_KEY"])
def internet_search(
query: str,
max_results: int = 5,
topic: Literal["general", "news", "finance"] = "general",
include_raw_content: bool = False,
):
"""Run a web search"""
return tavily_client.search(
query,
max_results=max_results,
include_raw_content=include_raw_content,
topic=topic,
)
agent = create_deep_agent(
model="ollama:devstral-2",
tools=[internet_search],
)
System prompt
Deep Agents come with a built-in system prompt. A deep agent’s value comes from the orchestration layer the SDK provides on top of the model—planning, virtual-filesystem tools, and subagents—and the model needs to know those exist and when to reach for them. The built-in prompt teaches the agent how to use that scaffolding so you don’t have to re-derive it for every project; tweak it through a profile or your ownsystem_prompt= rather than copying it verbatim.
When middleware add special tools, like the filesystem tools, it appends them to the system prompt.
Each deep agent should also include a custom system prompt specific to its specific use case:
from deepagents import create_deep_agent
research_instructions = """\
You are an expert researcher. Your job is to conduct \
thorough research, and then write a polished report. \
"""
agent = create_deep_agent(
model="google_genai:gemini-3.1-pro-preview",
system_prompt=research_instructions,
)
from deepagents import create_deep_agent
research_instructions = """\
You are an expert researcher. Your job is to conduct \
thorough research, and then write a polished report. \
"""
agent = create_deep_agent(
model="openai:gpt-5.4",
system_prompt=research_instructions,
)
from deepagents import create_deep_agent
research_instructions = """\
You are an expert researcher. Your job is to conduct \
thorough research, and then write a polished report. \
"""
agent = create_deep_agent(
model="anthropic:claude-sonnet-4-6",
system_prompt=research_instructions,
)
from deepagents import create_deep_agent
research_instructions = """\
You are an expert researcher. Your job is to conduct \
thorough research, and then write a polished report. \
"""
agent = create_deep_agent(
model="openrouter:anthropic/claude-sonnet-4-6",
system_prompt=research_instructions,
)
from deepagents import create_deep_agent
research_instructions = """\
You are an expert researcher. Your job is to conduct \
thorough research, and then write a polished report. \
"""
agent = create_deep_agent(
model="fireworks:accounts/fireworks/models/qwen3p5-397b-a17b",
system_prompt=research_instructions,
)
from deepagents import create_deep_agent
research_instructions = """\
You are an expert researcher. Your job is to conduct \
thorough research, and then write a polished report. \
"""
agent = create_deep_agent(
model="baseten:zai-org/GLM-5",
system_prompt=research_instructions,
)
from deepagents import create_deep_agent
research_instructions = """\
You are an expert researcher. Your job is to conduct \
thorough research, and then write a polished report. \
"""
agent = create_deep_agent(
model="ollama:devstral-2",
system_prompt=research_instructions,
)
Prompt assembly
Deep Agents builds the system prompt from up to four named parts so that caller-supplied instructions, the SDK’s built-in agent guidance, and any model-specific profile overrides can coexist with predictable precedence. Without this layering, a profile suffix tuned for Claude (for example) could overwrite or be overwritten by yoursystem_prompt= argument depending on call order; the named slots make the ordering explicit and stable.
In practice, most callers only encounter two slots: USER (your system_prompt=) and BASE (the SDK default). Selecting a model with a built-in profile—Anthropic or OpenAI today—adds a SUFFIX. The full four-part assembly is mainly relevant when you author a custom HarnessProfile or debug why a profile’s text appears where it does.
The four named parts (each may be absent):
| Name | Source | Notes |
|---|---|---|
USER | system_prompt= argument to create_deep_agent | str or SystemMessage; omitted when unset. |
BASE | The SDK default (BASE_AGENT_PROMPT) | Always present unless replaced by a profile’s CUSTOM. |
CUSTOM | HarnessProfile.base_system_prompt | Replaces BASE outright when a matching profile sets it. |
SUFFIX | HarnessProfile.system_prompt_suffix | Appended last when a matching profile sets it. |
USER -> (BASE or CUSTOM) -> SUFFIX, joined by blank lines (\n\n). Two invariants follow:
USERis always at the front. The caller’s text precedes any SDK or profile content, so persona/instructions take precedence regardless of which model is selected.SUFFIXis always at the end. Profile suffixes sit closest to the conversation history, where model-tuning guidance lands most reliably.
system_prompt= | profile base_system_prompt (CUSTOM) | profile system_prompt_suffix (SUFFIX) | Final assembled system prompt |
|---|---|---|---|
None | - | - | BASE |
None | - | ✓ | BASE + SUFFIX |
None | ✓ | - | CUSTOM |
None | ✓ | ✓ | CUSTOM + SUFFIX |
str | - | - | USER + BASE |
str | - | ✓ | USER + BASE + SUFFIX |
str | ✓ | - | USER + CUSTOM |
str | ✓ | ✓ | USER + CUSTOM + SUFFIX |
system_prompt_suffix, so a typical call lands in the str + - + ✓ row:
agent = create_deep_agent(
model="anthropic:claude-sonnet-4-6",
system_prompt="You are a customer-support agent for ACME Corp.",
)
# Final = USER + BASE + SUFFIX
# = "You are a customer-support agent for ACME Corp."
# + "\n\n"
# + BASE_AGENT_PROMPT
# + "\n\n"
# + <Claude-specific guidance>
Passing a
SystemMessage (rather than a string) triggers a different concatenation path: the right-hand assembly (BASE-or-CUSTOM plus any SUFFIX) is appended as an additional text content block onto the message’s existing content_blocks. The same logical ordering applies (caller blocks first), and any cache_control markers on the caller’s blocks are preserved — useful for placing explicit Anthropic prompt-cache breakpoints.Subagent prompts
Subagent prompts
The same overlay rules apply to declarative subagents — each subagent re-runs profile resolution against its own model, then applies the resolved profile’s
There is no
base_system_prompt / system_prompt_suffix to its authored system_prompt. The subagent’s system_prompt plays the BASE role; CUSTOM and SUFFIX come from the profile that matches the subagent’s model (which may differ from the main agent’s profile).spec["system_prompt"] | profile base_system_prompt (CUSTOM) | profile system_prompt_suffix (SUFFIX) | Final subagent system prompt |
|---|---|---|---|
| authored | - | - | authored |
| authored | - | ✓ | authored + SUFFIX |
| authored | ✓ | - | CUSTOM |
| authored | ✓ | ✓ | CUSTOM + SUFFIX |
USER segment for subagents — the spec’s authored system_prompt is the closest analog and stays in the BASE slot. A profile that ships only a system_prompt_suffix (the common case for built-in Anthropic / OpenAI profiles) just appends to whatever the subagent author wrote; a profile that sets base_system_prompt will replace the authored prompt outright, so reach for that field deliberately.General-purpose subagent prompt
General-purpose subagent prompt
The auto-added general-purpose subagent follows the same overlay rules with one extra layer: the GP base prompt is resolved as
If
general_purpose_subagent.system_prompt (if set) -> HarnessProfile.base_system_prompt (if set) -> SDK GP default. The profile suffix layers on top either way.The two override fields can both carry a base-prompt replacement, but they are not interchangeable. general_purpose_subagent.system_prompt is GP-specific configuration; base_system_prompt is a global override that primarily targets the main agent. When both are set, the GP-specific intent wins for the GP subagent so a user tuning both fields never sees their GP override silently dropped:register_harness_profile(
"anthropic",
HarnessProfile(
base_system_prompt="You are ACME's support orchestrator.", # main agent
general_purpose_subagent=GeneralPurposeSubagentProfile(
system_prompt="You are a research subagent. Cite sources.", # GP subagent
),
system_prompt_suffix="Always think step by step.",
),
)
| Stack | Final system prompt |
|---|---|
| Main agent | "You are ACME's support orchestrator." + SUFFIX |
| GP subagent | "You are a research subagent. Cite sources." + SUFFIX |
general_purpose_subagent.system_prompt is unset, the GP subagent falls back to base_system_prompt (when set) and finally to the SDK GP default.Middleware
Deep Agents support any middleware, including the built-in middleware listed below, prebuilt middleware from LangChain, provider-specific middleware, and custom middleware you write yourself. Pass middleware to themiddleware argument of create_deep_agent.
By default, Deep Agents have access to the following middleware:
TodoListMiddleware: Tracks and manages todo lists for organizing agent tasks and workFilesystemMiddleware: Handles file system operations such as reading, writing, and navigating directoriesSubAgentMiddleware: Spawns and coordinates subagents for delegating tasks to specialized agentsSummarizationMiddleware: Condenses message history to stay within context limits when conversations grow longAnthropicPromptCachingMiddleware: Automatic reduction of redundant token processing when using Anthropic modelsPatchToolCallsMiddleware: Automatic message history fixes when tool calls are interrupted or cancelled before receiving results
MemoryMiddleware: Persists and retrieves conversation context across sessions when thememoryargument is providedSkillsMiddleware: Enables custom skills when theskillsargument is providedHumanInTheLoopMiddleware: Pauses for human approval or input at specified points when theinterruptOnargument is provided
Prebuilt middleware
LangChain exposes additional prebuilt middleware that let you add-on various features, such as retries, fallbacks, or PII detection. See Prebuilt middleware for more. Thedeepagents library also exposes create_summarization_tool_middleware, enabling agents to trigger summarization at opportune times—such as between tasks—instead of at fixed token intervals. For more detail, see Summarization.
Provider-specific middleware
For provider-specific middleware that is optimized for specific LLM providers, see Official integrations and Community integrations.Custom middleware
You can provide additional middleware to extend functionality, add tools, or implement custom hooks:from langchain.agents.middleware import wrap_tool_call
from langchain.tools import tool
from deepagents import create_deep_agent
@tool
def get_weather(city: str) -> str:
"""Get the weather in a city."""
return f"The weather in {city} is sunny."
call_count = [0] # Use list to allow modification in nested function
@wrap_tool_call
def log_tool_calls(request, handler):
"""Intercept and log every tool call - demonstrates cross-cutting concern."""
call_count[0] += 1
tool_name = request.name if hasattr(request, "name") else str(request)
print(f"[Middleware] Tool call #{call_count[0]}: {tool_name}")
print(f"[Middleware] Arguments: {request.args if hasattr(request, 'args') else 'N/A'}")
# Execute the tool call
result = handler(request)
# Log the result
print(f"[Middleware] Tool call #{call_count[0]} completed")
return result
agent = create_deep_agent(
model="google_genai:gemini-3.1-pro-preview",
tools=[get_weather],
middleware=[log_tool_calls],
)
from langchain.agents.middleware import wrap_tool_call
from langchain.tools import tool
from deepagents import create_deep_agent
@tool
def get_weather(city: str) -> str:
"""Get the weather in a city."""
return f"The weather in {city} is sunny."
call_count = [0] # Use list to allow modification in nested function
@wrap_tool_call
def log_tool_calls(request, handler):
"""Intercept and log every tool call - demonstrates cross-cutting concern."""
call_count[0] += 1
tool_name = request.name if hasattr(request, "name") else str(request)
print(f"[Middleware] Tool call #{call_count[0]}: {tool_name}")
print(f"[Middleware] Arguments: {request.args if hasattr(request, 'args') else 'N/A'}")
# Execute the tool call
result = handler(request)
# Log the result
print(f"[Middleware] Tool call #{call_count[0]} completed")
return result
agent = create_deep_agent(
model="openai:gpt-5.4",
tools=[get_weather],
middleware=[log_tool_calls],
)
from langchain.agents.middleware import wrap_tool_call
from langchain.tools import tool
from deepagents import create_deep_agent
@tool
def get_weather(city: str) -> str:
"""Get the weather in a city."""
return f"The weather in {city} is sunny."
call_count = [0] # Use list to allow modification in nested function
@wrap_tool_call
def log_tool_calls(request, handler):
"""Intercept and log every tool call - demonstrates cross-cutting concern."""
call_count[0] += 1
tool_name = request.name if hasattr(request, "name") else str(request)
print(f"[Middleware] Tool call #{call_count[0]}: {tool_name}")
print(f"[Middleware] Arguments: {request.args if hasattr(request, 'args') else 'N/A'}")
# Execute the tool call
result = handler(request)
# Log the result
print(f"[Middleware] Tool call #{call_count[0]} completed")
return result
agent = create_deep_agent(
model="anthropic:claude-sonnet-4-6",
tools=[get_weather],
middleware=[log_tool_calls],
)
from langchain.agents.middleware import wrap_tool_call
from langchain.tools import tool
from deepagents import create_deep_agent
@tool
def get_weather(city: str) -> str:
"""Get the weather in a city."""
return f"The weather in {city} is sunny."
call_count = [0] # Use list to allow modification in nested function
@wrap_tool_call
def log_tool_calls(request, handler):
"""Intercept and log every tool call - demonstrates cross-cutting concern."""
call_count[0] += 1
tool_name = request.name if hasattr(request, "name") else str(request)
print(f"[Middleware] Tool call #{call_count[0]}: {tool_name}")
print(f"[Middleware] Arguments: {request.args if hasattr(request, 'args') else 'N/A'}")
# Execute the tool call
result = handler(request)
# Log the result
print(f"[Middleware] Tool call #{call_count[0]} completed")
return result
agent = create_deep_agent(
model="openrouter:anthropic/claude-sonnet-4-6",
tools=[get_weather],
middleware=[log_tool_calls],
)
from langchain.agents.middleware import wrap_tool_call
from langchain.tools import tool
from deepagents import create_deep_agent
@tool
def get_weather(city: str) -> str:
"""Get the weather in a city."""
return f"The weather in {city} is sunny."
call_count = [0] # Use list to allow modification in nested function
@wrap_tool_call
def log_tool_calls(request, handler):
"""Intercept and log every tool call - demonstrates cross-cutting concern."""
call_count[0] += 1
tool_name = request.name if hasattr(request, "name") else str(request)
print(f"[Middleware] Tool call #{call_count[0]}: {tool_name}")
print(f"[Middleware] Arguments: {request.args if hasattr(request, 'args') else 'N/A'}")
# Execute the tool call
result = handler(request)
# Log the result
print(f"[Middleware] Tool call #{call_count[0]} completed")
return result
agent = create_deep_agent(
model="fireworks:accounts/fireworks/models/qwen3p5-397b-a17b",
tools=[get_weather],
middleware=[log_tool_calls],
)
from langchain.agents.middleware import wrap_tool_call
from langchain.tools import tool
from deepagents import create_deep_agent
@tool
def get_weather(city: str) -> str:
"""Get the weather in a city."""
return f"The weather in {city} is sunny."
call_count = [0] # Use list to allow modification in nested function
@wrap_tool_call
def log_tool_calls(request, handler):
"""Intercept and log every tool call - demonstrates cross-cutting concern."""
call_count[0] += 1
tool_name = request.name if hasattr(request, "name") else str(request)
print(f"[Middleware] Tool call #{call_count[0]}: {tool_name}")
print(f"[Middleware] Arguments: {request.args if hasattr(request, 'args') else 'N/A'}")
# Execute the tool call
result = handler(request)
# Log the result
print(f"[Middleware] Tool call #{call_count[0]} completed")
return result
agent = create_deep_agent(
model="baseten:zai-org/GLM-5",
tools=[get_weather],
middleware=[log_tool_calls],
)
from langchain.agents.middleware import wrap_tool_call
from langchain.tools import tool
from deepagents import create_deep_agent
@tool
def get_weather(city: str) -> str:
"""Get the weather in a city."""
return f"The weather in {city} is sunny."
call_count = [0] # Use list to allow modification in nested function
@wrap_tool_call
def log_tool_calls(request, handler):
"""Intercept and log every tool call - demonstrates cross-cutting concern."""
call_count[0] += 1
tool_name = request.name if hasattr(request, "name") else str(request)
print(f"[Middleware] Tool call #{call_count[0]}: {tool_name}")
print(f"[Middleware] Arguments: {request.args if hasattr(request, 'args') else 'N/A'}")
# Execute the tool call
result = handler(request)
# Log the result
print(f"[Middleware] Tool call #{call_count[0]} completed")
return result
agent = create_deep_agent(
model="ollama:devstral-2",
tools=[get_weather],
middleware=[log_tool_calls],
)
Do not mutate attributes after initializationIf you need to track values across hook invocations (for example, counters or accumulated data), use graph state.
Graph state is scoped to a thread by design, so updates are safe under concurrency.Do this:Do not do this:Mutation in place, such as modifying
from langchain.agents.middleware import AgentMiddleware
class CustomMiddleware(AgentMiddleware):
def __init__(self):
pass
def before_agent(self, state, runtime):
return {"x": state.get("x", 0) + 1} # Update graph state instead
class CustomMiddlewareBad(AgentMiddleware):
def __init__(self):
self.x = 1
def before_agent(self, state, runtime):
self.x += 1 # Mutation causes race conditions
self.x in before_agent or changing other shared values in hooks, can lead to subtle bugs and race conditions because many operations run concurrently (subagents, parallel tools, and parallel invocations on different threads).For full details on extending state with custom properties, see Custom middleware - Custom state schema.
If you must use mutation in custom middleware, consider what happens when subagents, parallel tools, or concurrent agent invocations run at the same time.Interpreters
Use interpreters to add aneval tool that runs JavaScript in a scoped QuickJS runtime. Interpreters are useful when the agent needs to compose tools programmatically, batch work, handle errors in code, or transform structured data without a full shell environment.
from deepagents import create_deep_agent
from langchain_quickjs import CodeInterpreterMiddleware
agent = create_deep_agent(
model="google_genai:gemini-3.1-pro-preview",
middleware=[CodeInterpreterMiddleware()],
)
from deepagents import create_deep_agent
from langchain_quickjs import CodeInterpreterMiddleware
agent = create_deep_agent(
model="openai:gpt-5.4",
middleware=[CodeInterpreterMiddleware()],
)
from deepagents import create_deep_agent
from langchain_quickjs import CodeInterpreterMiddleware
agent = create_deep_agent(
model="anthropic:claude-sonnet-4-6",
middleware=[CodeInterpreterMiddleware()],
)
from deepagents import create_deep_agent
from langchain_quickjs import CodeInterpreterMiddleware
agent = create_deep_agent(
model="openrouter:anthropic/claude-sonnet-4-6",
middleware=[CodeInterpreterMiddleware()],
)
from deepagents import create_deep_agent
from langchain_quickjs import CodeInterpreterMiddleware
agent = create_deep_agent(
model="fireworks:accounts/fireworks/models/qwen3p5-397b-a17b",
middleware=[CodeInterpreterMiddleware()],
)
from deepagents import create_deep_agent
from langchain_quickjs import CodeInterpreterMiddleware
agent = create_deep_agent(
model="baseten:zai-org/GLM-5",
middleware=[CodeInterpreterMiddleware()],
)
from deepagents import create_deep_agent
from langchain_quickjs import CodeInterpreterMiddleware
agent = create_deep_agent(
model="ollama:devstral-2",
middleware=[CodeInterpreterMiddleware()],
)
Subagents
To isolate detailed work and avoid context bloat, use subagents:import os
from typing import Literal
from deepagents import create_deep_agent
from tavily import TavilyClient
tavily_client = TavilyClient(api_key=os.environ["TAVILY_API_KEY"])
def internet_search(
query: str,
max_results: int = 5,
topic: Literal["general", "news", "finance"] = "general",
include_raw_content: bool = False,
):
"""Run a web search"""
return tavily_client.search(
query,
max_results=max_results,
include_raw_content=include_raw_content,
topic=topic,
)
research_subagent = {
"name": "research-agent",
"description": "Used to research more in depth questions",
"system_prompt": "You are a great researcher",
"tools": [internet_search],
"model": "openai:gpt-5.4", # Optional override, defaults to main agent model
}
subagents = [research_subagent]
agent = create_deep_agent(
model="google_genai:gemini-3.1-pro-preview",
subagents=subagents,
)
Backends
Tools for a deep agent can make use of virtual file systems to store, access, and edit files. By default, deep agents use aStateBackend.
If you are using skills or memory, you must add the expected skill or memory files to the backend before creating the agent.
- StateBackend
- FilesystemBackend
- LocalShellBackend
- StoreBackend
- ContextHubBackend
- CompositeBackend
A thread-scoped filesystem backend stored in
langgraph state.Files persist across turns within a thread (via your checkpointer) and are not shared across threads.from deepagents import create_deep_agent
from deepagents.backends import StateBackend
# By default we provide a StateBackend
agent = create_deep_agent(model="google_genai:gemini-3.1-pro-preview")
# Under the hood, it looks like
agent2 = create_deep_agent(
model="google_genai:gemini-3.1-pro-preview",
backend=StateBackend(),
)
The local machine’s filesystem.
This backend grants agents direct filesystem read/write access.
Use with caution and only in appropriate environments.
For more information, see
FilesystemBackend.from deepagents import create_deep_agent
from deepagents.backends import FilesystemBackend
agent = create_deep_agent(
model="google_genai:gemini-3.1-pro-preview",
backend=FilesystemBackend(root_dir=".", virtual_mode=True),
)
A filesystem with shell execution directly on the host. Provides filesystem tools plus the
execute tool for running commands.This backend grants agents direct filesystem read/write access and unrestricted shell execution on your host.
Use with extreme caution and only in appropriate environments.
For more information, see
LocalShellBackend.from deepagents import create_deep_agent
from deepagents.backends import LocalShellBackend
agent = create_deep_agent(
model="google_genai:gemini-3.1-pro-preview",
backend=LocalShellBackend(root_dir=".", virtual_mode=True, env={"PATH": "/usr/bin:/bin"}),
)
A filesystem that provides long-term storage that is persisted across threads.
from deepagents import create_deep_agent
from deepagents.backends import StoreBackend
from langgraph.store.memory import InMemoryStore
agent = create_deep_agent(
model="google_genai:gemini-3.1-pro-preview",
backend=StoreBackend(
namespace=lambda rt: (rt.server_info.user.identity,),
),
store=InMemoryStore(), # Good for local dev; omit for LangSmith Deployment
)
When deploying to LangSmith Deployment, omit the
store parameter. The platform automatically provisions a store for your agent.The
namespace parameter controls data isolation. For multi-user deployments, always set a namespace factory to isolate data per user or tenant.Durable filesystem storage in a LangSmith Hub repo.For more details, see
from deepagents import create_deep_agent
from deepagents.backends import ContextHubBackend
agent = create_deep_agent(
model="google_genai:gemini-3.1-pro-preview",
backend=ContextHubBackend("my-agent"),
)
ContextHubBackend.A flexible backend where you can specify different routes in the filesystem to point towards different backends.
from deepagents import create_deep_agent
from deepagents.backends import CompositeBackend, StateBackend, StoreBackend
from langgraph.store.memory import InMemoryStore
agent = create_deep_agent(
model="google_genai:gemini-3.1-pro-preview",
backend=CompositeBackend(
default=StateBackend(),
routes={
"/memories/": StoreBackend(namespace=lambda _rt: ("memories",)),
},
),
store=InMemoryStore(), # Store passed to create_deep_agent, not backend
)
Sandboxes
Sandboxes are specialized backends that run agent code in an isolated environment with their own filesystem and anexecute tool for shell commands.
Use a sandbox backend when you want your deep agent to write files, install dependencies, and run commands without changing anything on your local machine.
You configure sandboxes by passing a sandbox backend to backend when creating your deep agent:
- Modal
- Runloop
- Daytona
- LangSmith
pip install langchain-modal
uv add langchain-modal
import modal
from deepagents import create_deep_agent
from langchain_anthropic import ChatAnthropic
from langchain_modal import ModalSandbox
app = modal.App.lookup("your-app")
modal_sandbox = modal.Sandbox.create(app=app)
backend = ModalSandbox(sandbox=modal_sandbox)
agent = create_deep_agent(
model=ChatAnthropic(model="claude-sonnet-4-6"),
system_prompt="You are a Python coding assistant with sandbox access.",
backend=backend,
)
try:
result = agent.invoke(
{
"messages": [
{
"role": "user",
"content": "Create a small Python package and run pytest",
}
]
}
)
finally:
modal_sandbox.terminate()
pip install langchain-runloop
uv add langchain-runloop
import os
from deepagents import create_deep_agent
from langchain_anthropic import ChatAnthropic
from langchain_runloop import RunloopSandbox
from runloop_api_client import RunloopSDK
client = RunloopSDK(bearer_token=os.environ["RUNLOOP_API_KEY"])
devbox = client.devbox.create()
backend = RunloopSandbox(devbox=devbox)
agent = create_deep_agent(
model=ChatAnthropic(model="claude-sonnet-4-6"),
system_prompt="You are a Python coding assistant with sandbox access.",
backend=backend,
)
try:
result = agent.invoke(
{
"messages": [
{
"role": "user",
"content": "Create a small Python package and run pytest",
}
]
}
)
finally:
devbox.shutdown()
pip install langchain-daytona
uv add langchain-daytona
from daytona import Daytona
from deepagents import create_deep_agent
from langchain_anthropic import ChatAnthropic
from langchain_daytona import DaytonaSandbox
sandbox = Daytona().create()
backend = DaytonaSandbox(sandbox=sandbox)
agent = create_deep_agent(
model=ChatAnthropic(model="claude-sonnet-4-6"),
system_prompt="You are a Python coding assistant with sandbox access.",
backend=backend,
)
try:
result = agent.invoke(
{
"messages": [
{
"role": "user",
"content": "Create a small Python package and run pytest",
}
]
}
)
finally:
sandbox.stop()
LangSmith sandboxes are currently in private beta.
pip install "langsmith[sandbox]"
uv add "langsmith[sandbox]"
from deepagents import create_deep_agent
from deepagents.backends import LangSmithSandbox
from langchain_anthropic import ChatAnthropic
from langsmith.sandbox import SandboxClient
client = SandboxClient()
ls_sandbox = client.create_sandbox()
backend = LangSmithSandbox(sandbox=ls_sandbox)
agent = create_deep_agent(
model=ChatAnthropic(model="claude-sonnet-4-6"),
system_prompt="You are a Python coding assistant with sandbox access.",
backend=backend,
)
try:
result = agent.invoke(
{
"messages": [
{
"role": "user",
"content": "Create a small Python package and run pytest",
}
]
}
)
finally:
client.delete_sandbox(ls_sandbox.name)
Human-in-the-loop
Some tool operations may be sensitive and require human approval before execution. You can configure the approval for each tool:from langchain.tools import tool
from deepagents import create_deep_agent
from langgraph.checkpoint.memory import MemorySaver
@tool
def remove_file(path: str) -> str:
"""Delete a file from the filesystem."""
return f"Deleted {path}"
@tool
def fetch_file(path: str) -> str:
"""Read a file from the filesystem."""
return f"Contents of {path}"
@tool
def notify_email(to: str, subject: str, body: str) -> str:
"""Send an email."""
return f"Sent email to {to}"
# Checkpointer is REQUIRED for human-in-the-loop
checkpointer = MemorySaver()
agent = create_deep_agent(
model="google_genai:gemini-3.1-pro-preview",
tools=[remove_file, fetch_file, notify_email],
interrupt_on={
"remove_file": True, # Default: approve, edit, reject, respond
"fetch_file": False, # No interrupts needed
"notify_email": {"allowed_decisions": ["approve", "reject"]}, # No editing
},
checkpointer=checkpointer, # Required!
)
Skills
You can use skills to provide your deep agent with new capabilities and expertise. While tools tend to cover lower level functionality like native file system actions or planning, skills can contain detailed instructions on how to complete tasks, reference info, and other assets, such as templates. These files are only loaded by the agent when the agent has determined that the skill is useful for the current prompt. This progressive disclosure reduces the amount of tokens and context the agent has to consider upon startup. For example skills, see Deep Agents example skills. To add skills to your deep agent, pass them as an argument tocreate_deep_agent:
- StateBackend
- StoreBackend
- FilesystemBackend
from urllib.request import urlopen
from deepagents import create_deep_agent
from deepagents.backends import StateBackend
from deepagents.backends.utils import create_file_data
from langchain_quickjs import CodeInterpreterMiddleware
from langgraph.checkpoint.memory import MemorySaver
checkpointer = MemorySaver()
backend = StateBackend()
skill_url = "https://raw.githubusercontent.com/langchain-ai/deepagents/refs/heads/main/libs/cli/examples/skills/langgraph-docs/SKILL.md"
with urlopen(skill_url) as response:
skill_content = response.read().decode('utf-8')
skills_files = {
"/skills/langgraph-docs/SKILL.md": create_file_data(skill_content),
}
agent = create_deep_agent(
model="google_genai:gemini-3.1-pro-preview",
backend=backend,
skills=["/skills/"],
checkpointer=checkpointer,
middleware=[CodeInterpreterMiddleware(skills_backend=backend)], # for interpreter skills
)
result = agent.invoke(
{
"messages": [{"role": "user", "content": "What is langgraph?"}],
# Seed the default StateBackend's in-state filesystem (virtual paths must start with "/").
"files": skills_files,
},
config={"configurable": {"thread_id": "12345"}},
)
from urllib.request import urlopen
from deepagents import create_deep_agent
from deepagents.backends import StateBackend
from deepagents.backends.utils import create_file_data
from langchain_quickjs import CodeInterpreterMiddleware
from langgraph.checkpoint.memory import MemorySaver
checkpointer = MemorySaver()
backend = StateBackend()
skill_url = "https://raw.githubusercontent.com/langchain-ai/deepagents/refs/heads/main/libs/cli/examples/skills/langgraph-docs/SKILL.md"
with urlopen(skill_url) as response:
skill_content = response.read().decode('utf-8')
skills_files = {
"/skills/langgraph-docs/SKILL.md": create_file_data(skill_content),
}
agent = create_deep_agent(
model="openai:gpt-5.4",
backend=backend,
skills=["/skills/"],
checkpointer=checkpointer,
middleware=[CodeInterpreterMiddleware(skills_backend=backend)], # for interpreter skills
)
result = agent.invoke(
{
"messages": [{"role": "user", "content": "What is langgraph?"}],
# Seed the default StateBackend's in-state filesystem (virtual paths must start with "/").
"files": skills_files,
},
config={"configurable": {"thread_id": "12345"}},
)
from urllib.request import urlopen
from deepagents import create_deep_agent
from deepagents.backends import StateBackend
from deepagents.backends.utils import create_file_data
from langchain_quickjs import CodeInterpreterMiddleware
from langgraph.checkpoint.memory import MemorySaver
checkpointer = MemorySaver()
backend = StateBackend()
skill_url = "https://raw.githubusercontent.com/langchain-ai/deepagents/refs/heads/main/libs/cli/examples/skills/langgraph-docs/SKILL.md"
with urlopen(skill_url) as response:
skill_content = response.read().decode('utf-8')
skills_files = {
"/skills/langgraph-docs/SKILL.md": create_file_data(skill_content),
}
agent = create_deep_agent(
model="anthropic:claude-sonnet-4-6",
backend=backend,
skills=["/skills/"],
checkpointer=checkpointer,
middleware=[CodeInterpreterMiddleware(skills_backend=backend)], # for interpreter skills
)
result = agent.invoke(
{
"messages": [{"role": "user", "content": "What is langgraph?"}],
# Seed the default StateBackend's in-state filesystem (virtual paths must start with "/").
"files": skills_files,
},
config={"configurable": {"thread_id": "12345"}},
)
from urllib.request import urlopen
from deepagents import create_deep_agent
from deepagents.backends import StateBackend
from deepagents.backends.utils import create_file_data
from langchain_quickjs import CodeInterpreterMiddleware
from langgraph.checkpoint.memory import MemorySaver
checkpointer = MemorySaver()
backend = StateBackend()
skill_url = "https://raw.githubusercontent.com/langchain-ai/deepagents/refs/heads/main/libs/cli/examples/skills/langgraph-docs/SKILL.md"
with urlopen(skill_url) as response:
skill_content = response.read().decode('utf-8')
skills_files = {
"/skills/langgraph-docs/SKILL.md": create_file_data(skill_content),
}
agent = create_deep_agent(
model="openrouter:anthropic/claude-sonnet-4-6",
backend=backend,
skills=["/skills/"],
checkpointer=checkpointer,
middleware=[CodeInterpreterMiddleware(skills_backend=backend)], # for interpreter skills
)
result = agent.invoke(
{
"messages": [{"role": "user", "content": "What is langgraph?"}],
# Seed the default StateBackend's in-state filesystem (virtual paths must start with "/").
"files": skills_files,
},
config={"configurable": {"thread_id": "12345"}},
)
from urllib.request import urlopen
from deepagents import create_deep_agent
from deepagents.backends import StateBackend
from deepagents.backends.utils import create_file_data
from langchain_quickjs import CodeInterpreterMiddleware
from langgraph.checkpoint.memory import MemorySaver
checkpointer = MemorySaver()
backend = StateBackend()
skill_url = "https://raw.githubusercontent.com/langchain-ai/deepagents/refs/heads/main/libs/cli/examples/skills/langgraph-docs/SKILL.md"
with urlopen(skill_url) as response:
skill_content = response.read().decode('utf-8')
skills_files = {
"/skills/langgraph-docs/SKILL.md": create_file_data(skill_content),
}
agent = create_deep_agent(
model="fireworks:accounts/fireworks/models/qwen3p5-397b-a17b",
backend=backend,
skills=["/skills/"],
checkpointer=checkpointer,
middleware=[CodeInterpreterMiddleware(skills_backend=backend)], # for interpreter skills
)
result = agent.invoke(
{
"messages": [{"role": "user", "content": "What is langgraph?"}],
# Seed the default StateBackend's in-state filesystem (virtual paths must start with "/").
"files": skills_files,
},
config={"configurable": {"thread_id": "12345"}},
)
from urllib.request import urlopen
from deepagents import create_deep_agent
from deepagents.backends import StateBackend
from deepagents.backends.utils import create_file_data
from langchain_quickjs import CodeInterpreterMiddleware
from langgraph.checkpoint.memory import MemorySaver
checkpointer = MemorySaver()
backend = StateBackend()
skill_url = "https://raw.githubusercontent.com/langchain-ai/deepagents/refs/heads/main/libs/cli/examples/skills/langgraph-docs/SKILL.md"
with urlopen(skill_url) as response:
skill_content = response.read().decode('utf-8')
skills_files = {
"/skills/langgraph-docs/SKILL.md": create_file_data(skill_content),
}
agent = create_deep_agent(
model="baseten:zai-org/GLM-5",
backend=backend,
skills=["/skills/"],
checkpointer=checkpointer,
middleware=[CodeInterpreterMiddleware(skills_backend=backend)], # for interpreter skills
)
result = agent.invoke(
{
"messages": [{"role": "user", "content": "What is langgraph?"}],
# Seed the default StateBackend's in-state filesystem (virtual paths must start with "/").
"files": skills_files,
},
config={"configurable": {"thread_id": "12345"}},
)
from urllib.request import urlopen
from deepagents import create_deep_agent
from deepagents.backends import StateBackend
from deepagents.backends.utils import create_file_data
from langchain_quickjs import CodeInterpreterMiddleware
from langgraph.checkpoint.memory import MemorySaver
checkpointer = MemorySaver()
backend = StateBackend()
skill_url = "https://raw.githubusercontent.com/langchain-ai/deepagents/refs/heads/main/libs/cli/examples/skills/langgraph-docs/SKILL.md"
with urlopen(skill_url) as response:
skill_content = response.read().decode('utf-8')
skills_files = {
"/skills/langgraph-docs/SKILL.md": create_file_data(skill_content),
}
agent = create_deep_agent(
model="ollama:devstral-2",
backend=backend,
skills=["/skills/"],
checkpointer=checkpointer,
middleware=[CodeInterpreterMiddleware(skills_backend=backend)], # for interpreter skills
)
result = agent.invoke(
{
"messages": [{"role": "user", "content": "What is langgraph?"}],
# Seed the default StateBackend's in-state filesystem (virtual paths must start with "/").
"files": skills_files,
},
config={"configurable": {"thread_id": "12345"}},
)
from urllib.request import urlopen
from deepagents import create_deep_agent
from deepagents.backends import StoreBackend
from deepagents.backends.utils import create_file_data
from langchain_quickjs import CodeInterpreterMiddleware
from langgraph.store.memory import InMemoryStore
store = InMemoryStore()
backend = StoreBackend(namespace=lambda _rt: ("filesystem",))
skill_url = "https://raw.githubusercontent.com/langchain-ai/deepagents/refs/heads/main/libs/cli/examples/skills/langgraph-docs/SKILL.md"
with urlopen(skill_url) as response:
skill_content = response.read().decode('utf-8')
store.put(
namespace=("filesystem",),
key="/skills/langgraph-docs/SKILL.md",
value=create_file_data(skill_content),
)
agent = create_deep_agent(
model="google_genai:gemini-3.1-pro-preview",
backend=backend,
store=store,
skills=["/skills/"],
middleware=[CodeInterpreterMiddleware(skills_backend=backend)],
)
result = agent.invoke(
{"messages": [{"role": "user", "content": "What is langgraph?"}]},
config={"configurable": {"thread_id": "12345"}},
)
from deepagents import create_deep_agent
from deepagents.backends.filesystem import FilesystemBackend
from langchain_quickjs import CodeInterpreterMiddleware
from langgraph.checkpoint.memory import MemorySaver
# Checkpointer is REQUIRED for human-in-the-loop
checkpointer = MemorySaver()
root_dir = "/Users/user/{project}"
backend = FilesystemBackend(root_dir=root_dir)
agent = create_deep_agent(
model="google_genai:gemini-3.1-pro-preview",
backend=backend,
skills=[str(Path(root_dir) / "skills")],
interrupt_on={
"write_file": True,
"read_file": False,
"edit_file": True,
},
checkpointer=checkpointer, # Required!
middleware=[CodeInterpreterMiddleware(skills_backend=backend)], # for interpreter skills
)
result = agent.invoke(
{"messages": [{"role": "user", "content": "What is langgraph?"}]},
config={"configurable": {"thread_id": "12345"}},
)
Memory
UseAGENTS.md files to provide extra context to your deep agent.
You can pass one or more file paths to the memory parameter when creating your deep agent:
- StateBackend
- StoreBackend
- FilesystemBackend
from urllib.request import urlopen
from deepagents import create_deep_agent
from deepagents.backends.utils import create_file_data
from langgraph.checkpoint.memory import MemorySaver
with urlopen(
"https://raw.githubusercontent.com/langchain-ai/deepagents/refs/heads/main/examples/text-to-sql-agent/AGENTS.md"
) as response:
agents_md = response.read().decode("utf-8")
checkpointer = MemorySaver()
agent = create_deep_agent(
model="google_genai:gemini-3.1-pro-preview",
memory=[
"/AGENTS.md"
],
checkpointer=checkpointer,
)
result = agent.invoke(
{
"messages": [
{
"role": "user",
"content": "Please tell me what's in your memory files.",
}
],
# Seed the default StateBackend's in-state filesystem (virtual paths must start with "/").
"files": {"/AGENTS.md": create_file_data(agents_md)},
},
config={"configurable": {"thread_id": "123456"}},
)
from urllib.request import urlopen
from deepagents import create_deep_agent
from deepagents.backends.utils import create_file_data
from langgraph.checkpoint.memory import MemorySaver
with urlopen(
"https://raw.githubusercontent.com/langchain-ai/deepagents/refs/heads/main/examples/text-to-sql-agent/AGENTS.md"
) as response:
agents_md = response.read().decode("utf-8")
checkpointer = MemorySaver()
agent = create_deep_agent(
model="openai:gpt-5.4",
memory=[
"/AGENTS.md"
],
checkpointer=checkpointer,
)
result = agent.invoke(
{
"messages": [
{
"role": "user",
"content": "Please tell me what's in your memory files.",
}
],
# Seed the default StateBackend's in-state filesystem (virtual paths must start with "/").
"files": {"/AGENTS.md": create_file_data(agents_md)},
},
config={"configurable": {"thread_id": "123456"}},
)
from urllib.request import urlopen
from deepagents import create_deep_agent
from deepagents.backends.utils import create_file_data
from langgraph.checkpoint.memory import MemorySaver
with urlopen(
"https://raw.githubusercontent.com/langchain-ai/deepagents/refs/heads/main/examples/text-to-sql-agent/AGENTS.md"
) as response:
agents_md = response.read().decode("utf-8")
checkpointer = MemorySaver()
agent = create_deep_agent(
model="anthropic:claude-sonnet-4-6",
memory=[
"/AGENTS.md"
],
checkpointer=checkpointer,
)
result = agent.invoke(
{
"messages": [
{
"role": "user",
"content": "Please tell me what's in your memory files.",
}
],
# Seed the default StateBackend's in-state filesystem (virtual paths must start with "/").
"files": {"/AGENTS.md": create_file_data(agents_md)},
},
config={"configurable": {"thread_id": "123456"}},
)
from urllib.request import urlopen
from deepagents import create_deep_agent
from deepagents.backends.utils import create_file_data
from langgraph.checkpoint.memory import MemorySaver
with urlopen(
"https://raw.githubusercontent.com/langchain-ai/deepagents/refs/heads/main/examples/text-to-sql-agent/AGENTS.md"
) as response:
agents_md = response.read().decode("utf-8")
checkpointer = MemorySaver()
agent = create_deep_agent(
model="openrouter:anthropic/claude-sonnet-4-6",
memory=[
"/AGENTS.md"
],
checkpointer=checkpointer,
)
result = agent.invoke(
{
"messages": [
{
"role": "user",
"content": "Please tell me what's in your memory files.",
}
],
# Seed the default StateBackend's in-state filesystem (virtual paths must start with "/").
"files": {"/AGENTS.md": create_file_data(agents_md)},
},
config={"configurable": {"thread_id": "123456"}},
)
from urllib.request import urlopen
from deepagents import create_deep_agent
from deepagents.backends.utils import create_file_data
from langgraph.checkpoint.memory import MemorySaver
with urlopen(
"https://raw.githubusercontent.com/langchain-ai/deepagents/refs/heads/main/examples/text-to-sql-agent/AGENTS.md"
) as response:
agents_md = response.read().decode("utf-8")
checkpointer = MemorySaver()
agent = create_deep_agent(
model="fireworks:accounts/fireworks/models/qwen3p5-397b-a17b",
memory=[
"/AGENTS.md"
],
checkpointer=checkpointer,
)
result = agent.invoke(
{
"messages": [
{
"role": "user",
"content": "Please tell me what's in your memory files.",
}
],
# Seed the default StateBackend's in-state filesystem (virtual paths must start with "/").
"files": {"/AGENTS.md": create_file_data(agents_md)},
},
config={"configurable": {"thread_id": "123456"}},
)
from urllib.request import urlopen
from deepagents import create_deep_agent
from deepagents.backends.utils import create_file_data
from langgraph.checkpoint.memory import MemorySaver
with urlopen(
"https://raw.githubusercontent.com/langchain-ai/deepagents/refs/heads/main/examples/text-to-sql-agent/AGENTS.md"
) as response:
agents_md = response.read().decode("utf-8")
checkpointer = MemorySaver()
agent = create_deep_agent(
model="baseten:zai-org/GLM-5",
memory=[
"/AGENTS.md"
],
checkpointer=checkpointer,
)
result = agent.invoke(
{
"messages": [
{
"role": "user",
"content": "Please tell me what's in your memory files.",
}
],
# Seed the default StateBackend's in-state filesystem (virtual paths must start with "/").
"files": {"/AGENTS.md": create_file_data(agents_md)},
},
config={"configurable": {"thread_id": "123456"}},
)
from urllib.request import urlopen
from deepagents import create_deep_agent
from deepagents.backends.utils import create_file_data
from langgraph.checkpoint.memory import MemorySaver
with urlopen(
"https://raw.githubusercontent.com/langchain-ai/deepagents/refs/heads/main/examples/text-to-sql-agent/AGENTS.md"
) as response:
agents_md = response.read().decode("utf-8")
checkpointer = MemorySaver()
agent = create_deep_agent(
model="ollama:devstral-2",
memory=[
"/AGENTS.md"
],
checkpointer=checkpointer,
)
result = agent.invoke(
{
"messages": [
{
"role": "user",
"content": "Please tell me what's in your memory files.",
}
],
# Seed the default StateBackend's in-state filesystem (virtual paths must start with "/").
"files": {"/AGENTS.md": create_file_data(agents_md)},
},
config={"configurable": {"thread_id": "123456"}},
)
from urllib.request import urlopen
from deepagents import create_deep_agent
from deepagents.backends import StoreBackend
from deepagents.backends.utils import create_file_data
from langgraph.store.memory import InMemoryStore
with urlopen(
"https://raw.githubusercontent.com/langchain-ai/deepagents/refs/heads/main/examples/text-to-sql-agent/AGENTS.md"
) as response:
agents_md = response.read().decode("utf-8")
# Create the store and add the file to it
store = InMemoryStore()
file_data = create_file_data(agents_md)
store.put(
namespace=("filesystem",),
key="/AGENTS.md",
value=file_data,
)
agent = create_deep_agent(
model="google_genai:gemini-3.1-pro-preview",
backend=StoreBackend(namespace=lambda _rt: ("filesystem",)),
store=store,
memory=["/AGENTS.md"],
)
result = agent.invoke(
{
"messages": [
{
"role": "user",
"content": "Please tell me what's in your memory files.",
}
],
"files": {"/AGENTS.md": create_file_data(agents_md)},
},
config={"configurable": {"thread_id": "12345"}},
)
from urllib.request import urlopen
from deepagents import create_deep_agent
from deepagents.backends import StoreBackend
from deepagents.backends.utils import create_file_data
from langgraph.store.memory import InMemoryStore
with urlopen(
"https://raw.githubusercontent.com/langchain-ai/deepagents/refs/heads/main/examples/text-to-sql-agent/AGENTS.md"
) as response:
agents_md = response.read().decode("utf-8")
# Create the store and add the file to it
store = InMemoryStore()
file_data = create_file_data(agents_md)
store.put(
namespace=("filesystem",),
key="/AGENTS.md",
value=file_data,
)
agent = create_deep_agent(
model="openai:gpt-5.4",
backend=StoreBackend(namespace=lambda _rt: ("filesystem",)),
store=store,
memory=["/AGENTS.md"],
)
result = agent.invoke(
{
"messages": [
{
"role": "user",
"content": "Please tell me what's in your memory files.",
}
],
"files": {"/AGENTS.md": create_file_data(agents_md)},
},
config={"configurable": {"thread_id": "12345"}},
)
from urllib.request import urlopen
from deepagents import create_deep_agent
from deepagents.backends import StoreBackend
from deepagents.backends.utils import create_file_data
from langgraph.store.memory import InMemoryStore
with urlopen(
"https://raw.githubusercontent.com/langchain-ai/deepagents/refs/heads/main/examples/text-to-sql-agent/AGENTS.md"
) as response:
agents_md = response.read().decode("utf-8")
# Create the store and add the file to it
store = InMemoryStore()
file_data = create_file_data(agents_md)
store.put(
namespace=("filesystem",),
key="/AGENTS.md",
value=file_data,
)
agent = create_deep_agent(
model="anthropic:claude-sonnet-4-6",
backend=StoreBackend(namespace=lambda _rt: ("filesystem",)),
store=store,
memory=["/AGENTS.md"],
)
result = agent.invoke(
{
"messages": [
{
"role": "user",
"content": "Please tell me what's in your memory files.",
}
],
"files": {"/AGENTS.md": create_file_data(agents_md)},
},
config={"configurable": {"thread_id": "12345"}},
)
from urllib.request import urlopen
from deepagents import create_deep_agent
from deepagents.backends import StoreBackend
from deepagents.backends.utils import create_file_data
from langgraph.store.memory import InMemoryStore
with urlopen(
"https://raw.githubusercontent.com/langchain-ai/deepagents/refs/heads/main/examples/text-to-sql-agent/AGENTS.md"
) as response:
agents_md = response.read().decode("utf-8")
# Create the store and add the file to it
store = InMemoryStore()
file_data = create_file_data(agents_md)
store.put(
namespace=("filesystem",),
key="/AGENTS.md",
value=file_data,
)
agent = create_deep_agent(
model="openrouter:anthropic/claude-sonnet-4-6",
backend=StoreBackend(namespace=lambda _rt: ("filesystem",)),
store=store,
memory=["/AGENTS.md"],
)
result = agent.invoke(
{
"messages": [
{
"role": "user",
"content": "Please tell me what's in your memory files.",
}
],
"files": {"/AGENTS.md": create_file_data(agents_md)},
},
config={"configurable": {"thread_id": "12345"}},
)
from urllib.request import urlopen
from deepagents import create_deep_agent
from deepagents.backends import StoreBackend
from deepagents.backends.utils import create_file_data
from langgraph.store.memory import InMemoryStore
with urlopen(
"https://raw.githubusercontent.com/langchain-ai/deepagents/refs/heads/main/examples/text-to-sql-agent/AGENTS.md"
) as response:
agents_md = response.read().decode("utf-8")
# Create the store and add the file to it
store = InMemoryStore()
file_data = create_file_data(agents_md)
store.put(
namespace=("filesystem",),
key="/AGENTS.md",
value=file_data,
)
agent = create_deep_agent(
model="fireworks:accounts/fireworks/models/qwen3p5-397b-a17b",
backend=StoreBackend(namespace=lambda _rt: ("filesystem",)),
store=store,
memory=["/AGENTS.md"],
)
result = agent.invoke(
{
"messages": [
{
"role": "user",
"content": "Please tell me what's in your memory files.",
}
],
"files": {"/AGENTS.md": create_file_data(agents_md)},
},
config={"configurable": {"thread_id": "12345"}},
)
from urllib.request import urlopen
from deepagents import create_deep_agent
from deepagents.backends import StoreBackend
from deepagents.backends.utils import create_file_data
from langgraph.store.memory import InMemoryStore
with urlopen(
"https://raw.githubusercontent.com/langchain-ai/deepagents/refs/heads/main/examples/text-to-sql-agent/AGENTS.md"
) as response:
agents_md = response.read().decode("utf-8")
# Create the store and add the file to it
store = InMemoryStore()
file_data = create_file_data(agents_md)
store.put(
namespace=("filesystem",),
key="/AGENTS.md",
value=file_data,
)
agent = create_deep_agent(
model="baseten:zai-org/GLM-5",
backend=StoreBackend(namespace=lambda _rt: ("filesystem",)),
store=store,
memory=["/AGENTS.md"],
)
result = agent.invoke(
{
"messages": [
{
"role": "user",
"content": "Please tell me what's in your memory files.",
}
],
"files": {"/AGENTS.md": create_file_data(agents_md)},
},
config={"configurable": {"thread_id": "12345"}},
)
from urllib.request import urlopen
from deepagents import create_deep_agent
from deepagents.backends import StoreBackend
from deepagents.backends.utils import create_file_data
from langgraph.store.memory import InMemoryStore
with urlopen(
"https://raw.githubusercontent.com/langchain-ai/deepagents/refs/heads/main/examples/text-to-sql-agent/AGENTS.md"
) as response:
agents_md = response.read().decode("utf-8")
# Create the store and add the file to it
store = InMemoryStore()
file_data = create_file_data(agents_md)
store.put(
namespace=("filesystem",),
key="/AGENTS.md",
value=file_data,
)
agent = create_deep_agent(
model="ollama:devstral-2",
backend=StoreBackend(namespace=lambda _rt: ("filesystem",)),
store=store,
memory=["/AGENTS.md"],
)
result = agent.invoke(
{
"messages": [
{
"role": "user",
"content": "Please tell me what's in your memory files.",
}
],
"files": {"/AGENTS.md": create_file_data(agents_md)},
},
config={"configurable": {"thread_id": "12345"}},
)
from deepagents import create_deep_agent
from deepagents.backends import FilesystemBackend
from langgraph.checkpoint.memory import MemorySaver
# Checkpointer is REQUIRED for human-in-the-loop
checkpointer = MemorySaver()
agent = create_deep_agent(
model="google_genai:gemini-3.1-pro-preview",
backend=FilesystemBackend(root_dir="/Users/user/{project}"),
memory=[
"./AGENTS.md"
],
interrupt_on={
"write_file": True, # Default: approve, edit, reject
"read_file": False, # No interrupts needed
"edit_file": True, # Default: approve, edit, reject
},
checkpointer=checkpointer, # Required!
)
from deepagents import create_deep_agent
from deepagents.backends import FilesystemBackend
from langgraph.checkpoint.memory import MemorySaver
# Checkpointer is REQUIRED for human-in-the-loop
checkpointer = MemorySaver()
agent = create_deep_agent(
model="openai:gpt-5.4",
backend=FilesystemBackend(root_dir="/Users/user/{project}"),
memory=[
"./AGENTS.md"
],
interrupt_on={
"write_file": True, # Default: approve, edit, reject
"read_file": False, # No interrupts needed
"edit_file": True, # Default: approve, edit, reject
},
checkpointer=checkpointer, # Required!
)
from deepagents import create_deep_agent
from deepagents.backends import FilesystemBackend
from langgraph.checkpoint.memory import MemorySaver
# Checkpointer is REQUIRED for human-in-the-loop
checkpointer = MemorySaver()
agent = create_deep_agent(
model="anthropic:claude-sonnet-4-6",
backend=FilesystemBackend(root_dir="/Users/user/{project}"),
memory=[
"./AGENTS.md"
],
interrupt_on={
"write_file": True, # Default: approve, edit, reject
"read_file": False, # No interrupts needed
"edit_file": True, # Default: approve, edit, reject
},
checkpointer=checkpointer, # Required!
)
from deepagents import create_deep_agent
from deepagents.backends import FilesystemBackend
from langgraph.checkpoint.memory import MemorySaver
# Checkpointer is REQUIRED for human-in-the-loop
checkpointer = MemorySaver()
agent = create_deep_agent(
model="openrouter:anthropic/claude-sonnet-4-6",
backend=FilesystemBackend(root_dir="/Users/user/{project}"),
memory=[
"./AGENTS.md"
],
interrupt_on={
"write_file": True, # Default: approve, edit, reject
"read_file": False, # No interrupts needed
"edit_file": True, # Default: approve, edit, reject
},
checkpointer=checkpointer, # Required!
)
from deepagents import create_deep_agent
from deepagents.backends import FilesystemBackend
from langgraph.checkpoint.memory import MemorySaver
# Checkpointer is REQUIRED for human-in-the-loop
checkpointer = MemorySaver()
agent = create_deep_agent(
model="fireworks:accounts/fireworks/models/qwen3p5-397b-a17b",
backend=FilesystemBackend(root_dir="/Users/user/{project}"),
memory=[
"./AGENTS.md"
],
interrupt_on={
"write_file": True, # Default: approve, edit, reject
"read_file": False, # No interrupts needed
"edit_file": True, # Default: approve, edit, reject
},
checkpointer=checkpointer, # Required!
)
from deepagents import create_deep_agent
from deepagents.backends import FilesystemBackend
from langgraph.checkpoint.memory import MemorySaver
# Checkpointer is REQUIRED for human-in-the-loop
checkpointer = MemorySaver()
agent = create_deep_agent(
model="baseten:zai-org/GLM-5",
backend=FilesystemBackend(root_dir="/Users/user/{project}"),
memory=[
"./AGENTS.md"
],
interrupt_on={
"write_file": True, # Default: approve, edit, reject
"read_file": False, # No interrupts needed
"edit_file": True, # Default: approve, edit, reject
},
checkpointer=checkpointer, # Required!
)
from deepagents import create_deep_agent
from deepagents.backends import FilesystemBackend
from langgraph.checkpoint.memory import MemorySaver
# Checkpointer is REQUIRED for human-in-the-loop
checkpointer = MemorySaver()
agent = create_deep_agent(
model="ollama:devstral-2",
backend=FilesystemBackend(root_dir="/Users/user/{project}"),
memory=[
"./AGENTS.md"
],
interrupt_on={
"write_file": True, # Default: approve, edit, reject
"read_file": False, # No interrupts needed
"edit_file": True, # Default: approve, edit, reject
},
checkpointer=checkpointer, # Required!
)
Profiles
A harness profile packages per-provider or per-model tweaks (system prompt suffixes, tool description overrides, excluded tools or middleware, extra middleware, and general-purpose subagent edits) socreate_deep_agent applies them automatically when the matching model is selected.
from deepagents import HarnessProfile, register_harness_profile
# Append a system-prompt suffix whenever gpt-5.4 is selected.
register_harness_profile(
"openai:gpt-5.4",
HarnessProfile(system_prompt_suffix="Respond in under 100 words."),
)
Structured output
Deep Agents support structured output. You can set a desired structured output schema by passing it as theresponse_format argument to the call to create_deep_agent().
When the model generates the structured data, it’s captured, validated, and returned in the ‘structured_response’ key of the deep agent’s state.
import os
from typing import Literal
from pydantic import BaseModel, Field
from tavily import TavilyClient
from deepagents import create_deep_agent
tavily_client = TavilyClient(api_key=os.environ["TAVILY_API_KEY"])
def internet_search(
query: str,
max_results: int = 5,
topic: Literal["general", "news", "finance"] = "general",
include_raw_content: bool = False,
):
"""Run a web search"""
return tavily_client.search(
query,
max_results=max_results,
include_raw_content=include_raw_content,
topic=topic,
)
class WeatherReport(BaseModel):
"""A structured weather report with current conditions and forecast."""
location: str = Field(description="The location for this weather report")
temperature: float = Field(description="Current temperature in Celsius")
condition: str = Field(
description="Current weather condition (e.g., sunny, cloudy, rainy)"
)
humidity: int = Field(description="Humidity percentage")
wind_speed: float = Field(description="Wind speed in km/h")
forecast: str = Field(description="Brief forecast for the next 24 hours")
agent = create_deep_agent(
model=model,
response_format=WeatherReport,
tools=[internet_search],
)
result = agent.invoke(
{
"messages": [
{
"role": "user",
"content": "What's the weather like in San Francisco?",
}
]
}
)
print(result["structured_response"])
# location='San Francisco, California' temperature=18.3 condition='Sunny' humidity=48 wind_speed=7.6 forecast='Pleasant sunny conditions expected to continue with temperatures around 64°F (18°C) during the day, dropping to around 52°F (11°C) at night. Clear skies with minimal precipitation expected.'
Connect these docs to Claude, VSCode, and more via MCP for real-time answers.

