agent-skills:面向生产级LLM智能体的可复用能力契约规范
2026/9/16 22:17:52 网站建设 项目流程

1. “agent-skills”不是项目名,而是一套可复用的智能体能力工程规范

你第一次在 GitHub 上搜到agent-skills这个词,大概率是在某个 TypeScript + Nx 构建的 AI 工程仓库里——它不带 README,没有独立 npm 包,甚至没有package.json"name"字段。它藏在/libs/agent-skills目录下,目录结构干净得像手术室:src/,src/lib/,src/lib/core/,src/lib/tools/,src/lib/memory/,每个子模块都配着.spec.tsindex.ts。它不是框架,不是 SDK,更不是玩具 demo;它是我在过去三年里,带团队落地 7 个生产级 LLM 智能体系统后,从血里熬出来的能力抽象层契约

为什么需要它?因为所有“让大模型做点事”的项目,最终都会撞上同一堵墙:

  • 工具调用(Tool Calling)逻辑散落在各个 agent 实例里,改一个天气查询接口,要同步改 4 个地方;
  • 记忆管理(Memory)要么全靠Map<string, any>硬塞,要么直接耦合 Redis 客户端,测试时 mock 成灾难;
  • 多 step 的规划(Planning)流程写成 if-else 嵌套,debug 时得靠 console.log 画流程图;
  • 最致命的是——当你要把一个已上线的客服 agent,快速拆解出“订单查询”“物流追踪”“退换货政策”三个独立技能模块,供其他业务线复用时,发现代码根本没法拆。

agent-skills就是为解决这四个问题而生的。它不封装 LLM 调用(那是@langchain/corellamaindex的事),也不处理 prompt 工程(那是promptfoo或自研 DSL 的地盘),它只干一件事:定义“一个技能该长什么样”,并提供开箱即用的骨架、类型契约和生命周期钩子。关键词TypeScript是它的骨骼——所有接口、泛型约束、错误类型都强制收敛;Nx是它的循环系统——多 workspace 下的依赖拓扑、构建缓存、增量测试全部自动对齐;semantic-release是它的呼吸节奏——每次feat(tool/weather)提交,自动发布@myorg/agent-skills-tool-weather@1.2.0,版本号背后是语义化的变更日志,不是人工手敲的v1.1.13-beta.2

它解决的不是“怎么调用大模型”,而是“怎么让大模型的能力可维护、可测试、可组合、可审计”。如果你正在用 NestJS 写 agent 后端,用 Vue 做前端编排界面,用 Spring Boot 对接内部 ERP,那么agent-skills就是你跨技术栈的通用语言——后端工程师写的OrderQuerySkill,前端工程师可以直接 import 并传入uiConfig: { showLoading: true },测试工程师用jest.mock('@myorg/agent-skills-core')就能隔离验证整个技能链路。这不是理想主义,是我们去年在金融风控场景里跑通的真实路径:3 个团队,5 种语言栈,共用同一套agent-skills类型定义,API 文档自动生成,变更影响面自动分析。

提示:不要把它当成“又一个 LLM 工具库”去 npm install。它的价值不在npm publish那一刻,而在你第一次为PaymentValidateSkill写完canExecute(context: SkillContext): boolean方法,并发现这个布尔判断逻辑,被 3 个不同 agent 的路由层同时复用时——那种“终于不用再复制粘贴 if 条件”的轻松感。

2. 核心契约设计:为什么Skill<TInput, TOutput>必须带泛型,且execute()返回Promise<SkillResult<TOutput>>

agent-skills的灵魂藏在libs/agent-skills/src/lib/core/skill.ts这 87 行代码里。它没用任何花哨装饰器,没引入 rxjs,甚至没用class关键字(我们用interface+const工厂函数)。但就是这几十行,决定了整个能力体系的扩展边界。先看最简契约:

