Deep Agents:数千技能,先露名和简介,用到才读指令
技能是为智能体提供领域知识的最佳方式之一。一个技能包含一个指令、脚本和参考文件的文件夹,教智能体如何做事,比如准备客户会议,或者像你的销售团队那样审核通话记录。Agent Skills 是一项开放标准,适用于任何模型,并得到数十款智能体产品的支持。你也不必具备技术背景就能编写技能:其核心就是一个 markdown 文件。
技能之所以有效,依赖于渐进式披露。智能体一开始只看到每个技能的名称和描述,只有当任务需要时才读取完整指令。这样可以保持上下文精简,而上下文工程正是构建高效智能体的关键。
随着使用规模扩大,团队对技能的需求也在变化。我们看到企业技能注册表增长到数千个技能,并在团队和智能体之间共享。我们改进了 Deep Agents 中的技能支持,以解决一些常见需求:
- 将工具绑定到技能:绑定到技能的工具只在智能体读取该技能时加载。
- 固定技能:当用户明确请求某个技能(如 /meeting-prep)时,你的应用可以在下一次模型调用前加载它。
- 技能重载:长时间运行线程可以获取新增或变更的技能,而无需重新开始。
技能如何工作
一个技能是包含 SKILL.md 文件的目录:YAML frontmatter 包含名称和描述,后面是智能体遵循的指令。技能还可以在 scripts/、references/ 和 assets/ 下捆绑支持文件(规范)。
只有技能的名称和描述始终在上下文中。智能体按需读取指令,并且只在需要时加载脚本、参考文件和资源。
在本文中,我们将以我们的 GTM agent 作为贯穿示例。它基于 Deep Agents 构建,其超过 50 个技能的库涵盖了销售代表的重复性工作,如 meeting-prep、call-transcripts 和 competitive-intel-card。
技能分三级加载:
发现(Discovery)。启动时,智能体在系统提示中看到每个技能的名称和描述。
激活(Activation)。当任务与某个技能匹配时,智能体通过 read_file 读取完整的 SKILL.md。
执行(Execution)。智能体遵循指令,并且只在指令需要时读取脚本或参考文件。
智能体的上下文只按任务所需增长:启动时是每个技能的名称和描述,然后是一个技能的指令,再然后是一个参考文件。
在技能被使用之前,它只占用系统提示中的一行,因此技能库可以容纳大量技能引用而不会拥挤上下文。现在让我们深入探讨我们在 Deep Agents 中做出的增强。
将工具绑定到技能
技能通常告诉智能体如何使用特定工具,而有些工具只有在该智能体阅读了这些指令后才能正常工作。在此之前,技能和工具是分开披露的。你可以通过工具搜索将工具模式保持在上下文之外,但没有任何东西将工具与解释它的技能绑定:智能体可以不阅读技能就找到并调用工具,或者阅读了技能后仍然不得不搜索其工具。
现在,你可以将工具绑定到技能,这样技能和它的工具就会一起披露。绑定工具不会加入到上下文中,直到智能体读取了它的技能;在此之前调用它会被视为未知工具而失败。这保持了上下文的精简,也意味着智能体在调用工具之前已经阅读了如何使用它。在我们的 GTM agent 中,call-transcripts 解释了如何搜索通话和读取记录,因此它是绑定这些工具的自然位置。
在技能的 frontmatter 中的 metadata.include_tools 下列出工具:
将这些工具传给 SkillsMiddleware 而不是智能体。它们在智能体读取 call-transcripts 之前一直隐藏:
读取 call-transcripts 会解锁 search_calls 和 get_transcript。它们会出现在新的系统消息中,因此其上方的缓存前缀保持不变。
过去,在对话中途添加工具意味着要编辑请求的工具列表,这会使提示缓存失效。Anthropic 和 OpenAI 现在允许较新的模型在对话中途接受工具,因此在那些模型上,Deep Agents 会在技能被读取后立即添加技能的绑定工具,并且缓存前缀保持不变(Anthropic 和 OpenAI 集成文档)。在其他模型上,工具会像以前一样附加到请求中。
列表覆盖了大多数技能。要获得更多控制,技能可以列出标签而不是工具名称,你传给 SkillsMiddleware 的函数会将每个标签转换为工具。这允许你:
- 用一个名称披露整个工具组,比如 MCP 服务器上的所有工具,而无需在技能中列出每个工具。
- 根据运行时权限来门控工具。该函数接收图的运行时,因此它可以检查用户是谁,并只返回他们被允许使用的工具。
在这里,call-transcripts 获得 calls MCP 服务器上的所有工具,pipeline-forecast 获得 CRM 工具,但只有管理人员可以更新 forecast:
更多信息请参阅 Add tools to skills,比如将一个名称映射到 MCP 服务器上的每个工具。
固定技能
有时用户已经知道他们想要哪个技能。在我们的 GTM agent 中,销售代表可以输入 /meeting-prep for my Acme call tomorrow。如果不固定,模型只会看到技能的描述并必须去读取它。这会在工作开始前增加一次往返,而且模型不保证加载正确的技能。通过固定技能,你的应用会在消息中找到技能名称(或从 UI 中解析),并将它们传入 pinned_skills,中间件会在下一次模型调用前将每个技能的指令添加到对话中。Deep Agents 本身不解析消息,因此你可以选择语法:
键入 /meeting-prep 就指定了技能,因此应用可以将其固定,供智能体下一次模型调用使用。
固定技能的指令已经在对话中,因此智能体在第 1 次模型调用时就开始工作,而不是第 2 次。
这减少了延迟并使行为更可预测:指令保证在上下文中,固定技能的绑定工具也随之而来。每个固定技能作为带标签的消息被添加一次,因此之前的消息永远不会改变,提示缓存保持有效,聊天 UI 可以显示技能标签而不是完整文本。
线程中途重载技能
技能在每个线程开始时加载,并保存在智能体状态中,因此之后的每一轮都复用同一组技能。你现在可以通过在调用智能体时将 skills_metadata 设置为 None 来使该列表失效。如果队友向库中添加了 competitive-intel-card 技能,应用可以选择使技能列表失效,下一次运行将重新扫描每个来源:
将 skills_metadata 设置为 None 会使下一次运行重新扫描技能库,并获取自上次运行以来新增的技能。
重载发现新技能会改变系统提示,这会使提示缓存失效。对于一个空闲的线程来说,这种代价通常已经发生:提供商的缓存通常在不活动后的几分钟到一小时内过期(Anthropic、OpenAI),因此当销售代表回来时缓存已经冷了。
因为重置只是运行输入,你也可以将控制权交给用户。例如,客户端上的 /reload 命令:
你也可以从 update_state 或中间件进行重置,因此你的应用控制何时发生技能重载。参见 Reload skills。
开始使用
技能是为智能体提供有条理的领域知识的行业标准机制。这些更新使它们更易于大规模运行:工具只在技能需要时加载,工作流所需的技能预先加载,长时间运行的线程会随库的变化保持最新。而且由于技能是开放标准,你的团队编写的技能可以跨模型和智能体工作。
所有这些都可以在最新的 deepagents 中使用。阅读技能文档即可开始,并通过 GitHub issues、论坛或 X 告诉我们你的想法。
致谢
感谢 Rich Scarrott 主导开发这些新功能,感谢 Hunter Lovell 进行功能和博客审阅!