说说AI Agent 工程化开发实战(二):5 分钟跑通第一个 Deep Agent,然后拆开它

今天翻到一篇不错的技术分享,看完之后自己也琢磨了一下,把思路梳理记录下来。

目录

三、拆开它:套件内部长什么样四、工程化要点:递归认知与何时下沉附:「Deep Agents 等价实现」贴士模板参考文献

前言

主线:Agent Runtime → Harness。本篇是「自顶向下用」的第一步——直接从最高层的 Harness(套件)跑通第一个能调工具的 Agent,再把它拆开,看它内部就是 create_agent(薄壳)+ 一套内置中间件(中间件各自注入内置工具),最终落到 LangGraph 运行时。

一、为什么第一篇代码从套件起步

第 1 篇我们立了「双向认知」:自底向上是依赖顺序(学习用),自顶向下是使用顺序(开发用)。本系列按依赖顺序讲,是为了让你「会用且懂」;但真正上手写第一个 Agent,一定是自顶向下——直接站到最高层。

最高层是什么?就是 Deep Agents 套件,入口函数叫 create_deep_agent。它是整个生态里最省力的一个入口:一行代码,一个能调工具的 Agent(智能体)就起来了。

先别急着问「它里面是什么」。先把东西跑通,获得手感,再回来拆——这正是本篇标题「随后拆开它」的顺序。这个「默认从最高层起步、要控制再下沉」的方向,也是官方推荐的使用方式,后面篇章会把它展开成一棵完整的决策树,这里先按下不表。

二、实战案例:5 分钟跑通查天气

先交代模型。下面用 DeepSeek(国内可直连、按量付费便宜、OpenAI 兼容),是中文读者最省事的起步选择。但它不是硬依赖——create_deep_agent 只认「一个能调工具的聊天模型」。换模型的成本分两档:同厂商换模型(如 deepseek-chat → deepseek-reasoner)真的只改一行;换厂商(Anthropic 的 ChatAnthropic、OpenAI 的 ChatOpenAI、本地 Ollama 的 ChatOllama)则要改 import + model 两行,并额外装包、配 key(如 Ollama 要 pip install langchain-ollama)。

2.1 准备环境

# 一次性安装(首次安装依赖较多,请耐心等 pip 完成)
pip install deepagents==0.7.23 langchain-deepseek

# 配置 DeepSeek API Key(任选其一;注意:在同一个终端窗口里接着运行下面的 Python)
#   Windows CMD:   set DEEPSEEK_API_KEY=你的key
#   PowerShell:    $env:DEEPSEEK_API_KEY="你的key"
#   Linux / macOS: export DEEPSEEK_API_KEY=你的key

版本说明:这篇文章代码实测于 deepagents 0.7.23(create_deep_agent 的签名、内置工具、图结构都随版本演进,锁这个版本最稳)。set / $env: / export 只对当前终端窗口生效,换窗口要重新配;想永久保存可用 setx DEEPSEEK_API_KEY "你的key"(Windows)或写进 .env。

2.2 完整代码

天气工具这里用假数据,不接真实天气 API——这样零外部依赖、人人拿到就能跑,先把「Agent 会调工具」这件事跑通:

import sys

from langchain_core.messages import HumanMessage
from langchain_core.tools import tool
from langchain_deepseek import ChatDeepSeek
from deepagents import create_deep_agent

# Windows 控制台默认 GBK,模型回复若带 emoji,print 会抛 UnicodeEncodeError;强制 UTF-8 输出
sys.stdout.reconfigure(encoding="utf-8")

@tool
def get_weather(city: str) -> str:
    """查询某个城市的实时天气。"""
    # 演示用假数据,不接真实天气 API
    weather_db = {
        "北京": "晴,25°C,微风",
        "上海": "多云,28°C",
        "广州": "雷阵雨,32°C",
    }
    return weather_db.get(city, f"{city}:晴,22°C(默认)")

