用文件系统治理智能体Skill:SkillFS目录设计与实践
发布时间:2026/10/21 23:52:50 锦皓数字建站

1. Skill 数量失控的第一个信号维护成本开始吃掉迭代速度先说一个我自己的真实经历。去年我在做某个智能体项目的中期重构一开始系统里只有五六个 Skill用一张配置表维护绰绰有余每次新增一个技能往表里加一行把触发词、参数、回调函数名写进去就行。同事之间偶尔问问这个技能是干嘛的看一眼配置表也就清楚了。但项目跑到中期Skill 数量慢慢涨到了四五十个情况开始不对劲。最明显的变化是我每天花在找代码、改注册表、纠结这个技能到底被谁引用上的时间比真正写技能逻辑的时间还长。新增一个演示用的技能本来十分钟能搞定结果因为要在配置中心里核对依赖、检查键名是否冲突、确认启用状态硬生生拖到四十分钟。更难受的是有一次上线前自查发现两个 Skill 的 trigger 关键词重叠了导致 Agent 在某个场景下总是命中错误的技能而这个问题埋了两周才被用户反馈逼出来。1.1 几十个 Skill 意味着什么数量膨胀的典型过程Skill 的膨胀通常不是一步到位的。起步阶段你给 Agent 设计了查天气算数学调日历三五个技能一切都很清爽。随后你开始接外部工具每个工具对应一个 Skill接着你又拆出一些 Prompt 模板型技能比如会议纪要整理周报汇总再后来不同项目环境下的 Agent 变体开始各自维护几套技能副本……等回过神总量已经奔着五十、一百去了。数量到了这个级别技能这个抽象概念就开始暴露出它的复杂性。每个 Skill 不仅有自身的名称和描述还有输入输出协议、依赖的外部数据源、版本记录、适用场景、启停状态、所属的 Agent 类型。这些信息堆在一个二维表格里很快就变成一锅粥。你根本记不清某个 Prompt 模板技能是只在 A 环境生效还是全局生效你也不知道某个工具技能已经被新版本替代了但旧版本的注册条目还挂在系统里Timer 定时触发的场景还会误踩它。1.2 集中式 Skill 列表的三个致命问题我复盘那段混乱期发现所有问题都可以归到三个根因上这也是我后来坚决转向文件系统治理的导火索。第一个问题是索引与内容分离。配置表里存的是 Skill 的元信息真正的实现代码散落在各个目录、各个模块甚至各个仓库里。表里说这个技能叫export_report但你要顺着配置项一个个猜它的实现在哪。索引层和内容层不同步是绝大多数维护痛苦的来源。删表里的条目不等于删实现改了实现也不一定有人记得改表里的描述两边迟早脱节。第二个问题是看不到全貌。一个二维表格很难表达 Skill 之间的层级、依赖和分组关系。哪些技能属于基础能力层哪些属于业务场景层哪些只是临时的实验技能表格做不到这点。你在表格里看到四十行数据但看不出这四十个技能的结构、聚类和演进脉络。没有结构就没有治理没有治理就只能靠人肉记忆。第三个问题是变更没有痕迹。配置表被改就被改了谁改的、什么时候改的、为什么改统统没有记录。线上出了事故你想回滚到上一个稳定的 Skill 集合只凭一张表根本无从下手。表里存的是最终态天然不支持版本、分支、快照这类时间维度的操作。1.3 什么时候该下决心治理很多团队问过我到底几个 Skill 的时候开始治理比较合适我的经验是不要看数量看信号。当你发现自己开始频繁回答下面这些问题就该动手了这个技能在哪个文件里——回答这个问题需要超过两分钟这个技能能不能删——没人能给出确定答案线上跑的是哪一版技能定义——需要翻聊天记录才能确认新增技能时你第一反应是找个地方复制一下旧代码而不是从一个标准模板创建。出现其中任何一个信号说明 Skill 治理已经不是未雨绸缪而是火烧眉毛。我见过有团队硬撑到一百多个 Skill 才治理结果光是梳理资产的归属、删除死代码就花了两周代价远高于早期动手。别等早期切换的成本低得多因为那时候你的历史包袱还不大。2. 为什么是文件系统自然索引、所见即所得与零依赖决定治理 Skill 之后第一个问题必然是用什么做治理基座我们当时开了三次评审会候选方案列了一堆关系型数据库、配置中心、对象存储、自研注册中心……最后选定的却是最不起眼的方案——文件系统。这个选择现在回头看非常值但当时确实经历了一番论证。2.1 数据库和配置中心的对比先说说我们为什么没有选数据库。数据库当然能存 Skill 元信息字段想怎么设计就怎么设计查询还很灵活。但问题在于数据库是另一个系统。你的 Skill 实现代码明明在 Git 仓库里元信息却放在数据库里这就是上一节说的索引与内容分离的升级版。你提交代码和修改数据库是两件不同步的事必然有一个中间地带代码已经推到仓库了数据库还没来得及改或者数据库改了代码有 Bug 回滚了数据库却停在半路。配置中心之类的外部依赖同理。它们解决的是运行时读取配置的问题但 Skill 治理需要的是这个技能包括什么、它能做什么、它现在处于什么状态的完整画像。让一个外部配置中心承载这种内容型数据每次更新都要走发布流程加一个技能要等审批和部署太笨重了。我们项目里有很多快速迭代的实验性技能这种发布链路完全接受不了。文件系统则没有这个分离问题。Skill 的实现放在目录里元信息放在同一目录的清单文件里两者提交、发布、回滚的粒度和时机完全一致。一个 Skill 从创建到上线本质上就是在这个目录里放一组文件这跟 Git 的工作流天然对齐。2.2 文件系统作为Skill 的仓库的独特优势文件系统最打动我的一点是它自带世间万物皆文件的自然索引能力。每个 Skill 是一个目录目录名就是技能名目录里有实现文件、清单文件、样例文件、说明文档。大脑只需要记一条规则想找技能去 skills 目录下看一眼目录结构。 这比任何查询语句都直观。第二个优势是所见即所得。你在终端里敲一下tree整个技能资产的全貌立刻展现在眼前哪些是核心技能、哪些是实验技能、哪些已经标记下线、每个技能包含什么文件。这种一眼看全的体验是任何数据库查询都给不了的。我后来发现团队的新成员上手项目时不再需要拉着老同事问项目结构怎么组织自己打开目录看一圈就基本明白了。这种知识传递效率的提升是实实在在的隐性收益。第三个优势是零依赖。文件系统不需要额外部署服务、不需要管理连接池、不需要处理网络分区。只要有磁盘和路径SkillFS 的扫描器就能工作。哪怕最极端的情况——整套基础设施全挂只剩一台裸机你也能靠find命令把人肉可读的 Skill 清单找出来手工恢复运行。这种最坏情况下的可运维性在大型系统里很少被认真考虑但对智能体类系统来说可恢复性直接决定了故障时长。2.3 什么场景不适合文件系统当然文件系统不是万能药我得先说清楚它的边界免得有人盲目搬过去踩坑。如果你的 Skill 数量已经上千且技能之间存在复杂的运行时依赖关系比如技能 A 要动态编排技能 B、C、D依赖关系需要图数据库来管理那纯文件系统就不够用了。我的建议是文件系统做资产底座图关系索引放在内存或数据库里两者配合。再比如你的多个 Agent 实例运行在不同机器上需要共享同一份 Skill 集合那文件系统就得配合分布式文件服务比如对象存储挂载来使用。单机文件路径只适合单机或同构集群跨地域场景需要额外处理同步问题。一句话总结文件系统适合做可读、可审计、可版本化的静态资产层不适合做高频动态关系计算的运行时层。把前者交给文件系统把后者留给代码是最合理的分工。3. SkillFS 目录结构一套可直接抄走的治理布局理论说完了上实操。我下面这套目录结构是我们项目里踩过不少坑之后沉淀出来的方案你可以把它当作一个起点按自己项目的实际情况做增删。先看全貌skills/ ├── _shared/ # 全局共享能力不作为独立Skill │ ├── client_utils.py │ └── prompt_base.md ├── core/ # 核心基础技能 │ ├── calculator/ │ │ ├── skill.yaml │ │ ├── impl.py │ │ └── README.md │ ├── calendar_query/ │ │ ├── skill.yaml │ │ ├── impl.py │ │ └── test_fixtures.json │ └── ... ├── scene/ # 场景化业务技能 │ ├── meeting_minutes/ │ │ ├── skill.yaml │ │ ├── prompt.md │ │ ├── schema.json │ │ └── examples/ │ └── ... ├── experimental/ # 实验技能随时可能删除 │ ├── fortune_teller/ │ │ ├── skill.yaml │ │ └── impl.py │ └── ... └── retired/ # 已下线技能保留供追溯 ├── legacy_weather/ │ ├── skill.yaml │ ├── impl.py │ └── ARCHIVE.md └── ...3.1 顶层目录与 Skill 包的划分顶层分四层是有讲究的core放所有 Agent 实例都必须加载的基础技能scene放面向特定业务场景的组装级技能experimental放还没验证完的新技能retired放已下线但暂时不删的历史技能。这四层的本质是 Skill 生命周期状态的可视化什么东西在哪一层目录里代表它处于什么生命阶段任何人一眼就能判断。这里有个容易被忽略的点_shared目录不是技能而是被技能共享的公共代码和提示词模板。一开始我没分这个目录结果好几个技能各自复制了一份客户端工具代码后面改接口时改到崩溃。有了_shared之后依赖关系清晰了很多。每个 Skill 包就是一个独立目录。目录名建议用蛇形命名snake_case因为蛇形在文件名里最安全不会像驼峰那样在大小写不敏感的文件系统上引发歧义。目录内部文件尽量遵循固定模板至少要包含skill.yaml元数据清单、一个实现文件、一个 README 说明文档。README 容易被忽略但是它的价值很大很多维护信息比如这个技能为什么这么写只有 README 里能记。3.2 skill.yaml 清单文件设计skill.yaml是 SkillFS 的核心元数据文件我先给一个我们打磨后的模板name: calendar_query version: 2.3.1 status: active # active | deprecated | experimental | retired owner: agent-core description: 查询日历事件并按时间范围返回结果 trigger: - 查日历 - 日程 - calendar capabilities: - type: function entry: impl.py:query_events params_schema: schema.json # 可选参数JSON Schema - type: prompt_template entry: prompt.md dependencies: - skill: _shared.client_utils - python: requests2.28 tags: - calendar - office-scene created_at: 2024-03-12 updated_at: 2024-07-30这里每个字段都有它的设计意图。name必须和目录名一致这条约束是为了防止目录叫 A元数据里叫 B的错位我后面会单独讲这个坑。status和顶层目录分层形成双重确认目录决定资产放置位置元数据决定运行时动作。比如retired/legacy_weather目录里的 skill.yaml 里 status 也标retired扫描器看到目录路径和元数据一致才会完全跳过加载。trigger字段是触发词列表。这个字段值得多说一句我们后来把它拆成了实际触发匹配词和语义参考词两组避免 Agent 在意图识别时被太宽的触发词带偏。比如calendar作为英文字符串既可能是真实触发也可能出现在无关上下文里。拆组之后误触发率显著下降。capabilities是运行时最关心的字段它定义了技能的具体实现入口——函数入口、Prompt 模板入口、参数校验 Schema 都在这里声明。dependencies用来表达 Skill 之间的依赖关系虽然是静态声明但已经能为加载器提供足够信息去做拓扑排序。3.3 命名规范与目录约束命名规范是治理二字最容易落地也最容易被忽视的部分。我们当时定了几条硬规则这几条规则后来帮我省掉了很多不必要的排查时间目录名必须是合法标识符只允许小写字母、数字、下划线不允许空格这条规则保证目录名可以安全地出现在代码里、URL 里、日志里。技能名全局唯一哪怕是 retired 状态的技能名字也不允许复用。这条规则防止历史资产被新技能顶替保证审计链路完整。版本号放skill.yaml不放进目录名有的人喜欢在目录名里加 v1/v2我们试过之后放弃了。目录名一旦带上版本号升级就要改目录名引用它的其他技能全部要跟着改代价太大。目录约束是让结构不腐烂的关键。我们的扫描器会强制执行这些约束任何违反命名规则或目录结构的提交都会在 CI 阶段直接失败。可能有人觉得这有点死板但我跟你讲没有强制执行约束就是一张废纸。人总有偷懒的时候尤其是赶进度的时候一旦破例一次后面就刹不住车了。4. 从文件到运行时Skill 的注册、加载与动态发现目录摆好了下一步是把文件系统里的资产变成运行时可以被 Agent 使用的技能。这一步涉及三个核心环节扫描目录生成索引、按依赖顺序加载实现、持续监听变更做热更新。4.1 扫描器与索引缓存扫描器的作用是定期遍历 skills 目录读取所有skill.yaml生成一份内存索引。我直接给一个最小可用的 Python 扫描器实现这个代码我们已经跑了几个月稳得很# skillfs_scanner.py import hashlib import os from pathlib import Path def scan_skill_packages(root: Path) - dict: 扫描skills根目录返回 {skill_name: skill_meta} 字典。 每个Skill包必须是一个子目录且包含skill.yaml。 index {} for skill_dir in root.iterdir(): if not skill_dir.is_dir(): continue manifest skill_dir / skill.yaml if not manifest.exists(): continue # 用文件名修改时间生成内容指纹用于后面判断是否真的变更 stat manifest.stat() fingerprint hashlib.sha256( f{skill_dir.name}:{stat.st_mtime_ns}:{stat.st_size}.encode() ).hexdigest()[:16] meta load_yaml(manifest) # yaml.safe_load meta[_dir] str(skill_dir) meta[_fingerprint] fingerprint index[skill_dir.name] meta return index注意几个细节。第一我用目录名作为索引的 key而不是用skill.yaml里的name然后通过校验保证两者一致。这样当出现不一致时扫描器能立刻报警而不是静默容忍。第二指纹用的是目录名修改时间文件大小的组合而不是盲目对比整个文件内容扫描上千个文件时性能也能接受。第三扫描器不主动做深度的语法校验那些交给 CI运行时只关心加载。索引缓存我一般放到内存字典里外加一个定时器每 30 秒手动触发一次增量重扫。为什么不用 inotify 这类事件驱动机制因为跨平台兼容性太差了Windows、macOS、Linux 三套 API 轮着来调试成本高于收益。定时扫描加指纹对比30 秒的延迟对 Skill 变更来说完全够用。4.2 加载协议与依赖解析拿到索引之后下一步是真正把 Skill 的实现加载到运行时。我们定义了一套加载协议每种capabilities.type对应一种加载方式capabilities.type加载动作注释放到function通过importlib动态导入impl.py解析entry指向的函数函数对象注册到技能注册表prompt_template读取prompt.md文本编译模板变量占位符模板字符串注册到提示词库tool_spec解析schema.json生成 OpenAI 工具调用格式描述工具定义注册到工具清单加载顺序必须处理依赖。我们会在扫描之后做一次拓扑排序按dependencies字段把 Skill 排成加载序列。比如meeting_minutes依赖_shared.prompt_base那_shared必须先加载。真实项目中依赖关系不会太复杂主要是一棵浅树用 Kahn 算法几十行代码就能搞定不需要引入重型图计算库。这里有一个实践技巧加载失败不要静默跳过也不要抛异常终止全部加载。我们的做法是失败名单机制——加载失败的技能会进入degraded状态系统日志记录完整错误栈同时其他技能照常工作。Agent 在遇到需要这个技能的场景时会返回一个明确的技能暂不可用错误而不是基于不完整上下文硬猜一种回答。用户对这种透明错误其实更信任。4.3 热更新与优雅下线Skill 的变更不能总是走全量重启。我们的 Agent 是长驻进程每次改个 Prompt 模板就重启一遍用户体验会很差。文件系统方案天然热更新友好因为每个 Skill 的解耦点在目录边界上所以只要监听目录变更就能精准热替换单个技能。热更新流程是定时扫描对比指纹 - 发现变更 - 标记旧技能为updating- 加载新版实现 - 原子替换运行时绑定 - 释放旧对象等待 GC。这里原子替换是关键我们用一个SkillRegistry类封装所有技能引用的读写内部用读写锁控制保证读取方在任何时刻看到的都是完整的新版或旧版技能而不是加载到一半的残缺状态。import threading class SkillRegistry: def __init__(self): self._lock threading.RLock() self._skills {} # name - skill_runtime self._degraded {} # name - error_info def register(self, name: str, runtime): with self._lock: self._skills[name] runtime def unregister(self, name: str): with self._lock: old self._skills.pop(name, None) if old: old.shutdown() # 释放资源、关闭会话 def get(self, name: str): with self._lock: if name in self._skills: return self._skills[name] raise SkillNotFoundError(name)优雅下线比热更新更考验细节。当你把某个 Skill 标记为deprecated且下线时不能直接把它从索引里抹掉否则正在执行中的会话会突然找不到技能。我们的做法是三步走先标记状态为disabling此时不再接收新请求但已在执行的请求会执行完等到所有持引用方释放资源后再把它从注册表移除最后把skill.yaml的 status 改成retired并挪到retired/目录。这套软下线流程虽然多几步但线上事故率几乎归零。还有一个小提示热更新虽然好用但不要把它当成生产环境的主力发布手段。生产环境仍然建议走 CI/CD用镜像或制品包整体替换。热更新更适合开发调试和小步实验两者场景不同。5. 基于文件系统的进阶治理能力权限、版本与审计文件系统方案的最大红利是治理能力不需要自研——操作系统和 Git 已经帮你实现了。这一节我讲三个我们在实践中真正用起来的进阶能力。5.1 用文件权限矩阵管理 Skill 可见性很多团队忽略了一点文件系统的权限模型天然就是一套 Skill 治理的 RBAC。谁可以修改某个技能的实现谁只能读取触发词谁完全看不到某个实验技能这些都可以映射到文件权限上。我们当时的做法是划分了三类角色技能维护者拥有写权限、Agent 编排者只读权限、审计员只读加历史查看权限。在本地开发环境大家都有写权限这没问题但在共享开发机或 CI 执行环境中跑 Agent 的服务账号只授予读取技能目录的权限。这样即使出现恶意或失误的代码注入运行时进程也不具备改动技能文件的能力攻击面被显著缩小。更实用的一个组合是把experimental/目录的写权限只开放给少数人core/目录的写权限必须通过代码评审后才能合并。这样 Skill 的分层治理和代码评审流程绑定在一起管理成本几乎为零。5.2 版本管理与回滚git 与符号链接的组合文件系统治理下版本管理最自然的承载体是 Git。每个 Skill 包从创建开始就是一个普通的文件目录所有修改都有 commit 记录。出问题时git revert或git checkout一个历史目录就能精准回滚某个技能而不影响其他技能。相比数据库里手动 UPDATE 一条配置这个优势是降维打击。但 Git 有一个体验问题它的分支是指整个仓库的做不到单个 Skill 目录级别的分支切换。为了弥补这一点我们引入了一套基于符号链接的版本别名机制。在代码仓库里维护一个releases/目录里面每个技能名都是一个符号链接指向skills/下的某个具体版本目录# 当前稳定版符号链接 releases/calendar_query - ../../skills/core/calendar_query_v2.3.1 # 切换回旧版本 rm releases/calendar_query ln -s ../../skills/core/calendar_query_v2.1.0 releases/calendar_query这里目录名里带版本号是与前面目录名不带版本号原则的一个有意识例外——skills/下的规范资产目录保持纯净版本化目录只存在于releases/的发布快照里。这样既保留了常规开发的便利又在发布维度获得了版本切换能力。扫描器只需要读取releases/下的符号链接解析结果就能知道当前运行时应该加载哪一版技能。5.3 审计与统计从目录树读出治理状态治理做到位之后你想要什么统计口径几乎都能用一行命令或一个简单脚本从目录树里分析出来。文件系统以极低成本提供了可审计性。我维护了一个小脚本skillfs_report.py每天跑一次会输出一份治理健康报告包含每个状态的技能数量active / experimental / retired近一周变更过的技能列表依赖了_shared中已被标记 deprecated 的工具函数的技能清单超过 60 天没有更新的技能列表用于识别僵尸资产缺失 README 或 skill.yaml 格式非法的技能清单。这个报告不需要任何额外的数据库所有数据都来自对文件树的遍历和skill.yaml的解析。某次技术评审会上我用这份报告展示了我们到底有多少资产、哪些资产在腐烂比空口说我们要治理一下有力得多。数据驱动治理从文件系统开始。还有一个审计能力是文件系统自带的时间戳和日志。因为 Skill 变更都发生在 Git 仓库里git log --follow -- skills/core/calendar_query/就能看到这个技能的完整演进史。谁在什么时候把description改得更宽泛了谁把trigger加了一个高风险词连同 commit message 和 code review 记录一起全链路可追溯。这对质量回溯和事故复盘来说价值太大了而且你一分钱额外成本都没有花。6. 实测中的三个大坑与修复记录再好的方案落地时不踩几个坑都不好意思说做过真项目。我们跑 SkillFS 期间记录了不少问题我挑三个最有代表性的、也是别人大概率会遇到的坑说下症状、根因和修复过程。6.1 符号链接导致的循环扫描症状很典型扫描器程序突然在启动阶段疯狂递归CPU 打满最终报maximum recursion depth exceeded。第一次遇到时我还以为是扫描器代码写错了查了半天才发现是releases/里的符号链接闹的鬼。情况是这样的我用ln -s把 release 目录指向了技能目录然后扫描器为了支持发布快照会在扫描时把符号链接也作为合法目录解析进去。结果某次手滑一个 release 符号链接指回了skills/的根目录等于让扫描器遍历目录时出现了环skills/ - releases/ - skills/ - releases/ - ...。文件系统层面的目录访问没有防环机制死循环就这么来了。修复方案有两层。第一层是快而粗暴的扫描器跳过所有符号链接目录只扫描真实目录。但这样一来发布快照就用不了了等于砍掉了一个重要功能。第二层是引入已访问目录集扫描器维护一个visited集合记录所有已经展开过的真实路径用Path.resolve()解析后的路径。在递归进入任意目录前先检查解析后的路径是否在集合里在就直接跳过。这个方案彻底解决了循环问题同时保留了符号链接能力。6.2 并发扫描与运行时加载的锁冲突第二个坑出现在我们做热更新机制的时候。扫描器线程每 30 秒会遍历文件树刷新索引而 Agent 的运行时线程同时可能正在执行某个技能。两条路径都访问同一个技能目录下的文件看着各管各的但在某些操作下有隐藏冲突。具体症状是偶发性的file changed as we read it异常。比如扫描器在遍历skill.yaml时恰好运行时线程因为热更新在写同一个文件。Python 的读取和写入没有原子性保证读侧可能拿到一半的 YAML 内容导致解析失败。更隐蔽的是某些情况下目录里的文件列表在扫描过程中发生变化比如examples/目录正在被复制扫描器遍历到一半文件数对不上索引数据不完整。排查过程很有意思因为问题不是必现的压测才能稳定复现。后来我用strace跟踪文件读写时序确认了冲突窗口就出现在扫描器打开文件和热更新写入文件之间。修复方案是双管齐下一是给所有热更新写入动作加一个统一的文件锁利用操作系统级别的flock保证同一时刻只有一个写者二是扫描器读取文件时增加完整性校验——读取之后立即重新 stat 文件修改时间如果发现读入期间文件有变更则丢弃本次结果下个周期重新扫。两个措施叠加之后这个偶发异常彻底消失了。6.3 文件名编码与跨平台不一致第三个坑最隐蔽也最容易被团队在新人入职后引爆。我们有个设计师同事在某个 Skill 的 README 里放了一个 emoji 表情做装饰文件名没受影响。但另一个场景里有人把技能描述用中文做成了目录名查询天气/在 macOS 和 Linux 上跑得好好的一到 Windows 就整个目录加载不了。根因是文件系统编码策略不一致。macOS 的 APFS 默认用 NFD 归一化形式存储文件名Windows 的 NTFS 用的是 NFCLinux 原生是任意字节序列。导致的结果是同一个中文目录名在不同系统上os.listdir()拿到的字节序列不一样扫描器用字符串比对就匹配不上skill.yaml更严重的是某些字符在两套系统里甚至会表现为完全不同的码点组合目录名直接对不上。修复其实很简单但执行起来需要决心全面禁止非 ASCII 字符进入目录名CI 里加一条 lint 规则任何包含非 ASCII 字符的目录名直接拒绝合并。这对国内团队来说有点逆人性毕竟中文命名很顺手。但为了跨平台一致性这个代价是值得的。你可以把展示用的中文名放到skill.yaml的display_name字段里目录名用拼音或英文都行运行时展示层完全可以用中文。除了上面三个坑还有一个小问题是git 树冲突——多人同时往一个 Skill 目录加文件merge 时冲突一堆。我们的解决办法是鼓励每个技能目录保持小职责单一真正只属于一个负责人。这不完全是技术问题但治理方案里要包含组织分工这一项。技术方案只能帮你降低协作成本人和人的协作规范还得靠制度。现在这套 SkillFS 方案在我们项目里稳定运行了半年多五十多个 Skill 的增删改都有章可循维护成本比我预想的低得多。我最大的感受是治理不是搞一堆复杂的系统把资产放进一个可读可溯源的空间里规则足够简单、强制执行到位大部分问题会自动消失。如果你的 Agent 项目也在为 Skill 数量头疼不妨从整理一个目录开始试试。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。