运维 | 给 AI 助手减重:工具集、技能索引与每周一次的体检

有些东西不是坏掉的,只是长回来了。裁一次不难,难的是它每周都会问你一遍要不要再来一次。

写在前面

起因是一篇讲「按职责裁剪」的文章。作者说,一台跑了几个月的 Agent 会同时在三个地方变重:每个 profile 都开满工具,同名技能在各处各存一份,失败的 MCP 往日志里一直写。

我的部署比他简单得多:单用户、单 profile,跑在 NAS 的 Docker 里。所以我没有直接照搬,而是先对着自己这台机器把每一项都量了一遍——结论是文章说的三处里,两处与我无关,一处确实存在,而真正占地方的东西,文章没提。

一、先量,再裁

Hermes 自带一个诊断命令,能把系统提示和工具 schema 拆成明细,而且不联网、不发请求。量出来的数字是这样的:

项量级
系统提示三十多 KB
其中技能索引十几 KB(一百多个技能的名字和一句话描述)
工具 schema四十多 KB(二十来个工具)
每轮常驻合计七十多 KB

也就是说,模型还没看到我说一个字,就已经先背了七十多 KB 的说明书。这里面技能索引占两成,工具 schema 占一半多。哪个更贵,一眼就知道。

二、文章说的三处,两处与我无关

多 profile 各存一份技能——我只跑一个 profile,那条「用外部目录共享技能 + 禁用名单」的方案在我这儿没有意义。

报错的 MCP 往日志里写——翻了日志,MODULE_NOT_FOUND 一条都没有;日志滚动也早就配好了,单文件到几 MB 就切、保留几份。这条不用抄。

面板上关掉的工具,聊天里还开着——这条是真的,而且原因很值得记下来。

Hermes 里每个平台(命令行、各种聊天平台)各有一份工具集列表,分开存是有道理的:命令行能跑命令,聊天平台只能发消息,混在一张表里对不上。问题出在没有给某个平台写列表的时候——它回落到平台默认组合,而不是空。

所以你在面板上关掉一项,它只写了命令行那一份。命令行里确实没了,聊天里发一句还是能用。

三、真正的坑:一份列表管三个平台

修法不复杂,写一份显式列表就行。麻烦的是「以后」。面板每改一次工具,一份列表就变一次,另外两份不动,迟早对不上。

于是我加了一个同步脚本,规则固定成一句话:

聊天平台列表 = 命令行列表 - 全局排除项 + 该平台专属项

命令行那份是唯一事实来源,其余两份由脚本推导。检查是默认动作,只报不改;要写回得显式加一个 --apply,而且走 CLI 改配置,会自动留一份带时间戳的备份。

这条规则本身比脚本重要:当一份配置能推导出来时,就不要让第二份成为另一个事实来源。

四、顺手抓到的空转功能

改列表的时候发现一个更贵的东西。

列表里有个任务看板工具集,展开是十几个工具、二十几 KB 的 schema。我去翻它的数据库——八张表,零行;又去翻所有定时任务,零个引用。它从来没有被用过一次。

也就是说,每轮那七十多 KB 里,有接近三分之一是在描述一个空功能。

从三份列表里一起摘掉之后,命令行侧的工具从五十多个降到二十来个。教训很简单:一个功能只要挂着,就有成本。它不需要被调用,只需要被描述。

五、「删掉本地副本」这件事,别照抄

文章建议把所有本地同名副本删干净,只留共享层,我差点就照做了。

查下来是两个:一个内容跟内置版逐字节一致,纯冗余;另一个是我自己改过的——里面写着这台机器的约定、踩过的坑、还有几条不许推翻的规则。文件大小比内置版多出两成。

照文章删,删掉的不是冗余,是这几个月攒下来的全部经验。结构和内容长得一样,价值可以完全不同。 这条最终只留了那个真正冗余的。

六、裁技能,省不了多少

文章里说裁完技能条目少了一大半,看着很解气。我在自己这儿把「看着永远不会用」的那几组全挑出来——机器学习那一组、创意素材那一组、数据科学、社媒——索引加起来一 KB 出头。

