import os
from typing import Literal
from deepagents import create_deep_agent
from deepagents.backends import FilesystemBackend
from deepagents.middleware import SkillsMiddleware
from langchain_core.tools import tool
from tavily import TavilyClient
from agent.my_llm import llm

tavily_client = TavilyClient(api_key='')
@tool
def internet_search(query: str,
    max_results: int = 5,
    topic: Literal["general", "news", "finance"] = "general",
    include_raw_content: bool = False,):
    """使用 Tavily API 进行网络搜索,获取最新的新闻和信息。

    支持通用搜索、新闻搜索和金融搜索三种模式,可以获取实时网络信息。

    Args:
        query: 搜索查询词,描述要搜索的内容
        max_results: 返回的最大结果数量,默认 5
        topic: 搜索主题类型,可选 "general"(通用)、"news"(新闻)、"finance"(金融)
        include_raw_content: 是否包含原始页面内容,默认 False

    Returns:
        包含搜索结果的字典,包括标题、URL、内容片段等信息
    """
    print(f'调用网络查询工具,查询内容:{query}')
    return tavily_client.search(query=query, max_results=max_results, topic=topic, include_raw_content=include_raw_content)


backend = FilesystemBackend(root_dir=os.getcwd(),virtual_mode=True)
skills_middleware = SkillsMiddleware(
    backend=backend,
    sources=["skills"],
)

agent = create_deep_agent(
    model=llm,
    tools = [internet_search],
    system_prompt="你是一名研究助理。你可以使用 'web_search' 技能来寻找最新信息。",
    middleware=[skills_middleware]
)
result = agent.invoke({"messages": [{"role": "user", "content": "2026特朗普访华新闻"}]})
print(result['messages'][-1].content)

        2025 年 10 月中旬,Anthropic 正式发布 Claude Skills。 两个月后,Agent Skills 作为开放标准被进一步发布,意在引导一个新的 AI Agent 开发生态。Agent 可通过加载不同的 Skills 包,来具备不同的专业知识、工具使用能力,稳定完成特定任务。 Skills  是模块化的能力,扩展了 Agent 的功能。每个Skill 都打包了 LLM 指令、元数据、可选资源(脚本、模板等),Agent 会在需要时自动使用他们。

什么是 Agent Skill?

        Agent Skill 是一个自包含、按需加载的知识/行为模块,通常表现为一个标准文件夹,内含核心的 SKILL.md 指令文件以及可选的脚本、参考文档等资源。

  • 它不是普通工具:普通工具(Tool)只负责“执行一个原子操作”(如搜索、计算),而 Skill 更关注“如何完成一个相对复杂的任务流程”,它可能指导模型组合调用多个工具、遵守特定格式、处理错误、分步推理

  • 它是动态提示词:Skill 本质上是可被 Agent 在运行时按需读取并注入到上下文中的长指令。Agent 平时只“知道”有哪些 Skill(名称+简短描述),当用户问题匹配某个 Skill 时,才读取其完整内容。

        用通俗的话讲:Agent Skill 就是一份“工作说明书”,平时只看到书名,需要做具体工作时才翻开看详细步骤。

Agent Skills 能做什么?

Skill 赋予 Agent 以下几类核心能力:

1. 封装复杂流程,降低主提示词负担

        你可以把一个 5000 字的业务操作指南放进一个 Skill。Agent 平时只消耗几十个字符的 description,需要时才加载全文。
        示例postgres-query Skill 里写明如何连接数据库、如何构造安全查询、如何解释结果,主提示词只需一句“当你需要查询数据库时使用此技能”。

2. 实现多步骤任务的稳定复现

        Skill 可以将成功经验固化,避免 Agent 每次都“重新发明轮子”。
        示例:一个 customer-complaint Skill 定义了收到投诉后:① 识别情绪 → ② 调用工单系统 → ③ 生成标准回复 → ④ 记录日志。Agent 按此执行,输出质量稳定。

3. 让 Agent 安全地调用敏感工具

        通过 Skill 里的 allowed-tools 元数据(虽然目前多是提示),你可以告知模型“执行此 Skill 时可安全使用哪些工具”,降低越权风险。
        示例send-email Skill 只允许 write_file 和 send_smtp 工具,禁止 delete_file

4. 实现角色扮演或领域专家模式

        一个 Skill 可以让 Agent 临时变身为“财务专家”、“法律顾问”或“客服代表”,切换系统提示和行为约束。
        示例tax-expert Skill 内写满税法条款和计算规则,一旦启用,Agent 回答税务问题会更专业严谨。

