跳到正文
LangChain Blog·· 2 小时前精选AI 评分62

LangChain 为 Deep Agents 重构 Skills 支持

Revamping Skills in Deep Agents

AI 导读

LangChain 为 Deep Agents 重构 Skills 支持,新增三项能力:工具可绑定到技能,只有智能体读取该技能时才加载;用户显式请求的技能可固定,在下一次模型调用前载入;长线程可通过将 skills_metadata 设为 None 重新扫描技能库。技能是包含 SKILL.md 的目录,采用渐进式披露,启动时上下文只保留每个技能的名称和描述,正文称企业技能注册表已增长到数千个技能。

推荐理由

原文给出技能与工具绑定、固定技能和线程内重载三项改动,读者可据此判断大规模技能库的上下文成本与延迟变化。

正文 · AI 翻译

技能是为智能体赋予领域知识的最佳方式之一。技能是一个包含指令、脚本和参考文件的文件夹,教会智能体如何做事,比如像你的销售团队那样准备客户会议或审阅通话记录。Agent Skills 是一项开放标准,可与任何模型配合使用,并受到数十种智能体产品的支持。你也不需要懂技术就能编写一个:其核心就是一个 markdown 文件。

技能之所以有效,是因为渐进式披露。智能体一开始只能看到每个技能的名称和描述,只有在任务需要时才读取完整指令。这样可以让上下文保持精简,而上下文工程是构建高效智能体的关键。

随着使用规模扩大,团队对技能的需求也在变化。我们看到企业技能注册表增长到数千个技能,跨团队和智能体共享。我们改进了Deep Agents 中的技能支持,以解决一些常见需求:

  • 将工具绑定到技能:绑定到某个技能的工具只有在智能体读取该技能时才会加载。
  • 固定技能:当用户明确请求某个技能时,例如 /meeting-prep,你的应用可以在下一次模型调用前加载它。
  • 技能重新加载:长时间运行的线程可以获取新的或更改过的技能,而无需重新开始。

技能如何工作

一个技能是一个目录,其中包含一个 SKILL.md 文件:带有 name 和 description 的 YAML frontmatter,后面是智能体遵循的指令。一个技能还可以在 scripts/、references/ 和 assets/ 下捆绑支持文件(规范)。

Only a skill's name and description are always in context. The agent reads the instructions on demand, and loads scripts, references, and assets only when needed.

只有技能的名称和描述始终在上下文中。智能体按需读取指令,并且只在需要时加载脚本、参考文件和资源。

在本文中,我们将使用我们的 GTM 智能体作为贯穿示例。它构建在 Deep Agents 之上,其包含 50 多个技能的库涵盖了销售代表的重复性工作,例如 meeting-prep、call-transcripts 和 competitive-intel-card。

技能分三个层级加载:

  1. 发现。启动时,智能体在其系统提示中看到每个技能的 name 和 description。
  2. 激活。当任务匹配某个技能时,智能体读取带有 read_file 的完整 SKILL.md。
  3. 执行。智能体遵循指令,并且只在需要时读取脚本或参考文件。

The agent's context grows only by what the task needs: every skill's name and description at startup, then one skill's instructions, then one reference file.

智能体的上下文只按任务所需增长:启动时每个技能的名称和描述,然后是一个技能的指令,然后是一个参考文件。

在技能被使用之前,它只占用系统提示中的一行,因此一个库可以容纳大量技能的引用,而不会挤占上下文。现在让我们深入了解我们在 Deep Agents 中做出的增强。

将工具绑定到技能

技能通常会告诉智能体如何使用特定工具,而有些工具只有在智能体读取了这些指令后才能很好地工作。到目前为止,技能和工具是分开披露的。你可以通过工具搜索将工具 schema 排除在上下文之外,但没有任何东西将工具与解释它的技能绑定起来:智能体可能找到并调用某个工具,却没有读取其技能,或者读取了技能却仍然不得不搜索其工具。

现在你可以将工具绑定到技能,这样技能及其工具会一起被披露。绑定的工具在 agent 读取其技能之前不会被加入上下文,在此之前调用它会因未知工具而失败。这保持了上下文的精简,也意味着 agent 在能够调用工具之前已经读取了如何使用它的说明。在我们的GTM agent中,call-transcripts 解释了如何搜索通话和读取转录,因此它是绑定这些工具的自然位置。

在技能 frontmatter 的 metadata.include_tools 下列出这些工具:

call-transcripts SKILL.md frontmatter listing include_tools: search_calls get_transcript

将这些工具传递给 SkillsMiddleware 而不是 agent:

Python: create_deep_agent with SkillsMiddleware(tools=[search_calls, get_transcript])

