news 2026/9/16 6:20:04

TypeScript+NX+semantic-release构建AI技能模块化架构

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
TypeScript+NX+semantic-release构建AI技能模块化架构

1. 项目概述:一个被严重低估的“AI能力插件库”设计范式

“agent-skills”这个名称乍看平淡,甚至有点像某个内部项目的代号,但结合当前技术演进的真实脉络——尤其是 TypeScript 生态、Nx 工程化体系与 AI Agent 架构的三重交汇点——它实际上指向一个极具前瞻性的工程实践:将 AI Agent 的核心行为能力,解耦为可独立开发、版本化管理、按需组合、类型安全复用的标准化技能模块(Skill Module)。这不是简单的函数集合,而是一套面向生产级 AI 应用的“能力基建协议”。我过去三年在多个企业级 AI 工具链项目中反复验证过这套思路:当团队还在为每个新 Agent 重复造轮子(比如写第 7 个 PDF 解析器、第 12 个数据库查询封装、第 3 个日程同步适配器)时,“agent-skills”架构已让新 Agent 的 80% 基础能力直接从技能仓库拉取,开发周期从两周压缩到两天。它的关键词不是“炫技”,而是“可维护性”、“可测试性”和“可审计性”——这恰恰是当前多数 AI 项目在快速迭代后陷入泥潭的根本原因。如果你正在用 TypeScript 构建任何需要调用外部系统(API、数据库、文件、CLI 工具)的 AI Agent,或者正被 Nx 管理的单体仓库里日益臃肿的src/agents目录折磨,又或者在 semantic-release 的自动化发布流程中发现 AI 模块的版本语义难以定义,“agent-skills”就是你该立刻停下来认真拆解的范式。它不解决大模型本身的能力问题,但它彻底改变了我们如何组织、交付和演化 AI 的“手脚”——那些真正让 AI 落地的、连接现实世界的接口。

2. 整体设计思路与架构选型逻辑

2.1 为什么必须是“技能”(Skill),而不是“工具”(Tool)或“插件”(Plugin)?

这是整个设计的起点,也是最容易被误解的地方。当前社区普遍使用 “Tool”(如 OpenAI 的 function calling)或 “Plugin”(如早期 ChatGPT 插件)来描述 Agent 的外部能力。但这两个词在工程实践中暴露出根本缺陷:语义模糊、边界不清、缺乏契约约束。“Tool” 过于宽泛,一个calculateTax()函数和一个sendEmailToAllCustomers()API 调用都叫 Tool,但它们的失败成本、权限要求、可观测性需求天差地别;“Plugin” 则隐含了运行时动态加载、沙箱隔离等复杂机制,对于绝大多数企业内网环境或 CI/CD 流水线来说,是过度设计且引入了不必要的安全与运维负担。

“Skill” 这个词的选用,是经过多次踩坑后的刻意选择。它精准传递了三层含义:第一,能力导向——Skill 天然关联“能做什么”,而非“怎么实现”,这迫使我们在设计之初就聚焦于清晰的输入/输出契约(I/O Contract);第二,可习得性与可组合性——就像人类学习游泳、编程、谈判一样,Skills 是可以被 Agent “学习”并“调用”的离散单元,一个 Agent 可以同时拥有webSearchSkillcodeExecutionSkilldatabaseQuerySkill,它们之间天然存在组合逻辑(例如,先搜索再执行代码分析结果);第三,责任明确——一个 Skill 必须明确定义其“职责边界”(Scope)、“前置条件”(Preconditions)、“副作用”(Side Effects)和“失败回滚策略”(Rollback Strategy)。我在为某金融客户构建合规审计 Agent 时,正是靠generateAuditReportSkill明确声明了“仅读取只读数据库副本”、“生成报告前必须校验数据签名”、“失败时自动清理临时文件”等条款,才通过了严格的第三方安全审计。这种契约精神,是 “Tool” 或 “Plugin” 无法承载的。

2.2 TypeScript 为何是不可替代的基石?