5. 构建可插拔的 Agent 能力生态

         为了更好的理解,你可以把 Skills 理解为“通用 Agent 的扩展包”: Agent 可通过加载不同的 Skills 包,来具备不同的专业知识、工具使用能力,稳定完成特定任务。

        团队或个人可以像“安装插件”一样共享、复用 Skill,只需把 Skill 文件夹放入指定目录,Agent 自动识别。
        示例:一个开源的 weather-forecast Skill 被下载后,放入 ./skills/ 文件夹,Agent 立刻具备全球天气查询能力。

为什么提出 Agent Skills?

        提出 Agent Skill 是为了同时解决传统方法中的两大矛盾

矛盾一:大模型上下文窗口有限 vs. 我们希望它掌握海量知识

  • 直接放进系统提示:会迅速撑爆上下文(例如让 Agent 记住 100 个复杂任务的详细步骤)。

  • 靠微调(Fine-tuning):成本高、更新慢,无法实时添加新能力。

  • 靠检索增强(RAG):虽然能外挂知识库,但对过程性、指令性知识(“如何做”)的检索效果不如结构化 Skill。

        Skill 的解法渐进式披露(Progressive Disclosure)—— 先给目录,按需翻正文。用极小的元数据开销,换取无限的详细指令扩展。

矛盾二:Agent 的行为随机性强 vs. 业务场景需要稳定流程

  • 普通 Prompt 下,模型对同一任务的执行方式可能每次不同,导致不可预测。

  • 手写复杂的工具调用链(LangChain Chain / Graph)虽然稳定,但开发成本高、不够灵活。

Skill 的解法流程固化 + 自然语言约束。Skill 中用 Markdown 写明“步骤1做什么,步骤2做什么,如果出现异常怎么办”,模型被引导沿着稳定路径前进,同时保留了自然语言的适应性。

额外动机:能力复用的工业化需求

  • 过去每个 Agent 的能力都需要定制开发(写工具、写提示)。

  • Skill 提出后,团队可以把一个“技能”打包成文件夹,上传到内部仓库或 GitHub,其他人复制粘贴即用。这类似于AI Agent 领域的 “Docker 容器”,大大提高了能力复用效率。

工具和skills对比

Agent Skills和Milti-Agent对比

        Agent Skills​ Multi-Agent架构​ 都旨在解决“如何让AI Agent处理复杂任务”的问题,但它们的思路、实现路径和适用场景有本质区别。

        Agent Skills是“模块化的方式强化个人”,而Supervisor多Agent是“协作的方式建设团队”。

使用场景

核心机制:为何它能“知晓一切”又不“内存爆炸”?

这个巧妙的平衡,依赖于一个叫做“渐进式披露 (Progressive Disclosure)”的机制。整个过程分为三步:

  1. 加载“目录”:Agent启动时,只会读取所有Skill的简要信息(name 和 description),并将其作为一份目录整合到系统提示词里。初始加载成本极低,模型只知道有这些能力存在,但并不清楚具体怎么做。

  2. 判断与选择:当你提出需求时,Agent会根据需求,与“目录”中的描述进行匹配,判断是否需要调用某个Skill。

  3. 只读“正文”:当确定需要时,Agent才会去完整读取该Skill文件夹下的 SKILL.md 等具体文件,获取如何执行的详细指令并据此执行任务。

这个机制的精妙之处在于,它将“知道有什么能力”和“知道如何使用能力”分成了两步,从而用极小的上下文成本,赋予了模型海量的“知识”。

SKILL.md:一个Skill的精髓

SKILL.md 是定义能力的唯一入口。它的内部结构由两部分组成:

  • YAML 前置元数据 (Frontmatter):用 --- 包裹,包含供Agent快速识别的字段。

    • name (必填):Skill的唯一标识,要求使用小写字母和连字符,1-64个字符。通常与Skill的文件夹同名。

    • description (必填):用一句话说明这个Skill的功能和使用场景,1-1024个字符。这是Agent决定是否调用的关键依据。

    • license (可选):技能许可协议,如 MITApache-2.0

    • compatibility (可选):说明运行该技能所需的环境要求,如特定软件、网络访问等。

    • allowed-tools (可选):提供一个信任的“允许列表”,告知模型在执行此技能时可以安全地使用哪些工具。

  • Markdown 指令 (Instructions):这是YAML之后的核心内容。需要用清晰的语言指导Agent在什么时机、按什么步骤、采用什么格式来执行该技能。

