1. 从“技能越攒越乱”说起:Hermes Curator 要解决的真实痛点做过技能后台维护的人大概都有同感:系统刚上线时干干净净,几十个技能条目整整齐齐。跑上三个月,条目数量翻了几倍,重复的、过期的、语义相近但命名不同的技能堆在一起,检索命中率肉眼可见地下滑。更麻烦的是,这些技能条目往往还挂着调用统计、依赖关系、版本标记,删也不是、留也不是,最后只能靠人工定期翻一遍,费时费力还容易漏。Hermes Curator 这个项目,本质上就是冲着这个场景去的。它要做的不是简单的“定时清理”,而是一套技能后台维护机制,核心由两个相位组成:自动归档相位和LLM 整合相位。前者负责把长期不活跃、低价值、重复的技能条目识别出来并归入冷区;后者负责用大模型对语义相近的条目做合并、重写和归一化,让技能库始终保持“少而精、精而准”的状态。这套机制适合谁参考?如果你正在维护一个技能市场、插件仓库、内部工具目录、Prompt 模板库,或者任何“条目会随时间自然膨胀”的后台系统,那这套双相位思路基本可以直接借鉴。它不依赖某个特定框架,核心是判定逻辑 + 归档策略 + 模型整合这三件事怎么串起来。下面我会把每个环节拆开讲,包括我实际落地时踩过的坑和调参经验。2. 自动归档相位:判定一个技能该不该“进冷宫”2.1 归档判定不能只看“最后调用时间”很多人第一反应是:超过 N 天没被调用就归档。这个逻辑简单,但实测下来误伤率很高。我遇到过一种情况——某个技能是季度性使用的,比如每季度末才跑一次报表生成,平时 80 天没动静,按“90 天未调用”规则差点被归档,结果季度末业务方找不到入口,直接投诉。所以 Hermes Curator 的归档判定采用的是多因子加权,而不是单一时间阈值。我实际用的因子包括:因子含义权重参考最近调用间隔距最后一次调用的天数0.35调用频次趋势近 30 天 vs 前 30 天的调用量变化0.25依赖被引用数有多少其他技能/流程依赖它0.20唯一性得分与库内其他技能的语义相似度0.15人工标记是否被标记为“保留”0.05加权总分低于阈值(我设的是 0.3)才进入候选归档池。注意依赖被引用数这一项权重不低,因为一个技能哪怕自己没人直接调,只要被别的活跃技能依赖,就不能动。这一点是很多简单清理脚本会忽略的。2.2 归档不是删除:冷区设计与可恢复性归档动作本身要设计得足够“温柔”。我的做法是给每个技能条目加一个lifecycle_state字段,取值active、archived、merged、deprecated。归档只是把状态改成archived,同时记录archived_at和archive_reason,数据本身不删。这样做的好处有三个:一是误归档可以一键恢复;二是归档原因可追溯,方便后续调权重;三是 LLM 整合相位可以只扫描active状态的条目,减少计算量。提示:归档阈值不要一次调太激进。我第一版把阈值设成 0.5,结果一周内归档了 40% 的条目,业务方直接炸锅。后来降到 0.3,并且加了“归档前 3 天预告”机制,才稳定下来。2.3 归档相位的调度与幂等性归档任务我放在每天凌晨低峰期跑,用的是一个轻量调度器。这里有个容易忽略的点:幂等性。如果任务因为异常中断重跑,不能出现同一条技能被重复归档、或者归档时间被覆盖的情况。我的处理是每次归档前先查lifecycle_state,只有active才处理,并且用archived_at IS NULL作为二次保险。另外,归档批次要限制单次处理量,比如一次最多 200 条。原因很简单:如果某天阈值配置出错,一次性归档几千条,恢复起来非常痛苦。分批处理给了你一个“刹车”的机会。3. LLM 整合相位:让模型做“语义去重”而不是“字符串去重”3.1 为什么字符串相似度不够用技能条目的命名往往很随意。比如“生成周报”“周报自动生成”“weekly report generator”这三个,字符串相似度可能不高,但语义上就是同一个东西。反过来,“数据清洗”和“数据清晰度检查”字符串很像,语义却完全不同。所以整合相位必须依赖语义理解,这就是 LLM 介入的地方。我的流程是:先对active状态的技能做向量化,用嵌入模型把每个技能的“名称 + 描述 + 输入输出示例”编码成向量,然后做近邻检索,把相似度超过 0.85 的条目聚成候选簇。注意这里用的是技能完整信息而不是只编码名称,因为名称太短,区分度不够。3.2 让 LLM 做“合并决策”而不是“合并执行”候选簇出来之后,不要直接让模型去合并。我的做法是分两步:第一步让 LLM 判断这个簇里的条目是否真的应该合并,输出一个结构化结果,包含should_merge、canonical_name、merge_reason;第二步才是根据这个结果去执行实际的合并操作。为什么拆两步?因为模型直接执行合并容易“过度合并”。我遇到过模型把一个“发送邮件”和一个“发送短信”合并成“发送通知”,虽然语义上有交集,但实际调用参数完全不同,合并后反而没法用。拆成“决策”和“执行”之后,决策结果可以先落库、人工抽检,确认没问题再执行,安全很多。3.3 合并时的字段取舍策略合并两个技能条目时,字段怎么取是个细活。我的策略是:名称:优先取 LLM 给出的canonical_name,如果模型没给,取调用量最高的那个名称。描述:取信息量最全的,通常是最长的那条,但要去掉重复表述。输入输出 schema:做并集,冲突字段人工确认。调用统计:累加。依赖关系:合并去重。lifecycle_state:被合并的条目置为merged,并记录merged_into指向主条目。这套取舍逻辑我写成了一个配置化的合并器,不同字段可以配不同的策略,避免硬编码。4. 双相位如何协同:时序、触发与冲突处理4.1 先归档还是先整合这两个相位的执行顺序有讲究。我试过两种顺序:先整合再归档,和先归档再整合。实测下来先归档再整合更合理。原因在于:归档会把一批低价值条目移出active集合,整合相位扫描的范围就小了,LLM 调用成本直接下降。如果先整合,那些本该归档的条目也会参与语义聚类,浪费算力,还可能干扰聚类结果。所以我的调度是:每天凌晨先跑归档相位,跑完更新active集合,再触发整合相位。两个相位之间通过一个中间状态表衔接,记录本次归档了哪些条目,整合相位启动时读取这个表来缩小扫描范围。4.2 触发方式:定时 + 事件双通道纯定时有个问题:如果业务方刚录入了一批新技能,要等到第二天凌晨才整合,体验不好。所以我加了事件触发通道——当新增技能数量超过阈值(比如 20 条),或者人工手动触发时,立即跑一次整合相位。定时通道则保证兜底,防止事件通道漏掉。两个通道要有互斥锁,避免同时跑导致重复合并。我用的是一个基于数据库的轻量锁,锁的粒度是“整合任务”级别,不是全局锁,这样归档和整合可以并行不冲突。4.3 冲突处理:当归档和整合意见不一致有一种边界情况:某个技能被归档相位判定为“该归档”,但整合相位认为它和某个活跃技能语义高度相似、应该合并。这时候听谁的?我的处理原则是整合优先。因为合并本身就会让这个条目“消失”(变成merged状态),比单纯归档更彻底。具体做法是:整合相位在扫描时,除了active集合,还会把“本次归档候选中相似度超过 0.9 的条目”也纳入,先做合并决策,合并完再让归档相位重新评估剩余条目。5. 落地时踩过的坑与调参经验5.1 嵌入模型的选型与成本控制嵌入模型我换过三次。第一版用的是一个通用大模型,效果好但成本高,每天全量编码一次账单很难看。后来改成“增量编码 + 缓存”:只有新增或修改过的技能才重新编码,没变的直接读缓存向量。这一下把成本降了 80% 以上。模型选型上,我建议用中等规模、专门做语义相似度的嵌入模型,而不是拿生成式大模型硬编码。生成式模型编码出来的向量在近邻检索上反而不如专用嵌入模型稳定。这个结论是我对比了三种方案后得出的,供参考。5.2 相似度阈值的动态调整0.85 这个阈值不是拍脑袋定的。我的做法是:先跑一周“只记录不合并”模式,把候选簇和人工判断结果对比,算准确率和召回率,然后画一条曲线找平衡点。实测下来,0.85 在我的数据集上准确率约 92%,召回约 78%。如果业务方更怕误合并,可以把阈值提到 0.88;如果更怕漏合并,降到 0.82。注意:阈值不要设成全局固定值。不同技能类别的语义密度不一样,比如“数据处理类”技能之间相似度普遍偏高,“通知类”技能之间偏低。我后来按类别分别设阈值,效果明显更好。5.3 人工兜底入口不能省无论模型多准,一定要留人工兜底。我的后台有一个“整合审核”页面,展示所有should_merge=true的候选簇,运营可以一键确认或驳回。驳回的案例会回流成负样本,用于后续调阈值。这个闭环跑了两周之后,误合并率从 8% 降到了 2% 以内。另外,归档操作也要有“撤销”按钮,并且撤销后要能恢复依赖关系。我见过一次误归档导致下游流程报错,就是因为恢复时只改了状态,没恢复依赖边。6. 从这套机制里能复用到其他场景的思路Hermes Curator 的双相位设计,核心思想其实是“先做减法,再做归一”。这个思路可以迁移到很多后台维护场景。比如内容平台的标签体系维护、代码仓库的分支清理、监控告警规则的治理,都可以套用:先用多因子判定把低价值项归档,再用语义模型把重复项合并。我个人的体会是,这套机制最难的不是模型调用,而是判定逻辑的透明性和可调性。权重、阈值、合并策略,全部要配置化,不能写死在代码里。因为业务在变,今天合理的阈值明天可能就不合理了。把调参权交给运营,比你自己反复改代码高效得多。最后分享一个小技巧:归档和整合的日志一定要分开存,并且带上批次 ID。这样出问题时可以按批次回滚,而不是全量重跑。我吃过一次亏,整合任务出错后全量重跑,结果把已经人工确认过的合并又覆盖了一遍,白白浪费了半天人工审核。分开存日志、按批次操作,这个习惯能帮你省下很多返工时间。
1. 从“技能越攒越乱”说起:Hermes Curator 要解决的真实痛点做过技能后台维护的人大概都有同感:系统刚上线时干干净净,几十个技能条目整整齐齐。跑上三个月,条目数量翻了几倍,重复的、过期的、语义相近但命名不同的技能堆在一起,检索命中率肉眼可见地下滑。更麻烦的是,这些技能条目往往还挂着调用统计、依赖关系、版本标记,删也不是、留也不是,最后只能靠人工定期翻一遍,费时费力还容易漏。Hermes Curator 这个项目,本质上就是冲着这个场景去的。它要做的不是简单的“定时清理”,而是一套技能后台维护机制,核心由两个相位组成:自动归档相位和LLM 整合相位。前者负责把长期不活跃、低价值、重复的技能条目识别出来并归入冷区;后者负责用大模型对语义相近的条目做合并、重写和归一化,让技能库始终保持“少而精、精而准”的状态。这套机制适合谁参考?如果你正在维护一个技能市场、插件仓库、内部工具目录、Prompt 模板库,或者任何“条目会随时间自然膨胀”的后台系统,那这套双相位思路基本可以直接借鉴。它不依赖某个特定框架,核心是判定逻辑 + 归档策略 + 模型整合这三件事怎么串起来。下面我会把每个环节拆开讲,包括我实际落地时踩过的坑和调参经验。2. 自动归档相位:判定一个技能该不该“进冷宫”2.1 归档判定不能只看“最后调用时间”很多人第一反应是:超过 N 天没被调用就归档。这个逻辑简单,但实测下来误伤率很高。我遇到过一种情况——某个技能是季度性使用的,比如每季度末才跑一次报表生成,平时 80 天没动静,按“90 天未调用”规则差点被归档,结果季度末业务方找不到入口,直接投诉。所以 Hermes Curator 的归档判定采用的是多因子加权,而不是单一时间阈值。我实际用的因子包括:因子含义权重参考最近调用间隔距最后一次调用的天数0.35调用频次趋势近 30 天 vs 前 30 天的调用量变化0.25依赖被引用数有多少其他技能/流程依赖它0.20唯一性得分与库内其他技能的语义相似度0.15人工标记是否被标记为“保留”0.05加权总分低于阈值(我设的是 0.3)才进入候选归档池。注意依赖被引用数这一项权重不低,因为一个技能哪怕自己没人直接调,只要被别的活跃技能依赖,就不能动。这一点是很多简单清理脚本会忽略的。2.2 归档不是删除:冷区设计与可恢复性归档动作本身要设计得足够“温柔”。我的做法是给每个技能条目加一个lifecycle_state字段,取值active、archived、merged、deprecated。归档只是把状态改成archived,同时记录archived_at和archive_reason,数据本身不删。这样做的好处有三个:一是误归档可以一键恢复;二是归档原因可追溯,方便后续调权重;三是 LLM 整合相位可以只扫描active状态的条目,减少计算量。提示:归档阈值不要一次调太激进。我第一版把阈值设成 0.5,结果一周内归档了 40% 的条目,业务方直接炸锅。后来降到 0.3,并且加了“归档前 3 天预告”机制,才稳定下来。2.3 归档相位的调度与幂等性归档任务我放在每天凌晨低峰期跑,用的是一个轻量调度器。这里有个容易忽略的点:幂等性。如果任务因为异常中断重跑,不能出现同一条技能被重复归档、或者归档时间被覆盖的情况。我的处理是每次归档前先查lifecycle_state,只有active才处理,并且用archived_at IS NULL作为二次保险。另外,归档批次要限制单次处理量,比如一次最多 200 条。原因很简单:如果某天阈值配置出错,一次性归档几千条,恢复起来非常痛苦。分批处理给了你一个“刹车”的机会。3. LLM 整合相位:让模型做“语义去重”而不是“字符串去重”3.1 为什么字符串相似度不够用技能条目的命名往往很随意。比如“生成周报”“周报自动生成”“weekly report generator”这三个,字符串相似度可能不高,但语义上就是同一个东西。反过来,“数据清洗”和“数据清晰度检查”字符串很像,语义却完全不同。所以整合相位必须依赖语义理解,这就是 LLM 介入的地方。我的流程是:先对active状态的技能做向量化,用嵌入模型把每个技能的“名称 + 描述 + 输入输出示例”编码成向量,然后做近邻检索,把相似度超过 0.85 的条目聚成候选簇。注意这里用的是技能完整信息而不是只编码名称,因为名称太短,区分度不够。3.2 让 LLM 做“合并决策”而不是“合并执行”候选簇出来之后,不要直接让模型去合并。我的做法是分两步:第一步让 LLM 判断这个簇里的条目是否真的应该合并,输出一个结构化结果,包含should_merge、canonical_name、merge_reason;第二步才是根据这个结果去执行实际的合并操作。为什么拆两步?因为模型直接执行合并容易“过度合并”。我遇到过模型把一个“发送邮件”和一个“发送短信”合并成“发送通知”,虽然语义上有交集,但实际调用参数完全不同,合并后反而没法用。拆成“决策”和“执行”之后,决策结果可以先落库、人工抽检,确认没问题再执行,安全很多。3.3 合并时的字段取舍策略合并两个技能条目时,字段怎么取是个细活。我的策略是:名称:优先取 LLM 给出的canonical_name,如果模型没给,取调用量最高的那个名称。描述:取信息量最全的,通常是最长的那条,但要去掉重复表述。输入输出 schema:做并集,冲突字段人工确认。调用统计:累加。依赖关系:合并去重。lifecycle_state:被合并的条目置为merged,并记录merged_into指向主条目。这套取舍逻辑我写成了一个配置化的合并器,不同字段可以配不同的策略,避免硬编码。4. 双相位如何协同:时序、触发与冲突处理4.1 先归档还是先整合这两个相位的执行顺序有讲究。我试过两种顺序:先整合再归档,和先归档再整合。实测下来先归档再整合更合理。原因在于:归档会把一批低价值条目移出active集合,整合相位扫描的范围就小了,LLM 调用成本直接下降。如果先整合,那些本该归档的条目也会参与语义聚类,浪费算力,还可能干扰聚类结果。所以我的调度是:每天凌晨先跑归档相位,跑完更新active集合,再触发整合相位。两个相位之间通过一个中间状态表衔接,记录本次归档了哪些条目,整合相位启动时读取这个表来缩小扫描范围。4.2 触发方式:定时 + 事件双通道纯定时有个问题:如果业务方刚录入了一批新技能,要等到第二天凌晨才整合,体验不好。所以我加了事件触发通道——当新增技能数量超过阈值(比如 20 条),或者人工手动触发时,立即跑一次整合相位。定时通道则保证兜底,防止事件通道漏掉。两个通道要有互斥锁,避免同时跑导致重复合并。我用的是一个基于数据库的轻量锁,锁的粒度是“整合任务”级别,不是全局锁,这样归档和整合可以并行不冲突。4.3 冲突处理:当归档和整合意见不一致有一种边界情况:某个技能被归档相位判定为“该归档”,但整合相位认为它和某个活跃技能语义高度相似、应该合并。这时候听谁的?我的处理原则是整合优先。因为合并本身就会让这个条目“消失”(变成merged状态),比单纯归档更彻底。具体做法是:整合相位在扫描时,除了active集合,还会把“本次归档候选中相似度超过 0.9 的条目”也纳入,先做合并决策,合并完再让归档相位重新评估剩余条目。5. 落地时踩过的坑与调参经验5.1 嵌入模型的选型与成本控制嵌入模型我换过三次。第一版用的是一个通用大模型,效果好但成本高,每天全量编码一次账单很难看。后来改成“增量编码 + 缓存”:只有新增或修改过的技能才重新编码,没变的直接读缓存向量。这一下把成本降了 80% 以上。模型选型上,我建议用中等规模、专门做语义相似度的嵌入模型,而不是拿生成式大模型硬编码。生成式模型编码出来的向量在近邻检索上反而不如专用嵌入模型稳定。这个结论是我对比了三种方案后得出的,供参考。5.2 相似度阈值的动态调整0.85 这个阈值不是拍脑袋定的。我的做法是:先跑一周“只记录不合并”模式,把候选簇和人工判断结果对比,算准确率和召回率,然后画一条曲线找平衡点。实测下来,0.85 在我的数据集上准确率约 92%,召回约 78%。如果业务方更怕误合并,可以把阈值提到 0.88;如果更怕漏合并,降到 0.82。注意:阈值不要设成全局固定值。不同技能类别的语义密度不一样,比如“数据处理类”技能之间相似度普遍偏高,“通知类”技能之间偏低。我后来按类别分别设阈值,效果明显更好。5.3 人工兜底入口不能省无论模型多准,一定要留人工兜底。我的后台有一个“整合审核”页面,展示所有should_merge=true的候选簇,运营可以一键确认或驳回。驳回的案例会回流成负样本,用于后续调阈值。这个闭环跑了两周之后,误合并率从 8% 降到了 2% 以内。另外,归档操作也要有“撤销”按钮,并且撤销后要能恢复依赖关系。我见过一次误归档导致下游流程报错,就是因为恢复时只改了状态,没恢复依赖边。6. 从这套机制里能复用到其他场景的思路Hermes Curator 的双相位设计,核心思想其实是“先做减法,再做归一”。这个思路可以迁移到很多后台维护场景。比如内容平台的标签体系维护、代码仓库的分支清理、监控告警规则的治理,都可以套用:先用多因子判定把低价值项归档,再用语义模型把重复项合并。我个人的体会是,这套机制最难的不是模型调用,而是判定逻辑的透明性和可调性。权重、阈值、合并策略,全部要配置化,不能写死在代码里。因为业务在变,今天合理的阈值明天可能就不合理了。把调参权交给运营,比你自己反复改代码高效得多。最后分享一个小技巧:归档和整合的日志一定要分开存,并且带上批次 ID。这样出问题时可以按批次回滚,而不是全量重跑。我吃过一次亏,整合任务出错后全量重跑,结果把已经人工确认过的合并又覆盖了一遍,白白浪费了半天人工审核。分开存日志、按批次操作,这个习惯能帮你省下很多返工时间。