DeepAgents(三):Quick Start:装完到跑通,只定 4 个决定

2026-09-30 16:460 条评论8 次阅读

Quick Start:装完到跑通,只定 4 个决定

装上 deepagents 之后有 2 件事值得先弄清:一条 pip install 到底往环境里放了什么,create_deep_agent 那 18 个参数里又有哪几个是第一次装配必须定的。这篇按「装、定、验」3 步走,共 7 节,读完约 5 分钟。

要准备的只有 2 样:装好 deepagents,以及一个可用的模型凭据。走完你会得到一个能跑通的 Agent,和 3 个随时能自查装配结果的手法。依赖树读自包元数据,装配结果用一个假模型捕获,全程零 API 费用;环境是 deepagents 0.7.13 与 langchain 1.4.0,数字都是本机实测,引用官方原话的地方标了出处。

一、先把三步的结论摆出来

步 做什么 结论
装 pip install deepagents 11 条依赖,7 条硬拉,捎带 3 个包
定 给 create_deep_agent 传参 18 个参数,0 个必需,要定 4 个
验 确认装配结果 模型侧 8 个工具 / 11 个中间件实例 / 图里 5 个节点

二、装:一条命令,捎带 3 个包

用标准库 importlib.metadata 读 deepagents 的元数据,Requires-Dist 一共 11 条。判断标准很硬:条目里出现 extra == 就是可选,没有就是硬依赖。

类型 条数 内容
硬依赖 7 langchain / langchain-core / langchain-anthropic / langchain-google-genai / langsmith / packaging / wcmatch
extra 4 对应官方声明的 3 组:aws / quickjs / video

所以这条命令会把 langchain-anthropic、langchain-google-genai、langsmith 一起装进来,3 个都是完整集成包。

from importlib import metadata

name = "deepagents"
d = metadata.distribution(name)
for r in d.requires or []:
    if "extra ==" not in r:
        print(r)

硬依赖只说明 pip 会装它,不说明程序会用到它。在一个干净子进程里先 import langchain 与 import langgraph(harness 的前置),模块数只有 802;再 import deepagents 并建一次 Agent,涨到 3591。

这 3 个模块都在里面:langchain_anthropic、langchain_google_genai、langsmith。它们卸不掉,harness 要开箱支持 Anthropic 与 Gemini 的 prompt caching,索性把集成包硬拉进来。想卸只剩一条路:不用官方那份 create_deep_agent,自己按顺序装配中间件。

装 1 个 deepagents

硬依赖 7 条
跟着就装

extra 3 组
要显式写

连带 3 个集成包
anthropic · google-genai
langsmith

三、定:18 个参数里只定 4 个

用 inspect.signature 数出来是 18 个参数,没有一个是必需的。第一次装配要定的是下面 4 个。

决定 落在哪个参数 不传时会怎样 一句话
模型怎么给 model(第 1 位) 只告警,仍能跑 1.0 起从「可省略」改成「必须给」
工具从哪来 tools(第 2 位) 8 个内置工具 只能加,减不掉
提示词给多少 system_prompt(第 3 位) 0 字符 给多少就是多少,逐字还原
backend backend(第 9 位) StateBackend 文件在图的 state 里,不落磁盘

剩下 14 个分 2 类:扩展面有 subagents / skills / memory / middleware / permissions / interrupt_on / response_format,运行时钩子有 state_schema / context_schema / checkpointer / store / cache / debug / name。它们每一个都能单独撑起一篇,但都不是「不决定就跑不起来」的东西。

create_deep_agent
18 个参数

4 个决定
第一次装配要定

14 个扩展与钩子
以后再说

模型 · 工具
提示词 · backend

模型有 2 种给法。给名字形如 openai:gpt-5.5,走的是 init_chat_model,要真的解析 provider 并找凭据;本机没有 OpenAI 凭据,实测报 OpenAIError: Missing credentials。给实例更省事,但必须是 BaseChatModel 子类,包装一层就会踩到第五节那个报错。

完全不传 model 现在只抛一条弃用告警,告警里有这两句:

Passing model=None to create_deep_agent is deprecated and will be removed in deepagents==1.0.0. The model parameter type will change from BaseChatModel | str | None to BaseChatModel | str.

现在不传能跑,1.0 起变成必填,今天就显式指定等于给将来省一次改版。

backend 不传时用的哪个,源码给得很直接:

# create_deep_agent 源码第 367 行
backend = (
    backend if backend is not None
    else StateBackend())

deepagents.backends 一共导出 6 个 backend 类。默认的 StateBackend 是内存态,文件存在图的 state 里,不落磁盘;它也不实现沙箱协议,所以 execute 工具在默认装配下不会出现在模型侧。

提示词这一条最反直觉:给多少,模型侧就是多少。

system_prompt 传入 模型侧 system 消息 模型侧工具数
不传 0 字符 8
8 字符 8 字符 8
27 字符 27 字符 8

一个字符都不多。官方 docstring 的原话是:「With system_prompt=None and no profile base_system_prompt or system_prompt_suffix, the model receives an empty authored system prompt.」

