SKILL.md 技能文档
能力目标
对着一个已构造的智能体,回答四个可验证的问题:它的执行图里有哪些节点、它实际能调哪些工具、框架替你装了哪几件中间件、每轮真正发给模型的工具集是什么。这是排查「能力没生效」类问题的第一手段,也是改配置前后做对照的标准动作。
前置
- 已能用
create_deep_agent构造一个智能体(见 bootstrapping-deepagents-env)。 create_deep_agent的产物是一张编译后的 LangGraph 状态图,下面所有自省手段都基于这个事实。
实操流程
列执行图节点,确认预装能力有名有姓。节点名是「类名.钩子名」格式:
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__。后两个没被你传进去却在图里,就是框架预装的直接证据。反查实际挂载的工具清单。这是查「我的工具挂上没 / 内置工具有哪些」的正确路径:
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这些框架注入的工具。做「有无预装」对照,量化某个配置带来的落差。用同一个工具分别喂给两个构造入口:
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)))捕获框架实际装配的中间件清单。编译后的图不直接暴露这个列表,用一个临时替身函数在放行前截下入参:
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 步的工具清单里。抓每轮真正发给模型的工具集(运行期口径)。挂一个探针中间件,在包裹模型调用时截下
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 状态图,下面所有自省手段都基于这个事实。
怎么使用
使用步骤
列执行图节点,确认预装能力有名有姓。节点名是「类名.钩子名」格式:
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__。后两个没被你传进去却在图里,就是框架预装的直接证据。反查实际挂载的工具清单。这是查「我的工具挂上没 / 内置工具有哪些」的正确路径:
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这些框架注入的工具。做「有无预装」对照,量化某个配置带来的落差。用同一个工具分别喂给两个构造入口:
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)))捕获框架实际装配的中间件清单。编译后的图不直接暴露这个列表,用一个临时替身函数在放行前截下入参:
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 步的工具清单里。抓每轮真正发给模型的工具集(运行期口径)。挂一个探针中间件,在包裹模型调用时截下
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)