5. 插件与工具扩展
这是什么:工具(tool) = Agent 能调用的能力,如读文件、跑命令、搜网页;插件(plugin) = 不改核心代码就往里塞新工具、钩子和命令的扩展包。
为什么用:内置工具再多也覆盖不了你的私有系统——公司内部 API、监控面板、只有你会用的脚本。而写插件是加能力,不是改源码。
如何用:本章先分清三条扩展路线,再用最小例子写一个属于自己的插件。
5.1 三条路线,先选对
| 路线 | 适合 | 怎么接 |
|---|---|---|
| 内置工具集 | 用自带的能力 | hermes tools 开关 |
| MCP 服务器 | 接现成的第三方工具生态 | config.yaml 写 mcp_servers |
| Python 插件 | 接私有系统、写你会用的工具 | ~/.hermes/plugins/ 建目录 |
判断标准很简单:这工具别人做过吗? 做过找 MCP,没人做过就写插件。
5.2 路线一:内置工具集
hermes tools
交互界面里按平台勾选:终端、文件操作、网页浏览、图像生成、语音……不同平台(CLI / Telegram / Discord)可开不同工具集,存在 config.yaml 的 platform_toolsets 下。所以「Telegram 上不许碰我的文件」勾两下就实现。
5.3 路线二:MCP
MCP(Model Context Protocol,模型上下文协议) 是一套标准:外部程序按它暴露工具,Agent 就能调用。GitHub、Notion、数据库客户端都有现成的 MCP 服务器。
在 ~/.hermes/config.yaml 里声明:
mcp_servers:
github:
command: "npx"
args: ["-y", "@modelcontextprotocol/server-github"]
env:
GITHUB_PERSONAL_ACCESS_TOKEN: "ghp_xxx"
tools:
include: [list_issues, create_issue, search_code]
resources: false
prompts: false
远程的 HTTP 服务器用 url + headers:
mcp_servers:
stripe:
url: "https://mcp.stripe.com"
headers:
Authorization: "Bearer sk_test_xxx"
tools:
exclude: [delete_customer, refund_payment]
几个关键机制:tools.include 是白名单(设了就只注册列出的工具),tools.exclude 是黑名单,两者同时设include 优先;trust: untrusted 让写操作逐次批准;enabled: false 则完全跳过但保留配置。
工具注册后的名字是 mcp_<服务器>_<工具>。注意:连字符、点号会自动换成下划线,但过滤时用原始名称。
改完 MCP 配置,用斜杠命令重载:/reload-mcp。
5.4 路线三:写一个插件
插件就是一个目录,放在 ~/.hermes/plugins/ 下:
~/.hermes/plugins/hello-world/
├── plugin.yaml # 清单
└── __init__.py # register():把 schema 和处理器绑定
plugin.yaml
name: hello-world
version: "1.0"
description: 一个最小示例插件
__init__.py
"""最小 Hermes 插件:注册一个工具和一个钩子。"""
import json
def register(ctx):
schema = {
"name": "hello_world",
"description": "Returns a friendly greeting for the given name.",
"parameters": {
"type": "object",
"properties": {
"name": {"type": "string", "description": "Name to greet"}
},
"required": ["name"],
},
}
def handle_hello(params, **kwargs):
del kwargs
name = params.get("name", "World")
return json.dumps({"success": True, "greeting": f"Hello, {name}!"})
ctx.register_tool(
name="hello_world",
toolset="hello_world",
schema=schema,
handler=handle_hello,
)
def on_tool_call(tool_name, params, result):
print(f"[hello-world] tool called: {tool_name}")
ctx.register_hook("post_tool_call", on_tool_call)
放好重启 Hermes,模型就能调 hello_world 了。
ctx 的 API:register_tool() 添加工具、register_hook() 添加钩子、register_command() 添加斜杠命令、register_cli_command() 添加 CLI 子命令、register_skill() 打包技能、llm.complete() 调用宿主模型、inject_message() 注入消息。
工具描述写在 schema["description"] 里——模型看到的就是这串字,写清楚它才知道何时该调。
钩子一共有 24 个生命周期事件:pre_tool_call、transform_tool_result、post_tool_call 等,分「指令拦截」「变换结果」「观察记录」三类。
5.5 关键安全设计:插件默认是关的
通用插件和用户安装的后端,默认禁用。 Hermes 会发现它们(所以出现在 hermes plugins 里),但在你点头前插件代码一行都不跑。
# ~/.hermes/config.yaml
plugins:
enabled:
- hello-world
disabled: # 可选拒绝名单,同时在两个列表时 disabled 优先
- noisy-plugin
三种开关方式:
hermes plugins # 交互式界面,空格勾选
hermes plugins enable hello-world
hermes plugins disable hello-world
你会看到(示意):
$ hermes plugins list
NAME STATUS KIND
disk-cleanup enabled general [bundled]
hello-world not enabled general
image_gen/openai enabled backend
这设计有道理:插件 = 任意 Python 代码,装上就跑等于交出电脑。
例外是自动加载的内置平台插件和图像生成后端;memory provider、context engine、model provider 属「单选」类型。
插件有四个来源:内置(<repo>/plugins/)、用户(~/.hermes/plugins/)、项目(.hermes/plugins/,默认禁用,需设 HERMES_ENABLE_PROJECT_PLUGINS=true)、pip 入口点(hermes_agent.plugins)。同名后者覆盖前者。
5.6 不用写 Python 的两种扩展
Shell 钩子——在 config.yaml 的 hooks: 下声明,事件发生时跑一条 shell 命令(发通知、记日志):
hooks:
post_tool_call:
- command: "notify-send 'Hermes 调用了工具'"
Gateway 事件钩子——放个目录进去就能用(~/.hermes/hooks/my-hook/HOOK.yaml + handler.py),触发时机有 gateway:startup、session:start、agent:end。
动手改
- 跑
hermes plugins list,看看哪些插件「已发现但未启用」,挑一个enable试试。 - 照着 5.4 的模板建
~/.hermes/plugins/my-plugin/,注册一个hello_world工具,重启 Hermes 让它调一次。 - 挑一个现成的 MCP 服务器(GitHub 最容易),用
tools.include只放行一两个只读工具。
小结
- 三条路线:
hermes tools开内置工具集 /config.yaml挂 MCP /~/.hermes/plugins/写插件 - MCP 用
mcp_servers声明,include优先于exclude,trust: untrusted要逐次批准写操作 - 插件最小结构 =
plugin.yaml+__init__.py的register(ctx) - 工具描述写在
schema["description"],那是模型唯一看得见的说明 - 插件默认禁用,必须进
plugins.enabled或hermes plugins enable才生效 - 不想写 Python:shell 钩子写
config.yaml,Gateway 钩子丢目录进~/.hermes/hooks/
下一章:综合练习 🐸