# 换成你的模型(换厂商要改 import + model 两行并装包配 key),例如:
#   from langchain_anthropic import ChatAnthropic
#   model = ChatAnthropic(model="claude-sonnet-4-5")   # 模型名以官方列表为准
model = ChatDeepSeek(model="deepseek-chat")

agent = create_deep_agent(
    model=model,
    tools=[get_weather],
    system_prompt="你是一个乐于助人的助手,会按需调用工具查询信息。",
)

def main() -> None:
    result = agent.invoke(
        {"messages": [HumanMessage(content="北京今天天气怎么样?")]}
    )
    print(result["messages"][-1].content)

if __name__ == "__main__":
    main()

跑一遍,输出大概是这样:

北京今天天气晴朗,气温25°C,有微风,是个不错的天气!😊

2.3 这一行 invoke 背后发生了什么

你没有手写任何「循环」,Agent 自己做好了一次典型的四步闭环:

步骤消息角色发生了什么1human你的坑「北京今天天气怎么样?」进入状态2ai模型判断「这要查天气」,产出一次工具调用 get_weather("北京")3tool执行工具,返回「晴,25°C,微风」4ai模型把工具结果组织成自然语言,回复你

这就是一个最小 Agent 的完整闭环:模型决策 → 调用工具 → 拿到结果 → 组织回复。后面讲工具调用循环的篇章会把这四步背后的机制(model 节点 + tools 节点 + 条件路由)逐行拆给你看,现在先记住「它自己会循环」即可。另外,上面四步是「典型路径」——模型偶尔会不调工具直接回答、或多次调用工具,都属正常,不必当成跑错了。

三、拆开它:套件内部长什么样

现在拆。把上面那行 create_deep_agent 沿第 1 篇的调用链往下剥,它其实等于:

create_deep_agent(model, tools)
    = create_agent(model, tools)               ← 第 3 层:薄壳(LangChain 在 LangGraph 之上的那半)
    + 内置中间件栈(Filesystem / SubAgent / Summarization / PatchToolCalls …)
       └─ 这些中间件各自注入「内置工具」(文件 / 执行 / 子 Agent)

这里要先立住一个关键认知:那些「内置工具」不是与中间件并列的独立一类,而是由中间件注入的——文件工具由 FilesystemMiddleware 注入,task 子 Agent 由 SubAgentMiddleware 注入。所以准确的公式是「套件 = 薄壳 + 内置中间件栈(中间件各自注入工具)」,不是「薄壳 + 工具 + 中间件」三块并列。核心是 create_agent——就是第 1 篇说的「薄壳」,它负责组装一个标准的「模型 ↔ 工具」循环图。套件在它外面加了一层中间件栈:

① 内置工具(由中间件注入,默认就有,不用你传)。你的 tools=[get_weather] 是「追加」,不会覆盖它们(以下为不完全列举,完整能力清单与可裁剪项见后文的能力全景篇):

  • 文件操作:ls / read_file / write_file / edit_file / glob / grep / delete —— 由 FilesystemMiddleware 注入
  • 执行代码:execute(需沙箱 backend,如 SandboxBackend;默认的 StateBackend 下不可用)
  • 调子 Agent:task —— 由 SubAgentMiddleware 注入
所以一个 Deep Agent 天生会读写文件、能派活给子 Agent——这些是「生产级 Agent 几乎都要用」的能力,套件替你装好了。

② 内置中间件栈。中间件(middleware)是包在「模型 ↔ 工具」循环外面的「插桩」,在模型调用前后、工具调用时等时机插入自定义逻辑。套件默认挂了一串:FilesystemMiddleware(管文件工具)、SubAgentMiddleware(注入 task 子 Agent 能力)、SummarizationMiddleware(长对话自动摘要)、PatchToolCallsMiddleware(修正工具调用)等。

能够用一个对照实验坐实这个结论。同样一个 get_weather,用薄壳 create_agent 再起一次,看两张图的节点(完整真源见 code/02-五分钟跑通第一个DeepAgent/inspect_graph.py):

from langchain.agents import create_agent

