1. 项目概述:这不是一个“技能库”,而是一套可复用、可验证、可演进的智能体能力工程体系
你搜“agent-skills”时,看到的多半是零散的 GitHub 仓库、某篇博客里几行代码示例,或是面试题里一句“请手写一个工具调用函数”。但真正做过生产级智能体(Agent)落地的人心里都清楚:技能(Skills)不是功能函数的堆砌,而是能力交付的最小契约单元。它必须能被发现、被描述、被验证、被组合、被审计,还要能跨框架复用——这正是agent-skills这个命名背后隐含的工程意图。它不是一个玩具项目,而是一套面向 TypeScript + Node 生态的智能体能力标准化实践方案,核心目标就一个:让 AI 应用里的“调用外部系统”这件事,从“每次重写 try-catch”变成“声明式注册 + 类型安全调用”。
我带团队在金融风控、政务问答、工业设备巡检三个场景落地 Agent 时,踩过最深的坑不是模型不准,而是技能模块失控:同一个天气查询逻辑,在三个项目里分别有 4 种参数名、3 种错误码定义、2 种超时策略,连 mock 测试数据都不统一。后来我们倒逼出一套规范——所有技能必须满足:输入输出类型可静态推导、执行过程可拦截审计、失败原因可结构化归因、版本变更可语义化追溯。agent-skills就是这套规范的 TypeScript 实现载体,它天然绑定 Nx 工程体系,因为只有单体多项目(monorepo)架构才能支撑技能的跨域复用与独立演进;它默认集成 semantic-release,因为技能的 API 变更直接影响下游 Agent 的行为,必须靠自动化版本号传递契约变更信号。
你不需要立刻理解所有术语,但请记住这个判断标准:如果一个“技能”不能被npm install @your-org/skills-weather后直接 import 并通过类型检查,那它就还没达到agent-skills的准入门槛。它服务的对象很明确——不是初学者练手,而是需要将 LLM 能力嵌入现有业务系统的中高级开发者;不是教你怎么写 prompt,而是帮你把“调用 CRM 接口查客户余额”这件事,变成和调用本地函数一样可靠、可测、可维护的工程资产。接下来我会拆解它怎么做到这一点,不讲虚概念,只说你明天就能抄作业的实操细节。
2. 核心设计逻辑:为什么必须用 Nx + TypeScript + semantic-release 构建技能体系
2.1 技能不是函数,是契约:TypeScript 类型即文档
很多团队把技能写成普通函数:
// ❌ 危险的“技能”写法 export function getWeather(city: string) { return fetch(`https://api.example.com/weather?city=${city}`) .then(r => r.json()) .catch(e => console.error(e)); }问题在哪?三处致命缺陷:
第一,输入无约束——city: string允许传入空字符串、超长字符串、非法字符,调用方根本不知道合法值域;
第二,输出无定义——.json()返回任意对象,调用方无法静态知道data.temp是否存在、是否为 number;
第三,错误不可控——console.error是日志,不是错误契约,下游 Agent 无法区分“城市不存在”和“网络超时”,更没法做差异化重试。
agent-skills的解法是强制使用Schema-first 类型定义:
// ✅ agent-skills 标准写法 import { z } from 'zod'; export const WeatherInput = z.object({ city: z.string().min(2).max(50).regex(/^[a-zA-Z\u4e00-\u9fa5]+$/), unit: z.enum(['celsius', 'fahrenheit']).default('celsius'), }); export const WeatherOutput = z.object({ temp: z.number().min(-100).max(100), condition: z.enum(['sunny', 'rainy', 'cloudy', 'snowy']), humidity: z.number().min(0).max(100), }); export type WeatherInput = z.infer<typeof WeatherInput>; export type WeatherOutput = z.infer<typeof WeatherOutput>; export async function getWeather( input: WeatherInput, context: SkillContext // 后文详解 ): Promise<WeatherOutput> { const validated = WeatherInput.parse(input); // ... 实际请求逻辑,返回前用 WeatherOutput.safeParse 验证 }这里的关键不是用了 zod,而是类型定义与实现函数强绑定。WeatherInput不仅是类型,更是运行时校验器;WeatherOutput不仅是返回值提示,更是结果可信度的担保。我在某银行项目里强制要求所有技能必须提供.d.ts声明文件,结果发现 73% 的历史技能因类型不匹配被自动拦截——不是代码报错,而是 CI 检查失败。这种“类型即契约”的设计,让技能交接成本下降 60%,新成员看类型定义就能 80% 理解接口语义。
2.2 技能不是孤岛,是网络:Nx monorepo 解决复用与隔离矛盾
当技能数量超过 20 个,你会面临经典困境:
- 放一个 repo?每次改一个技能都要全量发布,版本号混乱,下游不敢升级;
- 每个技能单独 repo?依赖管理爆炸,
@org/skills-db更新了,@org/skills-email却还在用旧版@org/shared-types; - 手动管理子包?
lerna bootstrap在复杂依赖下经常锁死,CI 时间翻倍。
agent-skills选择 Nx 的根本原因,是它用project graph + task pipeline替代了传统包管理思维。在 Nx workspace 中,每个技能是一个独立 project:
libs/ ├── skills-weather/ # 定义 WeatherInput/Output + 实现 ├── skills-crm/ # 定义 CRM 查询参数 + 实现 ├── skills-file-upload/ # 定义上传策略 + 实现 └── shared-types/ # 所有技能共用的基础类型(如 SkillContext)关键操作不是npm publish,而是nx build skills-weather—— Nx 会自动分析依赖图,只构建被修改的技能及其上游依赖。更重要的是,技能间可以直连引用:
// skills-crm/src/index.ts import { getWeather } from '@org/skills-weather'; // 不是 npm 包,是本地路径引用 export async function getCustomerInfo(id: string) { const weather = await getWeather({ city: 'Shanghai' }); // 类型安全,IDE 自动补全 // ... 结合 CRM 数据返回增强结果 }这解决了两个痛点:
- 开发体验:改完
skills-weather,在skills-crm里立即看到类型更新,不用等npm publish+yarn add; - 发布控制:Nx 的
nx release插件会基于 git commit 分析哪些 project 被修改,自动生成对应版本号(如skills-weather@2.1.0,skills-crm@1.3.0),避免“一个 bug 修复导致所有包升 patch 版”。
我在某政务项目中用 Nx 管理 47 个技能,CI 时间从 22 分钟降到 6 分钟,版本发布错误率归零——因为nx release生成的 changelog 是机器可读的 JSON,下游 Agent 项目用nx migrate就能自动更新依赖并运行迁移脚本。
2.3 技能不是快照,是演进:semantic-release 强制契约变更可视化
技能 API 的微小改动可能引发 Agent 行为剧变。比如把WeatherInput.unit从 string 改为 enum,表面是增强类型安全,实际却让所有未适配的调用方 runtime 报错。agent-skills用 semantic-release 不是为了“自动化发版”,而是把 API 变更变成可审计、可追溯、可预警的工程事件。
配置核心在nx.json:
{ "pluginsConfig": { "@nx/semantic-release": { "branches": ["main"], "plugins": [ "@semantic-release/commit-analyzer", "@semantic-release/release-notes-generator", "@semantic-release/npm", "@semantic-release/github" ] } } }关键规则是commit message 必须符合 Conventional Commits 规范:
# ✅ 正确:触发 minor 版本(新增功能,向后兼容) git commit -m "feat(skills-weather): add support for forecast days" # ✅ 正确:触发 major 版本(破坏性变更,必须人工确认) git commit -m "feat(skills-weather)!: change unit from string to enum" # ❌ 错误:不会触发发布,且 CI 检查失败 git commit -m "fix weather api"!符号是 semantic-release 的魔法开关——它告诉系统:“这个提交包含 breaking change,必须升 major 版”。我们在 CI 中加入强制检查:
# nx.json 中的 prebuild hook "targets": { "prebuild": { "executor": "@nx/workspace:run-commands", "options": { "commands": ["npx commitlint --from=origin/main"] } } }效果是什么?当工程师提交feat(skills-weather)!: ...,CI 会:
- 自动运行
nx release,生成v3.0.0版本; - 在 GitHub Release 页面自动生成结构化 changelog,明确列出“哪些输入字段被移除”“哪些错误码被废弃”;
- 向所有订阅
@org/skills-weather的 Agent 项目发送 Slack 通知,并附带变更影响分析报告(由 Nx 插件自动生成)。
这比“发个公告说下周升级”靠谱 10 倍。某物流客户曾因未及时处理skills-tracking的 breaking change,导致分拣机器人指令解析失败——后来我们把 semantic-release 的 changelog 解析成 JSON,接入内部运维平台,任何技能升级都会自动创建工单并指派给对应 Agent 维护人。
3. 核心模块实现:从 SkillContext 到可插拔执行引擎
3.1 SkillContext:技能的“操作系统内核”
所有技能函数签名都包含context: SkillContext参数,这不是装饰,而是能力治理的基础设施。SkillContext定义如下:
export interface SkillContext { // 执行上下文标识,用于链路追踪 readonly traceId: string; // 当前 Agent 的身份与权限(JWT 解析结果) readonly auth: { userId: string; roles: string[] }; // 技能执行元数据(谁调用、何时调用、超时设置) readonly metadata: { caller: string; // 调用方技能名 timeoutMs: number; retryPolicy: { maxRetries: number; backoffMs: number }; }; // 可插拔的执行中间件(日志、监控、熔断) readonly middleware: SkillMiddleware[]; // 依赖注入容器(用于获取数据库连接、缓存客户端等) readonly inject: <T>(token: InjectionToken<T>) => T; } // 中间件类型定义 export type SkillMiddleware = ( context: SkillContext, next: (ctx: SkillContext) => Promise<any> ) => Promise<any>;为什么必须有context?看三个真实场景:
- 审计需求:某金融项目要求所有技能调用留痕,
context.traceId直接注入到日志中,配合 ELK 可秒级定位“哪个用户、哪个对话、哪次调用触发了风控技能”; - 权限控制:
context.auth.roles让skills-crm在执行前自动校验调用方是否有crm:read权限,避免把客户数据暴露给客服机器人; - 弹性保障:
context.metadata.retryPolicy让技能无需自己写重试逻辑,中间件统一处理——我们在skills-payment中用它实现了“支付失败时按指数退避重试 3 次,第 4 次降级为短信通知”。
实操技巧:SkillContext的创建由 Agent Runtime 统一管理,技能开发者绝不手动构造。我们提供createSkillContext工厂函数:
// libs/shared-context/src/index.ts export function createSkillContext({ traceId, auth, caller, timeoutMs = 5000, }: { traceId: string; auth: { userId: string; roles: string[] }; caller: string; timeoutMs?: number; }): SkillContext { return { traceId, auth, metadata: { caller, timeoutMs, retryPolicy: { maxRetries: 2, backoffMs: 1000 } }, middleware: [logMiddleware, monitorMiddleware, circuitBreakerMiddleware], inject: (token) => container.resolve(token), // 使用 InversifyJS 容器 }; }提示:不要在技能内部修改
context属性!它是只读的。所有状态变更(如添加日志字段)必须通过middleware注入,保证执行链路纯净。
3.2 可插拔中间件:技能的“能力增强器”
agent-skills的中间件机制模仿 Express,但更轻量。以logMiddleware为例:
export const logMiddleware: SkillMiddleware = async ( context, next ) => { const startTime = Date.now(); try { const result = await next(context); console.log( `[SKILL] ${context.metadata.caller} -> ${context.traceId} | SUCCESS | ${Date.now() - startTime}ms` ); return result; } catch (error) { console.error( `[SKILL] ${context.metadata.caller} -> ${context.traceId} | ERROR | ${error.message} | ${Date.now() - startTime}ms` ); throw error; // 保持错误冒泡 } };关键设计点:
- 中间件可组合:
context.middleware是数组,顺序执行,next控制流程; - 中间件可配置:
circuitBreakerMiddleware接收熔断阈值作为参数,不同技能可配置不同策略; - 中间件可替换:测试时用
mockMiddleware替换真实日志,避免测试污染;
我们在某工业项目中为skills-machine-status添加了专用中间件:
// libs/skills-machine-status/src/middleware.ts export const machineStatusGuard: SkillMiddleware = async (context, next) => { const machineId = context.metadata.caller.split('-')[1]; // 从调用方名提取设备ID const status = await redis.get(`machine:${machineId}:status`); if (status !== 'online') { throw new SkillError('MACHINE_OFFLINE', `Machine ${machineId} is offline`); } return next(context); };这个中间件在技能执行前检查设备在线状态,把“设备离线”这个业务异常转化为结构化错误,Agent 可据此触发告警而非重试。它不侵入技能实现,却赋予了所有机器状态技能统一的健康检查能力。
3.3 技能注册中心:动态发现与元数据驱动
agent-skills不要求技能硬编码在 Agent 中,而是通过SkillRegistry动态加载:
// libs/skill-registry/src/index.ts export class SkillRegistry { private skills = new Map<string, RegisteredSkill>(); register(skill: RegisteredSkill) { this.skills.set(skill.name, skill); } get(name: string): RegisteredSkill | undefined { return this.skills.get(name); } list(): RegisteredSkill[] { return Array.from(this.skills.values()); } } export interface RegisteredSkill { name: string; // 技能唯一标识 description: string; // 供 LLM 理解的自然语言描述 inputSchema: ZodSchema; // 用于 LLM 参数生成 outputSchema: ZodSchema; // 用于 LLM 结果解析 execute: (input: any, context: SkillContext) => Promise<any>; tags: string[]; // 用于分类搜索(如 ['io', 'auth', 'payment']) }注册示例:
// apps/agent-core/src/skills.ts import { SkillRegistry } from '@org/skill-registry'; import { getWeather } from '@org/skills-weather'; import { WeatherInput, WeatherOutput } from '@org/skills-weather'; const registry = new SkillRegistry(); registry.register({ name: 'get_weather', description: 'Get current weather for a city. Use this when user asks about temperature or conditions.', inputSchema: WeatherInput, outputSchema: WeatherOutput, execute: getWeather, tags: ['io', 'public-api'], });这个设计让 Agent 具备“认知扩展”能力:
- LLM 工具调用:Agent Runtime 将
registry.list()转为 JSON Schema,喂给 LLM,LLM 自动生成调用参数; - 前端技能面板:管理后台读取
registry.list()渲染技能目录,支持按 tag 过滤; - 自动化测试:测试框架遍历
registry.list(),对每个技能运行 schema 验证测试;
注意:
inputSchema和outputSchema必须是 zod schema,不能是 type 或 interface——因为 LLM 需要 JSON 可序列化的结构来理解参数格式。我们用zod-to-json-schema库自动转换,避免手写冗余 JSON Schema。
4. 实操全流程:从初始化 workspace 到发布第一个技能
4.1 初始化 Nx workspace(跳过 node 安装陷阱)
很多新手卡在第一步:npx create-nx-workspace@latest失败。根本原因不是网络,而是Node 版本与 Nx 兼容性。截至 2024 年,Nx 17+ 要求 Node 18.17+,但国内镜像常滞后。正确姿势:
# 1. 用 nvm 精确安装(推荐) curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash # 重启终端后 nvm install 18.17.0 nvm use 18.17.0 # 2. 配置 npm 国内镜像(避免后续卡住) npm config set registry https://registry.npmmirror.com npm config set disturl https://npmmirror.com/dist # 3. 创建 workspace(关键:指定插件) npx create-nx-workspace@latest agent-skills \ --preset=apps \ --cli=nx \ --nxCloud=false \ --packageManager=pnpm为什么选 pnpm?因为agent-skills依赖树深(zod + axios + @types/node),pnpm 的硬链接节省 70% 磁盘空间,pnpm store全局缓存让nx build速度提升 3 倍。如果你已用 yarn,务必加--packageManager=yarn,否则混合包管理器会引发诡异冲突。
4.2 创建技能库(libs/skills-weather)
# 在 workspace 根目录执行 nx g @nx/js:library skills-weather \ --directory=libs \ --importPath=@org/skills-weather \ --publishable \ --buildable \ --unitTestRunner=jest \ --no-interactive关键参数说明:
--publishable:生成package.json,支持npm publish;--buildable:启用nx build skills-weather,产出 ESM/CJS 双格式;--importPath=@org/skills-weather:设置包名,避免相对路径引用;
生成后,进入libs/skills-weather/src/lib/index.ts,按前文标准编写技能:
import { z } from 'zod'; import axios from 'axios'; export const WeatherInput = z.object({ city: z.string().min(2).max(50), }); export const WeatherOutput = z.object({ temp: z.number(), condition: z.string(), }); export type WeatherInput = z.infer<typeof WeatherInput>; export type WeatherOutput = z.infer<typeof WeatherOutput>; export async function getWeather( input: WeatherInput, context: SkillContext ): Promise<WeatherOutput> { const validated = WeatherInput.parse(input); try { const res = await axios.get( `https://api.openweathermap.org/data/2.5/weather?q=${validated.city}&appid=${process.env.OPENWEATHER_API_KEY}`, { timeout: context.metadata.timeoutMs } ); const output = { temp: Math.round(res.data.main.temp - 273.15), condition: res.data.weather[0].main.toLowerCase(), }; return WeatherOutput.parse(output); // 强制类型校验 } catch (error) { if (axios.isAxiosError(error)) { throw new SkillError('WEATHER_API_ERROR', error.message); } throw error; } }4.3 配置 semantic-release(自动化发布流水线)
在libs/skills-weather/project.json中添加 release target:
{ "targets": { "release": { "executor": "@nx/semantic-release:release", "dependsOn": ["build"], "options": { "branch": "main", "plugins": [ "@semantic-release/commit-analyzer", "@semantic-release/release-notes-generator", "@semantic-release/npm", "@semantic-release/github" ] } } } }然后在根目录nx.json中配置全局插件:
{ "pluginsConfig": { "@nx/semantic-release": { "branches": ["main"], "repositoryUrl": "https://github.com/your-org/agent-skills.git" } } }重要:设置 GitHub Token
在 GitHub Settings → Developer settings → Personal access tokens → Generate new token,勾选public_repo和packages权限,保存为环境变量:
# 在 CI 环境中(如 GitHub Actions) echo "GH_TOKEN=${{ secrets.GITHUB_TOKEN }}" >> $GITHUB_ENV本地测试发布流程:
# 1. 提交符合规范的 commit git add . git commit -m "feat(skills-weather): add getWeather function" # 2. 推送到 main 分支 git push origin main # 3. CI 自动触发 nx release,发布到 npm # 查看效果:npm view @org/skills-weather4.4 在 Agent 中集成技能(apps/agent-core)
nx g @nx/js:application agent-core \ --directory=apps \ --frontendProject=none \ --e2eTestRunner=none在apps/agent-core/src/main.ts中注册技能:
import { SkillRegistry } from '@org/skill-registry'; import { getWeather } from '@org/skills-weather'; import { WeatherInput, WeatherOutput } from '@org/skills-weather'; const registry = new SkillRegistry(); // 注册技能 registry.register({ name: 'get_weather', description: 'Get current weather for a city', inputSchema: WeatherInput, outputSchema: WeatherOutput, execute: getWeather, tags: ['io'], }); // 启动 Agent startAgent({ skillRegistry: registry, model: 'gpt-4-turbo', });此时,Agent 就具备了调用天气技能的能力。关键验证点:
- 类型安全:
getWeather的参数和返回值在 IDE 中有完整提示; - 错误隔离:
skills-weather的 bug 不会影响agent-core启动; - 独立升级:
nx release发布@org/skills-weather@2.0.0后,agent-core只需pnpm update @org/skills-weather即可升级,无需修改代码。
5. 常见问题与实战排障指南
5.1 “npm : 无法加载文件 d:\node\npm.ps1” —— Windows PowerShell 执行策略问题
这是 Windows 用户最高频问题,本质是 PowerShell 默认禁止运行本地脚本。不要禁用执行策略(安全风险),正确解法:
# 1. 以管理员身份打开 PowerShell # 2. 查看当前策略 Get-ExecutionPolicy # 3. 为当前用户设置 RemoteSigned(允许本地脚本) Set-ExecutionPolicy RemoteSigned -Scope CurrentUser # 4. 验证 Get-ExecutionPolicy -Scope CurrentUser # 应显示 RemoteSigned注意:
-Scope CurrentUser确保只影响当前用户,不影响系统其他账户。如果公司策略禁止修改执行策略,改用 Windows Terminal + WSL2,彻底避开 PowerShell 限制。
5.2 “The requested module 'node:util' does not provide an export named” —— Node 版本与 ESM 兼容性
此错误表明你的 Node 版本低于 18.12,或type: "module"配置冲突。排查步骤:
确认 Node 版本:
node -v # 必须 >= 18.12检查
package.json:{ "type": "module", // Nx 项目必须设为 module "exports": { ".": { "import": "./src/index.ts", // 注意:Nx 默认生成 .js,需改为 .ts "require": "./dist/index.cjs" } } }修正 tsconfig.json:
{ "compilerOptions": { "module": "ESNext", "moduleResolution": "Bundler", "target": "ES2020", "lib": ["ES2020", "DOM"], "types": ["node"] // 关键:必须包含 node 类型 } }
5.3 Nx 构建失败:“Cannot find module '@org/skills-weather'”
这不是路径问题,而是TS 模块解析未配置。在tsconfig.base.json中添加:
{ "compilerOptions": { "baseUrl": ".", "paths": { "@org/*": ["libs/*"] } } }同时确保libs/skills-weather/tsconfig.lib.json继承正确:
{ "extends": "../../tsconfig.base.json", "compilerOptions": { "outDir": "../../dist/out-tsc", "declaration": true, "types": ["node"] } }5.4 semantic-release 不触发发布
常见原因及对策:
| 现象 | 原因 | 解决方案 |
|---|---|---|
nx release无输出 | 未配置branches或分支名不匹配 | 检查nx.json中@nx/semantic-release.branches是否为["main"],确认当前分支是main |
提交了feat:却未升 minor 版 | commit message 格式错误 | 用npx commitlint --from=origin/main本地验证,确保feat(skills-weather): ...无空格、无多余符号 |
| GitHub Release 创建失败 | GH_TOKEN 权限不足 | 进入 GitHub Token 设置页,确认勾选了public_repo和packages |
5.5 技能执行超时,但日志无记录
这是中间件未生效的典型表现。检查SkillContext创建流程:
// ❌ 错误:未传入 middleware const context = { traceId: 'abc', auth: { userId: '123', roles: [] }, metadata: { caller: 'test', timeoutMs: 3000 }, // missing middleware! }; // ✅ 正确:显式传入 const context = createSkillContext({ traceId: 'abc', auth: { userId: '123', roles: [] }, caller: 'test', timeoutMs: 3000, });实操心得:我们给所有技能函数添加了运行时校验:
export function assertContext(context: SkillContext) { if (!context.middleware || context.middleware.length === 0) { throw new Error('SkillContext must include middleware array'); } }在技能开头调用
assertContext(context),CI 中立即暴露问题。
6. 进阶扩展:从技能到能力网络的演进路径
agent-skills的终点不是封装函数,而是构建可组合的能力网络。我们已在三个方向验证其延展性:
6.1 技能编排(Orchestration)
当单一技能无法满足需求,如“订机票”需串联航班查询、价格比对、支付网关,我们引入SkillOrchestrator:
export async function bookFlight( input: BookFlightInput, context: SkillContext ) { const flight = await getFlights({ ...input }, context); const price = await comparePrices({ flights: flight }, context); const payment = await processPayment({ amount: price.min }, context); return { ...flight, price, payment }; }关键创新:SkillOrchestrator本身也是一个技能,可被更高层 Agent 调用,形成能力分层。我们在某旅游平台用此模式,将 12 个原子技能组合成 3 个业务技能,Agent 调用复杂度下降 80%。
6.2 技能市场(Marketplace)
将SkillRegistry对接内部 npm registry,构建私有技能市场:
# 发布技能到私有 registry pnpm publish --registry https://your-company.com/npm/ # Agent 项目一键安装 pnpm add @org/skills-erp@latest配套开发skill-marketplace应用,提供:
- 技能搜索(按 tag、描述关键词);
- 依赖图谱(查看某技能被哪些 Agent 使用);
- 兼容性检查(输入 Agent 的 Node 版本,提示技能兼容性);
6.3 技能沙箱(Sandbox)
为高危技能(如数据库写入、设备控制)提供隔离执行环境:
// libs/skills-sandbox/src/index.ts export async function runInSandbox<T>( skillName: string, input: any, context: SkillContext ): Promise<T> { // 启动 Docker 容器执行技能 const result = await docker.exec( 'node:18-slim', ['node', '-e', `require('./${skillName}').execute(${JSON.stringify(input)})`] ); return JSON.parse(result.stdout) as T; }沙箱模式让skills-db-write可以在无权限的容器中运行,即使 SQL 注入也无法影响宿主机。某车企用此方案,将车间设备控制技能的事故率降至 0。
最后分享一个真实教训:我们曾以为技能越多越好,半年内积累了 89 个技能,结果维护成本飙升。后来推行“技能健康度评分”,每月自动计算:
- 调用频率(低于阈值自动归档);
- 错误率(>5% 触发重构);
- 文档完整度(README 缺失字段自动告警);
- 类型覆盖率(zod schema 覆盖率 <90% 拒绝合并);
现在团队只保留 32 个核心技能,但覆盖了 95% 的业务场景。agent-skills的价值不在数量,而在每个技能都经得起生产环境拷问——就像你不会因为家里有 100 把螺丝刀就认为修车技术好,真正重要的是那把能精准拧紧航天器螺栓的扳手。