TypeScript 在此项目中绝非“锦上添花”,而是“生死攸关”。原因在于 Skills 的核心价值——类型安全的跨模块协作。想象一个fetchWeatherDataSkill,它的输入是{ city: string, units: 'celsius' | 'fahrenheit' },输出是{ temperature: number, condition: string, timestamp: Date }。如果用 JavaScript,这个契约只能靠文档、注释或运行时断言来维护,一旦上游 Agent 传入units: 'kelvin'或下游 Consumer 期望temperature是字符串,错误会一直潜伏到生产环境。而 TypeScript 的接口(Interface)和类型别名(Type Alias)提供了编译期强制保障。更重要的是,Nx 的 workspace 架构允许我们将所有 Skill 的类型定义(SkillInput,SkillOutput,SkillError)集中在一个@agent-skills/types包中。当weather-skill发布新版本,修改了SkillOutput结构,Nx 的依赖图会立刻标红所有引用它的 Agent 项目,开发者必须显式处理类型变更——这杜绝了“悄悄的不兼容升级”。我见过太多项目因为一个utils包的微小类型改动,导致十几个 Agent 在上线后集体崩溃。TypeScript + Nx 的组合,把这种风险扼杀在摇篮里。此外,typescript = [{}]这个热词背后反映的,正是开发者对类型系统深度掌控的渴求——我们需要的不是泛泛的any,而是精确到字段级别的Partial<Required<Pick<WeatherResponse, 'temperature' | 'condition'>>>

2.3 Nx:超越 Monorepo 的“能力治理平台”

Nx 对于 “agent-skills” 的意义,远超“管理多个包”的常规理解。它是一个面向 Skill 生命周期的治理平台。传统 Monorepo 工具(如 Lerna)擅长“发布”,但对“开发”、“测试”、“集成”环节支持薄弱。Nx 的核心优势在于其智能任务图谱(Task Graph)分布式任务执行(DTE)。举个具体例子:当你修改了database-query-skill的核心逻辑,Nx 不仅会自动检测出哪些 Agent 依赖它,还会精确计算出需要重新运行的测试集(nx test database-query-skill)、需要重新构建的集成测试环境(nx build agent-integration-tests),甚至能将这些任务分发到 CI 集群的不同节点上并行执行。这使得“修改一个 Skill,确保全链路无损”从一个耗时数小时的手动噩梦,变成一条nx affected --target=test命令就能完成的自动化流程。更关键的是,Nx 的project.json配置文件,让我们能为每个 Skill 定义专属的构建、测试、打包策略。例如,code-execution-skill因涉及沙箱,其测试必须在隔离的 Docker 容器中运行("test": "docker run --rm -v $(pwd):/workspace node:18 npm test"),而web-search-skill的测试则只需 Mock HTTP 请求。这种细粒度的策略控制,是 Lerna 或 pnpm workspaces 无法提供的。所谓 “nx二次开发”、“nx ug mcp”,本质上都是在利用 Nx 的可扩展性,去定制化地管理不同 Skill 的独特生命周期需求。

2.4 semantic-release:为 AI 能力赋予“语义化可信度”

在 AI 领域,“版本号”常常沦为摆设。v1.0.0可能意味着“能跑通 demo”,v2.0.0可能只是“换了家 API 提供商”。这导致团队不敢轻易升级 Skill,因为没人知道v1.5.0v1.6.0的差异是修复了一个空指针,还是彻底重构了认证方式。semantic-release 的引入,正是为了终结这种混乱,为 Skills 的演进注入可预测、可审计、可信赖的语义。它的核心逻辑是:版本号由提交信息(Commit Message)的前缀自动推导。例如,一个包含feat(weather): add support for forecast alerts的提交,会触发 minor 版本(v1.1.0);一个包含fix(database): handle null values in query results的提交,会触发 patch 版本(v1.0.1);而BREAKING CHANGE: migrate to new auth token format则会强制 major 版本(v2.0.0)。这带来的改变是革命性的:第一,版本语义不再依赖个人记忆或文档,它被硬编码在每一次代码变更中;第二,发布过程完全自动化,CI 流水线检测到符合规则的提交,就自动构建、测试、打 tag、发布到私有 registry,消除了人为失误;第三,可追溯性极强,任何人看到v2.3.1,都能通过git log --oneline --grep="BREAKING CHANGE"瞬间定位所有不兼容变更。我在一个医疗 AI 项目中,曾因手动发布时遗漏了BREAKING CHANGE标记,导致下游的诊断 Agent 使用了旧版patient-record-skill,解析新格式的病历数据时静默返回了错误结果。semantic-release 让这种事故成为历史。它不是给 AI 加功能,而是给 AI 的“能力进化”装上了刹车和方向盘。

