Extending¶
Every keyword argument create_deep_search_agent does not recognize is passed
through unchanged to create_deep_agent (tools, checkpointer, store,
skills, interrupt_on, ...), so the full deepagents surface stays available.
Adding a retrieval agent (RAG) over an internal knowledge base¶
Extra sub-agents are added alongside the built-in ones. They may not reuse the
reserved names (search-agent, fetch-agent, fact-check-agent).
rag_agent = {
"name": "rag-agent",
"description": "Retrieval over the internal company knowledge base",
"system_prompt": "Search the vector store and save results to findings/.",
"tools": [my_vector_store_tool],
}
agent = create_deep_search_agent(
model="anthropic:claude-sonnet-4-6",
subagents=[rag_agent],
)
Adding search engines¶
search_tools are made available to both search-agent and
fact-check-agent, alongside the built-in SearxNG tool.
from langchain_tavily import TavilySearch
agent = create_deep_search_agent(
model="anthropic:claude-sonnet-4-6",
search_tools=[TavilySearch(max_results=5)],
)
Persistent backend for findings¶
The orchestrator and every sub-agent share a single backend, so the
findings/<source-slug>.md files a sub-agent writes flow back to the
orchestrator on the same filesystem. By default that backend is an ephemeral
StateBackend; pass an explicit backend to point the agent at a real
directory with a FilesystemBackend:
from deepagents.backends import FilesystemBackend
agent = create_deep_search_agent(
model="anthropic:claude-sonnet-4-6",
backend=FilesystemBackend(root_dir="./research", virtual_mode=True),
)
Restricting SearxNG engines¶
agent = create_deep_search_agent(
model="anthropic:claude-sonnet-4-6",
searxng_engines=["duckduckgo", "wikipedia"],
)
Customizing the rubric¶
Pass a newline-delimited checklist as rubric to change how the evaluator
grades answers:
agent = create_deep_search_agent(
model="anthropic:claude-sonnet-4-6",
rubric=(
"- Every claim is backed by at least two independent sources\n"
"- All sources are dated and linked\n"
"- The answer states remaining uncertainties explicitly"
),
)
Collecting session metrics¶
Pass a SessionMetrics instance to observe how much work the orchestrator and
its sub-agents did. The collector is thread-safe and accumulates over every
research cycle (and across successive invocations of the same agent) until you
call reset():
from deep_search_agent import create_deep_search_agent, SessionMetrics
metrics = SessionMetrics()
agent = create_deep_search_agent(
model="anthropic:claude-sonnet-4-6",
metrics=metrics,
)
agent.invoke({"messages": [{"role": "user", "content": "..."}]})
# Typed access:
print(metrics.total_duration) # overall execution time (s)
print(metrics.global_tool_calls) # {tool_name: count} across orchestrator + sub-agents
print(metrics.global_subagent_invocations)
for name, stats in metrics.subagent_stats.items():
print(name, stats.count, stats.avg_time, stats.min_time, stats.max_time)
for cycle in metrics.cycles: # per research cycle
print(cycle.orchestrator_tool_calls, cycle.subagent_invocations)
# Or a JSON-serializable snapshot:
import json
print(json.dumps(metrics.to_dict(), indent=2))
What is recorded, per research cycle and globally:
- how many times the orchestrator called each of its own tools (the
taskdelegation tool is tracked as a sub-agent invocation instead); - how many times each sub-agent was invoked;
- how many times each sub-agent called each of its tools;
- per-sub-agent execution time (average, min, max) and the overall execution time.
Reusing the tools standalone¶
The tool factories are part of the public API and can be used outside the agent: