Delegate AI Work to Subagents
Build a multi-agent workflow and compare its cost and speed to a single agent.
Introduction
30 Second Summary
Complex work becomes harder when one person handles every stage. The same bottleneck appears when one digital assistant handles an entire request.
In this project, you will build a Python AI agent with specialist subagents using deepagents. You will trace their handoffs before comparing the result with a single-agent run.
What You'll Build
You will watch the main agent coordinate specialist work while a trace reveals every handoff.
By the end of this project, you'll have:
- Delegated research that shows the main agent spawning a search-enabled research subagent.
- Specialist writing that shows a lower-cost writer subagent receiving the draft without tool access.
- A visible trace of the subagent order. A comparison table for time, tokens, and cost.
- Secret Mission: An optional challenge to push your skills further.
Are there any prerequisites?
You need Python plus an LLM API key before you begin. Step 1 guides you through both setup checks.
Before We Start
Specialist subagents need a stable place to run before the main agent can delegate any work.
This step prepares Python 3.11 or later for Deep Agents. You will isolate the package in a virtual environment.
Your model credential stays in an environment variable. This keeps the credential out of the Python script you build next.
In this step, get ready to:
- Confirm that your Python runtime meets the minimum version.
- Prepare an active virtual environment with the deepagents package installed.
- Store your model provider key in an environment variable.
Confirm Python is ready
Deep Agents requires Python 3.11 or later. Checking the installed version now prevents dependency errors during installation.
- Press Cmd+Space on macOS or the Windows key on Windows to open system search.
- Type Terminal on macOS or PowerShell on Windows.
- Press Enter to open the terminal.
macOS
- Check your installed Python version by running this command:
python3 --version
What does this command do?
The command asks the Python executable to report its version. The first two numbers tell you whether the runtime meets the minimum requirement.
Windows
- Check your installed Python version by running this command:
python --version
What does this command do?
The command asks the Python executable to report its version. The first two numbers tell you whether the runtime meets the minimum requirement.
✔️ I see version 3.11 or higher
Your Python runtime meets the requirement when the version is 3.11 or higher. That clears the first compatibility check.
ⓧ I see an older version
Your current command points to a Python version below 3.11. A supported release gives deepagents the runtime features it expects.
- Visit the official Python downloads page.
- Download the latest stable Python 3 release for your operating system.
- Complete the installer using its recommended options.
- Close your current terminal after the installation finishes.
- Open a fresh terminal through system search.
- Repeat the version check for your operating system.
You are ready to continue when the output reports Python 3.11 or higher.
ⓧ Command not found
Your terminal cannot find a Python installation yet. Installing the current stable release adds the runtime needed for this project.
- Visit the official Python downloads page.
- Download the latest stable Python 3 release for your operating system.
- Complete the installer using its recommended options.
- Close your current terminal after the installation finishes.
- Open a fresh terminal through system search.
- Repeat the version check for your operating system.
You are ready to continue when the output reports Python 3.11 or higher.
Prepare the Python environment
A virtual environment gives this project its own package space. Its dependencies stay separate from the packages used by other Python projects.
macOS
- Create the .venv environment in your home folder by running these commands:
cd ~
python3 -m venv .venv
source .venv/bin/activate
What do these commands do?
- The first command moves your terminal to your home folder.
- The second command creates an isolated Python environment named .venv.
- The third command activates that environment for the current terminal session.
You should see (.venv) at the start of your terminal prompt. That prefix confirms the isolated environment is active.
Missing the environment prefix?
Check that the environment folder is named exactly .venv. A different name changes the activation path.
Still stuck? Help me activate my Python virtual environment on macOS.
Windows
- Create the .venv environment in your home folder by running these commands:
cd ~
python -m venv .venv
.venv\Scripts\Activate.ps1
What do these commands do?
- The first command moves your terminal to your home folder.
- The second command creates an isolated Python environment named .venv.
- The third command activates that environment in PowerShell.
You should see (.venv) at the start of your PowerShell prompt. That prefix confirms the isolated environment is active.
Activation command blocked?
PowerShell may block local activation scripts because of its execution policy. Use the error details to confirm that script execution caused the failure.
Still stuck? Help me activate my Python virtual environment in PowerShell.
- Install deepagents with its required dependencies by running this command in the active environment:
pip install deepagents
What does this command do?
The pip installer downloads deepagents into the active virtual environment. It also installs the Python packages that Deep Agents depends on.
The terminal should display downloaded packages. It should return to the (.venv) prompt without an installation error.
Package installation failed?
Confirm that (.venv) still appears at the start of the prompt. An inactive environment can send the installation to a different Python runtime.
Still stuck? Help me diagnose my Deep Agents installation error.
Store the model key safely
An API key authorizes model requests under your provider account. Treat the key like a password because another person could use it to make requests.
You will use Google AI Studio for the model credential. The terminal stores the key for the current session without placing it inside your script.
Keep the key private
The provider shows your credential so you can copy it into your own environment. Keep it out of screenshots as you complete this step.
- Open the official Gemini API key instructions.
- Follow the page instructions to create or view a Gemini API key.
- Copy the key when it is shown.
- Return to the terminal where (.venv) appears.
macOS
- Replace your-api-key with your copied key. Store it in the current terminal session by running:
export GOOGLE_API_KEY="your-api-key"
How is the key stored?
The GOOGLE_API_KEY environment variable becomes available to programs launched from this terminal. Your Python process can read the credential without placing it in source code.
Windows
- Replace your-api-key with your copied key. Store it in the current PowerShell session by running:
$Env:GOOGLE_API_KEY = "your-api-key"
How is the key stored?
The GOOGLE_API_KEY environment variable becomes available to programs launched from this PowerShell session. Your Python process can read the credential without placing it in source code.
- Leave the terminal open so the active environment remains available.
- Leave the terminal open so the API key remains available.
- Press Cmd+Space on macOS or the Windows key on Windows to open system search.
- Type the name of your installed code editor into the search field.
- Press Enter to open the editor.
- Return to the terminal for the final setup check.
Before you run the check, do you expect Python to confirm both parts of your setup?
- Verify that Python can access the key and import Deep Agents by running this command:
python -c "import os; from deepagents import create_deep_agent; print(bool(os.environ.get('GOOGLE_API_KEY'))); print('deepagents is ready')"
What does this check prove?
- The environment check returns a Boolean value without printing your secret key.
- The import confirms that deepagents is installed in the active Python environment.
You should see True on the first line. You should see deepagents is ready on the second line.
That is the setup complete. Your Python process can import Deep Agents and access the model credential without revealing it.
One of the checks failed?
A False result means the current terminal session cannot read GOOGLE_API_KEY. Repeat the environment variable command in the same terminal.
An import error means the active Python environment cannot find deepagents. Confirm that (.venv) appears before reinstalling the package.
Still stuck? Help me diagnose my final Python environment check.
Your environment is ready for agent work. Next, you will create a single agent and give it its first research task.
Run a Single Agent
Your Python environment can now reach your chosen model without exposing the API key. The next question is how much work one agent can handle on its own.
In this step, you will use the Deep Agents library to create a main agent with delegation disabled. You will give it a fixed research task so its answer becomes the baseline for every comparison later.
In this step, get ready to:
- Create a single main agent with your selected primary model.
- Give the main agent a repeatable research task.
- Run the script and view the answer in your terminal.
Define the single-agent baseline
Deep Agents normally includes a general-purpose subagent. This baseline disables that option so the main agent completes the task without delegation.
- Set your primary model value to provider:model-name using the model that matches the API key from earlier.
- Create a file named agent_comparison.py inside the folder already open in your code editor.
- Paste this baseline configuration into agent_comparison.py.
from deepagents import (
GeneralPurposeSubagentProfile,
HarnessProfile,
create_deep_agent,
register_harness_profile,
)
PRIMARY_MODEL = "[[PRIMARY_MODEL=\"provider:model-name\"]]"
RESEARCH_TASK = (
"Research when a software team should use AI subagents instead of one agent."
" Return three benefits, three risks, and a recommendation."
)
# Remove delegation so this run measures only the main agent
register_harness_profile(
PRIMARY_MODEL,
HarnessProfile(
general_purpose_subagent=GeneralPurposeSubagentProfile(enabled=False)
),
)
# Build the baseline agent with the selected primary model
single_agent = create_deep_agent(
model=PRIMARY_MODEL,
system_prompt="You are a research analyst. Give concise, structured answers.",
)
print(f"Baseline agent ready with {PRIMARY_MODEL}.")
What does this setup do?
- PRIMARY_MODEL stores the model used by the main agent.
- RESEARCH_TASK keeps the prompt identical across later comparisons.
- GeneralPurposeSubagentProfile(enabled=False) removes the built-in delegation option from this baseline.
- create_deep_agent() constructs the main agent with your selected model.
- Save agent_comparison.py.
- Check that the baseline agent can be created by running this command:
python agent_comparison.py
What does this command do?
The active virtual environment runs agent_comparison.py with its installed dependencies. This first check constructs the agent without sending the research task.
You should see Baseline agent ready with followed by your selected model. Good work. Your script can now construct a main agent without delegation.
Baseline agent not starting?
- Confirm that PRIMARY_MODEL uses the provider and model format supported by your configured API key.
- Confirm that the terminal still shows your active virtual environment before running the script.
- Check that all four imports remain inside the parentheses after the from deepagents import line.
Still stuck? Help me diagnose why my Deep Agents baseline script cannot create the main agent.
Run the research task
The agent is ready, but the baseline needs an actual answer. The final message returned by the run contains the main agent's response.
- In agent_comparison.py, find this line:
print(f"Baseline agent ready with {PRIMARY_MODEL}.")
- Add the following code directly below that line:
# Run the fixed task directly in the main agent
result = single_agent.invoke(
{"messages": [{"role": "user", "content": RESEARCH_TASK}]}
)
# Display the final message so the baseline answer is visible
print("\nSingle-agent answer:\n")
print(result["messages"][-1].content)
What does this run do?
- single_agent.invoke() sends the fixed research task to the main agent.
- result["messages"][-1] selects the final message produced by the run.
- content gives you the answer text that will serve as the comparison baseline.
- Save agent_comparison.py.
✔️ Awesome, I've got everything!
Your file now creates one main agent, runs the fixed research task, and prints the final answer.
ⓧ I'd like to double check the full code
from deepagents import (
GeneralPurposeSubagentProfile,
HarnessProfile,
create_deep_agent,
register_harness_profile,
)
PRIMARY_MODEL = "[[PRIMARY_MODEL=\"provider:model-name\"]]"
RESEARCH_TASK = (
"Research when a software team should use AI subagents instead of one agent."
" Return three benefits, three risks, and a recommendation."
)
# Remove delegation so this run measures only the main agent
register_harness_profile(
PRIMARY_MODEL,
HarnessProfile(
general_purpose_subagent=GeneralPurposeSubagentProfile(enabled=False)
),
)
# Build the baseline agent with the selected primary model
single_agent = create_deep_agent(
model=PRIMARY_MODEL,
system_prompt="You are a research analyst. Give concise, structured answers.",
)
print(f"Baseline agent ready with {PRIMARY_MODEL}.")
# Run the fixed task directly in the main agent
result = single_agent.invoke(
{"messages": [{"role": "user", "content": RESEARCH_TASK}]}
)
# Display the final message so the baseline answer is visible
print("\nSingle-agent answer:\n")
print(result["messages"][-1].content)
- Run the completed baseline script with this command:
Before you run it, do you expect one agent to produce a complete recommendation from the task alone?
python agent_comparison.py
What does this command prove?
This run sends the fixed prompt through the main agent without a custom research or writer subagent. The displayed response becomes the single-agent result you will compare against later.
You will see Single-agent answer: followed by a model-generated response covering benefits, risks, and a recommendation. That is your baseline complete. The main agent can accept the research task and return a visible answer.
No answer in the terminal?
- Confirm that the API key environment variable still exists in the terminal session running the script.
- Confirm that result["messages"][-1].content matches the final print statement exactly.
- Check your provider account if the request is rejected before the model returns a response.
Need another pair of eyes? Help me debug why my single Deep Agents run does not print its final answer.
Your single-agent baseline is working. Next, you will give the main loop a specialist research subagent and watch it decide when to delegate.
Add a Research Subagent
Your first Deep Agents run proved that one agent can complete the research task. You now have a working baseline for comparison.
The main loop currently handles every detail itself. In this step, you will give it a specialist research subagent that can search for sources inside its own context.
In this step, get ready to:
- Add a credential-free search tool for the specialist.
- Configure a research specialist for sourced investigation.
- Run the task through the main loop to prove that delegation happened.
Add a focused search tool
A research specialist needs a source it can inspect. This helper searches Wikipedia through the public MediaWiki API.
The helper returns five concise result snippets. That limit keeps raw search output out of the main agent's context.
- In agent_comparison.py, place this block below the existing imports:
import re
import requests
def wikipedia_search(query: str) -> str:
"""Search Wikipedia and return concise result snippets."""
# Query a public endpoint without adding another credential.
response = requests.get(
"https://en.wikipedia.org/w/api.php",
params={
"action": "query",
"format": "json",
"list": "search",
"srsearch": query,
"srlimit": 5,
},
headers={"User-Agent": "NextWork deepagents tutorial"},
timeout=20,
)
response.raise_for_status()
# Keep only readable titles and snippets for the subagent.
results = response.json()["query"]["search"]
return "\n".join(
f"{item['title']}: {re.sub(r'<[^>]+>', '', item['snippet'])}"
for item in results
)
What does this search tool do?
- The query parameter holds the question that the research subagent wants to investigate.
- The request uses the MediaWiki search endpoint to retrieve matching Wikipedia pages.
- The srlimit value caps each search at five results.
- The re.sub() call removes HTML tags from each result snippet.
- Save agent_comparison.py.
- Confirm the baseline still runs after this edit by running this command:
python agent_comparison.py
What does this check prove?
Your existing single-agent answer should print again. That result confirms the new imports are available.
It also confirms that Python can parse the search helper before you give it to the specialist.
Good progress. Your baseline still works with the search capability ready beside it.
Does the baseline stop before answering?
- Confirm that your virtual environment from the previous step is still active.
- Check that every line inside wikipedia_search() uses consistent indentation.
- Confirm that your terminal has an internet connection to reach the search endpoint.
Still stuck? Help me debug the new search helper in agent_comparison.py.
Configure the research subagent
Deep Agents defines a custom subagent with a dictionary. The main loop reads its description to decide when the specialist fits a task.
The tools list acts as the specialist's permission boundary. This configuration gives the research subagent access to wikipedia_search only.
- Copy the model identifier from your existing single-agent configuration into: your existing provider:model identifier.
- Choose the specialist's model by recording its identifier here: your research provider:model identifier.
- Place this configuration below wikipedia_search():
# Give the specialist a narrow research role and one permitted tool.
research_subagent = {
"name": "research-agent",
"description": (
"Researches factual questions with Wikipedia search and returns concise findings."
),
"system_prompt": (
"You are a research specialist. Search before answering. "
"Return a concise summary with the source titles you used."
),
"tools": [wikipedia_search],
"model": "[[RESEARCH_MODEL=\"your research provider:model identifier\"]]",
}
How is the specialist defined?
- The name value becomes the identity shown when the main loop spawns this specialist.
- The description value tells the main loop which tasks belong with this specialist.
- The system_prompt value requires a search before the specialist answers.
- The explicit model value gives the specialist its own model assignment.
- Save agent_comparison.py.
- Confirm that the tools list contains only wikipedia_search.
- Confirm that the model field contains the research model identifier you selected.
Does the subagent configuration look incomplete?
- Check that research_subagent is aligned with the left edge of the file.
- Confirm that every dictionary field has a comma after its value.
- Check that wikipedia_search is defined above this dictionary.
Need another set of eyes? Help me inspect my research subagent configuration.
Run the delegated research task
Registering a specialist gives the coordinator a delegation option. The coordinator prompt makes that option the expected path for every research request.
A streamed run exposes lifecycle events from both agents. You can see the specialist start before the main agent returns its answer.
- Copy your existing research task into: your existing research task.
- Append this function below the existing baseline run in agent_comparison.py:
def run_multi_agent() -> None:
"""Run the task through a visible coordinator and specialist stream."""
# Build a coordinator that must delegate research work.
multi_agent = create_deep_agent(
model="[[PRIMARY_MODEL=\"your existing provider:model identifier\"]]",
system_prompt=(
"Delegate every research request to research-agent with the task tool. "
"Return the specialist's sourced summary."
),
subagents=[research_subagent],
name="main-agent",
)
# Stream agent events so the handoff is visible in the terminal.
stream = multi_agent.stream_events(
{"messages": [{"role": "user", "content": "[[RESEARCH_TASK=\"your existing research task\"]]"}]},
version="v3",
)
for channel, item in stream.interleave("messages", "subagents"):
if channel == "messages" and item.text:
print("[main-agent]", item.text)
elif channel == "subagents":
print(f"[{item.name}] started")
for message in item.messages:
print(f"[{item.name}]", message.text)
print(f"[{item.name}] status: {item.status}")
run_multi_agent()
How does this make delegation visible?
- The subagents argument registers the research specialist with the coordinator.
- The stream_events() call exposes messages from the coordinator plus lifecycle updates from the specialist.
- The interleave() loop prints each event as it arrives.
- The item.name value identifies which specialist the main loop spawned.
- Save agent_comparison.py.
Before you run it, which worker do you expect the main loop to spawn for this research task?
- Run the baseline plus the new multi-agent path with this command:
python agent_comparison.py
What should you see?
- Your original single-agent answer prints from the baseline section.
- A line beginning with [research-agent] started proves that the main loop spawned the specialist.
- Lines prefixed with [research-agent] show messages from the delegated run.
- A line prefixed with [main-agent] contains the coordinator's final response.
That handoff is now real. Your main loop can assign source gathering to a specialist with a restricted tool set.
Did the main agent skip the research specialist?
- Confirm that the coordinator prompt names research-agent exactly.
- Check that subagents=[research_subagent] appears inside the multi-agent configuration.
- Confirm that the delegated task is a research request that requires sourced information.
Still seeing only the main agent? Help me trace why the coordinator is not spawning research-agent.
✔️ Awesome, I've got everything!
Great. Confirm that you saved agent_comparison.py after seeing the research specialist start.
ⓧ I'd like to double check the full code
Compare your complete file with this reference. Keep your model key in its environment variable.
import re
import requests
from deepagents import create_deep_agent
def wikipedia_search(query: str) -> str:
"""Search Wikipedia and return concise result snippets."""
# Query a public endpoint without adding another credential.
response = requests.get(
"https://en.wikipedia.org/w/api.php",
params={
"action": "query",
"format": "json",
"list": "search",
"srsearch": query,
"srlimit": 5,
},
headers={"User-Agent": "NextWork deepagents tutorial"},
timeout=20,
)
response.raise_for_status()
# Keep only readable titles and snippets for the subagent.
results = response.json()["query"]["search"]
return "\n".join(
f"{item['title']}: {re.sub(r'<[^>]+>', '', item['snippet'])}"
for item in results
)
# Give the specialist a narrow research role and one permitted tool.
research_subagent = {
"name": "research-agent",
"description": (
"Researches factual questions with Wikipedia search and returns concise findings."
),
"system_prompt": (
"You are a research specialist. Search before answering. "
"Return a concise summary with the source titles you used."
),
"tools": [wikipedia_search],
"model": "[[RESEARCH_MODEL=\"your research provider:model identifier\"]]",
}
# Preserve the single-agent baseline for the later comparison.
single_agent = create_deep_agent(
model="[[PRIMARY_MODEL=\"your existing provider:model identifier\"]]",
name="single-agent",
)
single_result = single_agent.invoke(
{"messages": [{"role": "user", "content": "[[RESEARCH_TASK=\"your existing research task\"]]"}]}
)
print("Single-agent answer:")
print(single_result["messages"][-1].content)
def run_multi_agent() -> None:
"""Run the task through a visible coordinator and specialist stream."""
# Build a coordinator that must delegate research work.
multi_agent = create_deep_agent(
model="[[PRIMARY_MODEL=\"your existing provider:model identifier\"]]",
system_prompt=(
"Delegate every research request to research-agent with the task tool. "
"Return the specialist's sourced summary."
),
subagents=[research_subagent],
name="main-agent",
)
# Stream agent events so the handoff is visible in the terminal.
stream = multi_agent.stream_events(
{"messages": [{"role": "user", "content": "[[RESEARCH_TASK=\"your existing research task\"]]"}]},
version="v3",
)
for channel, item in stream.interleave("messages", "subagents"):
if channel == "messages" and item.text:
print("[main-agent]", item.text)
elif channel == "subagents":
print(f"[{item.name}] started")
for message in item.messages:
print(f"[{item.name}]", message.text)
print(f"[{item.name}] status: {item.status}")
run_multi_agent()
Your research handoff works. Next up, you will add a writer subagent that turns those findings into a draft without receiving search permission.
Add a Writer Subagent
The research specialist now brings focused material back to your main loop. That proves your Deep Agents agent can delegate a specialist task.
Raw findings still need to become a clear final answer. A writer specialist moves that drafting work onto a lower-cost model with no supplied tools.
In this step, get ready to:
- Configure a writer subagent with a lower-cost model and no supplied tools.
- Route the research material into the writer subagent.
- Run the workflow to verify the research-to-writing handoff.
Configure writer delegation
The writer receives material selected by the main loop. Its narrow role makes the model choice and tool boundary easy to inspect.
What belongs in the writer configuration?
- The name field uniquely identifies the writer subagent.
- The description field tells the main loop to use this specialist for drafting the final response.
- The system_prompt field tells the writer to use supplied research and preserve relevant citations.
- The model field uses your lower-cost provider:model identifier.
- The tools field contains an empty list so the writer receives no supplied tools.
- The subagent list contains both the research specialist and the writer specialist.
- The main agent instructions require research to finish before the material goes to the writer.
- Switch back to agent_comparison.py in the code editor from earlier.
- Find the existing multi-agent configuration that contains the research subagent.
- Update the multi-agent configuration to match every item in the checklist above.
Why use an empty tool list?
An explicitly configured tools field overrides the custom tools that a subagent would otherwise inherit. An empty list keeps the search tool with the research specialist.
The writer works only from the material passed into its delegated task. That boundary makes each specialist responsible for one stage of the workflow.
✔️ Awesome, I've got everything!
Your multi-agent configuration now includes a research specialist and a writer specialist with separate responsibilities.
ⓧ I'd like to double check the full code
- Confirm the original research subagent still has its assigned model and search tool.
- Confirm the writer subagent has its own name, description, system_prompt, model, and tools fields.
- Confirm the writer model is your lower-cost provider:model identifier.
- Confirm the writer's tools field contains an empty list.
- Confirm the subagent list includes both specialists.
- Confirm the main agent instructions send research material to the writer before returning the final answer.
Verify the writer handoff
The configuration becomes useful when the main loop passes one specialist's result into another specialist. The terminal output gives you visible proof of that handoff.
- Save agent_comparison.py.
- In the terminal from earlier, press the Up Arrow key to recall the previous multi-agent run command.
You'll see the previous command at the terminal prompt.
Before you run it, which specialist do you expect to produce the final prose after the research finishes?
- Press Enter to run the multi-agent workflow.
You'll first see evidence that the research specialist handled the information-gathering task. The output then identifies the writer specialist as the recipient of research material or a draft.
That handoff is the key win. One specialist gathers the material while a lower-cost specialist turns it into the written result.
Writer missing from the run?
- Check that the writer subagent appears in the same subagent list as the research specialist.
- Check that the writer description clearly assigns final drafting to that specialist.
- Check that the main agent instructions require the research result to be passed into the writer task.
- Remove any copied search tool from the writer's tools field.
Still stuck? Help me debug why my Deep Agents main loop uses the research subagent but does not delegate the final draft to my writer subagent.
Your agent now separates research from drafting across two specialists. Next, you'll turn on tracing to inspect the order they ran in and the material each one received.
Trace the Subagent Workflow
Your Deep Agents workflow now delegates research to one specialist before passing the material to a writer.
The terminal showed the final answer. It did not expose the full execution order or the context each specialist received.
In this step, you will use LangSmith tracing to inspect the main loop, the research subagent, the writer subagent, and each handoff.
In this step, get ready to:
- Create a tracing key without placing it in your Python script.
- Run the multi-agent workflow with tracing enabled.
- Inspect the execution order and each subagent handoff.
Create a LangSmith tracing key
A trace records the steps produced during one agent request. Its nested structure lets you follow the main loop into each delegated task.
What does a trace capture?
The trace tree preserves the order of model calls, tool calls, and subagent activity.
Each run can include its inputs and outputs. Those details reveal the context available at every handoff.
- Open the LangSmith website in your browser.
- Create an account from the sign-in page if you do not already have one.
- Sign in to LangSmith.
Protect your tracing key
LangSmith displays the key once after creation. Store it securely because the key can submit traces to its selected workspace.
Keep the key outside agent_comparison.py. Do not include it in screenshots.
- Select Settings.
- Select API Keys.
- Select API Key.
- Select Tracing Only.
- Enter subagent workflow trace as the description.
- Select the workspace that will receive this trace.
- Select an expiration date.
- Select Create API Key.
Good progress. You now have a credential limited to submitting trace data for this workflow.
- Copy the tracing key before closing the dialog.
The tracing settings belong in the terminal session that runs the script. The command syntax depends on your operating system.
macOS
- Replace your-langsmith-api-key in the command below with the tracing key you copied.
- Enable tracing in the current terminal by running these commands:
export LANGSMITH_API_KEY="your-langsmith-api-key"
export LANGSMITH_TRACING=true
What do these settings do?
- The LANGSMITH_API_KEY environment variable authenticates trace submission.
- The LANGSMITH_TRACING=true setting enables automatic tracing for the supported agent calls.
- Confirm that the terminal returns to the prompt without an error.
Windows
- Replace your-langsmith-api-key in the command below with the tracing key you copied.
- Enable tracing in the current PowerShell session by running these commands:
$env:LANGSMITH_API_KEY = "your-langsmith-api-key"
$env:LANGSMITH_TRACING = "true"
What do these settings do?
- The LANGSMITH_API_KEY environment variable authenticates trace submission.
- The LANGSMITH_TRACING environment variable enables automatic tracing when its value is true.
- Confirm that PowerShell returns to the prompt without an error.
Tracing key unavailable?
The Tracing Only option requires permission to create tracing keys in the selected workspace. Ask a workspace administrator for access if the option is unavailable.
Still blocked? Help me check my LangSmith tracing-key permissions.
Run the traced workflow
The environment variables wrap the existing multi-agent invocation with tracing. No source-code change is needed inside agent_comparison.py.
Before you rerun the workflow, do you expect tracing to change the written answer or reveal more detail about how the answer was produced?
- Rerun agent_comparison.py in the current terminal with the same command you used for the previous multi-agent run.
- Keep the terminal open until the written result returns.
You should see another research-and-writing result in the terminal. The same run now sends its nested execution record to LangSmith.
Trace missing after the run?
- Confirm that you reran the script in the terminal where you enabled tracing.
- Confirm that you replaced the key placeholder before running the environment commands.
- Confirm that the multi-agent run completed before checking LangSmith.
Need another pair of eyes? Help me diagnose my missing Deep Agents trace.
Inspect the subagent handoffs
The trace connects child runs to the main invocation. Its nesting exposes the execution order while each run's details show the context that reached that step.
Before you open the newest trace, which specialist do you expect the main loop to call first?
- Return to the LangSmith browser tab.
- Select Tracing.
- Select the default tracing project.
- Open the newest completed run.
How to read the trace
The Trajectory view shows the conversation, tool calls, and subagent activity in order.
The Details view exposes a selected run's inputs and outputs. It also shows timing, token counts, errors, and metadata.
- Select Trajectory.
- Locate the original research task in the main loop's input.
- Open the first subagent action.
- Select Details.
- Inspect the research subagent's input.
- Inspect the research subagent's output.
- Return to Trajectory.
- Open the writer subagent action.
You should see the main loop begin with the original task. The research subagent should run before the writer subagent.
- Select Details for the writer subagent.
- Inspect the input passed to the writer subagent.
- Compare the writer input with the research subagent's output.
- Confirm that no search-tool run appears beneath the writer subagent.
What does the handoff prove?
The trace proves that the main loop delegated the research task before delegating the drafting task.
The writer receives research material from the earlier work. Its branch contains writing activity without search-tool access.
Can't find separate subagent runs?
- Confirm that you opened the newest trace created after tracing was enabled.
- Use Details to inspect child runs when the trajectory groups activity together.
- Check that the terminal output showed delegation to both specialists.
Still searching? Help me identify the research and writer handoffs.
That's the workflow exposed. Next, you will compare this traced multi-agent run with the single-agent baseline using time, tokens, and cost.
Compare Cost and Performance
Your trace proved that the main loop can hand research to a specialist subagent. It also proved that drafting can move to a separate specialist.
The remaining question is whether that extra orchestration earns its place. A fair comparison gives the same research task to both Deep Agents workflows.
Your comparison table records elapsed time. It also records token usage plus estimated model cost.
In this step, get ready to:
- Measure elapsed time, token usage, and estimated cost for the single-agent workflow.
- Run the same task through the multi-agent workflow to produce a comparison table.
- Decide when specialization helps enough to justify the orchestration overhead.
Measure the single-agent baseline
A useful benchmark isolates each run. Separate counters stop the baseline from inheriting usage produced by the multi-agent workflow.
The measurement helper uses LangChain's UsageMetadataCallbackHandler to collect usage from every model call within one invocation. A timer measures the full workflow from request to final response.
What should the measurement helper record?
- A new UsageMetadataCallbackHandler captures model usage for one workflow.
- The timer starts immediately before the agent invocation. It stops when the final response returns.
- The callback's usage_metadata groups input_tokens, output_tokens, and total_tokens by model.
- The cost estimate applies each provider's published pricing unit to the matching model counts.
- The helper returns one labelled row containing elapsed time, token usage, and estimated cost.
This benchmark makes fresh model calls, so it can add usage charges. Keep the first pass to one baseline run plus one multi-agent run.
- In agent_comparison.py from earlier, replace the existing baseline invocation with a reusable measurement helper that follows the rules above.
- Add the current published input price plus output price for every model reported in usage_metadata.
- Save agent_comparison.py.
Before you rerun the script, which baseline metric do you expect to be largest?
- Return to the terminal from earlier.
- Rerun agent_comparison.py with the same command you used before.
You should see the single-agent answer followed by a labelled baseline summary. The summary should contain elapsed time, token counts, and estimated cost.
Missing token or cost data?
- Confirm that the callback is passed through the invocation configuration so it receives every model call.
- Check whether your model provider returns usage metadata for the selected model.
- Match each price-map key to the model name shown in usage_metadata.
- Recheck the pricing unit before multiplying it by the token count.
Still stuck? Why is my comparison missing token or cost data?
Build the comparison table
Both workflows need identical measurement boundaries. Reusing the same helper keeps the task plus calculation method consistent.
What makes this comparison fair?
- Both workflows receive the exact same research task.
- Each workflow starts with a fresh usage callback plus a fresh timer.
- The baseline uses the single-agent configuration from earlier.
- The multi-agent run preserves tracing plus both specialist subagents.
- Both rows use the same pricing source plus calculation method.
- In agent_comparison.py, replace the existing multi-agent output section with a comparison section that passes both workflows through the measurement helper.
- Print the returned rows as one table with columns for workflow, elapsed time, token usage, and estimated cost.
- Save agent_comparison.py.
Before you run the finished comparison, which workflow do you expect to use more tokens?
- Return to the terminal from earlier.
- Rerun agent_comparison.py with the same command you used before.
You should see two completed workflow results followed by a comparison table. The table should contain one single-agent row plus one multi-agent row.
That is the benchmark working. Your script now measures both agent designs against the same research task.
Only seeing one comparison row?
- Confirm that the comparison section calls the measurement helper once for each workflow.
- Check that both returned metric rows are included in the table data.
- Keep the research subagent's search permission plus the writer subagent's restricted tool access unchanged.
- Preserve the traced configuration when invoking the multi-agent workflow.
Need a hand? Why does my workflow table contain only one row?
✔️ Awesome, I've got everything!
Your script now runs the same task through both workflows. It prints elapsed time, token usage, and estimated cost in one table.
ⓧ I'd like to double check the full code
Use this checklist to compare the completed agent_comparison.py file with the target project state.
- Confirm that one shared research task feeds the baseline plus multi-agent runs.
- Confirm that each measured run creates a fresh UsageMetadataCallbackHandler.
- Confirm that each measured run records its own elapsed time.
- Confirm that the cost calculation uses the actual model names returned in usage_metadata.
- Confirm that the research subagent still has its assigned model plus search tool access.
- Confirm that the writer subagent still uses its cheaper model with no tool access.
- Confirm that tracing remains enabled for the multi-agent run.
- Confirm that the final table contains both workflows with time, token, and cost metrics.
Interpret the trade-off
The table shows the size of the orchestration overhead. The trace from earlier explains where that overhead came from.
- Compare the elapsed time for the two workflows.
- Compare the total token usage for the two workflows.
- Compare the estimated model cost for the two workflows.
- Return to the trace from earlier to identify which coordinator calls plus specialist calls created the difference.
- Review whether the research subagent produced stronger sourced material for the writer.
- Review whether the cheaper writer model reduced the cost of drafting the final answer.
When does splitting the work pay off?
Subagents can improve specialization when research needs dedicated search access. A focused handoff can also keep raw tool output away from the main loop.
Extra coordination creates more model calls plus additional handoffs. Simple tasks can finish faster with the single-agent workflow.
The cheaper writer can lower drafting cost when it replaces output from the primary model. The benefit depends on whether those savings exceed the coordinator's extra calls.
Strong finish. Your agent design now comes with measured time, token, and cost trade-offs you can defend.
Secret mission
Stress-Test Your Benchmark
Repeat the workflow comparison twice more. Make a ship decision from three runs instead of one. You will learn whether the first winner was repeatable or lucky.
Clean Up Your Resources
Clean Up Your Resources
Keeping these local resources has no ongoing charge. Running the script again can create model provider usage.
Resources you used:
- Local comparison script agent_comparison.py.
- Active Python virtual environment containing deepagents plus its required dependencies.
- Tracing configuration enabled for the multi-agent run.
Keep everything running
No action is needed. Choose this option if you plan to test more research tasks.
- Keep agent_comparison.py for future single-agent comparisons.
- Keep the Python virtual environment for future runs.
- Leave tracing enabled only while you want new trace records.
- Keep your model provider API key only if you still use it.
Your comparison script stays ready for another task.
Pause - I'll come back to this later
Pausing preserves your script plus its installed dependencies. It also prevents accidental model runs from the current terminal session.
- Save agent_comparison.py in your code editor.
- Set the tracing configuration you enabled earlier to its disabled state.
- Close the active terminal session to leave the virtual environment.
- Keep the virtual environment directory for your next session.
Your local workflow remains available when you return.
Delete - I don't want to use this again
Remove the local project resources if you do not plan to repeat the comparison. Deletion is permanent, so keep a copy of the script first if you may need its results.
Delete the local files:
- Close the terminal session containing the active virtual environment.
- Locate agent_comparison.py in your code editor's file sidebar.
- Delete agent_comparison.py using your editor's file actions.
- Confirm that agent_comparison.py no longer appears in the file sidebar.
- Return to the virtual environment's location using Finder on macOS or File Explorer on Windows.
- Delete the virtual environment directory.
- Confirm that the virtual environment directory no longer appears.
Remove project access:
- Remove the tracing configuration from the same location where you enabled it.
- Revoke any model provider API key created only for this project through the provider's documented key-management flow.
- Keep any model provider API key that you still use elsewhere.
That clears the local project while protecting credentials that belong to other work.
Nice Work!
Nice Work!
You made it! Your agent_comparison.py script now runs the same research task through single-agent and specialist-subagent workflows.
You've learned how to:
- Build a main deepagents agent that sends research to a tool-enabled specialist. It sends drafting to a lower-cost specialist without tools.
- Use tracing to inspect the execution order. Follow the information passed to each subagent.
- Benchmark both workflows with a comparison table for elapsed time. Record token usage. Estimate model cost. Use the results to judge when specialization pays off.
- Extend the workflow through an optional Secret Mission to push your subagent orchestration skills further.
Ready to quiz yourself?