拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Hermes技能系统实战:从零构建Agent自定义技能

很多人用 Agent 的时候都会遇到一个尴尬的处境预置能力一大堆真到自己的业务场景却发现哪儿哪儿都不够用。要么让模型反复执行同一套流程却每次都要重新描述需求要么把一个固定的操作步骤硬塞进系统提示词里结果上下文一长就各种出岔子。我最初上手 Hermes 的时候也踩过这个坑——直到搞清楚它的技能Skill机制才明白这玩意儿其实就是一个可以随时扩展的“能力插槽”你把重复工作流打包成一个技能Agent 就能像学会一门新手艺一样直接调用。这篇文章就聊聊我是怎么看懂 Hermes 技能系统的以及在真实项目里如何把一个重复工作流程沉淀成自定义技能。如果你正在做 Agent 开发、搞 RPA 自动化或者单纯想让手头那个“半成品智能体”真正帮你干活这篇内容会给你一个可以直接复制的路径从技能的结构设计、脚本编写、参数定义到本地部署、调试上线我都会把实际踩过的坑和最终跑通的方案一起梳理出来。1. 为什么要给 Agent 创建自定义技能1.1 Agent 能力的边界问题先看一个最常见的场景你让 Agent 帮你“给每个新注册用户发一封欢迎邮件”。模型确实能理解这句话也能写出邮件内容但真正要落地的时候你会发现事情没那么简单——它需要调用邮件服务商的 API需要处理收件人列表需要按特定模板填充内容甚至还要在发送失败时单独记录下来。如果你只是把需求描述塞给 Agent它大概率会把“调用 API”这件事做得七零八落没带鉴权参数、模板字段对不上、跑一半就报错。这不是模型能力不行而是 Agent 缺少“确定性”的执行路径。大语言模型擅长的是理解意图和生成内容不擅长的是稳定复现一套固定流程。你让它写一封邮件它能写好但你让它每次都用完全相同的逻辑、参数、异常处理去执行一百遍它就会开始发挥“创造性”而“创造性”在这种场景下等于灾难。自定义技能要解决的正是这个问题把一个重复执行的流程包括指令模板、输入参数、处理逻辑、失败兜底全部固化成一段可复用的代码或配置。Agent 只需要知道“什么时候该调用这个技能”剩下的动作全部由技能本身按部就班地完成。这就像你教一个新员工做事先带他走一遍完整流程之后他就能自己按照标准作业程序去执行不需要你再重复叮嘱。1.2 技能机制解决的四个痛点我实际用了 Hermes 一段时间后发现它的技能机制是真的把下面这四个痛点一个个按死的指令模板复用固定模板不再需要每次通过自然语言重复描述技能本身就携带了执行指令Agent 调用技能时自动套用。参数结构化外部输入通过预定义的参数列表传入Agent 不再靠猜比如日期格式、收件人字段、超时时间都可以明确约束。调用权限可控技能可以限定在特定作用域内运行不会让 Agent 任意访问系统资源安全边界清晰很多。失败处理统一技能内部可以封装重试、熔断、告警逻辑Agent 只需要关心技能返回的结果状态。说白了技能机制就是给 Agent 装上“肌肉记忆”。它不用记住流程里的每一个细节只需要记住“遇到什么情况可以用哪个技能”剩下的事交给技能去办。这套思路不仅是 Hermes 的核心也是目前主流 Agent 框架都在走的路线——把不确定的推理和确定的执行分开推理交给模型执行交给技能。2. 认识 Hermes 技能系统2.1 技能的核心组成Hermes 的技能机制我理解下来其实就三件事技能是什么样子的、怎么被找到、怎么被执行。一个完整的 Hermes 技能通常由三个部分组成。第一个是技能描述Skill Manifest类似技能的“身份证”包括技能名称、一句话说明、适用场景、参数定义。这个描述不是给人看的而是给 Agent 的模型看的——模型读了描述之后才能判断“当前用户的请求是不是应该触发这个技能”。第二个是执行逻辑Executor也就是技能真正干活的代码。它接收参数执行具体操作返回结果。在 Hermes 里执行逻辑可以用 Python 脚本、Shell 命令甚至是一次 HTTP 请求的形式来定义灵活性挺高。第三个是声明文件Plugin Config用来把技能挂载到 Agent 运行时里。声明文件里写着技能的加载方式、依赖的插件、运行超时时间、日志级别这些元信息。缺了这部分Agent 就算知道有这个技能也不知道怎么把它跑起来。从使用者的角度看你只需要关心前两个部分描述得足够准确逻辑写得足够稳这个技能基本就能被 Agent 正确调用。声明文件的格式一般是 YAML 或 JSON配置起来也比较直白。2.2 技能的分类与触发方式Hermes 里技能大致可以分成两类按需技能和事件技能。按需技能是最普通的场景Agent 根据用户意图决定是否调用。比如用户说“帮我查一下下周的天气”Agent 在内部推理中会匹配到天气查询这个技能然后填充参数调起来执行。这里有个关键点技能的描述信息直接决定了模型能不能做出正确匹配。我见过很多技能写得很工整但描述写得含糊其辞结果 Agent 该触发的时候不触发不该触发的时候乱触发。描述里一定要写清楚这个技能“能做什么”“在什么条件下用”“不能做什么”。事件技能则是被动触发由系统事件或定时任务拉起。比如每天早上九点自动跑一次库存盘点或者当某个目录新增文件时自动触发归档。这类技能不需要 Agent 做意图判断更偏 RPA 的用法。我自己的体会是刚开始用 Hermes 时不要急着搞事件技能先把按需技能跑通理解整套触发链路之后再去碰主动调度会顺手很多。因为事件技能涉及的权限和生命周期管理比按需技能复杂一步到位容易调得怀疑人生。3. 创建你的第一个自定义技能3.1 环境准备在开始写技能之前先把 Hermes 的运行环境准备好。我这边因为之前踩过不少环境坑给你一条相对省心的路径。首先Hermes 依赖 Python 3.9 以上的环境推荐直接用虚拟环境隔离别图省事装到系统全局里。创建虚拟环境然后激活之后所有的包都装在这个虚拟环境里。其次用 pip 安装 Hermes 客户端和运行依赖具体的包名因版本而异但基本都集中在 hermes-agent 这一个主包里。装完后执行版本命令能看到对应的版本输出就说明安装成功。如果你打算让技能跑一些外部服务比如发邮件、调数据库记得提前把对应的 Python 库也装好例如 requests、smtplib、pymysql 这类。把这些依赖提前列到虚拟环境的 requirements.txt 里后面部署到新机器时会省掉很多麻烦。3.2 技能目录与文件规范Hermes 对技能目录的约束并不死板但建议从一开始就按照官方推荐的目录结构来否则技能一多直接就乱套了。我推荐的结构是在 Hermes 的根目录下建一个 skills 文件夹里面每个技能是一个独立子目录目录名就是技能名。每个技能目录里至少包含这三个文件skill.yaml描述与配置、executor.py执行逻辑、requirements.txt技能专属依赖。举个实际案例我想做一个“日报生成”技能目录结构大概长这样skills/ └── daily_report/ ├── skill.yaml ├── executor.py └── requirements.txt目录名用了小写加下划线不搞驼峰主要是为了在日志和命令行里输入的时候少踩一些大小写敏感的坑。另外每个技能目录独立声明自己的依赖这样不同技能之间哪怕用了不同版本的库也不会互相打架。3.3 编写技能脚本日报生成实例我拿“日报生成”这个技能来拆解因为它的逻辑足够简单又能覆盖大多数技能的共性。skill.yaml的内容核心就是定义名称、描述和参数。名称对应技能目录名描述要尽量写清楚“在什么情况下使用这个技能”而参数部分则定义了这个技能执行时需要接收的键值对。一个简化的声明文件大概长这样技能名称是 daily_report描述里明确写着“当用户需要生成当日工作总结或日报时使用输入为日报日期输出为 Markdown 格式的日报文本”参数里有一个 date 字段类型是 string必填项。接下来是executor.py。这个文件里只需要实现一个函数接收一个参数字典返回一个结果字符串或字典。日报生成的逻辑可以很简单根据传入日期拉取任务记录再按模板拼接成文本。考虑到 Hermes 会把执行逻辑与 Agent 的上下文隔离你的 executor 函数最好写成纯粹的函数式结构传入参数返回结果不要在里面写任何与外部交互的副作用逻辑除非这个技能本身就是做外部调用的。具体执行逻辑我写了一个精简版本读取系统里记录的任务表按日期过滤出当天完成的任务然后拼接成一个 Markdown 格式的日报字符串返回。如果日期参数为空就用今天的日期兜底。这个技能看起来小但它已经包含了参数解析、业务逻辑、返回结构这几个核心环节。实际项目中你可能要在这里塞进数据库查询甚至调用内部 API思路是一样的。3.4 注册与加载技能文件写完之后还要让 Hermes 认识这个新技能。技能注册的方式有两种一种是修改 Hermes 的总配置在技能列表里加上新目录路径另一种是用命令行工具手动加载。我更推荐先用命令行工具手动加载试跑因为总配置改起来要重启整个 Agent 服务而命令行试跑可以快速反馈技能能不能跑通。比如执行加载命令然后指定技能目录路径如果输出里出现类似“skill loaded successfully”的信息说明技能已经被当前会话正确识别。之后你在对话里输入“帮我生成昨天的日报”Agent 就会自动匹配到这个技能并调用执行。4. 实操过程从定义到上线4.1 定义技能意图与参数很多人写技能时最容易漏掉的就是“意图定义”这一步总想着逻辑写完就万事大吉结果 Agent 一直触发不了。你在skill.yaml里写的描述其实是给模型做意图识别用的写得越精确触发越准。我写描述会遵循一个模板这个技能是什么它能在什么场景下被调用它接收什么关键参数它不负责做什么。最后一条尤其重要因为防止 Agent 用错技能比让它多触发一个技能更麻烦。比如日报生成技能不负责发送邮件接邮件需求就别触发它否则会把这个流程搞得很混乱。参数定义也一样要在声明文件里明确每个参数的类型、是否必填、取值范围。这样 Agent 在调用技能之前会把用户输入里的信息转换到对应的字段里你再在 executor 里取值就不用做那么多防御性判断了。4.2 实现执行逻辑与异常兜底执行逻辑这一块我给你的建议是把主流程做得“窄”一点把异常处理做得“宽”一点。主流程窄指的是只做这个技能该做的事不要试图在技能里去覆盖所有可能的用户需求。比如日报生成技能就是根据日期拿数据、生成 Markdown最多再返回一个结果状态。不要在里面加什么“顺便分析一下今天的数据趋势”那是另一个技能该干的事混在一起会让技能的复用性大打折扣。异常处理宽指的是要考虑到各种“一定会发生”的失败情况。数据源连不上怎么办日期格式传错了怎么办生成内容为空怎么办我都会在技能里加上 try-except 结构把异常吞掉并返回一个带错误信息的结构体这样 Agent 看到结果之后能自己决定下一步该怎么回复用户而不是技能直接崩溃导致整个调用链挂掉。我自己常用的返回结构就是三个字段status 用来表示成功还是失败data 放核心结果message 用来放错误说明或补充信息。这个结构简单Hermes 在解析结果时也方便。4.3 测试技巧单测与模拟调用技能写完不是直接上线就完事了得先在单测环境里把它跑稳。我的做法是先把 executor 单独拿出来构造一组测试数据直接调用它对应的函数看看返回是否正常。这一步不经过 Agent纯粹验证逻辑对不对。如果逻辑有问题先在这里调通别拿去烦 Agent。第二步是做模拟调用通过 Hermes 的命令行或 API手动传入参数来触发这个技能。这一步验证的是“技能从声明到底层执行的链路是否打通”。我经常在这里发现一些奇怪的坑比如 YAML 配置缩进错误导致参数解析不了或者依赖没有装全导致导入失败。手动触发可以帮助你快速隔离问题到底出在配置层还是执行层。最后才是放到对话里用自然语言触发一次完整流程。注意这一步要尽量模拟真实用户的口吻不要每次都说很标准的指令。模型能不能听懂变体表达也是测试的重要一环。4.4 部署与调度技巧技能本身跑通了剩下的就是把它的运行环境固定下来。这里我把部署拆成两件事环境固定和调度固定。环境固定方面我会为 Hermes 写一个Dockerfile把 Python 版本、依赖库、技能目录全部打包到镜像里。为的就是让技能在本机跑得好好的到了服务器上却因为缺一个系统库直接扑街。用 Docker 容器承载技能能保证“我这边能跑你那边也能跑”这是降低部署焦虑最简单粗暴的手段。调度固定方面对于事件型和定时型技能我一般用 crontab 或外部的调度系统来触发 Hermes 的 API 接口。比如日报生成技能每天 17:45 定时触发一次生成当天日报并保存到某个目录。这里的技巧是调度器只负责发起调用请求技能内部按参数判断要做什么。这样便于你之后把同一个技能复用到其他时段或其他任务上。5. 常见问题与排查技巧实录5.1 技能加载失败最开始最容易碰到的是加载失败。我知道看日志很烦但这个阶段日志就是你唯一的朋友。典型的错误有两种一种是 YAML 解析错误常见原因是缩进不对或字段名拼错。YAML 对空格敏感一个缩进错了整份配置就废了检查的时候先从缩进开始。另一种是依赖导入错误。executor 里 import 了某个库但当前 Python 环境里没装加载时就会直接报 module not found。遇到这种情况把依赖写进技能目录下的requirements.txt然后单独给这个技能装一次依赖基本就能解决。5.2 参数匹配错误参数匹配的坑在于模型在理解用户意图时可能把信息填到错误的字段里。比如用户说“帮我生成本周四的日报”模型可能会把“周四”解析到一个字符串的日期字段里但你的日期字段其实希望接收的是标准的“YYYY-MM-DD”格式。我的解法是在 executor 里统一做一次参数清洗不管模型传进来的是什么格式都尝试用标准库解析一次日期如果解析失败就返回一个明确的错误提示让 Agent 向用户追问标准化格式。这里的核心思路是既然模型的对齐能力不可控那就把解析职责收回到代码里代码总是确定性最强的。5.3 执行超时与环境依赖问题技能执行超时是一个容易忽略的坑。默认超时时间在很多环境里只有几十秒如果你的技能里有个外部 API 请求慢得像蜗牛就会莫名其妙被中断掉。排查时先把超时时间调大或者把慢操作改成异步执行。另一个常见问题是 Docker 容器里时区不对导致定时任务比预期早跑了几小时。解决方法是启动容器时挂载宿主机的/etc/localtime或者在技能里显示指定时区不要依赖系统默认值。5.4 排查工具与日志我说一个比较笨但极其有效的排查方式给每个技能加一个 debug 开关。当开关打开时技能会把传入的参数、执行过程、每一步的结果全部打印出来。不要小看这几个 print在真实调用链里很多问题是模型层和代码层互相误解导致的有了详细的日志你才能判断是模型把这个技能调错了还是技能逻辑本身有 bug。另外Hermes 自带的日志系统会记录每次技能调用的上下文比如触发了哪个技能、传了什么参数、返回了什么结果。我把这些日志统一收集到一个文件里出了问题先看这个文件基本能定位到八九成。最后再分享一个小技巧给技能命名时不要起太宽泛的名字比如“工具”或“处理”这不仅让模型更难理解技能用途也不利于你自己在日志里辨认。尽量用动词加名词的组合像“gen_daily_report”“send_welcome_mail”一眼就能看出这个技能做什么排查问题的时候效率高很多。这些细节看着不起眼实际用起来才知道多省心。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门