返回资源广场

Skills 资源 / 技能包

inspecting-agent-graph-and-tools

把一个 create_deep_agent 建出来的智能体拆开看:列出执行图节点、列出实际挂载的工具、捕获框架预装的中间件清单、抓取每轮真正发给模型的工具集。Use when 需要确认某项能力是否真的挂上了、排查「我的工具去哪了 / 这些工具哪来的 / 内置工具到底几个」、验证自定义中间件是否进了图、或要在改配置前后做结构对照时。涵盖图节点自省、工具清单反查、中间件清单捕获、编译期与运行期工具集差异;不含具体能力的用法。

SKILL.md 技能文档

能力目标

对着一个已构造的智能体,回答四个可验证的问题:它的执行图里有哪些节点、它实际能调哪些工具、框架替你装了哪几件中间件、每轮真正发给模型的工具集是什么。这是排查「能力没生效」类问题的第一手段,也是改配置前后做对照的标准动作。

前置

  • 已能用 create_deep_agent 构造一个智能体(见 bootstrapping-deepagents-env)。
  • create_deep_agent 的产物是一张编译后的 LangGraph 状态图,下面所有自省手段都基于这个事实。

实操流程

  1. 列执行图节点,确认预装能力有名有姓。节点名是「类名.钩子名」格式:

    agent = create_deep_agent(model=model, tools=[])
    for node in agent.get_graph().nodes.keys():
        print(node)
    

    典型输出是 __start__、model、tools、TodoListMiddleware.after_model、PatchToolCallsMiddleware.before_agent、__end__。后两个没被你传进去却在图里,就是框架预装的直接证据。

  2. 反查实际挂载的工具清单。这是查「我的工具挂上没 / 内置工具有哪些」的正确路径:

    tools_by_name = agent.nodes["tools"].bound.tools_by_name
    for name in sorted(tools_by_name.keys()):
        print(name)
    

    只传 1 个自己的工具时,清单里会同时出现 write_todos、ls、read_file、write_file、edit_file、glob、grep、task、execute 这些框架注入的工具。

  3. 做「有无预装」对照,量化某个配置带来的落差。用同一个工具分别喂给两个构造入口:

    from langchain.agents import create_agent
    from deepagents import create_deep_agent
    
    def tools_of(agent):
        return sorted(agent.nodes["tools"].bound.tools_by_name.keys())
    
    plain = create_agent(model=model, tools=[get_weather])
    deep = create_deep_agent(model=model, tools=[get_weather], system_prompt="x")
    print(len(tools_of(plain)), len(tools_of(deep)))
    
  4. 捕获框架实际装配的中间件清单。编译后的图不直接暴露这个列表,用一个临时替身函数在放行前截下入参:

    import deepagents.graph as dg
    
    captured = {}
    _orig = dg.create_agent
    
    def _spy(*a, **kw):
        captured["middleware"] = list(kw.get("middleware", []))
        return _orig(*a, **kw)
    
    dg.create_agent = _spy
    deep = create_deep_agent(model=model, tools=[get_weather], system_prompt="x")
    dg.create_agent = _orig
    for mw in captured["middleware"]:
        print(type(mw).__name__)
    

    捕获到的清单形如 TodoListMiddleware、FilesystemMiddleware、SubAgentMiddleware、摘要中间件、PatchToolCallsMiddleware、Anthropic 提示缓存中间件。注意其中的摘要中间件不提供任何工具,所以它出现在中间件清单里、却不在第 2 步的工具清单里。

  5. 抓每轮真正发给模型的工具集(运行期口径)。挂一个探针中间件,在包裹模型调用时截下 request.tools 并短路返回,省掉一次真实模型调用:

    from langchain.agents.middleware import AgentMiddleware
    from langchain_core.messages import AIMessage
    
    class ToolsProbeMW(AgentMiddleware):
        def __init__(self):
            self.captured_tools = None
    
        def wrap_model_call(self, request, handler):
            self.captured_tools = [t.name for t in request.tools]
            return AIMessage(content="[PROBE] 工具列表已捕获")
    
    probe = ToolsProbeMW()
    agent = create_deep_agent(model=model, tools=[get_weather], middleware=[probe])
    agent.invoke({"messages": [{"role": "user", "content": "test"}]})
    print(len(probe.captured_tools), probe.captured_tools)
    

校验回路

  • 第 1 步能打印出至少一个「类名.钩子名」形态的节点,说明预装中间件确实进了图;挂了自定义中间件后,覆盖 before_* / after_* 钩子的那一件会以自己的类名出现在节点列表里。
  • 第 2 步的清单里能找到你传进去的工具名,也能找到框架注入的工具名。
  • 第 3 步的两个数字应有明显落差:裸构造器只有你传的那一个,装具入口多出一批。
  • 第 5 步捕获到的工具名列表 = 你传入的工具 + 框架注入的工具,其中 write_todos 来自规划中间件、task 来自子智能体中间件、ls/read_file/write_file/edit_file/glob/grep 六个来自文件系统中间件。

常见陷阱

  • 用 agent.graph.nodes 取图结构:编译后的状态图没有 .graph 属性,会抛 AttributeError。公开方法是 agent.get_graph().nodes。
  • 用 agent.nodes['tools'].data 取工具:该对象没有 .data 属性,同样抛 AttributeError。正确路径是 .bound.tools_by_name——.bound 指向工具节点、工具节点才有这个字典。
  • 编译期清单与运行期清单对不上:execute 会出现在第 2 步的编译期工具字典里,却不在第 5 步的运行期工具集里。文件系统中间件在包裹模型调用时会检查当前后端是否具备执行命令的能力,默认后端不具备,于是把 execute 动态过滤掉、不发给模型。数工具个数时先说清是哪个口径。
  • 拿工具数去对支柱数:工具数不等于能力支柱数。文件操作那一族一件中间件就贡献六到七个工具,而上下文管理那一件一个工具都不提供。
  • 想直接取源码里被装饰过的工具函数:write_todos 这类经过工具装饰器包装后已不是普通函数,inspect.getsource(write_todos) 会抛 TypeError。取底层带下划线前缀的原函数(如 _write_todos)。