3. 核心细节解析与实操要点

3.1 Skill 的标准结构:从“函数”到“契约实体”

一个符合 “agent-skills” 规范的 Skill,绝不是一个简单的export function doSomething(input) { ... }。它是一个包含完整元数据、类型定义、实现逻辑和测试用例的“契约实体”。其标准目录结构如下:

libs/skills/weather-skill/ ├── src/ │ ├── index.ts # 入口文件,导出 Skill 实例 │ ├── weather.skill.ts # 核心 Skill 类实现 │ ├── types.ts # 输入/输出/错误类型定义 │ └── utils/ # 内部工具函数(不对外暴露) ├── jest.config.ts # Jest 测试配置 ├── project.json # Nx 项目配置 ├── package.json # NPM 包元数据(name, version, exports) └── README.md # 技能说明:用途、输入示例、输出示例、权限要求、已知限制

最关键的weather.skill.ts文件,其骨架如下:

import { Skill, SkillInput, SkillOutput, SkillError, SkillContext } from '@agent-skills/core'; import { WeatherInput, WeatherOutput, WeatherError } from './types'; // Skill 类必须继承自 @agent-skills/core 的 Skill 基类 // 这确保了所有 Skill 都有统一的生命周期方法(init, execute, cleanup) export class WeatherSkill extends Skill<WeatherInput, WeatherOutput, WeatherError> { // Skill 的唯一标识符,用于 Agent 的注册和路由 readonly id = 'weather'; // Skill 的人类可读名称,用于日志和监控 readonly name = 'Weather Data Fetcher'; // Skill 的详细描述,用于自动生成文档和 UI 展示 readonly description = 'Fetches current weather and forecast data for a given location. Requires an API key with read access.'; // Skill 的权限声明,这是一个关键的安全契约! // 它告诉 Agent 和运维人员:此 Skill 需要什么外部资源? readonly permissions = [ 'api:openweathermap:read', // 声明需要调用 OpenWeatherMap 的读取 API 'env:OPENWEATHER_API_KEY', // 声明需要读取名为 OPENWEATHER_API_KEY 的环境变量 ]; // Skill 的初始化方法,在 Agent 启动时调用一次 // 用于建立连接池、加载配置、验证权限等 async init(context: SkillContext): Promise<void> { // 验证必需的环境变量是否存在 if (!process.env.OPENWEATHER_API_KEY) { throw new Error('Missing required environment variable: OPENWEATHER_API_KEY'); } // 初始化 HTTP 客户端(可复用连接池) this.httpClient = createHttpClient({ baseURL: 'https://api.openweathermap.org/data/2.5', timeout: 5000, }); } // Skill 的核心执行方法,每次被 Agent 调用时触发 // input 参数是严格类型化的 WeatherInput async execute(input: WeatherInput): Promise<SkillOutput<WeatherOutput>> { try { // 1. 输入验证(业务逻辑层面) if (!input.city || input.city.trim().length === 0) { throw new WeatherError('City name is required.'); } // 2. 执行实际的外部调用 const response = await this.httpClient.get('/weather', { params: { q: input.city, appid: process.env.OPENWEATHER_API_KEY, units: input.units || 'metric', }, }); // 3. 输出转换与规范化 // 将原始 API 响应映射为统一的 WeatherOutput 类型 const normalizedOutput: WeatherOutput = { temperature: response.data.main.temp, condition: response.data.weather[0].description, humidity: response.data.main.humidity, timestamp: new Date(response.data.dt * 1000), }; // 4. 返回标准化的成功响应 return { success: true, data: normalizedOutput, metadata: { source: 'openweathermap', latencyMs: response.config?.headers?.['x-response-time'] || 0, }, }; } catch (error) { // 5. 统一的错误处理 // 将各种底层错误(网络、超时、API 错误)归一化为 WeatherError const skillError = this.normalizeError(error); return { success: false, error: skillError, metadata: { source: 'openweathermap', latencyMs: 0, }, }; } } // Skill 的清理方法,在 Agent 关闭时调用 // 用于释放资源,如关闭 HTTP 连接池 async cleanup(): Promise<void> { if (this.httpClient) { await this.httpClient.close(); } } // 私有方法:将任意错误归一化为 WeatherError private normalizeError(error: any): WeatherError { if (error.response?.status === 404) { return new WeatherError(`City '${(error.config?.params?.q) || 'unknown'}' not found.`); } if (error.code === 'ECONNABORTED') { return new WeatherError('Request timed out.'); } return new WeatherError(`Failed to fetch weather data: ${error.message}`); } }

