5.4. 自定义 Skill 开发可以复用任何 Python 库或 API

自定义 Skill 开发可以复用任何 Python 库或 API

读完本章你将理解:任何一个 Python 库、任何一行公开的 API 调用,都能被封装为 Hermes 可调用的标准 Skill。你不只是在“写个脚本”,而是在为 Agent 的决策回路增加一块可组合、可测试、可演进的功能积木。

时间线回到 2026 年 4 月,Hermes Agent v0.16.0 版本已经收敛出一套稳定的 Skill 规范——不论你是在 Notion 里搜笔记,还是用 requests 调一个外部服务,输出形态都变成了同一种东西:一个带有 schema、可被 Tool Dispatch 发现和调度的 Python 类。接下来的所有代码都可以在你自己的机器上直接跑通,只要你能写 Python、能 pip install,就等于拿到了通往 Agent 工具箱的钥匙。


1. 你需要什么

项目 说明
运行环境 Python ≥ 3.10,任意操作系统
依赖库 requests(用于调用外部 API),jsonschema(参数校验,可选)
测试工具 pytest(≥ 7.0)
前置理解 你已经知道 Tool Dispatch 是技能调用的统一后端(上一章内容)
预计时间 约 25 分钟(含编写、测试、集成)

本章的示例代码不依赖 Hermes Agent 的内部包,我们会先手动模拟 Agent 的调用方式,确保你可以在隔离环境里独立运行和测试,之后再一键挂载到真实 Agent 上。


2. 最终成果:一个“查询 GitHub 用户信息”的可调用 Skill

我们将从零实现一个 GithubProfileSkill,Agent 只需发出:

{"skill": "github_profile", "params": {"username": "torvalds"}}

就能拿回结构化的用户数据——名称、头像、仓库数、粉丝数等,就像调用一个本地函数一样自然。

为什么做这个?
它能直观证明两件事:

  • 复用已有的 Python 生态:requests 这个库你早就用熟了,现在它能直接进入 Agent 的决策流。
  • 参数自动校验:如果你写错了 username 类型,Skill 根本不会执行,避免脏数据进入后续链路。

3. 步骤说明

步骤 1:搭建最小项目骨架

创建一个独立目录,结构如下:

hermes-skill-demo/
├── skills/
│   └── github_profile/
│       ├── __init__.py
│       └── skill.py
└── tests/
    └── test_github_profile.py

在项目根目录下初始化一个虚拟环境并安装依赖:

python -m venv venv
source venv/bin/activate   # Windows 为 venv\Scripts\activate
pip install requests jsonschema pytest

预期结果pip list 中能看到 requestsjsonschemapytest,没有报错。


步骤 2:编写最小可运行 Skill 类

一个符合 Tool Dispatch 规范的 Skill 必须包含三个核心部分:

  • 标识信息:名称、描述、参数定义(JSON Schema)
  • 生命周期方法__init__ 用于加载配置,execute 用于执行业务逻辑

打开 skills/github_profile/skill.py,写入以下代码:

# skills/github_profile/skill.py
import requests

class GithubProfileSkill:
    # 1. 标识元信息(类变量)
    name = "github_profile"
    description = "获取指定 GitHub 用户的公开信息(头像、仓库数等)"
    schema = {
        "type": "object",
        "properties": {
            "username": {
                "type": "string",
                "description": "GitHub 用户名"
            }
        },
        "required": ["username"]
    }

    # 2. 初始化(可传入额外配置,如 API Token,本例暂时不用)
    def __init__(self, config: dict = None):
        self.config = config or {}

    # 3. 核心执行方法——Agent 真正调用的入口
    def execute(self, params: dict) -> dict:
        """按 schema 的约定接收参数,返回结构化结果"""
        username = params["username"]
        url = f"https://api.github.com/users/{username}"
        resp = requests.get(url, timeout=10)
        resp.raise_for_status()  # 非 2xx 将抛出异常,由上层处理

        data = resp.json()
        return {
            "login": data["login"],
            "name": data.get("name", ""),
            "avatar_url": data["avatar_url"],
            "public_repos": data["public_repos"],
            "followers": data["followers"],
            "following": data["following"],
            "bio": data.get("bio", "")
        }

关键设计execute 返回一个干净的 dict,而不是 requests.Response。这使得后续处理链路(日志、记忆、学习)可以统一消费数据,不受底层库具体类型的干扰。


步骤 3:加入参数模式与验证(Schema 落地)

上面已经在 schema 里定义了 JSON Schema,但 Agent 调用时是否一定传入合法参数?真实环境中,Tool Dispatch 会根据 schema 自动校验,但为了你独立验证 Skill 的正确性,我们可以手动加上一道防线。

修改 execute 方法,增加参数校验:

# skills/github_profile/skill.py(新增部分)
import jsonschema
from jsonschema import validate, ValidationError

class GithubProfileSkill:
    # ... 前面内容保持不变 ...

    def execute(self, params: dict) -> dict:
        # 手动校验参数
        try:
            validate(instance=params, schema=self.schema)
        except ValidationError as e:
            raise ValueError(f"参数校验失败: {e.message}") from e

        # 正常业务逻辑
        username = params["username"]
        # ...

