有个问题我琢磨了很久:为什么同样的底层模型,有的 Agent 用起来像个实习生,有的却像个靠谱助手?
答案往往不在模型本身,而在工具。更准确点说,在"工具是怎么被设计出来的"。

去年我评估过几个开源 Agent 框架,发现它们对工具的理解差异巨大。有的框架把工具当成"函数调用",只要能执行就行;有的框架考虑到了工具描述怎么写才能让模型理解;但真正做得好的,会把工具当成一个完整的"接口设计"问题来思考——包括工具怎么组织、怎么发现、怎么安全执行。
DeepAgents 在工具这块下了很大功夫。它不是只塞给你几个内置工具,而是试图把整个工具生态搭起来:Skills 负责复用工作流,MCP 负责接外部服务,沙箱模型负责把执行边界收住。这一篇我们就顺着这条线,一层层往下剥。
内置工具不是摆设
先回到基础。DeepAgents 默认给你的工具,不是摆在那里凑数的,每一个都带着明确的使用意图。
write_todos 看似简单,但它的提示词里藏着细节:
Use this tool to track multi-step tasks. Break down complex objectives into concrete, actionable items.
Mark items as complete when done. Update the list as requirements change.
它其实是在引导 Agent 形成"规划-执行-检查"的工作习惯。看起来只是待办清单,背后其实是任务管理的思维方式。
文件操作工具族的设计也很有讲究。read_file 支持指定行范围,edit_file 支持字符串替换,glob 和 grep 支持批量搜索。这套组合覆盖了代码分析的完整工作流:先搜索定位,再细读内容,再修改保存。
特别想提一下 edit_file。它不是简单的"覆盖写入",而是支持类似 sed 的替换操作:
edit_file(
path="/path/to/file.py",
old_string="def old_function():",
new_string="def new_function():"
)
为什么是替换而不是直接写?因为替换天然带一点"验证"意味。如果 old_string 在文件里找不到,工具会报错,而不是盲目写入把文件搞坏。这种防御性设计,在生产环境里能少掉很多低级事故。
但这些只是基础。真正的扩展能力来自 Skills 和 MCP。
Skills:可复用的工作流
Skills 是 DeepAgents 里我很喜欢的设计。它解决了一个特别实际的问题:怎么让 Agent 掌握某个领域里已经被验证过的最佳实践?
举个例子。假设你有个内部流程:每次代码审查都要检查安全漏洞、性能隐患、是否符合编码规范。你当然可以把这套流程写成文档给 Agent 看,但那毕竟是静态的。Skills 的价值在于,它能把这套流程变成可复用的模块。
Skill 的结构
一个 Skill 就是一个目录,里面必须有个 SKILL.md 文件:
/skills/code-review/
├── SKILL.md # 核心定义
└── helper.py # 可选的辅助代码
SKILL.md 的格式是 YAML frontmatter + Markdown 内容:
---
name: code-review
description: Perform comprehensive code review focusing on security, performance, and maintainability
license: MIT
---
# Code Review Skill
## When to Use
Use this skill when:
- User asks you to review code
- Pull request needs analysis
- Security audit is required
## Review Checklist
### Security
- [ ] Check for SQL injection vulnerabilities
- [ ] Validate input sanitization
- [ ] Review authentication logic
### Performance
- [ ] Identify N+1 queries
- [ ] Check for unnecessary loops
- [ ] Review memory usage patterns
### Maintainability
- [ ] Verify code follows project conventions
- [ ] Check documentation completeness
- [ ] Assess test coverage
## Output Format
Provide findings in this structure:
Critical Issues (must fix)
-
• …
Warnings (should fix)
-
• …
Suggestions (nice to have)
-
• …
Skills 系统会解析这个文件,提取元数据(name, description, license),然后把 Markdown 内容注入到 Agent 的系统提示里。
渐进式披露
Skills 系统有个很精妙的设计叫"渐进式披露"(Progressive Disclosure)。
第一次加载 Skill 时,系统只读取 YAML frontmatter(也就几十 tokens),知道有这么个 Skill、大概干什么的。只有当 Agent 真正决定用这个 Skill 时,才把完整的 Markdown 内容加载进来。
看 skills.py 里的实现:
class SkillMetadata(TypedDict):
path: str
name: str
description: str
# ... 其他元数据
class SkillsMiddleware(AgentMiddleware):
def __init__(self, backend, sources):
# 启动时只加载元数据
self._skills_metadata = self._load_metadata(sources)
def modify_request(self, request):
# 第一次只注入元数据
skills_intro = self._format_skills_intro()
# ...
def _get_skill_full_content(self, skill_name):
# 真正用到时才加载完整内容
return self._backend.read_file(self._skill_paths[skill_name])
这个设计非常实用。你想想,假设有 20 个 Skill,每个平均 5KB,如果全塞进系统提示,那上下文一下就鼓起来了,token 成本也跟着爆。渐进式披露的好处就是,启动成本主要跟 Skill 数量有关,而不是跟 Skill 正文长度正相关。
Skill 的层级
Skills 可以从多个来源加载,形成层级覆盖:
agent = create_deep_agent(
skills=[
"/skills/base/", # 公司基础规范
"/skills/team/", # 团队特定规则
"/skills/project/", # 项目定制流程
]
)
同名的 Skill,后面的覆盖前面的。这种设计让组织可以建立 Skill 体系:基础层提供通用能力,上层逐级定制。
MCP:打破围墙花园
Skills 解决的是"复用"问题,但还有另一个更现实的问题:怎么跟外部世界连接?
你的 Agent 可能需要查数据库、发 Slack 消息、操作 GitHub PR。这些能力不应该硬编码在 Agent 里,而是通过标准协议动态接入。
这就是 MCP(Model Context Protocol)的用武之地。
MCP 是什么
简单说,MCP 就像 AI 应用的"USB 接口"。它定义了一套标准协议,让任何服务都可以暴露给 LLM 使用,而不用在 Agent 侧关心后端到底是什么。
一个 MCP Server 可以提供:
-
• Tools —— 可调用的函数 -
• Resources —— 可读取的数据 -
• Prompts —— 可复用的提示模板
DeepAgents 通过 langchain-mcp-adapters 集成 MCP:
from langchain_mcp_adapters import load_mcp_tools
from deepagents import create_deep_agent
# 连接到一个 MCP Server
mcp_tools = load_mcp_tools("https://my-mcp-server.com/sse")
agent = create_deep_agent(
tools=mcp_tools + [my_custom_tool]
)
实战:接入数据库查询
假设你有个内部数据库,想让 Agent 能查询。传统做法一般是写个 query_database 工具,把连接字符串和查询逻辑都硬编码进去。但这样耦合太紧了。
MCP 的做法是:单独部署一个 MCP Server,专门处理数据库访问。
# mcp_server.py
from mcp.server import Server
server = Server("database-server")
@server.tool()
async def query_database(sql: str) -> str:
"""Execute SQL query and return results"""
# 连接数据库、执行查询、返回结果
return results
@server.resource("schema://tables")
async def get_tables() -> str:
"""Return database schema"""
return schema_info
然后在 DeepAgents 里接入:
from langchain_mcp_adapters import load_mcp_tools
# Agent 通过 MCP 协议使用数据库,不用关心具体实现
db_tools = load_mcp_tools("http://localhost:8000/sse")
agent = create_deep_agent(tools=db_tools)
好处很明显:
-
• 数据库逻辑独立维护,可以热更新 -
• 多个 Agent 可以共用同一个 MCP Server -
• MCP Server 可以自己控制权限、审计、限流 -
• Agent 侧代码干净,只关心业务逻辑
MCP 生态
MCP 协议是 Anthropic 发起的,但正在形成开放生态。目前已经有官方和社区实现的 Server:
-
• 文件系统 —— 读写本地文件 -
• PostgreSQL —— 数据库查询 -
• GitHub —— 操作 PR、Issues -
• Slack —— 发送消息 -
• Puppeteer —— 浏览器自动化
DeepAgents 的思路很清楚:内置工具覆盖通用需求,MCP 接住特定场景。这样既保留开箱即用的体验,又不会把扩展空间封死。
沙箱安全模型
工具能力越强,安全问题越突出。DeepAgents 有个 execute 工具能执行 shell 命令,如果滥用就是远程代码执行漏洞。
DeepAgents 的安全哲学很简单:Trust the LLM,但把边界 enforcement 放在工具层。
这不是说"相信模型不会干坏事",而是说"就算模型想干坏事,工具层也得拦得住"。
Backend 的安全层级
DeepAgents 的 Backend 设计体现了这种分层安全思想。
最底层是 BackendProtocol,定义文件操作的基本接口。然后有 SandboxBackendProtocol 扩展,增加了执行能力:
class BackendProtocol:
"""基础后端:只支持文件操作"""
def read_file(self, path: str) -> ReadResult: ...
def write_file(self, path: str, content: str) -> WriteResult: ...
class SandboxBackendProtocol(BackendProtocol):
"""沙箱后端:额外支持执行"""
def execute(self, command: str) -> ExecuteResult: ...
注意这个继承关系。execute 不是基础能力,是额外能力。只有显式使用支持 Sandbox 的 Backend,execute 工具才可用。
后端类型对比
StateBackend —— 最安全的选项
from deepagents.backends import StateBackend
agent = create_deep_agent(backend=StateBackend)
-
• 文件存在内存里,不对真实文件系统做操作 -
• 不支持 execute,调用会返回错误 -
• 适合不需要持久化的场景,或者纯粹的分析任务
FilesystemBackend —— 有持久化需求时用
from deepagents.backends import FilesystemBackend
agent = create_deep_agent(
backend=FilesystemBackend(root_dir="./safe_zone")
)
-
• 文件写入真实磁盘,但限制在 root_dir下 -
• 仍然不支持 execute -
• 适合需要保存结果,但不需要执行命令的场景
Sandbox Backends —— 需要执行时用
DeepAgents 支持多种沙箱后端:
# Modal 沙箱
from deepagents.backends.sandbox import ModalBackend
agent = create_deep_agent(
backend=ModalBackend(
image="python:3.11",
secrets=["MY_API_KEY"]
)
)
# Daytona 沙箱
from deepagents.backends.sandbox import DaytonaBackend
agent = create_deep_agent(
backend=DaytonaBackend(
timeout=300,
language="python"
)
)
这些沙箱后端在隔离环境里执行命令,有资源限制、超时控制、网络隔离。即使 Agent 执行了恶意代码,也只影响沙箱内部。
最小权限原则
配置 Agent 时,问自己:这个任务真的需要执行权限吗?真的需要写文件吗?
如果只需要读文件分析,用 StateBackend。如果需要保存结果但不需要执行,用 FilesystemBackend。只有确实需要运行命令(比如构建项目、运行测试),才上 Sandbox。
这种"默认拒绝,显式开启"的设计,很符合安全领域的最小权限原则。
Human-in-the-Loop
沙箱是第一道防线,但有时候业务需要更细粒度的控制。比如允许 Agent 读任何文件,但写文件需要人工确认。
DeepAgents 的 interrupt_on 配置就是干这个的:
agent = create_deep_agent(
backend=FilesystemBackend(root_dir="./workspace"),
interrupt_on={
"write_file": True, # 写文件前暂停
"edit_file": True, # 编辑前暂停
"execute": { # 执行命令时根据内容决定
"condition": lambda tool_call: "rm" in tool_call["args"]["command"]
}
}
)
当 Agent 调用这些工具时,执行会暂停,系统抛出中断,等待人类审批。审批可以修改工具参数,或者直接拒绝。
这在生产环境里特别重要。你可以让 Agent 自动处理常规任务,但在关键操作前,比如写生产代码、删文件、发邮件,再让人来拍板。
自定义 Backend 开发
如果现有的 Backend 都不满足需求,你可以自己实现。
Backend 的核心是实现 BackendProtocol:
from deepagents.backends.protocol import BackendProtocol, ReadResult, WriteResult, LsResult
class MyCustomBackend(BackendProtocol):
def __init__(self, config):
self.config = config
# 初始化你的存储连接
def read_file(self, path: str) -> ReadResult:
# 实现读取逻辑
content = self._fetch_from_my_storage(path)
return ReadResult(content=content)
def write_file(self, path: str, content: str) -> WriteResult:
# 实现写入逻辑
self._save_to_my_storage(path, content)
return WriteResult(success=True)
def ls(self, path: str) -> LsResult:
# 实现列表逻辑
files = self._list_my_storage(path)
return LsResult(files=files)
然后在创建 Agent 时使用:
agent = create_deep_agent(
backend=lambda runtime: MyCustomBackend(config)
)
为什么这里要用 lambda?因为某些 Backend(比如 StateBackend)需要运行时 context 才能初始化。lambda 的作用,就是把 Backend 的创建延迟到真正需要的时候。
实战:S3 Backend
假设你想把文件存在 AWS S3 而不是本地磁盘:
import boto3
from deepagents.backends.protocol import BackendProtocol, ReadResult, WriteResult
class S3Backend(BackendProtocol):
def __init__(self, bucket: str):
self.s3 = boto3.client('s3')
self.bucket = bucket
def read_file(self, path: str) -> ReadResult:
try:
response = self.s3.get_object(Bucket=self.bucket, Key=path)
content = response['Body'].read().decode('utf-8')
return ReadResult(content=content)
except self.s3.exceptions.NoSuchKey:
return ReadResult(error="file_not_found")
def write_file(self, path: str, content: str) -> WriteResult:
self.s3.put_object(
Bucket=self.bucket,
Key=path,
Body=content.encode('utf-8')
)
return WriteResult(success=True)
# 使用
agent = create_deep_agent(
backend=lambda rt: S3Backend(bucket="my-agent-bucket")
)
这样 Agent 的所有文件操作都透明地落在 S3 上,天然支持多实例共享、持久化、备份。
小结
这一篇其实想说明一件事:真正把 Agent 做强的,往往不是模型参数,而是工具体系是不是成型。
内置工具解决的是最常见的脏活累活,Skills 解决的是经验复用,MCP 解决的是外部连接,沙箱和 Human-in-the-Loop 解决的则是边界控制。把这几层拼起来,你得到的就不再是"能调几个函数的 Agent",而是一套能逐步接近生产环境的工作系统。
所以我更愿意把 DeepAgents 理解成"工具生态框架",而不只是"多塞了几个工具的 Agent 封装"。这两者看起来差不多,落到实际项目里差别会非常大。