技术实现:如何让Agent拥有Skills?

        在技术层面,这主要靠 SkillsMiddleware 来实现。它就像搭在Agent和底层存储系统之间的桥梁,负责从你指定的目录加载Skill,并协调“渐进式披露”的流程。这让你可以灵活选择文件系统、云端存储甚至数据库来存放你的Skills。

方法对比:技能加载的两种方式

        在deepagents中,主要有两种方式来加载技能,理解它们的区别对你选择合适的写法会很有帮助:

最佳实践:如何写出一个好的Skill?

想写出高质量的Skill,可以从以下几点入手:

  • 单一职责:一个Skill只专注做好一件事,保持模块的简洁和清晰。

  • Meta指令先行:在 description 中写清“何时使用”和“解决什么问题”,这是Agent调用Skill的“第一道门”。

  • 善用技能组合:一个复杂的业务可以由多个简单的Skill组合完成。不同Skill之间可以通过 SKILL.md 中的 Tool 调用其他Skill或外部工具来实现复杂流程。

  • 保持"目录"精简SKILL.md 文件本身应保持小巧(建议<5k tokens),将详细的API文档、代码示例等放在 reference/ 等子文件夹中,仅供Agent按需查阅。

  • 版本控制:将Skill及其配套文件纳入Git等版本管理,便于追踪变更、进行Code Review和协同开发。

  • 评测驱动迭代:收集真实任务作为测试基准,基于评测结果持续优化Skill的指令和逻辑。

注意事项与常见问题

  • 文件大小限制:为了性能考虑,每个 SKILL.md 文件的大小有限制(如在Deep Agents中必须小于10 MB),过大的文件会被跳过。

  • allowed-tools 仅为提示:请注意,allowed-tools 字段目前仅是一个给Agent的“提示”(hint),中间件并不会强制执行这一限制。

  • 工具隔离性:Skill本质上是“提示片段”,而不是“运行时单元”,因此没有开始和结束事件可供钩子捕捉。

  • 命名规则:Skill的 name 必须严格遵循命名规范(小写字母、连字符、数字),不要使用下划线或空格。

示例一:使用 skills 参数 (最推荐)

这种方式是最快捷的,适合大多数情况

目录结构:

在项目根目录下创建一个 skills 文件夹,并按照官方规范创建技能描述文     件 web_search/SKILL.md。请确保该文件中使用YAML格式定义了技能的 name 和 description

SKILL.md内容如下:

---
name: web_search
description: 当你需要从互联网上查找最新信息来回答用户问题时,使用此技能。
---

# Web Search Skill
- **何时使用**:当用户的问题需要联网搜索、获取实时数据或背景信息时。
- **如何执行**:通过调用 `internet_search` 工具来完成。你需要分析用户的问题,提炼出精确的搜索关键词,并将其作为 `query` 参数进行搜索。

测试代码:

import os
from typing import Literal
from deepagents import create_deep_agent
from langchain_core.tools import tool
from tavily import TavilyClient
from agent.my_llm import llm

tavily_client = TavilyClient(api_key='')
@tool
def internet_search(query: str,
    max_results: int = 5,
    topic: Literal["general", "news", "finance"] = "general",
    include_raw_content: bool = False,):
    """使用 Tavily API 进行网络搜索,获取最新的新闻和信息。

    支持通用搜索、新闻搜索和金融搜索三种模式,可以获取实时网络信息。

    Args:
        query: 搜索查询词,描述要搜索的内容
        max_results: 返回的最大结果数量,默认 5
        topic: 搜索主题类型,可选 "general"(通用)、"news"(新闻)、"finance"(金融)
        include_raw_content: 是否包含原始页面内容,默认 False

    Returns:
        包含搜索结果的字典,包括标题、URL、内容片段等信息
    """
    print(f'调用网络查询工具,查询内容:{query}')
    return tavily_client.search(query=query, max_results=max_results, topic=topic, include_raw_content=include_raw_content)


agent = create_deep_agent(
    model=llm,
    tools = [internet_search],
    system_prompt="你是一名研究助理。你可以使用 'web_search' 技能来寻找最新信息。",
    skills=["skills"]
)
result = agent.invoke({"messages": [{"role": "user", "content": "2026特朗普访华新闻"}]})
print(result['messages'][-1].content)

示例二:使用 SkillsMiddleware 中间件 (适合高度定制)

这种方式提供了更多的控制权,适合需要深度定制的场景

  1. 技能文件夹结构
    与方式一相同,需要一个 skills/web_search/SKILL.md 文件

测试代码如下:
 

import os
from typing import Literal
from deepagents import create_deep_agent
from deepagents.backends import FilesystemBackend
from deepagents.middleware import SkillsMiddleware
from langchain_core.tools import tool
from tavily import TavilyClient
from agent.my_llm import llm

