
最近半年我一直在折腾一件事把手头十几个AI编程工具、几十个Agent框架的技能全部收拢到一个桌面中枢里统一管理。起因非常朴素——我一天里要在Cursor、Windsurf、Copilot、Trae之间来回切换还得伺候一堆命令行Agent每个工具都有一套自己的技能配置、Prompt体系和上下文管理方式同一个项目的编码规范和代码评审标准要在五六个地方各写一遍改了还要同步好几遍实在忍无可忍。这个Skills Manager项目就是为了解决这个割裂问题把54 AI编程工具Agent的技能抽象成一套统一标准做成一个跨平台的桌面中枢。简单说你只需要在这个中枢里维护一份技能它就能通过适配层把技能注入到不同工具的Agent里让Cursor、Windsurf、Copilot、Trae、Aider、Codex CLI这些工具用上完全一致的技能。听起来简单真正落地时牵扯到技能描述规范、适配器机制、并发执行、平台差异、Agent沙盒环境等一系列问题。这篇文章我就把整个项目的设计思路、核心实现、踩坑过程完整梳理一遍给同样在多个AI编程工具之间疲于奔命的人一个可直接参考的方案。1. 为什么我会想做一个统一技能中枢1.1 工具越来越多技能越来越碎先说我面对的具体场景。我日常参与的项目不算少有老旧的Java服务端、有Go写的中间件、有TypeScript全栈应用还有一些Python数据分析脚本。每个项目我都会同时打开一个IDE类工具比如Cursor或Windsurf和一个命令行Agent比如Aider或Codex CLI。理想状态下这些工具应该共享我对项目积累下来的所有经验——比如Go项目的错误处理规范、前端组件必须遵守的a11y要求、Python脚本如何组织模块等。实际情况是这些技能碎在各个工具各自的目录里。Cursor里我维护了一套.cursor/rules文件Windsurf里有.windsurf/rulesCopilot有.github/copilot-instructions.mdTrae有自己的配置目录Aider要用CONVENTIONS.mdCodex CLI又要读AGENTS.md。更不用说那些Agent框架每个都要单独配置SKILL.md、人设Prompt、工具调用列表。有一次我更新了一条代码审查规范改完Cursor的配置后忘了同步到Aider结果Aider提交的PR依然按旧规范执行被同事当场抓包。从那一刻起我萌生了做一个统一层的念头所有技能只维护一份所有工具从中获取。1.2 我把技能拆成了三层在动手之前我先想清楚了一个问题所谓技能到底是什么经过梳理我发现所有AI编程工具里的技能本质上都可以拆成三层。第一层是元数据就是技能的ID、版本、适用语言、适用工具范围、触发条件这些描述信息负责让Agent或用户知道这个技能是干嘛的。第二层是指令模板也就是真正喂给大模型的Prompt它规定了模型在特定场景下应该怎么思考、怎么输出。第三层是资源文件包括参考文档、代码示例、命令脚本、测试用例等这些是技能执行时需要用到的外部素材。市面上大多数工具的技能配置就是这三样东西的某种排列组合只是格式和存放位置各不相同。比如Cursor的rules就是纯指令模板加上一些匹配规则Aider的CONVENTIONS.md是纯指令IntelliJ的AI Assistant插件又是一种格式。一旦我建立了技能元数据指令模板资源文件这个统一心智模型后续的抽象和适配就清晰多了。1.3 这个方案适合谁我并不觉得所有人都需要这样一个统一中枢。如果你只是在一个固定IDE里写个人项目技能割裂的问题基本不存在没必要给自己加重量。但如果你是像我一样的多工具流浪者或者团队里既有IDE派又有CLI派再或者你在做Agent开发、要同时对接多个Agent框架那么这个需求会非常真实。另外这个项目也适合那些正在做Agent基础设施的人参考。技能管理这件事本质上是Agent工程里绕不开的一环。吴恩达讲Agent开发时反复强调技能和工具是Agent能力的重要边界。我把这套东西做成桌面中枢既是解决我自己的痛点也可以理解为一次Agent技能管理的最佳实践探索。2. 整体架构设计一个中枢、两层适配、三种接口2.1 三个关键设计原则这个项目我最开始就定了三条设计原则后面所有实现都围绕它们展开。第一本地优先。技能是开发者的核心资产里面有大量项目私有的规范、代码模式甚至业务敏感信息绝不能为了跨设备同步就把这些数据送进云端。所有技能数据存放在本地目录用户可以自己选择目录位置甚至用Git仓库来管理版本。第二声明式技能。所有技能都用纯文本的声明式格式描述不绑定任何具体编程语言或运行时。技能文件就是一个SKILL.md加一个skill.yaml元数据文件任何工具只要能读这两个文件就能消费这个技能。第三运行时隔离。技能执行时可能依赖命令行工具、脚本、甚至外部API这些执行过程必须在受控的沙盒环境里运行不能把宿主机搞得一团糟。这三条原则直接决定了架构形态。桌面应用采用Tauri搭建后端用Rust处理文件扫描与进程管理前端用WebView渲染操作界面。选择Tauri而不是Electron纯粹是因为我需要在本地高频扫描大量技能文件、维护索引缓存还要跟各种外部进程打交道Rust在这类IO密集、并发热点上的表现确实比Node.js稳得多。2.2 统一技能模型SKILL.md 与 YAML 元数据技能模型是整个系统的地基。我参考了Agent Skills生态里的通用约定把每个技能定义成两个文件。一个是skill.yaml负责元数据。它包含技能ID、名称、版本、作者、描述、适用场景、触发关键词、依赖资源列表、执行权限声明等。另一个是SKILL.md负责指令模板。这是技能的核心内容用Markdown写成里面是给AI看的完整指令。指令模板需要写得足够细致让任何Agent读完之后都能按同样的逻辑执行。SKILL.md里我强烈要求写入以下区块角色定义、任务目标、执行步骤、输入输出格式、质量标准、禁止事项、参考资源路径。这样技能的确定性才强。如果只是一句请检查代码质量问题不同工具执行结果会天差地别而一旦写出检查顺序从安全到性能再到可读性每个问题标注文件与行号按P0/P1/P2分级所有工具的行为就能对齐。2.3 跨平台适配层三座大山的真实差异跨平台是这个项目里最头疼的部分没有之一。Windows、macOS、Linux三个平台的差异不只是路径分隔符和换行符的问题而是深入到进程管理、文件监听、Shell环境、权限模型等多个层面。第一路径转换。技能资源里如果写了/path/to/project这种绝对路径在Windows上立刻失效。我的方案是适配层拦截并转换路径协议所有路径统一用{{PROJECT_ROOT}}这类占位符跨平台时由适配器替换为实际路径。第二Shell差异。很多技能会要求Agent执行命令行操作比如跑测试、查日志。在Windows上这可能是PowerShell脚本在macOS/Linux上是Bash脚本。我的做法是技能里尽量声明意图而不是命令比如运行项目测试然后由适配层根据平台映射到具体命令。如果技能必须要写具体命令则同时提供run.test.win.ps1和run.test.sh两种变体。第三换行与编码。我再强调一次这类细节坑死人。Windows默认CRLFmacOS/Linux是LF如果技能模板里有多行Prompt且没有正确配置注入到Agent时可能被拆成多段Agent就完全理解错上下文了。统一中枢在生成配置文件时会主动做行尾归一化这一步必须自动化。2.4 为什么不做云端聚合很多朋友听说Skills Manager后第一反应是这不就是个云端技能市场吗我确实想过做云同步但最终放弃了。一方面技能资产高度私有上传云端会带来安全和合规问题很多公司内部规范根本不允许把代码评审标准、安全红线这种内容放到第三方服务上。另一方面Agent工具的本地配置文件种类繁多、格式各异云端聚合意味着要维护海量工具适配映射这个维护成本不是一两个人能长期承担的。本地方案每次升级只需要更新适配器目录用户自己拉取即可灵活多了。架构上最终形态是桌面中枢负责技能的注册、编辑、编排、导出每个被纳管的工具对应一个适配器配置中枢根据目标工具的格式要求把统一技能渲染成该工具自己的配置格式写入对应配置文件或启动参数中。这相当于一个格式转换网关只不过跑在本地。3. 实操从零搭起Skills Manager的核心模块3.1 技能注册与发现扫描、解析、去重技能中枢的第一步是让系统知道你有哪些技能。我设计了三种发现方式。第一种是目录扫描。你指定一个技能仓库根目录里面可以按skills/技能ID/组织中枢递归扫描所有SKILL.md和skill.yaml解析出技能索引。扫描过程用Rust的并行遍历54个技能的目录扫描耗时基本在几十毫秒级。第二种是Git仓库同步。很多技能其实是团队维护的放在Git仓库里。中枢可以配置远程仓库地址定时拉取并增量更新索引这样团队技能规范就能一键分发。第三种是手动创建。用户通过图形界面或CLI创建一个空技能模板然后编辑元数据和指令内容。解析时最麻烦的是去重和版本选择。同一技能可能在不同目录出现多个版本我引入了版本优先级规则如果技能声明了version字段且不相同按SemVer取最高版如果版本相同但内容不同则取修改时间最新的那个并打上警告标记。这个逻辑虽小却省去了大量心智负担。3.2 技能编排引擎依赖解析与动态组合单一技能管理并不难真正有价值的是技能之间能编排组合。比如一个发布Java服务流程可以拆成运行测试、构建产物、生成发布说明、回滚预案四个子技能每个子技能单独维护、单独测试再由编排引擎组合成高阶流程。编排引擎我实现了一个非常轻量的DAG调度器。每个技能声明depends_on字段指定它依赖的其他技能ID。系统启动时通过拓扑排序检测循环依赖。执行时按依赖序依次执行每个技能的输出比如生成的检查报告可以作为下一个技能输入的一部分。这里的关键是技能输出标准化。我要求每个技能执行完必须输出一个JSON摘要包含status、artifacts、summary三个字段。这样一来编排层就能根据status决定是否中断流水线根据artifacts传递后续路径根据summary整理最终报告。如果技能本身没有产出JSON的能力则由执行器捕获stdout和stderr做简单的结构化封装。3.3 与54工具的适配适配器模式这个项目里最繁琐也最透明的部分是适配器层。所谓适配器本质上是一个声明式配置文件加一小段转换逻辑。每个适配器描述三件事目标工具识别方式、统一技能到目标格式的映射模板、注入位置与生效范围。以Cursor为例适配器会把SKILL.md转换为.cursor/rules/*.mdc格式把技能元数据里的触发关键词转成glob或alwaysApply等匹配规则。Aider适配器则简单很多它是纯文本工具只接受单一指令文件所以适配器把多个技能按指定顺序拼接进CONVENTIONS.md。Codex CLI读取AGENTS.md格式与Aider类似但头部约束更强也需要单独映射。我统计过54个工具的适配难度其实呈长尾分布最常见的前5个工具Cursor、Windsurf、Copilot、Trae、Aider解决了80%的使用场景中间20个工具是常规格式剩余30个左右则是一些小众工具或框架很多只需要最简单的拼接逻辑。所以适配器架构上把通用文本拼接器做成了一个公共基座新接一个工具通常只需要新增一段几十行的模板映射。3.4 一个完整技能示例代码评审规范直接上一份我在实际项目里用着的技能定义供你参考。先看skill.yamlid: code-review-standard name: 代码评审规范 version: 2.3.0 lang: - go - typescript - python triggers: - code review - 评审 - review depends_on: [] requires_scripts: - scripts/scan_forbidden_patterns.py execution: sandbox: true timeout_sec: 120再看SKILL.md的指令模板核心片段# 角色定义 你是一名资深代码评审专家熟悉 Go、TypeScript、Python 三个语言栈。 # 任务目标 对给定变更代码进行系统性评审按优先级输出问题清单。 # 执行步骤 1. 先读取 scripts/scan_forbidden_patterns.py 的扫描结果。 2. 依次检查安全性、并发正确性、可读性、性能、测试覆盖。 3. 每个问题标注文件路径、行号、严重级别P0/P1/P2、修复建议。 # 输出格式 严格输出 JSON结构为 {issues: [{file: , line: 0, level: P0, desc: , suggestion: }], summary: 总体评价}这份技能在5个工具里测试过执行结果高度一致。之所以一致是因为我刻意用JSON输出锁定了结果结构任何Agent在严格遵守指令的情况下产出的格式都差不多。技能里最好不要写模糊的请给出优雅的修改建议而要写明建议必须附带具体代码片段。3.5 执行引擎沙盒与超时控制技能执行时往往要跑脚本比如上面示例里的scan_forbidden_patterns.py。我的处理方式是用Rust创建一个受控子进程设置CPU和内存限制指定工作目录并把临时文件全部放在系统临时目录下的独立子目录里。这样技能脚本就算写得很烂也影响不到宿主机。超时控制是必须有的。我默认给每个脚本120秒超时超时后直接杀掉子进程并把日志标记为失败。一开始我没有做超时控制结果有个技能脚本因为网络请求挂起整个编排流程卡了十分钟还占着CPU不释放。后来所有脚本强制走执行引擎统一纳入超时和资源限制编排任务再也没卡死过。4. 踩坑实录常见问题与排查技巧4.1 同名技能互相覆盖这是早期最多的问题。当我同时纳管两个Git仓库时两个仓库各自定义了名为test-runner的技能版本号还恰好都是1.0.0结果中枢在注入配置时出现了不确定行为一些工具拿到了A版本另一些拿到了B版本。排查看下来根因是我的去重逻辑只比对id和version忽略了内容哈希。修正后我在索引阶段为每个技能文件生成SHA256一旦发现同ID同版本但内容哈希不同的技能就在界面上亮出冲突卡片要求用户选择保留某个仓库的版本或创建新版本。此外我还加了source字段每条技能记录都指明来自哪个仓库、哪个子目录排查时能快速溯源。4.2 平台路径与换行符的连环坑我在2.3节提到过换行符问题这里再讲一个具体案例。某个技能模板里有一段多行Shell脚本我用它生成Windsurf的rules文件。在Windows上生成之后Agent读取规则时脚本被拆成了多段行为完全错乱。后来我在适配器的输出链路里统一加了normalize_line_endings()步骤同时把技能模板文件在仓库里强制用LF存储配合.gitattributes声明*.md text eollf问题才彻底消失。另一个典型问题是硬编码路径。技能资源文件里如果直接写/Users/me/...在Windows上会直接报错。我从一开始就在资源引用里禁掉绝对路径统一用协议占位符适配层解析时再根据当前平台展开。如果你要做类似项目这条约定越早建立越好否则后续改存量技能的成本很高。4.3 Agent上下文窗口被技能撑爆当你同时启用几十个技能把这些技能的指令模板全部注入到Agent上下文时你会立刻遇到上下文窗口爆掉的问题。Cursor这类IDE工具还好它有自己的规则过滤机制但Aider这种单文件模式会把全部技能拼接成一个大Prompt很快就把Context撑满Agent开始频繁遗漏指令。解决方案是在编排层引入按需注入。技能定义里的triggers字段非常关键适配层会根据任务的初始描述做一次轻量关键词匹配只注入命中触发词的那部分技能。没命中时比如你只是在改一个CSS样式细节就完全没必要把数据库迁移规范塞给Agent。这样90%场景下实际注入的技能控制在3到5个上下文占用降低一半以上。4.4 技能并发执行与Agent沙盒更新冲突项目中期我遇到过一个和Agent沙盒相关的诡异问题某个Agent在报告更新Agent沙盒之后会静默丢失技能状态。排查下来这是因为沙盒重建时把外部注入的技能配置目录删掉了而Agent的工作目录没变产生了悬空引用。这个问题的通用解法是技能配置持久化。我不再依赖目标工具自己的配置目录而是在项目根目录生成一个.skills-manager/目录统一下发技能文件同时通过工具的额外配置指令告诉Agent从该目录读取技能。这样即使Agent沙盒重建只要项目目录还在技能就能被重新读取。另外我还在执行引擎里加了启动钩子每次Agent启动时做一次技能配置完整性校验缺失则自动重新注入。4.5 排查工具链日志、状态、开关做这种本地工具排查手段必须自己备齐。我集成了三个层面。第一层面是本地日志。中枢对整个生命周期打结构化日志包括技能发现、适配渲染、注入目标、执行结果全部输出到logs/目录按天滚动。排查问题时直接按时间线拉日志。第二个层面是状态检查面板。在桌面界面上展示当前每个工具的技能接入状态绿色表示配置已同步黄色表示配置过期红色表示注入失败。我很多问题其实不用读日志看一眼面板颜色就知道哪些工具掉线了。第三层面是一键导出。如果某个工具有问题我可以一键导出它的完整最终配置直接看渲染结果到底是哪里不对。这种能力在面对第三方工具版本升级导致配置不兼容时尤其有用。4.6 性能与并发不要让几十个脚本拖垮你的电脑很多技能脚本会频繁调Python环境、Node进程如果编排引擎把这些任务全部并发执行小内存笔记本会直接卡死。Rust虽然性能好但调度策略不合理一样会拖垮系统。我的调度器最终采用了令牌桶式并发控制默认同时最多运行2个外部脚本进程CPU占用超过阈值时降为串行。又配合了技能级别的priority字段测试类任务优先级高于文档类任务。这套机制上线后无论同时跑多少个技能编排我的开发机都能保持流畅。如果你也做类似本地Agent编排工具一定提前把资源预算和并发上限设计进去别等到用户吐槽电脑卡了才补救。5. 几点真实的体会做到现在Skills Manager已经稳定纳管了身边大部分工具也成了我日常开发流程里离不开的一层基础设施。凡是经历过改一条规范要在5个工具里同步这种破事的人应该都能理解这种爽感。我个人的体会是统一技能管理这件事真正的难点不是写几个适配器而是对技能这个概念做出足够清晰的抽象。一旦想清楚技能无非是元数据、指令、资源这三件套所有工具都能被归约到同一套模型上剩下的适配只是工作量问题。如果你也想搞类似的东西我的建议是从小处着手先挑你最常用的3个工具把它们的技能格式吃透写一个最小适配器跑通一次注入。等你觉得有点感觉了再逐步把长尾工具接进来。另外技能内容本身的质量管理也很重要毕竟中枢只是管道水龙头里出的水干不干净还得看你沉淀的技能写得是否足够精确。这个项目后面我还在继续扩展方向大概有两个一个是把技能执行结果做成可沉淀的项目知识库让Agent的能力在一次次执行中不断积累另一个是为Agent开发提供一个标准化的技能调试环境毕竟现在Agent多了做Agent技能的人反而缺一套像样的工具链。都是后话等有了新进展我再写一篇聊聊。