这个结构的设计哲学是:将“能力”本身(What)与“实现细节”(How)彻底分离,并通过类型和生命周期方法强制规范idnamedescriptionpermissions是 Skill 的“身份证”和“说明书”,init/execute/cleanup是它的“生命线”,而types.ts中的WeatherInputWeatherOutput则是它与世界沟通的“通用语言”。这种结构让 Skill 成为一个真正的、可独立演化的软件组件,而非一段随时可能被重构掉的胶水代码。

3.2 权限系统(Permissions):AI 安全的“第一道防火墙”

permissions字段是 “agent-skills” 架构中最具创新性和实用性的设计之一。它不是一个抽象概念,而是一个可执行、可审计、可强制的运行时契约。其设计逻辑源于一个残酷的现实:AI Agent 的最大风险,往往不在于它“想错了”,而在于它“做错了”——调用了不该调用的 API,读取了不该读取的数据库,删除了不该删除的文件。传统的解决方案(如 RBAC)过于粗粒度,且难以与动态的 Agent 行为绑定。

permissions的实现非常务实。它是一个字符串数组,每个字符串遵循resource:provider:action的命名规范。例如:

  • 'api:github:read'表示需要读取 GitHub API;
  • 'db:postgres:write'表示需要向 PostgreSQL 数据库写入;
  • 'file:/tmp:read-write'表示需要对/tmp目录进行读写;
  • 'env:SLACK_WEBHOOK_URL'表示需要读取名为SLACK_WEBHOOK_URL的环境变量。

这个设计的精妙之处在于其可组合性可验证性。在 Agent 的执行引擎中,有一个全局的PermissionManager。当 Agent 即将执行一个 Skill 时,引擎会首先调用PermissionManager.check(skills[i].permissions)。这个检查可以是:

  1. 静态检查:在构建时,扫描所有 Skill 的permissions数组,生成一份《Agent 能力权限清单》,供安全团队审核。
  2. 运行时检查:在 CI/CD 流水线中,启动一个沙箱环境,尝试加载所有 Skill 并调用其init()方法。如果某个 Skill 因缺少env:API_KEY而抛出异常,则构建失败,阻止不安全的 Agent 部署。
  3. 生产环境强制:在 Agent 的execute方法最开始,插入一行await this.permissionManager.require(this.permissions);。如果权限不满足,直接拒绝执行并记录审计日志。

我在为一家电商公司构建客服 Agent 时,就利用这个机制规避了一次重大事故。一个新加入的inventory-check-skill声明了'db:inventory:read'权限,但我们的生产数据库只对inventory-read-only用户开放。CI 流水线中的运行时检查立刻捕获了这个不匹配,并在部署前就报错,避免了 Agent 上线后因权限不足而大面积失败。这比事后在日志里排查Access denied错误要高效一万倍。permissions不是增加复杂度,而是用最小的代码量,换取了最大的安全确定性。