工具这一项实测很干脆:不传 tools,模型侧 8 个内置工具;传 1 个自己的工具,模型侧 9 个。内置的一个没少,差集里「消失」那一半是空的。官方原话是:「Passing tools here is additive — it never removes a built-in.」

要减掉内置工具得换口子,官方给的路径有 2 条:在 harness profile 里配 excluded_tools,或者自己传一个 FilesystemMiddleware 顶掉默认那份。知道「加的入口不等于减的入口」能省一次试错。

4 个决定一次配好:

import deepagents as da


def my_tool(q: str) -> str:
    """查库存。"""
    return "ok"


agent = da.create_deep_agent(
    model="openai:gpt-5.5",
    system_prompt="先给结论。",
    tools=[my_tool],
)

换任意 BaseChatModel 实例、把 tools 去掉,装配结果的数字都还是上面那些。

四、验:3 个手法看清装了什么

跑通之后还要能确认装配结果。下面 3 个手法各看一个面,都不发真实请求。

手法一,放个假模型进去:继承 BaseChatModel,覆写 bind_tools 记下工具清单,在 _generate 里量 system 消息长度。实测模型侧 8 个工具:ls / read_file / write_file / edit_file / delete / glob / grep / task,system 消息 0 字符。它看的是模型侧,不看源码也不看文档。

手法二,给中间件打补丁数实例:默认装配创建 11 个实例,主 Agent 的 5 个,默认 general-purpose 子 Agent 的 5 个,加 1 个 SubAgentMiddleware 桥接。也就是说默认装配里躺着 2 套完整中间件。补丁留着还能做因果对照,加一个参数看装配表多什么:

加的参数 中间件实例数 新增
什么都不加 11 —
skills=["/skills/"] 13 SkillsMiddleware 2 个
memory=["/memory/AGENTS.md"] 12 MemoryMiddleware 1 个
interrupt_on={"edit_file": True} 14 HumanInTheLoopMiddleware 3 个

同一个参数在不同位置的加法不一样:skills 同时装进主 Agent 与子 Agent,memory 只装进主 Agent。这种差异凭文档推不出来,补丁跑一遍就出来了。

手法三,读编译后的图:agent.get_graph() 实测 5 个节点 6 条边,节点是 __start__ / model / tools / PatchToolCallsMiddleware.before_agent / __end__。去掉首尾 2 个标记节点,可执行 3 个。11 个中间件实例只落成 1 个节点,因为绝大多数中间件是钩子式的,挂在 before_agent 与 after_agent 上,不产生独立节点。

声明面
文档写 6 加 execute 加 task

装配面
11 个中间件实例

模型面
8 个工具 · 0 字符

三者互不替代:spy 看不到装配过程,补丁看不到钩子有没有被真的调用,读图看不见钩子式中间件。问「谁收到了什么」用 spy,问「装了几个」用补丁,问「流程长什么样」用读图。

五、一次真实排查:报错跟真实原因差很远

有个报错值得单独讲。场景是把模型包一层,加个日志或计费之类的东西。包装对象对外看起来完全一样:invoke 在,bind_tools 在,直接调 invoke 也能跑,但 isinstance(包装对象, BaseChatModel) 是 False。

交给 create_deep_agent,报出来的是:

AttributeError: 'Spy' object has no attribute 'count'

根因是 resolve_model 用 isinstance 分流。是子类就走实例分支,不是子类就被当成模型名字符串,送进 apply_provider_profile,在那里读 model.count。排查时的一句话判据:isinstance(你的模型, BaseChatModel) 是不是 True。

六、这套默认装配适合什么,不适合什么

默认装配最大的优点是零配置可跑:不给模型名、不选 backend、不写提示词,8 个工具已经在手,循环就能转起来。适合学习和验证 harness 的行为,也适合任务边界清楚、跑完即弃的一次性脚本。

不适合的也很明确:

不适合的场景 原因 要改哪个决定
文件要跨进程留存 StateBackend 是内存态 backend
要跑 shell 命令 默认 backend 不实现沙箱协议 backend
说话风格要固定 提示词默认 0 字符 提示词
要收窄工具权限 tools= 只能加,减不掉 工具
要长期跑、要能恢复 不传 checkpointer 就没有持久状态 那 14 个参数里的钩子

这 4 个决定覆盖的是「第一次跑通」,不覆盖「长期运行」。要断点续跑、要做人工审批,都属于那 14 个参数的地盘。

七、结论

4 个决定里,3 个的默认值属于「安全但需要你知道」,1 个是「现在不报错,将来会报错」。

决定 建议的起点 什么时候改
模型 显式给,不省略 换模型时只改 1 处
工具 先不传,够用 要减内置时换口子
提示词 至少给 1 句 说话方式出问题时补
backend 先不传 要落盘或跑 shell 时换

装配这件事的反直觉之处在这里:18 个参数看着很多,第一次要做的决定只有 4 个。而且每一个的判据都不在参数说明里,在实测结果里。