thin = create_agent(model=model, tools=[get_weather])
print(list(thin.get_graph().nodes))          # ['__start__', 'model', 'tools', '__end__']

deep = create_deep_agent(model=model, tools=[get_weather])
print(list(deep.get_graph().nodes))          # ['__start__', 'model', 'tools',
                                             #  'PatchToolCallsMiddleware.before_agent', '__end__']

薄壳版是干净的 model + tools 两个节点;套件版多出一个中间件注入的 PatchToolCallsMiddleware.before_agent 节点。多出来的,就是「套件」相对于「薄壳」加的那层料。(你可能好奇:中间件列了不止一个,怎么只多出一个节点?因为 FilesystemMiddleware、SubAgentMiddleware、SummarizationMiddleware 的 hook 挂在既有的 model / tools 节点上、不新增独立节点;只有 PatchToolCallsMiddleware 的 before_agent hook 生成了这个独立节点——这也是默认最小配置下唯一新增的独立节点。)

一句话收口:套件 = 薄壳 + 内置中间件栈(内置工具由中间件注入)。它不发明新的执行语义,只是把「最省事的那条路」铺好。

四、工程化要点:递归认知与何时下沉

第 1 篇埋过一句话,本篇第一次用代码把它坐实了一半,这里扩展成完整的递归链条:

套件包着薄壳,薄壳包着运行时(Runtime),运行时依赖积木(langchain-core)。
  • create_deep_agent 内部就是调用 create_agent、把默认中间件栈传进去(源码里 return create_agent(...),讲 Deep Agents 源码的篇章可见)——所以「套件包着薄壳」;
  • create_agent 内部构建 StateGraph(讲 create_agent 源码的篇章你会亲眼看到)——所以「薄壳包着运行时」;
  • StateGraph 依赖 langchain-core 的 messages / tools / models——所以「运行时依赖积木」。
这条链条的实际用途是一个下沉指南:你在套件层改不动、找不到的东西,往下一层就摸得到。落到日常开发就是第 1 篇那句选型口诀的升级版:
  • 默认站套件——「能调工具、带记忆、能读写文件、明天要演示」,create_deep_agent 一行搞定;
  • 要精确控制某一步,就一路下沉到管那一步的那层——举个例子人工审批(HITL)要沉到运行时去接 interrupt(),多智能体拓扑要沉到 StateGraph 的子图去写。
判断标准只有一个:你现在要的是「省事」还是「控制」? 省事往高层走,控制往低层沉,没有中间态。

附:「Deep Agents 等价实现」贴士模板

从下一篇着手,我们会正式进入 LangGraph 运行时,逐篇手写 StateGraph 的节点、边、状态、检查点。为了让你随时能跳回高层,本系列约定:每篇 LangGraph 篇的末尾,都附一个「Deep Agents 等价实现」贴士——引言句式固定,等价代码按篇可变:

Deep Agents 等价实现 这篇文章手写的 ,在 Deep Agents 套件层的等价写法是 。举个例子最普通的「模型 + 工具」循环:
>
> agent = create_deep_agent(model=..., tools=[...], ...)
> 
> 要更细控制时,再回到这篇文章的底层写法。

这个模板在最常用的「模型 + 工具」循环场景就是上面这条;到讲人工审批(HITL)的篇章等价物换成 interrupt_on 高层配置、讲多智能体的篇章换成 task 子 Agent,各走各的等价物。本篇本身是从高层起步、往下拆,所以模板在这里定义并示范一次。

参考文献

[1] LangChain 官方文档 · Agents(create_agent)— https://docs.langchain.com/oss/python/langchain/agents
[2] LangChain 官方文档 · Middleware(中间件)— https://docs.langchain.com/oss/python/langchain/middleware
[3] Deep Agents 官方文档 · Customization(中间件栈顺序)— https://docs.langchain.com/oss/python/deepagents/customization


🎯 更多专栏系列文章能够查看博客主页📑 👍 若文章对你有所触动,恳请**


暂时整理到这里。以上都是个人理解,可能有疏漏,欢迎指正。

评论 (0)

暂无评论