I’ve been building agentic systems for a while — my second-brain and doppelganger projects both revolve around giving LLMs structured memory and tool access. Recently I came across a deep dive by mikelopster on Deep Agent, an Agent Harness framework built on LangChain Core and LangGraph Runtime. It clarified a lot of design decisions I’d been wrestling with.
Here’s what I learned.
What Deep Agent Is
Deep Agent sits on top of the LangChain ecosystem as the highest-level abstraction:
Deep Agent ← Agent Harness (planning, skills, memory, MCP)
↑
LangChain ← Components (tools, prompts, document loaders)
↑
LangGraph ← Runtime (state, checkpointing, human-in-the-loop)
LangChain gives you the building blocks — tool definitions, prompt templates, document loaders. LangGraph handles state machines, checkpointing, and branching workflows. Deep Agent wraps both and adds built-in capabilities that you’d otherwise have to code yourself:
- Planning & task breakdown — automatically decomposes large tasks into steps
- Virtual file system — read, write, edit, and list files without custom tooling
- Sub-agent spawning — delegates isolated subtasks to child agents
- Long-term memory — persists context across conversations
- Skills system — loads specialized capabilities via
agent.mdfiles - MCP support — connects to any MCP server as a tool source
The key insight: Deep Agent comes with these capabilities built in. You don’t implement planning logic or file system tools from scratch — you configure them through system prompts and the agent orchestrates the rest.
Example 1: Basic Deep Agent
The simplest Deep Agent pattern is wrapping functions as tools and handing them to the agent:
from langchain_deep_agent import create_deep_agent
def search_database(query: str) -> str:
"""Search the internal database for information."""
# ... implementation
return results
agent = create_deep_agent(
model="gemini-2.0-flash",
tools=[search_database],
system_prompt="You are a helpful assistant. Always plan before acting.",
)
The create_deep_agent function is the entry point. It accepts tools (just like LangChain tools), a system prompt, and a model. But unlike plain LangChain, Deep Agent automatically enables planning, file system operations, and step-by-step execution — you get them for free.
Example 2: Agents.md & Skills
This is where it gets interesting. Deep Agent supports a memory and skills system through structured markdown files. The concept is simple:
agent.mdfiles define the agent’s identity, capabilities, and stored knowledge- Skills are organized in folders — loaded only when needed
- The agent reads these files at startup to understand what it should remember
# agent.md
## Memory
- User prefers Python code examples over pseudocode
- Last project was about investment analysis
- Current focus: LLM tooling and agentic systems
## Skills
- database_query: skills/database.md
- file_analysis: skills/file-tools.md
When you ask the agent something, it checks its memory folder first. If it finds relevant agent.md files or skills, it loads them into context. This is exactly the pattern I used in my doppelganger agent — structured memory that persists across sessions.
The two key concepts are:
memory— stores facts, preferences, and session contextskills— loads specialized tools and behaviors on demand
This means you can build an agent that grows its capabilities over time by writing new skill files, without modifying the core agent code.
Example 3: MCP Integration
Model Context Protocol (MCP) is a standard for connecting LLMs to external tools. Deep Agent natively supports MCP through a MultiServerMCPClient adapter:
from langchain_deep_agent import create_deep_agent
from langchain_deep_agent.mcp import MultiServerMCPClient
# Wrap MCP servers as tools
client = MultiServerMCPClient()
mcp_tools = client.get_tools()
agent = create_deep_agent(
model="gemini-2.0-flash",
tools=[*mcp_tools],
system_prompt="You are a web automation agent.",
)
The MultiServerMCPClient connects to MCP servers via stdio or HTTP, discovers their available tools, and presents them to Deep Agent as regular tool functions. This means any MCP server — Playwright for browser automation, filesystem access, database queries — becomes instantly available to your agent.
In the demo, the agent navigated a browser using Playwright MCP to scrape GitHub trending repos, taking snapshots before every action to check the DOM. Even when the initial attempt failed (the page had bot protection), the fallback to a simpler site showed the pattern clearly: the agent plans, navigates, snapshots, clicks, and summarizes — all orchestrated through MCP tools.
Example 4: RAG with ChromaDB
The last example showed how to combine Deep Agent with a vector database for retrieval-augmented generation. The setup was an animal image search using ChromaDB:
from chromadb import PersistentClient
def search_animal_images(query: str, n: int = 3) -> list:
"""Search for animal images by text description."""
collection = client.get_collection("animal_images")
results = collection.query(query_texts=[query], n_results=n)
return results
agent = create_deep_agent(
model="gemini-2.0-flash",
tools=[search_animal_images],
system_prompt="""You are an animal search assistant.
Use search_animal_image to find animals from text descriptions.
Always plan before taking action.""",
)
The key design decision here is letting the agent decide when to use RAG. Instead of a rigid retrieval → generation pipeline, the agent treats the vector search as just another tool. It plans whether to search, what query to use, and how to present the results — all guided by the system prompt.
This is more flexible than traditional RAG pipelines. If the agent’s memory already contains the answer, it can skip retrieval entirely. If it needs to disambiguate, it can try multiple queries. The system prompt acts as the controller, and the agent’s planning capability handles the orchestration.
Why This Matters for Agent Builders
Watching this deep dive confirmed several patterns I’ve been applying in my own work:
-
Agent Harness as an abstraction — Deep Agent shows that the right level of abstraction for most agent work isn’t LangGraph’s state machines (too low-level) or LangChain’s tool chains (too simplistic). It’s the Agent Harness layer: planning + file system + sub-agents + memory, configured through prompts.
-
File system as memory — Instead of complex vector databases for every use case, well-organized markdown files in folders can serve as perfectly good memory for many scenarios. The agent can read, write, and edit its own memory files — just like my doppelganger does.
-
MCP is the universal plugin — The MCP integration pattern (wrap → discover → use) means your agent can connect to any tool ecosystem. I’m planning to expose my doppelganger’s memory layer as an MCP server so any client can consume it.
-
RAG is a tool, not a pipeline — Making retrieval just another function call that the agent decides to use is more robust than forcing every input through a retrieval step.
If you’re building agentic systems, I’d recommend watching the full video (it’s in Thai with helpful visual walkthroughs). The Deep Agent framework is worth studying even if you don’t use LangChain — the patterns for planning, tool orchestration, and structured memory transfer across any agent stack.