如果用户传入 {"username": 123},会立刻得到清晰的错误提示,而不是让错误发生在远端 API 调用里。

踩坑提醒

  • 不要忘记安装 jsonschema 库;从 Hermes Agent v0.16.0 的源码看,Tool Dispatch 内部也使用该库做校验,提前在本机验证能省去大量调试时间。
  • schema.properties 里的类型必须和实际期望一致,比如 username 应该是 "type": "string",若写成 "integer",检验逻辑会把正确的字符串参数也拒绝掉。

预期结果:现在手动调用 skill.execute({"username": "torvalds"}) 应该成功返回字典;传入 {"xx": 1} 会抛出 ValueError


步骤 4:编写单元测试与模拟环境

为了在不启动完整 Agent 的情况下验证 Skill,我们用 pytest 模拟 Agent 调用。

创建 tests/test_github_profile.py

# tests/test_github_profile.py
import pytest
from skills.github_profile.skill import GithubProfileSkill

# 模拟 Agent 调用工具函数
def simulate_agent_call(skill, params):
    """模拟 Tool Dispatch 的调用流程"""
    try:
        result = skill.execute(params)
        return {"status": "ok", "data": result}
    except Exception as e:
        return {"status": "error", "message": str(e)}

@pytest.fixture
def skill():
    return GithubProfileSkill()

def test_valid_username(skill):
    """正常查询一个真实用户"""
    response = simulate_agent_call(skill, {"username": "torvalds"})
    assert response["status"] == "ok"
    assert response["data"]["login"] == "torvalds"
    assert "name" in response["data"]
    assert response["data"]["public_repos"] > 0

def test_invalid_params(skill):
    """传入不符合 schema 的参数应被前置校验拦截"""
    response = simulate_agent_call(skill, {"username": 12345})
    assert response["status"] == "error"
    assert "参数校验失败" in response["message"]

运行测试:

pytest tests/

预期结果:两个测试全部通过(若网络正常)。测试输出中会显示绿色 .PASSED

设计思想simulate_agent_call 故意把调用入口包装成和 Tool Dispatch 一样的统一格式(status + data/message),这让你在没有 Agent 真实环境时也能察觉:这个 Skill 被集成后会产生什么输出、错误会如何向上传递。


步骤 5:向 Tool Dispatch 注册你的 Skill(最小集成路径)

在本地验证通过后,只需两步就能让真实 Agent 看到这个技能:

  1. skills/github_profile/ 整个文件夹复制到 Hermes 的 skill 目录(在配置文件中指定的 skill_dir,默认为 ~/.hermes/skills/)。
  2. 重启 Agent 服务,Tool Dispatch 启动时会自动扫描该目录,根据 nameschema 生成可调用工具。

无需修改任何核心代码,因为你的 Skill 已经符合接口约定。


4. 回顾:我们做了什么,花了多久

  • 搭建骨架并安装依赖:5 分钟
  • 编写 Skill 类init + execute):8 分钟
  • 加入参数校验并手动测试:5 分钟
  • 用 pytest 构建模拟测试:7 分钟

总计约 25 分钟,你从一个想法(“Agent 能查 GitHub 信息就好了”)走到了一个可以被 Agent 调用的、有测试守护的工具脚本。这里隐藏的核心能力远不止查一个 API——你写下的 execute 体里,可以放任何 Python 库:用 pandas 做数据分析、用 smtplib 发邮件、用 Pillow 处理图片……只要它能被 Python 完成,就能变成 Agent 的技能。


5. 行动清单

读完本章后,建议你完成以下几步来固化认知:

  1. GithubProfileSkill 替换为你自己常用的一段 Python 脚本(比如从数据库拉数据、读本地文件),改成符合以上格式的 Skill。
  2. 为你的新 Skill 编写至少两个测试:一个正常路径,一个参数异常路径。
  3. 观察 execute 返回值结构,思考它能否被 Agent 的后续模块(如记忆摘要、自动复盘)顺利消费。
  4. 在本机的 Hermes 实例中激活它,并直接通过聊天界面测试调用。
  5. 留意调用日志——Tool Dispatch 会记录 Skill 调用耗时、成功率等信息,为后续优化做准备。

上一章我们亲眼看到了 Tool Dispatch 如何充当技能调用的统一后端,把通信、校验、重试这些脏活累活全部屏蔽。本章之后,你手里已经有了产出标准化 Skill 的完整能力——任何 Python 库或 API 都能成为 Agent 可以理解并调用的工具。

然而,现实世界的服务不止有简单的 HTTP API。某些外部系统已经按照 Model Context Protocol(MCP)暴露了工具、资源和提示,如果我们能把这些现成的能力“原样吸收”,Hermes 的边界将被推向任意外部服务。下一章“通过 MCP 工具链可将 Hermes 能力边界扩展至任意外部服务” 将带你拆解 MCP 协议的接入方式,让 Agent 真正实现“即插即用”的工具生态。

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
讨论数量: 0
发起讨论 只看当前版本


暂无话题~