Reading call-transcripts unlocks search_calls and get_transcript. They arrive in a new system message, so the cached prefix above it stays unchanged.

读取通话转录会解锁 search_calls 和 get_transcript。它们会出现在一条新的系统消息中,因此其上方的缓存前缀保持不变。

在对话中途添加工具过去意味着编辑请求的工具列表,这会使提示缓存失效。Anthropic 和 OpenAI 现在允许较新的模型在对话中途接受工具,因此在这些模型上,Deep Agents 会在技能被读取后立即添加该技能绑定的工具,缓存前缀保持完整(Anthropic 和 OpenAI 集成文档)。在其他模型上,工具会像以前一样追加到请求中。

一个列表就能覆盖大多数技能。为了获得更多控制,技能可以列出一个标签而不是工具名称,而你传递给 SkillsMiddleware 的函数会将每个标签转换为工具。这让你可以:

  • 披露整个工具组,比如 MCP 服务器上的所有工具,用一个名称表示,而无需在技能中逐一列出每个工具。
  • 根据运行时权限控制工具。该函数会接收图的运行时,因此它可以检查用户是谁,并只返回他们被允许使用的工具。

在这里,call-transcripts 获取 calls MCP 服务器上的所有工具,pipeline-forecast 获取 CRM 工具,但只有经理可以更新预测:

SKILL.md frontmatter for call-transcripts (include_tools: call_tools) and pipeline-forecast (include_tools: crm_tools)

Python: resolve_skill_tools returns every calls MCP tool for call_tools, and update_forecast only for managers

更多内容请参见向技能添加工具。

固定技能

有时用户已经知道自己想要哪个技能。在我们的 GTM agent 中,销售代表可以输入 /meeting-prep for my Acme call tomorrow。如果不固定,模型只能看到技能的描述,并且必须读取它。这会在工作开始前增加一次往返,而且模型不保证会加载正确的技能。使用固定技能,你的应用会在消息中找到技能名称(或从 UI 中解析),并将它们传入 pinned_skills,中间件会在下一次模型调用之前将每个技能的指令添加到对话中。Deep Agents 本身不解析消息,因此语法由你选择:

Typing /meeting-prep names the skill, so the app can pin it for the agent's next model call.

输入 /meeting-prep 会指定该技能,因此应用可以为 agent 的下一次模型调用固定它。

Python: parse /meeting-prep from the message and pass it as pinned_skills to agent.invoke

A pinned skill's instructions are already in the conversation, so the agent starts the work on model call 1 instead of model call 2.

固定技能的指令已经在对话中,因此 agent 会在第 1 次模型调用时就开始工作,而不是第 2 次。

这降低了延迟,并使行为更可预测:指令保证在上下文中,而且固定技能绑定的工具也会随之而来。每个固定技能都会作为一条带标签的消息添加一次,因此较早的消息永远不会改变,提示缓存保持有效,聊天 UI 可以将该技能显示为标签而不是其全文。

在线程中途重新加载技能

技能会在每个线程开始时加载,并保存在 agent 状态中,因此之后的每一轮都会复用同一组技能。现在你可以在调用 agent 时将 skills_metadata 设置为 None 来使此列表失效。如果队友向库中添加了一个 competitive-intel-card 技能,应用程序可以选择使技能列表失效,下一次运行将重新扫描每个来源:

Python: agent.invoke with skills_metadata set to None

Setting skills_metadata to None makes the next run rescan the skill library and pick up a skill added since the last run.

将 skills_metadata 设为 None 会让下一次运行重新扫描技能库,并拾取自上次运行以来新增的技能。

重新加载时若发现新技能,会改变系统提示词,从而使提示词缓存失效。对于已经闲置一段时间的线程,这个代价通常已经付过了:提供商的缓存通常在闲置几分钟到一小时后过期(Anthropic、OpenAI),所以当代表回来时缓存已经冷了。

由于重置只是运行输入,你也可以把控制权交给用户。例如,客户端上的一个 /reload 命令:

Python: a /reload command sets skills_metadata to None in the run payload

你也可以从 update_state 或中间件中重置,这样你的应用就能控制技能重新加载的时机。参见重新加载技能。

开始使用

技能是为智能体提供有组织的领域知识的行业标准机制。这些更新让它们更容易大规模运行:工具只在技能需要时才加载,工作流所需的技能会预先加载,长时间运行的线程会随着你的库变化而保持最新。而且由于技能是开放标准,你的团队编写的技能可跨模型和智能体使用。

所有这些都可在最新的 deepagents 中使用。阅读技能文档开始使用,并通过GitHub issues、论坛或X告诉我们你的想法。

致谢

感谢Rich Scarrott主导这些新功能的开发,以及Hunter Lovell进行功能与博客审阅!

来源:LangChain Blog · langchain.com