§19 避坑指南:从一个真实重构说起
先给结论:绝大多数 DeepAgents 问题,是"没按框架设计意图用"。下面 6 个坑,我都亲眼见过。
我手头有个真实案例:一个图片生成系统,把 DeepAgents 当普通 LangGraph wrapper 用。 结果 HITL 失效、子代理不注册、Skills 架空、工具冻结。 我把它重构了一遍。下面这些坑,都来自那次。
坑 1:HITL 用了旧格式
错误:检查 __interrupt__(v1 格式),调用没传 version="v2"。 后果:中断信息取不到,恢复不了。
正确:
result = await agent.ainvoke(input_data, config=config, version="v2")
# 检查用属性
if getattr(result, "interrupts", None):
...
# 恢复
await agent.ainvoke(Command(resume={"decisions": decisions}), config=config, version="v2")
坑 2:子代理配置缺字段
错误:description 太模糊,没 skills,没 response_format。 后果:主 Agent 不知何时委派;返回自由文本要靠脆弱正则解析。
正确:description 写触发条件;用 response_format 拿结构化 JSON:
class ImageGenResult(BaseModel):
status: str
task_id: str
file_url: str | None = None
{"name": "image-generator",
"description": "用户要生成任何电商/营销图片时调用",
"system_prompt": "...",
"tools": [generate_image],
"skills": ["skills/ecom-details-image"],
"response_format": ImageGenResult}
坑 3:Skills 被架空
错误:模板硬编码进巨型 prompt,没有 SKILL.md。 后果:SkillsMiddleware 完全不介入;每轮白烧 token。
正确:建 skills/xxx/SKILL.md,用渐进式披露。删掉硬编码函数。
坑 4:工具内部轮询冻住 Agent
错误:generate_image 内部 for i in range(180): sleep(1) 轮询。 后果:Agent 被冻 180 秒。
正确:直接 await run_generation(task, ...)。要真异步,用 AsyncSubAgent。
坑 5:每线程新建 Agent 实例
错误:_agent_sessions 对每个 thread_id 建新 Agent + 新 checkpointer。 后果:实例浪费,checkpointer 不共享。
正确:全局只建一次 Agent + checkpointer,用 thread_id 区分会话:
_checkpointer = MemorySaver()
_agent = None
def get_agent():
global _agent
if _agent is None:
_agent = create_deep_agent(model=..., checkpointer=_checkpointer)
return _agent
坑 6:模型手动初始化 + 挂 callback
错误:ChatDeepSeek(... callbacks=[...])。 正确:用 "provider:model" 字符串;日志走中间件:
agent = create_deep_agent(model="deepseek:deepseek-v4-flash", ...)
@wrap_tool_call
def log_tool_calls(request, handler):
print(f"[TOOL] {request.name}")
return handler(request)
一张表记住
| 坑 | 现象 | 修法 |
|---|---|---|
| HITL 旧格式 | 中断取不到 | 加 version="v2",用 .interrupts |
| 子代理缺字段 | 不委派/脆弱解析 | 写好 description + response_format |
| Skills 架空 | token 浪费 | 建 SKILL.md,渐进披露 |
| 工具轮询 | Agent 冻结 | 直接 await / AsyncSubAgent |
| 每线程建实例 | 资源浪费 | 全局单例 + thread_id |
| 模型挂 callback | 中间件冲突 | 用字符串 + 中间件日志 |
标叔的经验:这 6 个坑,根子都是一个——"我没按框架的意思用"。DeepAgents 给了默认最佳实践。你绕过它自己造,往往造出它已经解决的问题。先用默认,遇到真瓶颈再改。
标叔的结论:学框架,先信它的默认。踩坑大多来自"我以为这样写也行"。
写在最后
DeepAgents 不是又一个 Agent 框架。 它是 LangChain 把"成功的深度 Agent"长什么样,做成默认配置。
你只要写 create_deep_agent(),就拿到: 规划、文件系统、子代理、记忆、压缩、HITL、Skills。
从五分钟跑通,到生产部署。 这本书的 19 章,是一条完整路径。
我最想说的就一句: 先用默认,跑起来,再谈优化。 别像我一样,先造轮子,再发现轮子框架早就给了。
标叔出品 | AI Native Coder · 独立开发者 公众号「标叔」| B站「Liangdabiao」
附录:核心 API 速查
create_deep_agent 常用参数
| 参数 | 作用 |
|---|---|
model |
"provider:model" 或模型实例 |
tools |
自定义工具列表 |
system_prompt |
自定义指令(置顶) |
middleware |
额外中间件 |
subagents |
子代理定义 |
skills |
SKILL.md 目录路径 |
memory |
AGENTS.md 路径(每轮加载) |
permissions |
文件权限规则 |
backend |
存储后端 |
interrupt_on |
HITL 配置 |
response_format |
结构化输出 schema |
checkpointer |
持久化层(HITL/多轮必配) |
store |
跨线程存储 |
五大内置能力工具
规划:write_todos
文件:ls read_file write_file edit_file glob grep
Shell:execute(沙箱)
子代理:task
压缩:compact_conversation
常用命令
pip install deepagents # 装 SDK
curl -LsSf https://langch.in/dcode | bash # 装 dcode
dcode # 启动终端编程代理