export interface Skill<TInput = unknown, TOutput = unknown> { id: string; name: string; description: string; canExecute(context: SkillContext): boolean; execute(input: TInput, context: SkillContext): Promise<SkillResult<TOutput>>; } export interface SkillResult<T = unknown> { success: boolean; data?: T; error?: SkillError; metadata?: Record<string, unknown>; }

表面看很朴素,但每个字段都有明确的工程意图。我们逐个拆解:

2.1idname的分离:解决运行时冲突与 UI 展示的双重需求

id是机器可读的唯一标识符,强制要求符合^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$正则(小写字母开头,连字符分隔,无空格)。为什么不用 UUID?因为id要参与构建技能调用链路的 traceId,例如order-query-v2c3b4e8f1-2a9d-4b6c-8e1f-0a2b3c4d5e6f更易 debug;更重要的是,Nx 的依赖图谱(Dependency Graph)会把id当作模块别名,nx graph --group-by-directory时能清晰看到agent-skills-tool-order依赖agent-skills-core。而name是面向用户的展示名,允许中文、空格、emoji(如"📦 订单查询(实时)"),它只用于前端下拉菜单或日志打印,绝不参与任何逻辑判断。这种分离避免了早期项目里常见的坑:某次重构把weather-tool改成weather-api-v2,结果前端配置里还写着旧 id,报错信息却是Cannot find skill 'weather-tool',排查半小时才发现是配置文件没同步。

2.2canExecute():把“是否执行”从execute()里剥离,是性能与可观测性的分水岭

很多团队把权限校验、前置条件检查全塞进execute()开头:

// ❌ 反模式:所有逻辑挤在 execute 里 async execute(input: OrderQueryInput) { if (!input.orderId) throw new Error('Missing orderId'); if (!this.authService.hasPermission('ORDER_READ')) throw new Error('No permission'); // ... real logic }

问题在哪?第一,execute()必须是异步的,哪怕只是做同步判断,也要await Promise.resolve(),白白增加 event loop 压力;第二,监控系统想统计“哪些技能被频繁拒绝”,只能从 error 日志里正则匹配,漏报率高;第三,前端想做灰度按钮(如“订单查询”按钮在用户无权限时置灰),还得调一次execute()才知道能不能点——这显然不合理。

agent-skills强制canExecute()是同步方法,且必须返回布尔值。它接收SkillContext,里面包含userRoletenantIdfeatureFlags等上下文快照。实操中,我们把它设计成纯函数:

// ✅ 正确:canExecute 是纯同步判断 canExecute(context: SkillContext): boolean { return ( context.featureFlags['enable-order-query'] && context.userRole === 'customer-service' && !!context.metadata?.sessionId ); }

这样,前端可以在渲染时直接调用skill.canExecute(context)决定按钮状态;监控系统在 agent 路由层统一拦截,记录canExecute: false的频次与原因;甚至 CI 流程里,nx affected --target=lint会扫描所有canExecute()方法,确保没有硬编码的return true——这是我们在支付网关项目里踩过的坑:某次紧急上线,开发为赶进度把风控技能的canExecute写成return true,导致沙箱环境误放行了 200+ 笔高风险交易。

2.3execute()的泛型与SkillResult:消灭any,让错误成为一等公民

execute(input: TInput, context: SkillContext): Promise<SkillResult<TOutput>>这个签名,是 TypeScript 类型安全的最后防线。TInputTOutput不是摆设——它们强制你在index.ts的导出层就声明清楚:

// libs/agent-skills-tool-weather/src/index.ts export * from './lib/weather-skill'; export type WeatherInput = { city: string; days: number }; export type WeatherOutput = { forecast: Array<{ date: string; temp: number; condition: 'sunny' | 'rainy' }>; source: 'openweathermap' | 'accuweather'; };

然后在技能实现里精准绑定:

export class WeatherSkill implements Skill<WeatherInput, WeatherOutput> { // ... async execute(input: WeatherInput, context: SkillContext) { const data = await this.api.getForecast(input.city, input.days); return { success: true, data: { forecast: data.items.map(i => ({ date: i.date, temp: i.temp, condition: i.cond })), source: 'openweathermap' } }; } }

SkillResult的设计更关键。它不允许dataerror同时存在(TypeScript 的 discriminated union),且error字段是SkillError类型,而非stringError实例:

export interface SkillError { code: string; // 如 'TOOL_UNAVAILABLE', 'RATE_LIMIT_EXCEEDED' message: string; // 用户友好的提示,如 '天气服务暂时不可用,请稍后再试' details?: Record<string, unknown>; // 技术细节,如 { statusCode: 503, retryAfter: 30 } severity: 'low' | 'medium' | 'high' | 'critical'; }

这个设计直接解决了两个高频痛点:一是前端不用再写if (res.data) {...} else if (res.error) {...}的冗余判断,TypeScript 编译器会强制你处理success分支;二是错误分类标准化后,SRE 团队可以基于code字段配置告警规则——比如所有code: 'DB_CONNECTION_TIMEOUT'的错误,自动触发数据库连接池扩容脚本,而不是等业务方提工单。

注意:SkillResultmetadata字段是留给 tracing 的。我们约定所有技能在execute()开头生成spanId,写入metadata.traceId,这样 Jaeger 里就能看到一条完整的技能调用链:AgentOrchestrator → OrderQuerySkill → ERPAdapter → PaymentValidateSkill,每个环节的耗时、输入输出、错误码一目了然。这个约定写在agent-skills-coreREADME.md里,且nx lint会检查每个execute()是否写了metadata.traceId

3. Nx 工作区架构:为什么libs/agent-skills-core必须是 workspace root 的 direct dependency

agent-skills的物理结构,是它能被大规模复用的底层保障。我们不用 monorepo 工具链(如 Turborepo),坚持用 Nx 2024 版本(v18+),核心原因只有一个:Nx 的 project graph 是唯一能精确表达“技能能力”与“执行环境”之间依赖关系的工具

先看标准目录布局:

/libs /agent-skills-core # 基础契约、类型、工具函数(无外部依赖) /agent-skills-tools # 工具类技能集合(依赖 core + axios) /agent-skills-memory # 记忆管理技能(依赖 core + redis client) /agent-skills-planning # 规划类技能(依赖 core + @langchain/core) /agent-skills-tool-weather # 具体天气技能(依赖 core + tools) /agent-skills-tool-order # 具体订单技能(依赖 core + tools + memory) /apps /agent-orchestrator # 主 agent 服务(NestJS,依赖 core + tools + memory + planning) /agent-dashboard # 前端管理台(Vue,依赖 core 的类型定义)

关键点在于:agent-skills-core必须被所有其他agent-skills-*库直接依赖,且不能通过agent-skills-tools间接传递。为什么?因为core里定义的Skill<TInput, TOutput>是所有技能的根类型,如果tool-order依赖tools,而tools依赖core,那么tool-orderexecute()方法签名里,TInput的类型推导就会变成import('agent-skills-tools').OrderInput,而非import('agent-skills-core').SkillInput——这会导致跨库类型不兼容,agent-orchestrator无法安全地将tool-order的实例传给泛型函数runSkill<Skill<OrderInput, OrderOutput>>(skill: Skill<OrderInput, OrderOutput>)

Nx 的nx graph命令能可视化这个约束:

nx graph --focus=agent-skills-core --include=agent-skills-tools,agent-skills-tool-order

你会看到agent-skills-core是中心节点,所有技能库都指向它,但agent-skills-toolsagent-skills-tool-order之间没有连线。这个图不是画出来的,是 Nx 从project.jsondependencies字段实时解析的。我们甚至在 CI 里加了校验脚本:

# .github/workflows/check-skills-deps.yml - name: Validate agent-skills dependencies run: | for lib in $(ls libs/agent-skills-*); do if [[ $lib != "libs/agent-skills-core" ]]; then deps=$(jq -r '.dependencies | keys[]' "$lib/project.json" 2>/dev/null) if ! echo "$deps" | grep -q "agent-skills-core"; then echo "ERROR: $lib must depend on agent-skills-core directly" exit 1 fi fi done

这个看似严苛的约束,换来的是真正的类型安全。举个真实案例:去年我们把agent-skills-tool-order从 v1 升级到 v2,OrderInput结构增加了tenantId字段。由于所有消费方(agent-orchestrator,agent-dashboard,agent-skills-planning)都直接依赖agent-skills-core,TypeScript 编译器在nx build时立刻报错:

error TS2345: Argument of type 'OrderInputV1' is not assignable to parameter of type 'OrderInputV2'. Property 'tenantId' is missing in type 'OrderInputV1' but required in type 'OrderInputV2'.

而不是等到上线后,某个前端页面传入旧版input导致execute()Cannot read property 'tenantId' of undefined。这就是 Nx + TypeScript 组合带来的确定性——错误发生在编译期,而非运行时。

另一个常被忽视的细节是agent-skills-corepackage.json

{ "name": "@myorg/agent-skills-core", "version": "0.0.0", // 注意:这里永远是 0.0.0 "peerDependencies": { "typescript": "^5.0.0" }, "devDependencies": { "@nx/workspace": "18.6.0" } }

version设为0.0.0是故意的。因为core库本身不发布到 npm,它只在 workspace 内部使用。Nx 的buildtarget 会把它编译成dist/libs/agent-skills-core,其他库通过paths映射引用:

// tsconfig.base.json "compilerOptions": { "baseUrl": ".", "paths": { "@myorg/agent-skills-core": ["dist/libs/agent-skills-core"], "@myorg/agent-skills-tools": ["dist/libs/agent-skills-tools"] } }

这样做的好处是:core的任何修改,都会触发 Nx 的增量构建(affected projects),自动 rebuild 所有依赖它的库,且dist目录里的 JS 文件永远是最新的。我们试过把core发布成 npm 包,结果每次改一个类型定义,都要npm publish+npm update,CI 时间从 2 分钟涨到 8 分钟,还经常因网络问题失败。现在,nx build agent-skills-core && nx build agent-skills-tool-order在本地 3 秒内完成,CI 里也稳定在 45 秒内。

提示:agent-skills-coreindex.ts只导出类型和接口,不导出任何 runtime 代码。所有工具函数(如createSkillResult())放在src/lib/utils/下,且必须通过export * from './utils'显式导出。这是为了防止 accidental exports——曾经有次误把fs模块的readFileSync从 utils 里导出,结果agent-dashboard(前端)构建时报错Can't resolve 'fs'。Nx 的nx dep-graph --type=dep能帮你发现这类跨环境依赖。

4. Semantic Release 实践:如何让feat(tool/weather)提交自动发布@myorg/agent-skills-tool-weather@1.2.0

agent-skills的发布机制,是它能被团队信任的关键。我们不用手动npm version patch && npm publish,而是完全交给 semantic-release,且配置极度精简——只有 3 个文件:.releaserc.jsonconventional-changelog-config.jspackage.json里的scripts。核心原则是:提交信息即契约,版本号即承诺,发布即自动化

先看.releaserc.json

{ "branches": ["main"], "plugins": [ "@semantic-release/commit-analyzer", "@semantic-release/release-notes-generator", "@semantic-release/npm", "@semantic-release/github", [ "@semantic-release/exec", { "verifyConditionsCmd": "nx build agent-skills-tool-weather", "prepareCmd": "cp -r dist/libs/agent-skills-tool-weather ./dist/" } ] ] }

重点在@semantic-release/exec插件。它不是用来跑测试的,而是确保每次发布前,agent-skills-tool-weather库必须能成功构建。nx build会触发 TypeScript 编译、类型检查、ESLint,任何一项失败,release 就中断。这比npm test更严格——因为test可能只覆盖 70% 的代码,而build覆盖 100% 的类型定义。

conventional-changelog-config.js则定制了 changelog 的生成逻辑:

module.exports = { preset: 'angular', releaseRules: [ { type: 'feat', scope: 'tool-weather', release: 'minor' }, { type: 'fix', scope: 'tool-weather', release: 'patch' }, { type: 'perf', scope: 'tool-weather', release: 'patch' }, { type: 'refactor', scope: 'tool-weather', release: 'patch' }, ], writerOpts: { transform: (commit) => { if (commit.type === 'feat' && commit.scope === 'tool-weather') { commit.type = '✨ New Feature'; } if (commit.type === 'fix' && commit.scope === 'tool-weather') { commit.type = '🐛 Bug Fix'; } return commit; } } };

这个配置让git commit -m "feat(tool/weather): add 7-day forecast support"自动生成语义化版本1.2.0(minor),并在 GitHub Release 页面生成带 emoji 的 changelog:

## ✨ New Feature - Add 7-day forecast support (commit abc123) ## 🐛 Bug Fix - Fix temperature unit conversion for Celsius (commit def456)

但真正的魔法在package.json的 scripts 里:

{ "scripts": { "release": "semantic-release", "prepublishOnly": "npm run build", "build": "nx build agent-skills-tool-weather" } }

注意prepublishOnly钩子。semantic-release@semantic-release/npm插件里会执行npm publish,而npm publish默认会运行prepublishOnly。这意味着:每次发布,都是先nx build生成dist/,再npm publish上传dist/目录下的文件,而非src/目录。我们特意在project.jsonbuildtarget 里配置了:

"outputs": ["{workspaceRoot}/dist/libs/agent-skills-tool-weather"]

这样nx build的输出路径和npm publish的默认路径一致,无需额外cp命令。dist/目录里只有index.d.tsindex.jspackage.json(由 Nx 自动生成),没有src/__tests__node_modules——体积控制在 12KB 以内。

这套流程带来的最大收益是:版本号不再由人决定,而是由提交内容决定。开发提交feat(tool/order): add refund policy lookup,CI 就发@myorg/agent-skills-tool-order@2.1.0;提交fix(tool/order): handle empty order items,就发@myorg/agent-skills-tool-order@2.1.1。产品经理不用再问“这个功能什么时候上线”,她只要看 GitHub 上agent-skills-tool-order的 latest release tag,就知道2.1.0已发布,且 changelog 里明确写了“支持退款政策查询”。

更关键的是,它消除了“发布恐惧症”。以前每次发版,都要开 30 分钟对齐会,确认谁改了什么、有没有回归风险、要不要回滚。现在,semantic-release的 CI 日志就是权威记录:

[12:03:45] [semantic-release] › ℹ Found 1 commits since last release [12:03:45] [semantic-release] › ℹ Start step "analyzeCommits" of plugin "@semantic-release/commit-analyzer" [12:03:45] [semantic-release] › ℹ The release type for the commit is "minor" [12:03:45] [semantic-release] › ℹ Start step "generateNotes" of plugin "@semantic-release/release-notes-generator" [12:03:45] [semantic-release] › ℹ Start step "prepare" of plugin "@semantic-release/exec" [12:03:46] [semantic-release] › ℹ Executing command "cp -r dist/libs/agent-skills-tool-weather ./dist/" [12:03:46] [semantic-release] › ℹ Start step "publish" of plugin "@semantic-release/npm" [12:03:47] [semantic-release] › ℹ Published @myorg/agent-skills-tool-weather@1.2.0 to npm

这条日志比任何会议纪要都可靠。我们甚至把semantic-release的 webhook 接入企业微信,每次发布成功,自动推送消息:“@myorg/agent-skills-tool-weather@1.2.0已发布,changelog: https://github.com/myorg/agent-skills/releases/tag/agent-skills-tool-weather%401.2.0”。

注意:semantic-releasebranches配置必须是["main"],不能是["main", "develop"]。因为agent-skills的所有技能库都走main直接发布,不设预发布分支。我们用nx affected --base=origin/main --head=HEAD --target=test在 PR 里做增量测试,确保main永远是可发布的。这个决策让我们省去了alpha/beta版本管理的复杂度,也避免了“某个技能发了 beta,但 core 还没发”的依赖地狱。

5. 实战避坑指南:从npm : 无法加载文件 d:\node\npm.ps1nx graph拓扑失效的完整排查链

agent-skills的落地过程,不是一帆风顺的。我整理了过去半年里,团队遇到的 5 类高频故障,每类都附上真实命令、错误日志、根因分析和修复步骤。这些不是教科书答案,而是我在凌晨 2 点 debug 时记下的血泪笔记。

5.1 PowerShell 执行策略错误:npm : 无法加载文件 d:\node\npm.ps1的本质是 Windows 安全策略,不是 Node.js 问题

现象:Windows 开发者 clone 仓库后,执行npm install报错:

npm : 无法加载文件 d:\node\npm.ps1,因为在此系统上禁止运行脚本。 有关详细信息,请参阅 https://go.microsoft.com/fwlink/?LinkID=135170 中的 "about_Execution_Policies"。 所在位置 行:1 字符:1 + npm install + ~~~~~~~~~~~ + CategoryInfo : SecurityError: (:) [],PSSecurityException + FullyQualifiedErrorId : UnauthorizedAccess

根因分析:这不是agent-skills的问题,而是 Windows PowerShell 默认执行策略(ExecutionPolicy)为Restricted,禁止运行任何本地脚本(包括npm.cmd包装的npm.ps1)。网上流传的“以管理员身份运行 PowerShell 再执行Set-ExecutionPolicy RemoteSigned -Scope CurrentUser”是治标不治本——因为nx的很多命令(如nx serve)会启动子进程,子进程的 PowerShell 策略可能重置。

正确修复步骤

  1. 打开 PowerShell(非管理员),执行:
    Get-ExecutionPolicy -List
    查看CurrentUserMachinePolicy的值。
  2. 永久修改当前用户策略(无需管理员):
    Set-ExecutionPolicy RemoteSigned -Scope CurrentUser -Force
  3. 关键一步:在package.jsonscripts里,强制指定 shell:
    "scripts": { "install": "cmd /c npm install", "start": "cmd /c nx serve" }
    这样npm install就走cmd.exe而非powershell.exe,彻底绕过策略限制。我们已在agent-skillsroot/package.json里预置了这些 script。

提示:这个错误在nx open命令里也会出现,因为nx open会尝试启动浏览器并执行nx graph,其底层也是调用npm。所以nx open前务必先npm install成功。

5.2nx graph拓扑图空白:不是 Nx 故障,而是project.jsontargets配置缺失

现象:执行nx graph,浏览器打开空白页面,控制台报错TypeError: Cannot read properties of undefined (reading 'targets')

根因分析nx graph依赖每个project.json文件里的targets字段来构建依赖图。如果某个库(如agent-skills-tool-weather)的project.json里只有rootsourceRoot,没有targets,Nx 就认为这个项目不可构建,直接跳过,导致图谱断裂。

排查链路

  1. 运行nx list,检查agent-skills-tool-weather是否在列表中。如果不在,说明project.json未被 Nx 识别。
  2. 检查libs/agent-skills-tool-weather/project.json,确认有:
    "targets": { "build": { "executor": "@nx/node:webpack", "options": { "outputPath": "dist/libs/agent-skills-tool-weather", "main": "libs/agent-skills-tool-weather/src/index.ts", "tsConfig": "libs/agent-skills-tool-weather/tsconfig.lib.json" } } }
  3. 如果targets存在,但nx graph仍空白,运行nx graph --verbose,查看日志里是否有Skipping project 'agent-skills-tool-weather' due to missing targets

修复方案:在project.json里补全targets,且executor必须是 Nx 官方插件(如@nx/node:webpack),不能是自定义 executor。我们曾用@myorg/custom-executor,结果nx graph完全不识别该项目。

5.3semantic-release发布失败:Cannot find module '@myorg/agent-skills-core'的真相是dist/路径未同步

现象:CI 里semantic-release执行到@semantic-release/npm阶段失败:

[15:22:33] [semantic-release] › ✖ Failed step "publish" of plugin "@semantic-release/npm" [15:22:33] [semantic-release] › ✖ An error occurred while running semantic-release: Error: Cannot find module '@myorg/agent-skills-core'

根因分析@semantic-release/npmnpm publish前,会require('package.json')并解析dependencies。如果agent-skills-tool-weatherpackage.json里写了"@myorg/agent-skills-core": "0.0.0",但dist/目录里没有node_modules/@myorg/agent-skills-corenpm publish就会报错——因为npm publish默认只上传当前包的dist/目录,不会递归上传 peerDependencies。

解决方案:在agent-skills-tool-weather/project.jsonbuildtarget 里,添加copyFiles选项:

"options": { "copyFiles": [ { "from": "dist/libs/agent-skills-core", "to": "dist/libs/agent-skills-core" } ] }

这样nx build会把coredist/复制到tool-weatherdist/下,npm publish就能找到它。我们已在agent-skills的模板里固化此配置。

5.4SkillResult类型不匹配:Property 'data' does not exist on type 'SkillResult<unknown>'的根源是泛型未显式声明

现象:在agent-orchestrator里调用weatherSkill.execute(input),TypeScript 报错:

const result = await weatherSkill.execute({ city: 'shanghai', days: 3 }); console.log(result.data.forecast); // ❌ Error: Property 'data' does not exist on type 'SkillResult<unknown>'

根因分析weatherSkill的类型是Skill<WeatherInput, WeatherOutput>,但execute()返回Promise<SkillResult<TOutput>>,如果TOutputunknownresult.data就是unknown。这是因为weatherSkill实例化时,没有显式指定泛型:

// ❌ 错误:类型推导失败 const weatherSkill = new WeatherSkill(); // ✅ 正确:显式声明泛型 const weatherSkill = new WeatherSkill<WeatherInput, WeatherOutput>();

修复方案:在agent-skills-tool-weather/src/lib/weather-skill.ts的类定义里,强制泛型:

export class WeatherSkill<TInput = WeatherInput, TOutput = WeatherOutput> implements Skill<TInput, TOutput> { // ... }

这样new WeatherSkill()就自动继承WeatherInput/WeatherOutput,无需手动指定。

5.5nx affected不触发增量构建:--base参数指向错误分支,导致所有项目都被 rebuild

现象:PR 里只改了agent-skills-tool-weather,但nx affected --target=build却 rebuild 了agent-orchestratoragent-dashboard

根因分析nx affected--base参数必须指向main分支的最新 commit,而不是origin/main。如果 CI 脚本写成--base=origin/main,而origin/main在 CI runner 里未更新,nx affected就会对比错误的 base,认为所有项目都受影响。

正确命令

# 在 CI 脚本里,先 fetch 最新 main git fetch origin main:refs/remotes/origin/main # 再运行 affected nx affected --base=origin/main --head=HEAD --target=build

我们已在.github/workflows/ci.yml里预置了git fetch步骤。

最后分享一个小技巧:在本地开发时,如果nx graph加载慢,可以加--file=graph.html参数生成静态 HTML,用浏览器打开,比 Web UI 快 3 倍。这个 HTML 文件里嵌入了所有依赖关系的 JSON 数据,离线也能看。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询