tavily_client = TavilyClient(api_key='')
@tool
def internet_search(query: str,
    max_results: int = 5,
    topic: Literal["general", "news", "finance"] = "general",
    include_raw_content: bool = False,):
    """使用 Tavily API 进行网络搜索,获取最新的新闻和信息。

    支持通用搜索、新闻搜索和金融搜索三种模式,可以获取实时网络信息。

    Args:
        query: 搜索查询词,描述要搜索的内容
        max_results: 返回的最大结果数量,默认 5
        topic: 搜索主题类型,可选 "general"(通用)、"news"(新闻)、"finance"(金融)
        include_raw_content: 是否包含原始页面内容,默认 False

    Returns:
        包含搜索结果的字典,包括标题、URL、内容片段等信息
    """
    print(f'调用网络查询工具,查询内容:{query}')
    return tavily_client.search(query=query, max_results=max_results, topic=topic, include_raw_content=include_raw_content)


backend = FilesystemBackend(root_dir=os.getcwd(),virtual_mode=True)
skills_middleware = SkillsMiddleware(
    backend=backend,
    sources=["skills"],
)

agent = create_deep_agent(
    model=llm,
    tools = [internet_search],
    system_prompt="你是一名研究助理。你可以使用 'web_search' 技能来寻找最新信息。",
    middleware=[skills_middleware]
)
result = agent.invoke({"messages": [{"role": "user", "content": "2026特朗普访华新闻"}]})
print(result['messages'][-1].content)

示例三:技能自包含脚本实现方法

目录如下:

SKILL.md文件内容如下:

---
name: tavily-search
description: 使用 Tavily API 搜索互联网,获取实时新闻、金融数据或通用信息。当用户询问最新新闻、实时事件、股价等需要联网的内容时,必须使用此技能。
allowed-tools: execute
---

# Tavily 搜索技能

## 何时使用
- 用户询问最新新闻、事件(如“特朗普2026年5月访华最新消息”)
- 用户需要实时数据、股价、天气等
- 任何你的内部知识无法回答且需要联网的问题

## 如何使用
你拥有 `execute` 工具,可以直接运行 Shell 命令。请按以下格式执行搜索脚本:

