把 LangGraph 的状态机编排能力与 Skills 的可复用能力相结合,关键在于将每个 Skill 封装成一个标准的节点(Node),然后交给 LangGraph 的状态图来调度。

以下从标准流程、三种集成方式和完整代码示例三个层面来拆解。


核心标准流程(发现 → 选择 → 加载 → 使用)

这是集成工作中最核心、业界通用的标准流程,它能实现按需加载,避免一次性把所有能力塞给模型 -3

  1. 发现 (Discovery):系统启动时,扫描 skills_library/ 目录下的所有子文件夹,只解析每个 SKILL.md 文件开头的 YAML 元数据(name 和 description)。这一步开销很小,约 100 tokens/技能 -3

  2. 选择 (Select):根据当前用户的具体任务,从发现的技能列表中匹配最合适的一个。匹配策略可以是简单的关键词匹配,也可以是由 LLM 进行语义判断 -3

  3. 加载 (Load):仅在确定需要某个技能后,才完整读取其 SKILL.md 文件的全部内容,并按需加载其 scripts/ 或 references/ 目录下的资源文件 -3

  4. 使用 (Use):将加载到的技能说明或代码,作为执行上下文交给 LLM 或直接运行,完成具体任务。

Progressive Disclosure(渐进式披露) 这一设计模式的核心思路。它是 Agent Skills 规范 中定义的一种优化策略,核心目的是将技能知识分层管理,按需加载,而不是一次性把所有信息塞入上下文,从而节省资源。

核心设计:三层结构

它将技能知识划分为三个层级,每个层级有不同的内容、加载时机和规模:

层级 内容 何时加载 典型规模
L1 元数据 name、description (frontmatter) 每次调用 ~100 tokens/技能
L2 指令 完整 SKILL.md 正文 选定技能后 <5000 tokens/技能
L3 资源 references/、assets/ 中的文件 技能明确引用时 按需

一个生动的类比

这个过程可以比作在餐厅点餐:

  1. L1:顾客先看菜单上的菜名和简短描述,决定要点什么。
  2. L2:然后向服务员询问具体做法和配料。
  3. L3:如果对某道菜的酱汁配方特别感兴趣,再要求看详细的配方卡。

这样做的好处是,顾客不必一进门就拿到所有菜品的完整菜谱,避免了信息过载。

实际效果示例
当用户提出“Review my blog post for SEO”的请求时:

  • 传统全量加载:需要将博客写作、SEO、研究、代码审查等四个技能的完整指令(约8000 token)全部放入上下文。
  • 采用渐进式披露
    1. 先加载L1(4个技能的名称和描述,约400 token)。
    2. Agent识别出需要SEO技能后,仅加载 seo-checklist 的L2指令(约300 token)。
    3. 只有当技能内部明确引用了 references/seo-guidelines.md 时,才加载L3资源。

通过这种方式,总消耗的Token数量从 8000 降低到了约 700,节省了大约 90% 的资源。

START
  ↓
discover (L1)     → 扫描 skills_library,解析每个 SKILL.md 的 frontmatter
  ↓
select           → 根据 user_task 从 L1 列表选出 1~N 个技能(LLM 语义匹配)
  ↓
load_l2          → 仅对选中技能读取完整 SKILL.md 正文
  ↓
execute          → 将 L2 作为 system 上下文,将 load_skill_resource 暴露为 Agent 工具;
                    Agent 根据 L2 指令按需调用工具加载 references/ 中的文件(L3)
  ↓
END

Specification

核心要素 说明
定义 一种轻量级、开放的格式,用于扩展 AI Agent 的能力。
核心文件 SKILL.md:包含元数据(Frontmatter)和指令。
目录结构 包含 scripts/ (脚本), references/ (参考资料), assets/ (资源) 等文件夹。
工作流 渐进式披露 (Progressive Disclosure):L1 发现元数据 -> L2 加载指令 -> L3 按需执行资源。

建议直接访问 agentskills.io/specification 查看最完整的详细文档。

三种主流集成方式

根据开源 Skills 的类型,可以选择不同的封装方式融入到 LangGraph 的状态图中 -9

封装方式 适用场景 集成说明
封装为工具 (Tool) 原子函数型技能 使用 @tool 装饰器将单个功能(如计算、搜索)快速封装,然后通过 create_react_agent 的 tools 参数传入,让模型自主调用 -9-10
封装为子图 (Subgraph) 流程任务型技能 对于本身包含多步骤逻辑的技能(如 TDD 开发流程),将其独立封装成一个 StateGraph,在主图中作为一个节点调用。这样能保持主流程的简洁 -9
封装为路由器 (Router) 复杂决策型技能 利用 SkillManager 管理所有技能的元数据,在 Supervisor 节点中注入 [GLOBAL_RULES] 和 [CONFLICT_RESOLUTION] 等知识,引导 LLM 做路由决策 -1

