LangChain 实现 Skill 框架

Skill 基本概念

Skills 的概念由 Anthropic 提出,本质上是一种更高层次的模块化能力封装,用于扩展智能体的功能边界。每一个 Skill 都封装了指令、元数据以及可选的资源(如脚本、模板等),智能体在执行任务时,会根据上下文相关性自动选择并调用合适的 Skill。

Skill 🆚 Tools:

  • Skill:加载专业知识
  • Tools:执行动作,调用API

Skills的核心功能:

  1. 专业工作流:特定领域的多步骤操作流程
  2. 工具集成:使用特定文件格式或 API 的指导说明
  3. 领域专长:企业特有知识、数据架构、业务规则
  4. 资源包:处理复杂和重复任务所需的脚本、参考文档和相关资源

Skills的组成部分:

  • SKILL.md
    • 头部元数据 (YAML 格式):包含 name(名称)和 description(描述)字段。
    • 主体内容(Markdown 格式):关于如何使用该技能的说明和指引。只有在技能被触发后才会加载。
  • 脚本 (scripts/):可执行代码(Python/Bash 等),适用于需要确保可靠性或经常重复编写的任务。
  • 参考资料 (references/):文档和参考材料,按需加载到上下文中,用于指导 Claude 的工作流程和思考方式。
  • 资源文件 (assets/):在最终输出内容中可能需要使用到的文件

Skills的核心特征:

特征 说明
Prompt 驱动 Skill 的本质是一段专业领域的 prompt,而非代码逻辑
按需加载 Agent 根据用户问题判断需要哪个 Skill,再动态加载
自动发现 SkillMiddleware 自动把所有 Skill 的简短描述注入 system prompt
团队解耦 不同团队可以独立开发和维护各自的 Skill(只需新建 .md 文件)
数据注入 需要案件数据的 Skill 在加载时自动注入相关数据

通过 LangChain 中间件实现 Skill 渐进式加载框架

整体框架

  1. 扫描Skills目录下所有的Skill的name和description,封装到系统提示词;
  2. Agent读取所有Skill的name和description,选定skill执行load_skill工具,获取skill的详细内容。

实现方法

  1. 在Skills目录下创建一个新的Skill,目录名称为skill的名称,必须包含Skill.md,可以包含 scriptsreferences等目录。
text 复制代码
---
name: food-calorie
description: 精准计算各类食物卡路里,支持按食材、重量、烹饪方式拆分核算总热量
metadata:
  author: nobody
  version: 2.0.0
---
  1. 根据Skill文件格式确定数据类型,部分skill可能包含脚本文件:
python 复制代码
class Skill(TypedDict):
    """文件夹型技能:支持 scripts / references / assets"""

    name: str  # 技能名 = 文件夹名
    description: str  # 简短描述(来自 SKILL.md 第一行)
    content: str  # SKILL.md 完整内容
    path: Path  # 技能根目录
    scripts: list[Path]  # scripts/ 下所有文件
    references: list[Path]  # references/ 下所有文件
    assets: list[Path]  # assets/ 下所有文件
  1. 从skills目录中读取所有skill的基础信息:
python 复制代码
def load_skills_from_dir(skills_root_dir: Path) -> list[Skill]:
    skills = []
    for skill_dir in sorted(skills_root_dir.iterdir()):
        if not skill_dir.is_dir():
            continue

        skill_md = skill_dir / "SKILL.md"
        if not skill_md.exists():
            continue

        text = skill_md.read_text(encoding="utf-8")

        # ======================
        # 修复点:从 YAML 头读取 description
        # ======================
        lines = text.splitlines()
        description = "No description"

        # 解析 --- 包裹的 YAML 头部
        if len(lines) > 2 and lines[0].strip() == "---":
            try:
                # 找到下一个 ---
                end_idx = lines[1:].index("---") + 1
                header_lines = lines[1:end_idx]

                # 读取 description 字段
                for line in header_lines:
                    if line.strip().startswith("description:"):
                        description = line.split(":", 1)[1].strip()
                        break
            except ValueError:
                pass

        skills.append(
            Skill(
                name=skill_dir.name,
                description=description,
                content=text,
                path=skill_dir,
                scripts=(
                    list((skill_dir / "scripts").glob("*"))
                    if (skill_dir / "scripts").exists()
                    else []
                ),
                references=(
                    list((skill_dir / "references").rglob("*"))
                    if (skill_dir / "references").exists()
                    else []
                ),
                assets=(
                    list((skill_dir / "assets").glob("*"))
                    if (skill_dir / "assets").exists()
                    else []
                ),
            )
        )
    return skills
    
SKILLS = load_skills_from_dir(Path(__file__).parent)
  1. 定义工具,供Agent加载指定的skill
