LangChain Deep Agents: what it is and how to run it on your own model
Deep Agents is a ready-made harness on top of LangChain: files, subagents, context summarization. What is inside, how to run it via a gateway and what it costs.
5 min · · агенты · development
LangChain Deep Agents is a separate library, deepagents, that builds around the "model calls tools" loop what long tasks usually fall apart without: a virtual filesystem, subagents, context management and optional planning. Below: what is inside Deep Agents, how it differs from a regular LangChain agent, and how to run an example on a model you chose yourself through an OpenAI-compatible gateway. We rely on the LangChain documentation (the Deep Agents section); check package versions and parameter names against it, as they evolve quickly.
LangChain Deep Agents: what is inside and how it differs from create_agent
The LangChain documentation calls Deep Agents an "agent harness": the same tool-calling loop as other frameworks, but with ready-made capabilities. They fall into four groups:
- Execution environment: tools, a virtual filesystem (
ls,read_file,write_file,edit_file,glob,grep), optionally a sandbox. - Context management: skills, memory, automatic history summarization and offloading large tool results to files.
- Delegation: a built-in
tasktool for launching subagents in an isolated context, and an optionalwrite_todosfor a plan. - Human steering: pausing for approval of sensitive calls (
interrupt_on).
For comparison, a plain LangChain create_agent is a minimal harness of model, tools, prompt and middleware where you assemble the rest yourself. Deep Agents is built on top of it and uses the LangGraph runtime. If you want an out-of-the-box agent for multi-step file work, take Deep Agents. If you want full manual control, take create_agent (gateway setup for LangChain is described in the LangChain guide).
Install and run on a model through the gateway
In the documentation examples the model is a string like provider:model. For your own address it is more convenient to pass a ready model object: the documentation explicitly allows a "configured model instance". For Zukko that is ChatOpenAI with base_url:
pip install deepagents langchain-openai
export ZUKKO_API_KEY="fetch_your_key"import os
from langchain_openai import ChatOpenAI
from deepagents import create_deep_agent
TICKETS = {
"101": "The confirmation email never arrives, my mailbox is on mail.ru.",
"102": "Payment went through but the balance was not topped up. Paid last night.",
"103": "How do I change the e-mail in my profile? The old mailbox is unavailable.",
}
def read_ticket(ticket_id: str) -> str:
"""Return the ticket text by its number."""
return TICKETS.get(ticket_id, "Ticket not found")This is the minimal launch: create_deep_agent(model=..., tools=[...], system_prompt=...). The documentation requires a model with tool calling support. If you are unsure whether your choice fits, test it on your task (the list of models comes from GET https://api.zukko.pro/v1/models).
Note the format: according to the documentation, an "openai:..." string in Deep Agents enables the Responses API, so for a custom address we pass a ChatOpenAI object rather than a string. For OpenAI clients the Zukko address ends with /v1.
Subagents: a cheap model for heavy lifting
Subagents in Deep Agents are described by dicts with the fields name, description, system_prompt and an optional model. A subagent works in its own context and returns a single final report, so long file reading does not bloat the main agent's context. And the model field lets you hand routine work to a cheap model:
cheap_model = ChatOpenAI(
model="deepseek-v4.1-flash",
base_url="https://api.zukko.pro/v1",
api_key=os.environ["ZUKKO_API_KEY"],
)
agent = create_deep_agent(
model=main_model,
tools=[read_ticket],
subagents=[{
"name": "ticket-reader",
"description": "Reads one ticket and returns its topic and gist in two sentences.",
"system_prompt": "Read the ticket via read_ticket and return the topic and gist.",
"tools": [read_ticket],
"model": cheap_model,
}],
system_prompt="You are a support analyst. Delegate ticket reading to the subagent.",
)Whether the agent decides to delegate depends on the model and the prompt: check in the trace that the subagent is actually called. The cascade scheme itself is covered in the article on model cascades.
Planning and middleware
Planning in Deep Agents (the write_todos tool) is explicit as of version 0.7: you pass TodoListMiddleware in the middleware parameter. The documentation notes that a plan is especially useful on long tasks and weaker models.
from langchain.agents.middleware import TodoListMiddleware
agent = create_deep_agent(
model=main_model,
tools=[read_ticket],
middleware=[TodoListMiddleware()],
)Middleware is a general LangChain mechanism: code that wraps the model call and tool calls. In Deep Agents the filesystem, subagents and memory are built on it. You can add your own middleware through the same parameter, and human approval is turned on through interrupt_on, for example interrupt_on={"edit_file": True}.
What it costs
An agent loop is expensive because every step resends the accumulated context. The estimate formula: number of model calls × average input × input price + number of calls × average output × output price. Say 30 calls, average input 20,000 tokens, output 1,000. That is 600,000 input tokens and 30,000 output tokens in total. Prices as of October 18, 2026, OpenAI format (the whole input at the input price):
| Model | Input, $ per 1M | Output, $ per 1M | Math | Total |
|---|---|---|---|---|
claude-sonnet-5-5 | 0.4 | 2 | 0.6 × 0.4 + 0.03 × 2 = 0.24 + 0.06 | $0.30 |
gpt-6.1-sol | 0.27 | 1.32 | 0.6 × 0.27 + 0.03 × 1.32 = 0.162 + 0.0396 | $0.2016 |
deepseek-v4.1-flash | 0.013 | 0.038 | 0.6 × 0.013 + 0.03 × 0.038 = 0.0078 + 0.00114 | $0.00894 |
The formula uses millions of tokens: 600,000 tokens is 0.6M. Mind one limitation: subagent tokens do not appear in the main agent's result["messages"], so for exact accounting compare the balance before and after a run (GET /v1/balance and the "Usage" section in the dashboard) or enable LangSmith tracing.
Cache: the Anthropic format
According to the documentation, for Anthropic models Deep Agents automatically marks the static parts of the system prompt for caching. For Claude, Zukko gives the cache discount only in the Anthropic format (/v1/messages), so for long sessions you can use ChatAnthropic with base_url="https://api.zukko.pro" (without /v1, the client adds the path itself). The math for a 15,000-token static prefix and 30 calls on claude-sonnet-5-5 (cache write $0.5, read $0.05 per 1M): without cache 30 × 15,000 × 0.4 / 1M = $0.18, with cache 15,000 × 0.5 / 1M + 29 × 15,000 × 0.05 / 1M = 0.0075 + 0.02175 ≈ $0.029. This holds only if the provider actually reports cache reads: check the usage fields in the response. More: cache in Zukko.
Do not let the agent go into the red
An autonomous agent can loop. Create a separate key for it with a daily dollar limit and a list of allowed models, and cap the number of steps in code (recursion_limit in the call config). More: the agent looped.
FAQ
How does Deep Agents differ from LangGraph?
LangGraph is a low-level runtime for graphs, while Deep Agents is a ready agent on top of it and LangChain. The choice depends on whether you need manual orchestration.
Must I use the models from the documentation examples?
No. Strings like anthropic:claude-sonnet-5 in the documentation are only examples; through ChatOpenAI(base_url=...) you can plug in any gateway model that supports tools. GLM models in Zukko have a 128K context while the others in the examples have 1M, keep that in mind for long sessions.
The subagent is never called. What now?
Refine the subagent's description (the main agent uses it to decide whom to call) and add a direct instruction to delegate in the system prompt. Make sure from the trace that the task tool is invoked.
Do I need LangSmith?
No, it is optional, but tracing helps you see the steps and the subagents' tokens.
To try it, create a key in the dashboard, set a daily limit and run the example above.
zukko
Pay 25×
less
for Claude Code & ChatGPT
One fetch_* key and base URL api.zukko.pro — for Cursor, Claude Code, Codex, and any SDK.
Related articles
- Prompt Injection: What It Is and How to Protect a Bot and an AgentHow prompt injection works through user input and third-party documents, and which measures limit the damage: data isolation, tool permissions, key limits.
- Claude Code YOLO: Permission Modes and Working Without PromptsClaude Code has no mode literally called YOLO, but it has several permission modes and flexible rules. How to stop clicking Yes without losing files.
- Claude Code: a checklist of best practices for daily workHabits that make working with Claude Code predictable: a short CLAUDE.md, a plan before edits, small tasks, checking results and keeping spend under control.
- An MCP server in Java: a minimal example with one toolWe write a minimal MCP server in Java with one tool, register it in Claude Code, and learn to find the cause when the agent doesn't see it.