代码实践解读

结合搜索到的资料,我们可以从动态技能管理和静态图编排两个角度,来理解具体的代码实现。

1. 动态:实现一个 Skills Manager

为了让系统能自动发现并加载技能,通常需要一个 SkillManager 类来管理 discover 和 load 的核心逻辑。参考 skill_loader.py 的设计 -3

from pathlib import Path
from typing import Dict, List, Optional

class SkillsManager:
    def __init__(self, skills_root: Path):
        self.skills_root = Path(skills_root)
        self.skills_cache = {}

    # 1. 发现阶段
    def discover_skills(self) -> List[Dict[str, str]]:
        """扫描技能库,仅读取SKILL.md的元数据(name, description),低开销"""
        skills_metadata = []
        for skill_dir in self.skills_root.iterdir():
            if not skill_dir.is_dir():
                continue
            skill_md_path = skill_dir / "SKILL.md"
            if not skill_md_path.exists():
                continue
            raw_content = skill_md_path.read_text(encoding="utf-8")
            # 解析 YAML frontmatter,提取 name 和 description
            metadata = self._parse_frontmatter(raw_content)
            if metadata.get("name"):
                skills_metadata.append(metadata)
        return skills_metadata

    # 2. 选择 & 3. 加载
    def load_skill(self, skill_name: str) -> str:
        """根据选中的技能名,读取并返回完整的SKILL.md正文"""
        skill_path = self.skills_root / skill_name / "SKILL.md"
        if not skill_path.exists():
            return ""
        return skill_path.read_text(encoding="utf-8")

    def _parse_frontmatter(self, content: str) -> Dict:
        # 实现具体的解析逻辑,提取 --- 之间的 YAML 内容
        pass
2. 静态:构建 LangGraph StateGraph

有了如上管理器,便可以在 StateGraph 中调用它。以下代码利用 InMemorySaver 实现对话记忆,复用 create_react_agent 简化了工具调用流程 -4-10

from langgraph.graph import StateGraph, END
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.prebuilt import create_react_agent, ToolNode
from langchain_openai import ChatOpenAI
from typing import TypedDict, Annotated
from langchain_core.messages import BaseMessage

# 1. 定义全局状态
class AgentState(TypedDict):
    messages: Annotated[list[BaseMessage], "add_messages"]

# 2. 初始化 Skills Manager
skills_mgr = SkillsManager(skills_root="./skills_library")

# 3. 将指定的 Skill 封装为工具
def wrap_skill_as_tool(skill_full_text: str):
    """一个简单的示例工具,实际应用中可能需要更复杂的解析"""
    from langchain_core.tools import tool
    @tool
    def dynamic_skill(query: str) -> str:
        """根据SKILL.md的说明执行任务"""
        # 这里通常会将 skill_full_text 作为 System Prompt 的一部分传给 LLM
        return f"根据技能说明({skill_full_text[:50]}...)处理了: {query}"
    return dynamic_skill

# 4. 构建 Agent
def build_agent():
    # 发现技能
    discovered = skills_mgr.discover_skills()
    if not discovered:
        raise Exception("未发现任何技能")
    
    # 假设根据任务选中第一个技能
    target_skill = discovered[0]
    print(f"选中技能: {target_skill['name']}")
    
    # 加载完整技能说明并封装为工具
    full_skill_md = skills_mgr.load_skill(target_skill['name'])
    my_tool = wrap_skill_as_tool(full_skill_md)
    
    # 创建 ReAct Agent,它内部自动实现了节点和工具调用循环
    model = ChatOpenAI(model="gpt-4")
    agent = create_react_agent(
        model=model, 
        tools=[my_tool], 
        checkpointer=InMemorySaver() # 启用记忆
    )
    return agent

def run_agent(user_input: str, thread_id: str):
    agent = build_agent()
    config = {"configurable": {"thread_id": thread_id}}
    result = agent.invoke({"messages": [("user", user_input)]}, config=config)
    return result

提示:除了用 create_react_agent,你也可以手动编写条件边(tools_condition)和工具节点(ToolNode)来更精细地控制流程,例如在调用工具前先做输入校验 -10

总结与建议

  1. 遵循规范是基础:无论内部使用还是开源,建议遵循 SKILL.md + 文件夹的规范,这能让你无缝接入社区生态(如 LangChain 官方 Skills)-3-8

  2. 从单技能开始验证:可以先让 LangGraph 调用一个简单的 Skill 走通流程,再逐步增加 Skills 数量和路由决策的复杂度。

  3. 善用检查点:利用 InMemorySaver 或 SqliteSaver 实现任务的断点续传和对话记忆,这对长任务场景非常重要 -4

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