适用范围与前置条件

  • 已能用 create_deep_agent 构造一个智能体(见 bootstrapping-deepagents-env)。
  • create_deep_agent 的产物是一张编译后的 LangGraph 状态图,下面所有自省手段都基于这个事实。

怎么使用

使用步骤

  1. 列执行图节点,确认预装能力有名有姓。节点名是「类名.钩子名」格式:

    agent = create_deep_agent(model=model, tools=[])
    for node in agent.get_graph().nodes.keys():
        print(node)
    

    典型输出是 __start__、model、tools、TodoListMiddleware.after_model、PatchToolCallsMiddleware.before_agent、__end__。后两个没被你传进去却在图里,就是框架预装的直接证据。

  2. 反查实际挂载的工具清单。这是查「我的工具挂上没 / 内置工具有哪些」的正确路径:

    tools_by_name = agent.nodes["tools"].bound.tools_by_name
    for name in sorted(tools_by_name.keys()):
        print(name)
    

    只传 1 个自己的工具时,清单里会同时出现 write_todos、ls、read_file、write_file、edit_file、glob、grep、task、execute 这些框架注入的工具。

  3. 做「有无预装」对照,量化某个配置带来的落差。用同一个工具分别喂给两个构造入口:

    from langchain.agents import create_agent
    from deepagents import create_deep_agent
    
    def tools_of(agent):
        return sorted(agent.nodes["tools"].bound.tools_by_name.keys())
    
    plain = create_agent(model=model, tools=[get_weather])
    deep = create_deep_agent(model=model, tools=[get_weather], system_prompt="x")
    print(len(tools_of(plain)), len(tools_of(deep)))
    
  4. 捕获框架实际装配的中间件清单。编译后的图不直接暴露这个列表,用一个临时替身函数在放行前截下入参:

    import deepagents.graph as dg
    
    captured = {}
    _orig = dg.create_agent
    
    def _spy(*a, **kw):
        captured["middleware"] = list(kw.get("middleware", []))
        return _orig(*a, **kw)
    
    dg.create_agent = _spy
    deep = create_deep_agent(model=model, tools=[get_weather], system_prompt="x")
    dg.create_agent = _orig
    for mw in captured["middleware"]:
        print(type(mw).__name__)
    

    捕获到的清单形如 TodoListMiddleware、FilesystemMiddleware、SubAgentMiddleware、摘要中间件、PatchToolCallsMiddleware、Anthropic 提示缓存中间件。注意其中的摘要中间件不提供任何工具,所以它出现在中间件清单里、却不在第 2 步的工具清单里。

  5. 抓每轮真正发给模型的工具集(运行期口径)。挂一个探针中间件,在包裹模型调用时截下 request.tools 并短路返回,省掉一次真实模型调用:

    from langchain.agents.middleware import AgentMiddleware
    from langchain_core.messages import AIMessage
    
    class ToolsProbeMW(AgentMiddleware):
        def __init__(self):
            self.captured_tools = None
    
        def wrap_model_call(self, request, handler):
            self.captured_tools = [t.name for t in request.tools]
            return AIMessage(content="[PROBE] 工具列表已捕获")
    
    probe = ToolsProbeMW()
    agent = create_deep_agent(model=model, tools=[get_weather], middleware=[probe])
    agent.invoke({"messages": [{"role": "user", "content": "test"}]})
    print(len(probe.captured_tools), probe.captured_tools)
    

继续探索

全部资源
Skills 资源 / 技能包

bootstrapping-deepagents-env

在一台干净机器上装好 DeepAgents 运行环境、接入一个 OpenAI 兼容大模型凭证,并跑通第一个 create_deep_agent 工具调用闭环。Use when 需要初始化 DeepAgents 开发环境、系统 Python 版本不达标装不上包、不确定装到了哪个版本、接 DeepSeek 之类国产模型报 ImportError 或 404 这类环境层故障时。涵盖解释器版本核对、虚拟环境置备、主包与提供方包安装、版本核验、凭证注入、最小示例验收;不含 Agent 各项能力的用法(见 tracking-task-progress-with-todos 等能力型 skill)。

Skills 资源 / 技能包

tracking-task-progress-with-todos

让智能体把多步任务拆成结构化待办清单写进状态,并从调用结果里取出清单、渲染成实时进度、兜底检测「勾完清单却没给答案」的失败形态。Use when 需要给长任务做进度面板、想稳定触发 write_todos、发现规划没被触发、或要把 todos 推给前端 UI 与日志时。涵盖稳定触发写法、取清单的两条路径、三态进度渲染、失败形态检测;不含子任务委派(见 delegating-subtasks-to-subagents)。

Skills 资源 / 技能包

delegating-subtasks-to-subagents

定义子智能体并挂进主智能体,用内置的 task 工具把多步子任务整体委派出去,主上下文只收一条结论。Use when 主智能体的消息历史被子任务中间过程撑爆、想让不同子任务跑在不同模型上做成本分层、需要隔离子任务上下文、或排查「委派没发生 / 子智能体不知道用户交代过的约束」这类路由与信息真空问题时。涵盖子智能体字典三必填字段、挂载与触发、双向隔离边界、描述写法、开销与适用判据;不含单个智能体内部的规划(见 tracking-task-progress-with-todos)。