python 复制代码
@tool
def load_skill(skill_name: str) -> str:
    """Load the full content of a skill into the agent's context."""
    for skill in SKILLS:
        if skill["name"] == skill_name:
            return f"Loaded skill: {skill_name}\n\n{skill['content']}"

    available = ", ".join(s["name"] for s in SKILLS)
    return f"Skill '{skill_name}' not found. Available skills: {available}"
  1. 通过 AgentMiddleware 中间件实现 Skill 渐进式信息披露:
python 复制代码
class SkillMiddleware(AgentMiddleware):
    """自动把所有【文件夹技能】注入系统提示"""

    tools = [load_skill, list_skill_files, read_skill_file]

    def __init__(self):
        skills_list = []
        for skill in SKILLS:
            skills_list.append(f"- **{skill['name']}**: {skill['description']}")
        self.skills_prompt = "\n".join(skills_list)

    def wrap_model_call(
        self,
        request: ModelRequest,
        handler: Callable[[ModelRequest], ModelResponse],
    ) -> ModelResponse:
        skills_addendum = (
            f"\n\n## Available Skills\n\n{self.skills_prompt}\n\n"
            "Use load_skill to get full instructions.\n"
            "Use list_skill_files to list files in a skill.\n"
            "Use read_skill_file to read any file in a skill."
        )

        new_content = list(request.system_message.content_blocks) + [
            {"type": "text", "text": skills_addendum}
        ]
        new_system_message = SystemMessage(content=new_content)
        modified_request = request.override(system_message=new_system_message)
        return handler(modified_request)
  1. 测试:
python 复制代码
def test_skill_middleware():
    llm = ChatOpenAI(model="qwen-flash", temperature=0.3)
    agent = create_agent(
        model=llm,
        middleware=[SkillMiddleware()],
        checkpointer=InMemorySaver(),
        system_prompt="你是一位运动与营养学的专家",
    )
    config = {"configurable": {"thread_id": "1"}}

    result = agent.invoke(
        input={
            "messages": [
                {
                    "role": "user",
                    "content": "我今天吃了10碗米饭,而且还用青椒肉丝的汤汁浇在米饭上,摄入的卡路里是多少?",
                },
            ]
        },
        config=config,
    )

    # Print the conversation
    for message in result["messages"]:
        if hasattr(message, 'pretty_print'):
            message.pretty_print()
        else:
            print(f"{message.type}: {message.content}")

可以看到 Agent 加载了 food-calori skill:

yaml 复制代码
================================== Ai Message ==================================
Tool Calls:
  load_skill (call_c790c732842245a98dc85c)
 Call ID: call_c790c732842245a98dc85c
  Args:
    skill_name: food-calorie
================================= Tool Message =================================
Name: load_skill

Loaded skill: food-calorie

---
name: food-calorie
description: 精准计算各类食物卡路里,支持按食材、重量、烹饪方式拆分核算总热量
metadata:
  author: DevTeam
  version: 2.0.0
---

# 食物卡路里计算专家指南
## 角色定位
你是专业营养学计算助手,擅长拆解混合食材、区分原生食材/加工烹饪方式、按国标营养热量标准,精准核算单种或多种食物总卡路里。
......
......

================================= Ai Message ==================================
Tool Calls:
  read_skill_file (call_76edf6d96c894868b889aa)
 Call ID: call_76edf6d96c894868b889aa
  Args:
    skill_name: food-calorie
    file_path: references/standard_calories.md
================================= Tool Message =================================
Name: read_skill_file

参考资料:

  1. LangChain 官方 Skills 文档
  2. Skills 框架教学文档
相关推荐
一知半解仙3 分钟前
从0到1!Spring Cloud微服务无缝集成AI智能体:架构设计+核心源码+生产落地全指南
人工智能·spring cloud·微服务
数字融合4 分钟前
透明化时空联合无缝追踪,构筑无断点全域态势感知网络专项技术
网络·人工智能·virtualenv
ltqvibe7 分钟前
异构系统对接的虚拟层架构:本体语义如何架在现有系统之上
人工智能·字段映射·jboltai·异构系统集成
cn分享汇9 分钟前
2026免费空间大的网盘软件有哪些推荐,主流网盘拆解
大数据·网络·人工智能
CTA量化套保16 分钟前
2026年量化入门路线,概念规则和简单实现逐步走
人工智能·python
神奇霸王龙17 分钟前
金融AI对决:Qwen3.7-Max屠榜降本60%
人工智能·ai·金融·prompt·aigc·ai金融
thesky12345622 分钟前
智能体面试准备(六):Agent 记忆系统设计——短期、长期与向量记忆的架构与实现
人工智能·面试·agent·智能体·记忆系统
wangxin20824 分钟前
CoordClaw 底层机制解构:多智能体协作的工程原理
人工智能·ai·多智能体·组织管理·openclaw·coordclaw·ai数字社会
眼泪划过的星空25 分钟前
大模型 Fine-tuning 通俗指南:从原理到实践
人工智能