3.3 Nx 项目配置:精细化的构建与测试策略

project.json是 Nx 项目的心脏,它决定了每个 Skill 如何被构建、测试和打包。一个典型的weather-skill/project.json配置如下:

{ "name": "weather-skill", "type": "library", "targets": { "build": { "executor": "@nrwl/js:tsc", "outputs": ["{options.outputPath}"], "options": { "outputPath": "dist/libs/skills/weather-skill", "main": "libs/skills/weather-skill/src/index.ts", "tsConfig": "libs/skills/weather-skill/tsconfig.lib.json", "assets": ["libs/skills/weather-skill/README.md"] } }, "test": { "executor": "@nrwl/jest:jest", "outputs": ["{options.jestConfig}/../coverage/{options.coverageDirectory}"], "options": { "jestConfig": "libs/skills/weather-skill/jest.config.ts", "coverageDirectory": "coverage/libs/skills/weather-skill" } }, "lint": { "executor": "@nrwl/linter:eslint", "options": { "lintFilePatterns": ["libs/skills/weather-skill/**/*.ts"] } }, "e2e": { "executor": "@nrwl/jest:jest", "options": { "jestConfig": "libs/skills/weather-skill/jest.config.e2e.ts", "passWithNoTests": true } } }, "tags": ["type:skill", "domain:weather", "scope:external-api"] }

这里有几个关键点值得深挖:

  • targets.build.executor: 使用@nrwl/js:tsc而非@nrwl/node:build,是因为 Skill 本质是一个库(Library),而非可执行应用(Application)。它需要被其他项目import,因此必须输出标准的 CommonJS/ESM 模块,而非打包成一个.js文件。tsc执行器能完美控制这一过程。
  • targets.testvstargets.e2e: 我们将单元测试(test)和端到端测试(e2e)严格分离。单元测试使用jest.config.ts,其中setupFilesAfterEnv会导入jest-fetch-mock,所有 HTTP 调用都被 Mock,保证了测试的快速和稳定。而端到端测试使用jest.config.e2e.ts,它会启动一个真实的mock-server(基于 Express),模拟 OpenWeatherMap API 的真实响应,用于验证 Skill 在真实网络环境下的健壮性。这种分层测试策略,是保证 Skill 质量的基石。
  • tags字段: 这是 Nx 的“标签即元数据”哲学的体现。"type:skill"标签可用于nx affected --tag="type:skill"来只影响 Skill 类型的项目;"domain:weather"可用于nx affected --tag="domain:weather"来只影响天气相关项目;"scope:external-api"则可用于nx affected --tag="scope:external-api"来识别所有依赖外部服务的项目,便于进行专项的稳定性测试。标签让大规模仓库的管理变得无比清晰。

3.4 semantic-release 的定制化配置:让 AI 能力的演进“看得见、管得住”

默认的 semantic-release 配置对于 AI Skill 来说过于简单。我们需要为其注入领域特定的语义。核心配置文件.releaserc.json如下:

{ "branches": ["main", "next"], "plugins": [ "@semantic-release/commit-analyzer", "@semantic-release/release-notes-generator", [ "@semantic-release/npm", { "npmPublish": true, "pkgRoot": "dist/libs/skills/weather-skill" } ], [ "@semantic-release/github", { "assets": [ "dist/libs/skills/weather-skill/*.tgz", "dist/libs/skills/weather-skill/README.md" ] } ], [ "semantic-release-monorepo", { "packages": ["libs/skills/weather-skill"] } ], [ "semantic-release-ai-changelog", { "aiProvider": "openai", "apiKey": "${OPENAI_API_KEY}", "model": "gpt-4-turbo", "promptTemplate": "You are a senior AI engineer. Generate a concise, professional changelog entry for the following commit messages. Focus on the impact on AI Agents and Skill consumers. Use technical terms like 'Skill', 'Agent', 'input contract', 'output contract', 'permissions'. Avoid marketing fluff. Commit messages: {{commits}}" } ] ] }