一百多个技能的索引总共才十几 KB,可裁的部分不到一成。与其在一 KB 上做取舍,不如去看那四十 KB 的工具描述。

七、噪音也是配置

顺着日志按出现频次排了一遍,占前几位的不是报错,是三类「配置和现实不一致」:

  • 本地语音转写:配置里开着,实际依赖根本没装,import 直接失败。这条每次启动都会提醒一次,而功能本来就是死的。关掉,要用再装回来。
  • 斜杠命令冲突:有个技能的名字被核心命令占了。我去读了注册逻辑,确认这是设计行为——命令名冲突时跳过自动注册,技能本身仍可按名字调用。这不是 bug,是我想当然。
  • 唤醒词:只走桌面端的启动路径,要往一个没有写权限的虚拟环境里装包。跟聊天链路无关,不动。

这里的教训跟技术无关:同一行日志出现几十次,先分清「坏了」和「本来就这样」。 前者该修,后者该闭嘴。

八、改完它会自己长回去

这是全文唯一我完整照搬的一条:漂移是常态,一次性手术没用。

会持续制造漂移的有三件事——一次更新会把技能重新塞回本地、面板改工具只改一份列表、任何一个出错的组件都会让日志重新开始涨。

所以留一个每周一次的静默巡检:周日早上跑,干净的时候一个字都不推,有问题才推一条,附上修法和刷新基线的命令。天天推消息的巡检,人很快会把它当背景音,真出事那条也看不见了。

巡检脚本的骨架大概是这样,纯标准库,容器里随便哪个 Python 都能跑:

# 三个检查项:常驻开销 / 配置漂移 / 日志超限
cur = run("hermes prompt-size --platform <平台> --json")   # 只读,不联网
base = json.load(open(BASELINE))

problems = []
for key, tol in (("system_prompt", 0.15), ("skills_index", 0.20), ("tools", 0.15)):
    if cur[key] > base[key] * (1 + tol):
        problems.append(f"常驻开销 {key} 涨到 {cur[key]},基线 {base[key]}")

if run("toolsets_sync.py").returncode != 0:      # 配置漂移
    problems.append("工具集与命令行列表不一致")

problems += [f"{n} 超过阈值" for n in big_logs(LOG_DIR, limit=20 * 1024 * 1024)]

if problems:
    print_report(problems)     # 有输出 = 会被投递
sys.exit(0)                    # 注意:有输出也要退 0,非零会被当成脚本崩了再报一次

最后那个 exit(0) 是踩出来的:无 LLM 的定时任务里,非零退出码会被当成脚本故障,额外发一条错误告警。结果是一次真问题推来两条消息,一条是报告,一条是「脚本出错」。

九、两个坑,都是我自己挖的

第一个:工具不让我改配置。 写配置文件的时候被安全闸拦了——「Agent 不能修改敏感配置」。只能用 CLI 改。反而更好:每次改动自动留备份,回滚就一条命令。

第二个:兜底解析器把自己坑了。 脚本要读配置,但系统 Python 里没有 YAML 库。我写了个纯标准库的兜底解析器,思路是「扫描全文,两格缩进的键就是平台名」——结果把配置里别的段当成了平台,脚本报「未配置」,我差点以为配置没写进去。

正确做法是只解析目标那一段,遇到下一个顶格键就停。解析器的边界,比解析器的能力重要。

还有一个不算坑的坑:命令返回成功,事情并没有发生。 我排的重启脚本日志里写着 rc=0,验收时发现进程还是前一天启动的——服务管理器管的那个服务,根本不是我以为的那个进程。配置最后是靠运行时的热加载生效的,跟那次「成功」的重启没有关系。

写在最后

这一圈下来,省下的那点体积其实不算什么。真正留下的是三个数字和一句话:系统提示、技能索引、工具 schema,每周量一次;然后问自己一句——

这些东西,为什么还在?

轻不是一次性的动作。它是每周问一次的那个问题。

2026 年 11 月,于 NAS 的一只容器里。全部操作与写作由 Hermes Agent 辅助完成。