```bash
python skills/tavily-search/search.py --query "搜索关键词" --topic general --max-results 5

search.py如下:

#!/usr/bin/env python3
"""
Tavily 搜索脚本 - 通过命令行调用
用法: python search.py --query "关键词" [--max-results 5] [--topic general]
"""

import os
import sys
import json
import argparse
from typing import Literal

# 设置 API Key(可以从环境变量读取)
TAVILY_API_KEY = os.environ.get("TAVILY_API_KEY")
if not TAVILY_API_KEY:
    print("错误: 请设置环境变量 TAVILY_API_KEY", file=sys.stderr)
    sys.exit(1)

# 优先使用 tavily 包,如果没有则使用 requests(更轻量)
try:
    from tavily import TavilyClient

    client = TavilyClient(api_key=TAVILY_API_KEY)
    USE_TAVILY_PACKAGE = True
except ImportError:
    import requests

    USE_TAVILY_PACKAGE = False


def internet_search(
        query: str,
        max_results: int = 5,
        topic: Literal["general", "news", "finance"] = "general",
        include_raw_content: bool = False,
) -> dict:
    """使用 Tavily API 进行网络搜索,返回字典结果"""
    print(f"🔍 正在搜索: {query} (主题: {topic})", file=sys.stderr)

    if USE_TAVILY_PACKAGE:
        # 使用官方包
        return client.search(
            query=query,
            max_results=max_results,
            topic=topic,
            include_raw_content=include_raw_content,
        )
    else:
        # 使用 requests 直接调用 API(无需安装 tavily-python)
        url = "https://api.tavily.com/search"
        payload = {
            "api_key": TAVILY_API_KEY,
            "query": query,
            "max_results": max_results,
            "topic": topic,
            "include_raw_content": include_raw_content,
            "include_answer": True,
        }
        resp = requests.post(url, json=payload, timeout=30)
        resp.raise_for_status()
        return resp.json()


def main():
    parser = argparse.ArgumentParser(description="Tavily 网络搜索")
    parser.add_argument("--query", "-q", required=True, help="搜索关键词")
    parser.add_argument("--max-results", "-n", type=int, default=5, help="最大结果数 (默认5)")
    parser.add_argument("--topic", "-t", choices=["general", "news", "finance"], default="general", help="搜索主题")
    parser.add_argument("--raw", action="store_true", help="包含原始内容")
    parser.add_argument("--json", action="store_true", help="以 JSON 格式输出")
    args = parser.parse_args()

    result = internet_search(
        query=args.query,
        max_results=args.max_results,
        topic=args.topic,
        include_raw_content=args.raw,
    )

    if args.json:
        print(json.dumps(result, ensure_ascii=False, indent=2))
        return

    # 文本输出(便于 Agent 阅读)
    if result.get("answer"):
        print(f"📌 答案摘要: {result['answer']}\n")

    results = result.get("results", [])
    if not results:
        print("未找到相关结果。")
        return

    print(f"共找到 {len(results)} 条结果:\n")
    for i, item in enumerate(results, 1):
        title = item.get("title", "无标题")
        url = item.get("url", "")
        content = item.get("content", "")[:300]
        print(f"{i}. {title}")
        print(f"   链接: {url}")
        print(f"   内容: {content}...\n")


if __name__ == "__main__":
    main()

测试代码:

import os
import subprocess
from pathlib import Path
from deepagents import create_deep_agent
from deepagents.backends import FilesystemBackend
from langchain_core.messages import HumanMessage
from langchain_core.tools import tool

# 假设你的 LLM 配置在 agent.my_llm 中
from agent.my_llm import llm

# 设置 Tavily API Key(也可以从环境变量读取,这里显式设置)
os.environ['TAVILY_API_KEY'] = ''

EXAMPLE_DIR = Path(__file__).parent

# 通用命令执行工具(所有技能共用)
@tool
def execute(command: str) -> str:
    """执行 Shell 命令并返回输出。用于运行 Python 脚本、系统命令等。"""
    try:
        result = subprocess.run(
            command,
            shell=True,
            capture_output=True,
            text=True,
            timeout=60,
            cwd=str(EXAMPLE_DIR)  # 确保在项目根目录执行
        )
        return result.stdout + result.stderr
    except subprocess.TimeoutExpired:
        return "命令执行超时(60秒)"
    except Exception as e:
        return f"执行错误: {e}"

# 创建 Agent:只有通用工具 + skills 目录
agent = create_deep_agent(
    model=llm,
    tools=[execute],                         # 唯一工具:执行命令
    backend=FilesystemBackend(root_dir=EXAMPLE_DIR, virtual_mode=False),
    skills=[str(EXAMPLE_DIR / 'skills')],    # 加载 skills 文件夹
    system_prompt=(
        "你是我的AI助手。当需要联网搜索、查询新闻或实时信息时,"
        "必须使用 'tavily-search' 技能。用 execute 工具运行 "
        "python skills/tavily-search/search.py --query ... 命令。"
    )
)

if __name__ == "__main__":
    resp = agent.invoke({
        "messages": [HumanMessage("帮我查询特朗普2026年5月访华的最新新闻")]
    })
    print(resp['messages'][-1].content)

示例四:下载网上的skill

下载地址:https://hub.cocoloop.cn/, 这里使用tavily-search-pro做测试,直接放在代码目录下

测试代码:

import os
from pathlib import Path
from deepagents import create_deep_agent
from deepagents.backends import FilesystemBackend
from langchain_core.messages import HumanMessage
from langchain_core.tools import tool

from agent.my_llm import llm
import subprocess


os.environ['TAVILY_API_KEY'] = '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'

EXAMPLE_DIR = Path(__file__).parent
# 提供通用命令执行工具
@tool
def execute_command(command: str) -> str:
    """执行 shell 命令并返回输出(用于运行 Python 脚本等)。"""
    try:
        print(f"执行脚本:{command}")
        result = subprocess.run(command, shell=True, capture_output=True, text=True, timeout=60)
        return result.stdout + result.stderr
    except subprocess.TimeoutExpired:
        return "命令执行超时(60秒)"
    except Exception as e:
        return f"执行错误: {e}"
agent = create_deep_agent(
        model=llm,
        tools=[execute_command],
        backend=FilesystemBackend(root_dir=EXAMPLE_DIR, virtual_mode=False),
        skills=[str(EXAMPLE_DIR / 'skills')],
        system_prompt="你是我的AI助手,当用户询问新闻、实时信息或需要搜索时,请务必使用tavily技能进行网络搜索。不要仅依赖自己的知识,要主动使用搜索技能获取最新信息。"
)


resp = agent.invoke(input={"messages": [HumanMessage("帮我查询特朗普2026年5月访华的最新新闻")]})

print(resp['messages'][-1].content)

Logo

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

更多推荐