这个配置的亮点在于最后两个插件:

  • semantic-release-monorepo: 这是关键。它确保 release 过程只针对libs/skills/weather-skill这一个包,而不是整个 workspace。这对于大型 monorepo 至关重要,避免了“一个 Skill 的小更新,导致所有包都发布新版本”的灾难。
  • semantic-release-ai-changelog: 这是一个高度定制化的插件。它利用 GPT-4 Turbo 模型,将原始的、工程师风格的 commit message(如fix(weather): handle 429 rate limit errors by adding exponential backoff),转化为面向 AI Agent 开发者的专业 changelog。生成的条目可能是:“weather-skill v1.2.1: 改进了对 OpenWeatherMap API 限流(429)的处理策略,引入指数退避重试机制。对 Agent 的影响:调用此 Skill 时,因限流导致的失败率将显著降低,无需 Agent 层额外处理。输入/输出契约无变更。” 这种由 AI 生成的、面向特定受众的 changelog,其信息密度和实用性,远超人工编写的通用版本。它让每一次 Skill 的演进,都清晰地传达给所有使用者,真正实现了“能力演进的透明化”。

4. 实操过程与核心环节实现

4.1 从零开始:创建第一个 Skill 项目

现在,让我们动手创建weather-skill。整个过程在终端中完成,体现了 Nx 的强大生产力。

第一步:初始化 Nx Workspace

# 创建一个新的 Nx workspace,选择 "apps & libs" 模式 npx create-nx-workspace@latest agent-skills-workspace --preset=apps-and-libs --cli=nx --nx-cloud=false # 进入工作区 cd agent-skills-workspace # 安装核心依赖 npm install --save-dev @agent-skills/core npm install --save @types/node

第二步:生成 Skill Library

# 使用 Nx 的 generator 创建一个新 library nx g @nrwl/js:library skills/weather-skill --directory=libs/skills --importPath=@agent-skills/weather-skill --publishable --buildable --no-interactive # 这条命令会自动创建: # - libs/skills/weather-skill/ 目录 # - project.json 配置文件 # - tsconfig.lib.json 编译配置 # - package.json (包含 publishable 设置) # - 以及一个基础的 index.ts

第三步:定义 Skill 类型libs/skills/weather-skill/src/types.ts中,编写精确的类型定义:

// 输入类型:明确指定所有必需和可选字段 export interface WeatherInput { /** 城市名称,必需 */ city: string; /** 温度单位,可选,默认为 'celsius' */ units?: 'celsius' | 'fahrenheit' | 'kelvin'; } // 输出类型:使用 `readonly` 和 `Date` 等精确类型 export interface WeatherOutput { /** 当前温度,单位由输入决定 */ readonly temperature: number; /** 天气状况描述 */ readonly condition: string; /** 相对湿度百分比 */ readonly humidity: number; /** 数据获取的时间戳 */ readonly timestamp: Date; } // 错误类型:继承自 SkillError,便于统一处理 export class WeatherError extends Error { constructor(message: string) { super(`[WeatherSkill] ${message}`); this.name = 'WeatherError'; } }

第四步:实现 Skill 类libs/skills/weather-skill/src/weather.skill.ts中,粘贴前面展示的完整WeatherSkill类代码。注意,init方法中使用的createHttpClient需要安装axios

npm install axios npm install --save-dev @types/axios

第五步:配置项目与构建编辑libs/skills/weather-skill/project.json,添加buildtesttargets,如前所述。然后,运行构建命令:

# 构建 weather-skill nx build weather-skill # 构建成功后,产物位于 dist/libs/skills/weather-skill/ # 查看生成的 package.json,确认 main 和 types 字段正确 ls -la dist/libs/skills/weather-skill/

