# Use Xantly with Deep Agents

[Deep Agents](https://github.com/langchain-ai/deepagents) is LangChain's framework for building **long-running, tool-using agents with planning and sub-agent delegation**: the same architecture pattern Claude Code, Manus, and Devin use internally. Because it runs on LangChain's `ChatModel` abstraction, pointing the model at Xantly routes every planning call, every sub-agent step, and every tool-use loop through smart routing, semantic cache, and persistent memory.

**Why this matters for Deep Agents specifically.** Deep Agents burn tokens fast, a single planning session can fire 50-200 LLM calls across sub-agents and tool loops. Running those on Claude Sonnet at default rates gets expensive within minutes. Xantly's per-tenant bandit router picks the cheapest model that can reliably emit tool calls for each step, often swapping quality-tier models in and out of sub-agent calls while keeping the main planner on a frontier model. The result: the same deep-agent run, up to 80% cheaper, with identical final output.

## Prerequisites

- Python 3.10+
- `pip install deepagents langchain-openai`
- A Xantly API key, [create one](/dashboard/api-keys)

## Setup

```python
from deepagents import create_deep_agent
from langchain_openai import ChatOpenAI

model = ChatOpenAI(
    base_url="https://api.xantly.com/v1",
    api_key="xantly_sk_...",
    model="xantly/auto-quality",
)

# Deep Agents 0.5+ API: model first, tools second, system_prompt as kwarg.
# Earlier releases used `instructions=`, if you're on <0.5, rename.
agent = create_deep_agent(
    model=model,
    tools=[],                       # your domain tools
    system_prompt="You are a thorough research agent.",
)

result = agent.invoke({
    "messages": [("user", "Research the impact of transformer architectures on speech recognition.")]
})
print(result["messages"][-1].content)
```

That's it, the agent now plans, sub-delegates, and runs tool loops through Xantly.

## Full example with tools

```python
from deepagents import create_deep_agent
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
import httpx

@tool
def search_web(query: str) -> str:
    """Search the web and return the top 3 results as text."""
    r = httpx.get("https://duckduckgo.com/?q=" + query, timeout=10)
    return r.text[:2000]

@tool
def fetch_url(url: str) -> str:
    """Fetch a URL and return its text content."""
    return httpx.get(url, timeout=15).text[:5000]

planner = ChatOpenAI(
    base_url="https://api.xantly.com/v1",
    api_key="xantly_sk_...",
    model="xantly/auto-quality",  # planning needs reasoning
)

agent = create_deep_agent(
    tools=[search_web, fetch_url],
    system_prompt=(
        "You are a technical research agent. Plan your research steps, "
        "delegate to sub-agents when appropriate, and produce a structured "
        "summary citing every source."
    ),
    model=planner,
)

result = agent.invoke({
    "messages": [("user", "What changed in open-weight LLM training between 2023 and 2025?")]
})
print(result["messages"][-1].content)
```

## Model choice, the split matters

Deep Agents are more cost-sensitive than any other agent framework because they fan out so aggressively. **Use different Xantly tiers for the planner vs sub-agents:**

```python
planner_model = ChatOpenAI(
    base_url="https://api.xantly.com/v1",
    api_key="xantly_sk_...",
    model="xantly/auto-quality",       # main planner, reasoning matters
)

sub_agent_model = ChatOpenAI(
    base_url="https://api.xantly.com/v1",
    api_key="xantly_sk_...",
    model="xantly/auto-value",         # sub-agents executing plans, 4-6x cheaper
)

agent = create_deep_agent(
    tools=[...],
    system_prompt="...",
    model=planner_model,
    subagents=[
        {
            "name": "researcher",
            "description": "Gathers information about a topic.",
            "prompt": "Research exhaustively and cite every source.",
            "model": sub_agent_model,
        },
        {
            "name": "summarizer",
            "description": "Compresses research into bullet points.",
            "prompt": "Extract the 5 most important facts, one line each.",
            "model": ChatOpenAI(
                base_url="https://api.xantly.com/v1",
                api_key="xantly_sk_...",
                model="xantly/auto-speed",   # summarization is a speed task
            ),
        },
    ],
)
```

Tier-by-tier recommendation:

| Agent role | Model ID | Why |
|---|---|---|
| **Main planner** | `xantly/auto-quality` or `anthropic/claude-sonnet-4.6` | Deep reasoning, long horizon |
| **Research sub-agent** | `xantly/auto-value` | Tool calls + extraction, balanced cost |
| **Summarization sub-agent** | `xantly/auto-speed` | Short, structured output |
| **Verification sub-agent** | `xantly/auto-safety` | Correctness-sensitive steps |
| **Code-edit sub-agent** | `anthropic/claude-sonnet-4.6` | Tool-calling reliability |

## Built-in file system tools

Deep Agents ships with `read_file`, `write_file`, `edit_file`, `ls` as virtual file system tools (in-memory by default). Every call to these is a tool_use round-trip with your model. Because Xantly caches tool_use output where safe, repeated file reads inside the same session return instantly.

No config needed, the file system tools just work with Xantly routing.

## Streaming

```python
for event in agent.stream({
    "messages": [("user", "Build a plan and execute it step by step")],
    "files": {},          # or a real file dict
}):
    print(event)
```

## Persistent memory across sessions

Deep Agents has its own in-memory planner state. Xantly adds **cross-session memory**: so the agent can recall prior research, prior plans, prior sub-agent conclusions even after the process restarts. Opt in by setting a request-level header:

```python
model = ChatOpenAI(
    base_url="https://api.xantly.com/v1",
    api_key="xantly_sk_...",
    model="xantly/auto-quality",
    default_headers={
        "X-Xantly-Memory-Mode": "recall",
        "X-Xantly-Session-Id": "project-deepresearch-2026",
    },
)
```

All calls from this model instance share the session id, so Xantly's L3 graph memory accumulates knowledge across agent invocations and resurfaces it automatically on future calls.

## Cost observability per step

Each LLM call inside Deep Agents logs separately in your [Xantly dashboard](/dashboard/mission-control/costs). Tag runs for attribution:

```python
model = ChatOpenAI(
    base_url="https://api.xantly.com/v1",
    api_key="xantly_sk_...",
    model="xantly/auto-quality",
    default_headers={
        "X-Xantly-Tag": "deepagent-run-42",
    },
)
```

Dashboard shows per-run: total tokens, per-sub-agent cost, cache hit rate, average tool-call latency.

## Verify

```bash
pip install deepagents langchain-openai
```

```python
from deepagents import create_deep_agent
from langchain_openai import ChatOpenAI

model = ChatOpenAI(
    base_url="https://api.xantly.com/v1",
    api_key="xantly_sk_...",
    model="xantly/auto-speed",
)

agent = create_deep_agent(tools=[], system_prompt="Reply in one word.", model=model)
print(agent.invoke({"messages": [("user", "Capital of France?")]})["messages"][-1].content)
```

Expected: a one-word response. If you get a response, the full Deep Agents → Xantly → upstream chain is working.

## What you get

- **Per-role routing.** Planner on quality, sub-agents on value, summarizers on speed, optimized for each step's actual complexity.
- **Semantic cache across sub-agent loops.** Deep Agents often re-ask overlapping sub-questions. L2 cache collapses these into single billable calls.
- **Waterfall fallback per call.** A provider outage mid-agent-run doesn't kill your plan, Xantly silently retries the next-best model in the same tier.
- **Cost per sub-agent.** Dashboard breaks down spend by planner / researcher / summarizer / whatever sub-agent name you configured.
- **Cross-session memory.** Your agent remembers its last research session when you restart.

## Gotchas

**Deep Agents emits a LOT of calls.** A single "research X exhaustively" prompt can fire 50-200 LLM calls. Set a **daily USD cap** on your Xantly API key (Dashboard → API Keys → Daily Budget) before your first serious run. The cap returns `402 Payment Required` when exceeded, the agent sees it cleanly and stops, rather than silently spending four figures.

**Tool-calling reliability matters more than any other framework.** If a sub-agent can't emit reliable tool calls, the planner loops. Always default sub-agents to `anthropic/claude-sonnet-4.6` or `xantly/auto-quality`, speed-tier models will misfire on complex tool schemas.

**Async.** `agent.ainvoke(...)` works. Underlying OpenAI/Anthropic SDKs are async-native.

**Structured output.** If your tools return JSON, stick with `xantly/auto-quality` or explicit strong models, schema adherence drops off fast in speed-tier models.

**File-system tools are in-memory by default.** Persist across runs by passing `files={}` explicitly and saving the result's `files` back in. Xantly caches content fingerprints but can't resurrect files from a crashed process.

**`xantly/auto-speed` may produce low-information responses on short prompts.** Cheap speed-tier models (especially when given Deep Agents' large boilerplate system prompt with no real workspace context) sometimes return generic refusals. Xantly detects this and replaces them with a structured diagnostic message that:

1. Starts with the marker `[xantly:fallback]` so callers can detect it on the wire
2. Names the model that failed and suggests `xantly/auto-quality`
3. Surfaces the reason in `xantly_metadata.fallback_applied` (values: `low_information`, `low_information_formal`, `empty_user_message`)
4. Is also reflected in the response header `x-xantly-fallback-applied: <reason>`

Mitigation in practice: use `xantly/auto-quality` (or pin `anthropic/claude-sonnet-4-5`) for the planner, leave `xantly/auto-value` for the sub-agents. In real production agent runs, the workspace context, file dumps, prior conversation, project metadata, gives sub-agents enough grounding that this rarely triggers.

```python
import uuid
SESSION = f"deepagent-{uuid.uuid4().hex[:8]}"

planner = ChatOpenAI(
    base_url="https://api.xantly.com/v1",
    api_key="xantly_sk_...",
    model="xantly/auto-quality",   # avoid speed-tier for the planner
    default_headers={
        "x-xantly-agent-framework": "deepagents",
        "x-xantly-agent-session": SESSION,
    },
)

# Detect synthesized responses programmatically:
response = planner.invoke("...")
if response.content.lstrip().lower().startswith("[xantly:fallback]"):
    # Upgrade and retry, log the incident, etc.
    ...
```

## Next steps

- [LangChain (Python)](/docs/use-with-langchain-python), the underlying library Deep Agents builds on.
- [LangGraph](/docs/use-with-langgraph), when you want explicit graph control rather than planner-delegation.
- [CrewAI](/docs/use-with-crewai), alternative role-based multi-agent.
- [AutoGen](/docs/use-with-autogen), Microsoft's conversation-based multi-agent framework.
- [Multi-Agent Orchestration](/docs/multi-agent-orchestration), native Xantly orchestration patterns.
- [Cost-Optimized Routing](/docs/cost-optimized-routing), how BaRP picks models per sub-agent.
