Skill 调试与冲突解决:为什么没触发?怎么修复? ------ Honcho 智能体排障完全手册
你精心编写的 Skill 怎么就是不触发?明明关键词匹配了,日志却一片空白?多个 Skill 互相"打架"谁都不干活?本文将带你系统掌握 Honcho Skill 的调试方法,从日志定位到冲突解决,手把手修复所有"不听话"的 Skill。
前言:Skill 是智能体的"肌肉记忆",但也会"抽筋"
在 Honcho 生态中,Skill(技能)是用户自定义的工作流------它告诉智能体:当满足某个条件时,执行一系列工具调用。Skill 让智能体从"每件事都要手动指挥"升级为"自动响应特定场景"。
但 Skill 并非永远可靠。你可能遇到过:
- 输入了触发词,Skill 毫无反应
- 明明只有一个 Skill 符合条件,却执行了另一个
- Skill 执行到一半报错,不知道哪一步出了问题
- 想修改 Skill 规则,却找不到在哪里编辑
这些问题本质上都是 Skill 调试与冲突 的范畴。本文将按照从易到难的顺序,带你掌握完整的排障流程。
全文包含 5 张 mermaid 流程图 和 大量实战案例,确保你能够快速定位并修复任何 Skill 问题。
1. 查看已加载 Skill:指令查询
1.1 为什么需要查看?
在调试之前,首先要确认:你的 Skill 到底有没有被 Honcho 成功加载? 很多"不触发"问题,根源就是 Skill 根本没加载上。
1.2 查看方法
方法一:通过对话指令查询
如果你已经接入了 Telegram、Slack 或国内办公平台,可以直接向智能体发送查询命令:
/list_skills
或者
/技能列表
Honcho 会返回当前已加载的所有 Skill 名称、描述和触发条件(摘要)。示例输出:
已加载 3 个 Skill:
1. weather_skill - 触发词:天气、气温、下雨
2. code_review - 触发词:review、检查代码、帮我看看这段代码
3. daily_report - 触发词:日报、今日总结
方法二:通过 API 查询
使用 curl 调用 Honcho 的 API:
bash
curl -X GET "http://localhost:8080/v1/skills" \
-H "Authorization: Bearer your_api_key"
返回 JSON 格式的 Skill 列表,包含每个 Skill 的完整定义。
方法三:直接查看文件系统
Skill 文件通常存储在 ~/.hermes/data/skills/ 目录下(取决于你的挂载配置)。每个 Skill 是一个 .yaml 或 .json 文件:
bash
ls -la ~/.hermes/data/skills/
你会看到类似:
weather_skill.yaml
code_review.yaml
daily_report.yaml
1.3 确认 Skill 状态
如果查询结果中没有你的 Skill,说明加载失败。可能原因:
- 文件格式错误(YAML 语法问题)
- 文件放在错误的目录
- 文件名不符合命名规范
- Honcho 启动时未扫描该目录
是
是
否
否
用户发送 /list_skills
Honcho 处理
读取 skills 目录
Skill 文件存在?
解析每个 Skill
格式正确?
返回 Skill 列表
记录错误日志,跳过
返回空列表
用户看不到该 Skill
2. 日志定位:~/.hermes/logs
2.1 日志文件位置
Honcho 的日志默认输出到挂载的 logs 目录(参考第 11 篇 Docker 部署),通常是:
~/.hermes/logs/hermes.log
如果使用 Docker 且未挂载日志目录,可以用 docker logs hermes 查看。
2.2 日志级别设置
在 config.yaml 中可以调整日志级别,调试时建议设为 debug:
yaml
logging:
level: debug # 可选: debug, info, warning, error
output: /app/logs/hermes.log
重启 Honcho 后生效。
2.3 关键日志条目
当用户发送一条消息时,Honcho 会记录以下关键步骤:
| 日志内容示例 | 含义 |
|---|---|
DEBUG: Received message: "今天天气怎么样" |
收到用户消息 |
DEBUG: Checking skills for message: "今天天气怎么样" |
开始匹配 Skill |
DEBUG: Skill 'weather_skill' trigger regex matched: '天气' |
某个 Skill 正则匹配成功 |
DEBUG: Executing skill 'weather_skill' |
开始执行 Skill |
ERROR: Tool 'web_get' failed: timeout |
工具调用失败 |
WARNING: Skill 'weather_skill' skipped due to missing param |
参数缺失,Skill 被跳过 |
2.4 快速定位技巧
bash
# 实时查看日志
tail -f ~/.hermes/logs/hermes.log
# 过滤出 Skill 相关日志
grep -i skill ~/.hermes/logs/hermes.log
# 查看最近 100 行错误
tail -100 ~/.hermes/logs/hermes.log | grep -i error
# 查看特定时间段的日志(需要日志带时间戳)
grep "2026-04-22 14:" ~/.hermes/logs/hermes.log
2.5 日志分析流程图
无匹配
有匹配
成功
失败
收到用户消息
日志: Received message
Skill 匹配阶段
日志: No skill matched
走默认 LLM 回复
日志: Skill X triggered
执行阶段
日志: Skill completed
日志: Error detail
分析错误类型
3. 触发失败常见原因
3.1 触发词/正则表达式问题
这是最常见的原因。Skill 的触发条件通常是一个正则表达式,用户消息必须匹配才能触发。
错误示例:
yaml
trigger: "天气" # 只匹配完全等于"天气"的消息,不匹配"今天天气"
正确示例:
yaml
trigger: ".*天气.*" # 匹配任何包含"天气"的消息
其他常见问题:
- 正则表达式写错(如未转义特殊字符)
- 大小写敏感(
.不匹配换行符) - 中文标点与英文标点混用
3.2 Skill 被禁用
检查 Skill 定义中是否有 enabled: false 字段:
yaml
name: weather_skill
enabled: false # 这会导致 Skill 被忽略
trigger: "天气"
3.3 优先级被抢占
如果多个 Skill 的触发条件都匹配,Honcho 会根据优先级选择一个执行。如果优先级设置不当,你期望的 Skill 可能被另一个 Skill 抢走。
查看优先级:
yaml
name: weather_skill
priority: 10 # 数字越大优先级越高,默认 0
3.4 参数缺失或类型错误
Skill 可能需要从消息中提取参数(如城市名)。如果提取失败,Skill 可能被跳过。
yaml
params:
- name: city
source: regex # 从消息中提取
pattern: "在(.*)的天气"
如果用户说"今天天气怎么样",没有匹配到"在X的天气",参数 city 提取失败,Skill 就不会执行。
3.5 工具调用失败
Skill 内部调用的工具(如 web_get, terminal)可能因为网络、权限等原因失败。这时 Skill 会中断,用户看不到完整回复。
3.6 上下文长度超限
Skill 执行过程中产生的中间结果过大,超出 LLM 上下文限制。这通常表现为"部分输出丢失"。
3.7 触发失败原因速查表
| 现象 | 可能原因 | 日志关键词 |
|---|---|---|
| 输入触发词,完全无反应 | 正则不匹配 / Skill 未加载 | No skill matched |
| 有时触发,有时不触发 | 正则边界问题 / 优先级冲突 | Multiple skills matched |
| 触发后报错"missing parameter" | 参数提取失败 | param .* not found |
| 触发后报错"tool execution failed" | 工具调用异常 | Tool .* failed |
| 触发后只输出了一部分内容 | 上下文超限 / 工具超时 | token limit, timeout |
4. 多 Skill 冲突处理
4.1 冲突场景
当多个 Skill 的触发条件同时满足时,Honcho 需要决定执行哪一个。这称为 Skill 冲突。
典型冲突案例:
- Skill A:触发词
.*日报.*(任何包含"日报"的消息) - Skill B:触发词
.*提交日报.*(提交日报的特定场景)
用户说"帮我提交日报",两个 Skill 都匹配。如果优先级相同,Honcho 会选择最先匹配到的(顺序不确定),可能导致执行错误。
4.2 解决方案
方案一:调整优先级
将更具体的 Skill 设置更高优先级:
yaml
# Skill B (更具体)
name: submit_daily_report
priority: 20
trigger: ".*提交日报.*"
# Skill A (更宽泛)
name: general_daily_report
priority: 10
trigger: ".*日报.*"
这样"提交日报"会优先匹配 Skill B。
方案二:使用互斥规则
在 Skill 定义中添加 exclusive 字段,表示当此 Skill 匹配时,不再检查其他 Skill:
yaml
name: submit_daily_report
exclusive: true # 匹配后停止继续匹配
方案三:合并 Skill
如果两个 Skill 逻辑相似,可以合并为一个,通过条件分支处理:
yaml
name: daily_report_handler
trigger: ".*日报.*"
steps:
- condition: "contains(user_message, '提交')"
then: submit_report
- else: general_report
4.3 冲突检测流程图
只有一个
多个
有最高优先级
优先级相同
用户消息
遍历所有启用的 Skill
收集所有匹配的 Skill
执行该 Skill
比较优先级
执行最高优先级
日志记录冲突
选择第一个匹配的
按加载顺序
4.4 查看冲突日志
当发生冲突时,debug 日志会记录:
DEBUG: Multiple skills matched: ['skill_a', 'skill_b']
DEBUG: Selected skill 'skill_b' due to higher priority (15 > 10)
如果优先级相同:
DEBUG: Multiple skills with same priority, selecting first: 'skill_a'
5. 手动编辑、禁用、删除 Skill
5.1 编辑 Skill
Skill 文件存储在 ~/.hermes/data/skills/ 目录下。直接编辑对应的 YAML 文件即可。
示例 Skill 文件 (weather_skill.yaml):
yaml
name: weather_skill
description: "查询天气"
enabled: true
priority: 5
trigger: ".*天气.*"
params:
- name: city
source: regex
pattern: "在?([^的]+)的天气"
steps:
- tool: web_get
params:
url: "https://api.weather.com/{{city}}"
output: weather_data
- tool: llm_generate
params:
prompt: "根据天气数据{{weather_data}}生成友好回复"
output: final_reply
- tool: reply
params:
message: "{{final_reply}}"
编辑后如何生效?
- 如果 Honcho 支持热加载(
watch_skills: true),保存文件后自动生效。 - 否则需要重启 Honcho:
docker restart hermes
5.2 禁用 Skill
两种方式:
- 在 Skill 文件中设置
enabled: false,保存后(或重启)生效。 - 通过命令动态禁用(如果支持):
/disable_skill weather_skill
5.3 删除 Skill
直接删除对应的 YAML 文件,然后重启 Honcho(或等待热加载)。
bash
rm ~/.hermes/data/skills/weather_skill.yaml
5.4 批量管理
如果你有大量 Skill,可以使用脚本批量操作。以下是一个简单的 Python 脚本示例:
python
import os
import yaml
skills_dir = os.path.expanduser("~/.hermes/data/skills/")
for filename in os.listdir(skills_dir):
if not filename.endswith(".yaml"):
continue
path = os.path.join(skills_dir, filename)
with open(path, 'r') as f:
skill = yaml.safe_load(f)
print(f"{filename}: enabled={skill.get('enabled', True)}")
6. 调试流程:一步一步定位
6.1 标准调试流程
当你的 Skill 不工作时,按照以下步骤操作:
第一步:确认 Skill 已加载
- 发送
/list_skills或在日志中搜索Loading skill - 如果没加载,检查文件格式和存放路径
第二步:开启 Debug 日志
- 设置
logging.level: debug,重启 Honcho
第三步:发送测试消息,实时观察日志
bash
tail -f ~/.hermes/logs/hermes.log
第四步:根据日志定位问题阶段
否
是
否
是
否
是
否
是
是
否
发送测试消息
日志中出现
'Received message'?
消息未到达 Honcho
检查网关配置
日志中出现
'Checking skills'?
Skill 匹配模块未运行
检查配置
日志中出现
'Skill X triggered'?
触发条件不匹配
检查正则/大小写
日志中出现
'Executing skill'?
Skill 被禁用或优先级问题
日志中出现错误?
根据错误类型修复
Skill 执行成功但无输出
检查回复步骤
6.2 调试案例
案例 :用户说"北京天气",但 weather_skill 没触发。
步骤:
-
/list_skills→ 确认weather_skill在列表中 ✅ -
开启 debug 日志,再次发送"北京天气"
-
查看日志:
DEBUG: Received message: "北京天气"
DEBUG: Checking skills...
DEBUG: Skill 'weather_skill' trigger regex '.天气.' matched: True
DEBUG: Extracting param 'city' with pattern '在?([^的]+)的天气'
DEBUG: Param 'city' extraction failed, skipping skill -
问题定位:参数提取正则不匹配"北京天气"。用户没有说"在北京的天气"。
-
修复:修改正则或让
city参数可选。
6.3 调试工具箱
| 工具/命令 | 用途 |
|---|---|
/list_skills |
查看已加载 Skill |
/enable_skill <name> |
启用 Skill(如果支持) |
/disable_skill <name> |
禁用 Skill |
tail -f ~/.hermes/logs/hermes.log |
实时查看日志 |
grep -i skill logs |
过滤 Skill 相关日志 |
curl -X GET /v1/skills |
API 获取 Skill 列表 |
7. 常见错误模板与修复
7.1 YAML 语法错误
错误现象 :Skill 文件无法加载,日志显示 YAML parsing error
常见错误:
yaml
steps:
- tool: web_get
params:
url: "https://example.com" # 这里少了一个空格?缩进不对
修复 :使用 YAML 校验工具(如 yamllint)检查。
7.2 正则表达式错误
错误 :trigger: "天气?" → 问号是量词,匹配"天"或"天气",但可能误匹配。
修复 :使用明确的正则:trigger: ".*天气.*"
7.3 工具参数引用错误
错误:
yaml
steps:
- tool: web_get
params:
url: "https://api.com/{{city_name}}" # city_name 未定义
修复 :确保变量名与 params 中定义的名称一致。
7.4 循环引用
两个 Skill 互相调用导致无限循环。Honcho 有最大步数限制(默认 10 步),超限会中断。
修复 :检查 Skill 的 steps 中是否调用了另一个 Skill,而另一个 Skill 又调回了它。
7.5 工具超时
错误日志 :Tool 'web_get' timeout after 30s
修复:
- 增加超时时间:
timeout: 60 - 或优化工具调用(如使用更快的 API)
7.6 参数类型不匹配
错误:工具期望整数,但传入了字符串。
修复:在 Skill 中添加类型转换步骤,或使用模板过滤器。
7.7 常见错误速查表
| 错误日志关键词 | 可能原因 | 修复方法 |
|---|---|---|
YAML parsing error |
语法错误 | 检查缩进、冒号、引号 |
Skill not found |
文件名与 name 不一致 | 确保文件名与 Skill 的 name 字段一致 |
param .* not found |
参数提取失败 | 调整正则或设置默认值 |
tool .* not registered |
工具名称错误 | 检查工具名拼写,确认工具已启用 |
max steps exceeded |
循环或过长链式调用 | 增加 max_steps 或简化逻辑 |
timeout |
工具执行超时 | 增加超时时间或优化调用 |
permission denied |
工具权限不足 | 检查 config.yaml 中的工具白名单 |
8. 总结:快速排障指南
8.1 核心原则
- 日志是上帝:95% 的问题都能从 debug 日志中找到线索。
- 先确认加载,再检查触发:Skill 没加载,一切都是白搭。
- 正则要宽松,但不要过宽 :
.*能匹配大部分,但可能与其他 Skill 冲突。 - 优先级解决冲突:具体场景用高优先级,通用场景用低优先级。
- 小步迭代:每次修改一个 Skill 后立即测试,不要积攒多个改动。
8.2 快速排障流程图
否
是
否
是
否
是
否
是
否
是
Skill 不触发
/list_skills 能看到?
检查文件路径/格式
重启 Honcho
Debug 日志有匹配记录?
检查 trigger 正则
注意大小写/中文标点
日志显示参数提取成功?
检查 params 中的正则
设置默认值
日志显示工具调用成功?
检查工具名称/网络/权限
最终有回复吗?
检查 reply 步骤
确认输出变量
问题解决
8.3 最佳实践建议
- 为 Skill 添加 description:帮助自己和其他开发者理解用途。
- 使用明确的优先级:避免依赖默认的加载顺序。
- 记录版本 :在 Skill 文件中添加
version字段,方便回滚。 - 单元测试:编写简单的测试消息集,每次修改后批量验证。
- 定期清理:删除不再使用的 Skill,减少冲突可能。
8.4 Skill 模板示例(含调试友好字段)
yaml
name: example_skill
version: "1.0"
description: "这是一个示例 Skill"
enabled: true
priority: 10
trigger: ".*示例.*"
params:
- name: keyword
source: regex
pattern: "示例(.*)"
default: "默认值" # 设置默认值,避免提取失败
steps:
- tool: log
params:
message: "开始执行 example_skill,keyword={{keyword}}"
- tool: llm_generate
params:
prompt: "用户提到了{{keyword}},请友好回应"
output: reply_text
- tool: reply
params:
message: "{{reply_text}}"
timeout: 30
max_steps: 10
8.5 一句话总结
Skill 不触发时,遵循"加载→匹配→参数→工具→回复"的五步调试法,配合 debug 日志,90% 的问题可以在 10 分钟内定位并修复。
下一步:掌握了调试技巧后,你可以尝试编写更复杂的 Skill------比如多步骤条件分支、循环调用、用户确认交互等。调试能力越强,你能实现的自动化场景就越丰富。
附录:常用正则表达式参考
| 需求 | 正则示例 |
|---|---|
| 包含关键词 | .*天气.* |
| 以关键词开头 | ^天气.* |
| 以关键词结尾 | .*天气$ |
| 提取城市名(中文) | 在?(.*?)的天气 |
| 提取数字 | \d+ |
| 匹配多种说法 | `(天气 |
| 忽略大小写 | (?i)weather |
| 匹配任意字符(包括换行) | [\s\S]* |
版权声明:本文为原创技术博客,采用 CC BY-NC-SA 4.0 许可。欢迎转载,请保留出处。如有 Skill 调试问题,欢迎评论区交流。