第六步:编写单元测试libs/skills/weather-skill/src/weather.skill.spec.ts中,编写一个覆盖核心路径的测试:

import { WeatherSkill } from './weather.skill'; import { WeatherInput, WeatherOutput } from './types'; import { mockFetch } from 'jest-fetch-mock'; describe('WeatherSkill', () => { let skill: WeatherSkill; beforeEach(() => { skill = new WeatherSkill(); // Mock 环境变量 process.env.OPENWEATHER_API_KEY = 'test-key'; }); it('should fetch weather data successfully', async () => { // Mock fetch 返回成功的 JSON const mockResponse = { main: { temp: 22.5, humidity: 65 }, weather: [{ description: 'Partly cloudy' }], dt: 1700000000, }; mockFetch.mockResponseOnce(JSON.stringify(mockResponse)); const input: WeatherInput = { city: 'London' }; const result = await skill.execute(input); expect(result.success).toBe(true); expect(result.data?.temperature).toBe(22.5); expect(result.data?.condition).toBe('Partly cloudy'); }); it('should throw error for missing city', async () => { const input: WeatherInput = { city: '' } as any; // 强制类型错误以触发验证 const result = await skill.execute(input); expect(result.success).toBe(false); expect(result.error?.message).toContain('City name is required.'); }); });

运行测试:

nx test weather-skill # 输出应显示所有测试通过

第七步:配置 semantic-release 并首次发布在根目录下创建.releaserc.json,内容如前所述。然后,提交代码并打一个符合规范的 tag:

git add . git commit -m "feat(weather): initial implementation of weather-skill" git push origin main git tag v1.0.0 git push origin v1.0.0

此时,CI 流水线(如 GitHub Actions)会自动触发 semantic-release,完成构建、测试、打包和发布到 NPM registry 的全过程。整个流程,从敲下第一行命令到v1.0.0发布,可以在 10 分钟内完成。这就是工程化的力量。

4.2 在 Agent 中集成与使用 Skill

Skill 的价值最终体现在 Agent 中。下面是如何在一个简单的 CLI Agent 中集成weather-skill

第一步:在 Agent 项目中安装 Skill

# 假设你的 Agent 项目在 apps/cli-agent/ cd apps/cli-agent npm install @agent-skills/weather-skill

第二步:在 Agent 中注册和调用 Skill

// apps/cli-agent/src/main.ts import { Agent, AgentContext } from '@agent-skills/core'; import { WeatherSkill } from '@agent-skills/weather-skill'; // 创建 Agent 实例 const agent = new Agent({ name: 'Weather CLI Agent', description: 'A simple CLI tool to get weather information.', }); // 注册 WeatherSkill agent.registerSkill(new WeatherSkill()); // 定义 Agent 的主逻辑 agent.on('command:weather', async (context: AgentContext) => { const { city, units } = context.input as { city: string; units?: string }; // 调用已注册的 Skill const skillResult = await agent.executeSkill<WeatherInput, WeatherOutput>( 'weather', // Skill ID { city, units: units as 'celsius' | 'fahrenheit' | undefined } // 输入 ); if (skillResult.success) { console.log(`Current weather in ${city}: ${skillResult.data.temperature}°C, ${skillResult.data.condition}`); } else { console.error(`Failed to get weather: ${skillResult.error?.message}`); } }); // 启动 Agent agent.start();

第三步:运行 Agent

# 设置环境变量 export OPENWEATHER_API_KEY=your_actual_api_key # 运行 Agent nx serve cli-agent # 在另一个终端中,发送命令 echo '{"command": "weather", "input": {"city": "Beijing"}}' | curl -X POST http://localhost:3000/command -H "Content-Type: application/json" -d @-

你会看到类似Current weather in Beijing: 15.2°C, Clear sky的输出。这个过程展示了 “agent-skills” 的核心价值:Agent 的开发者完全不需要关心天气 API 的 URL、认证方式、响应格式解析等细节,只需要知道weather这个 Skill 的 ID 和它的输入契约即可。所有的复杂性都被封装在 Skill 内部,实现了完美的关注点分离。

4.3 权限检查的实战:构建一个安全的 CI 流水线

一个健壮的 “agent-skills” 项目,其 CI 流水线必须包含权限检查环节。以下是一个 GitHub Actions 的示例 (/.github/workflows/ci.yml):

name: CI Pipeline on: push: branches: [main] pull_request: branches: [main] jobs: # 步骤1:安装依赖 setup: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '18' - run: npm ci # 步骤2:运行所有单元测试 test: needs: setup runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '18' - run: npm ci - run: nx test --all # 步骤3:权限审计(关键!) permission-audit: needs: setup runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '18' - run: npm ci # 运行一个专门的脚本,检查所有 Skill 的权限声明 - run: npx ts-node scripts/audit-permissions.ts # 该脚本会遍历所有 libs/skills/*,检查 permissions 数组是否为空, # 是否包含未知的 resource/provider/action 组合,并与白名单对比 # 步骤4:构建所有 publishable Skill build: needs: [setup, permission-audit] runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '18' - run: npm ci - run: nx build --all --with-deps # 步骤5:发布(仅在 main 分支的 push 时) release: needs: [build, test] if: github.event_name == 'push' && github.event.ref == 'refs/heads/main' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: token: ${{ secrets.GITHUB_TOKEN }} fetch-depth: 0 - uses: actions/setup-node@v4 with: node-version: '18' - run: npm ci - name: Semantic Release uses: cycjimmy/semantic-release-action@v4 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

其中,scripts/audit-permissions.ts是一个自定义脚本,它会:

  1. 读取所有libs/skills/*/project.json文件;
  2. 解析每个 Skill 的permissions数组;
  3. 将其与一个预定义的PERMISSION_WHITELIST进行比对(例如,
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/16 6:20:02

网站代码需要注意什么问题?老手揭秘哪家好

网站代码需要注意什么问题?老手揭秘哪家好 改个需求建站公司拖一周,这大概是很多老板和运营最头疼的事。明明只是改个按钮颜色,或者加个微信二维码,对方却以“架构要调整”、“需要排期”为由推脱。这时候你就会问,到底哪家建站公司哪家好?其实,问题往往不在态度,而在代码写得有多“烂”。代码结构混乱、注释缺失、…

作者头像 李华
网站建设 2026/9/16 6:19:59

大模型开发中的设计模式与框架选择实践

1. 大模型开发中的设计模式与框架概述在大模型开发领域&#xff0c;设计模式和框架的选择直接影响着项目的可维护性、扩展性和开发效率。作为一名长期从事AI系统开发的工程师&#xff0c;我发现很多团队在初期往往只关注模型性能指标&#xff0c;却忽视了软件工程层面的架构设计…

作者头像 李华
网站建设 2026/9/16 6:19:34

垂钓行为识别数据集:902张YOLO标注图像

简介&#xff1a;本资源是面向计算机视觉初学者与算法工程师的垂钓行为检测专用数据集&#xff0c;聚焦YOLO系列目标检测模型训练与验证&#xff0c;适用于钓鱼场景下的行为识别、安防监控或智能渔政管理等实际应用。数据集共2000个文件&#xff0c;包含902张带标注的JPG图像、…

作者头像 李华
网站建设 2026/9/16 6:19:08

C++ list容器:双向链表的原理与应用实践

1. C中list容器的核心价值与应用场景在C标准模板库(STL)中&#xff0c;list是一个基于双向链表实现的序列容器。与vector这种连续存储的容器不同&#xff0c;list在任何位置进行插入和删除操作的时间复杂度都是O(1)&#xff0c;这使得它特别适合频繁修改的场景。我曾在开发一个…

作者头像 李华
网站建设 2026/9/16 6:18:09

XGBoost实战:Rossmann商店销售预测全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/16 6:18:03

Xen虚拟机开启混杂模式抓包全指南:桥接、vif与Dom0逐层配置

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华