agent-skills:企业级智能体技能抽象层的工程实践
2026/9/16 11:03:21 网站建设 项目流程

1. “agent-skills”不是库名,而是工程级能力抽象层的设计原点

刚看到这个标题时,我下意识去 npm 搜了agent-skills——结果是空的。没有包、没有 README、没有 star 数。再翻 GitHub,搜关键词加 TypeScript + Nx,出来的是一批内部项目仓库,命名风格高度一致:platform-agent-coreai-agent-skill-kitnx-workspace-agent-runtime……它们的package.json里都有一行不起眼但极其关键的字段:"name": "@internal/agent-skills"。这才是真相:“agent-skills”根本不是开源项目代号,而是一个被刻意收敛在企业级单体工作区(monorepo)内部的能力契约标识符——它不对外暴露 API,不提供 CLI,甚至不生成独立文档,但它决定了整个智能体(Agent)系统中“技能”(Skill)模块的边界、形态与演化节奏。

这和你在网上搜到的“TypeScript 面试题”“Node 安装教程”“Nx 二次开发”看似无关,实则构成完整闭环:

  • TypeScript是契约的语言载体——类型即协议,interface Skill<T> { execute(input: T): Promise<any>; }这一行定义,比任何文字说明都更精确地约束了所有技能必须满足的输入/输出契约;
  • Node是执行环境底座——不是随便跑个node index.js就完事,而是要求每个技能包必须通过process.env.NODE_ENV=production下的tsc --build tsconfig.prod.json编译,且产物必须能被import()动态加载,拒绝 CommonJS 混用;
  • Nx是工程治理引擎——它强制把agent-skills设为 workspace 中的shared library,所有业务 Agent(如email-agentcalendar-agentllm-router-agent)只能通过@internal/agent-skills导入,禁止跨包直连底层 SDK(如@google/generative-aiopenai),所有依赖必须经由agent-skills的适配器层透出;
  • semantic-release是发布纪律的自动守门人——每次 PR 合并到main,Nx 自动识别哪些agent-skills的子包被修改,语义化版本号(patch/minor/major)由 commit message 的前缀(fix:/feat:/BREAKING CHANGE:)驱动,且只有通过nx affected --target=lint --base=origin/main的包才允许发布,彻底杜绝“改了一行正则,却把整个技能中心推到生产环境”的灾难。

所以,“agent-skills”四个字背后,是一套以类型系统为宪法、以构建流水线为执法队、以依赖图谱为疆域边界的微型操作系统。它解决的从来不是“怎么写一个技能函数”,而是“当 37 个团队、214 个技能模块、5 类异构执行环境(Node.js / WASM / Python subprocess)共存时,如何让新增一个天气查询技能,既不影响邮件归档 Agent 的稳定性,又能让新入职的实习生在 10 分钟内理解其调用方式”。

提示:如果你正在搭建类似系统,别急着写skill.ts,先花 2 小时配置 Nx 的project.jsontargets.build.dependenciesimplicitDependencies。这是唯一能防止“技能包偷偷引入fs-extra导致浏览器端崩溃”的防线。

我见过太多团队卡在这一步:开发者直接npm install openaiemail-agent包里,结果某天要将该 Agent 移植到 Deno 环境,才发现openai的 Node.js 特有依赖(node:crypto)根本无法 polyfill。而agent-skills的设计哲学是——技能不该知道它运行在哪,只该知道自己能做什么。这个抽象层级,才是标题真正的重量所在。

2. 为什么必须用 Nx 而非 pnpm workspaces 或 Turborepo?三张表说清本质差异

市面上常有人问:“Nx 太重,pnpm workspaces 不也能做 monorepo?” 或者 “Turborepo 构建更快,为啥不用?” 这些问题背后,是对agent-skills工程定位的根本误判。agent-skills不是普通工具库,它是技能生命周期的中央调度器,必须承担三类强耦合职责:依赖拓扑校验、跨环境构建策略分发、语义化发布链路管控。我们用三张对比表拆解:

2.1 依赖拓扑校验能力对比(核心生死线)

能力项pnpm workspacesTurborepoNx
检测循环依赖✅ 基础检测(pnpm graph❌ 无内置能力nx dep-graph可视化 +nx graph --group-by-type按包类型聚类
阻止非法跨层调用❌ 仅靠约定(如libs/不得引用apps/❌ 无机制nx-enforce-module-boundaries插件,可配置allowedImportPatterns(例:@internal/agent-skills/*只允许被@internal/agents/*引用)
动态影响分析❌ 修改agent-skills后,需手动pnpm run build所有依赖它的 Agentturbo run build --since=origin/mainnx affected:build --base=origin/main --head=HEAD(自动识别受影响的 Agent 并并发构建)

关键点在于第三行:agent-skills的任何变更,必须精准触发下游 Agent 的重新构建与测试。pnpm 无法自动识别“哪个 Agent 用了agent-skillsFileUploadSkill”,而 Nx 通过静态 AST 分析.ts文件中的import语句,构建出精确的依赖图。我曾遇到一次真实事故:某团队在agent-skills中升级了zod版本(从 v3 到 v4),因zodv4 的safeParse返回类型变更,导致document-parser-agent的类型推导失败。pnpm 方案下,该 Agent 的 CI 未被触发,上线后document-parser-agent在处理 PDF 元数据时静默返回undefined。而 Nx 的affected检测在 PR 阶段就报错:“document-parser-agent依赖@internal/agent-skills,需重新构建”,强制阻断了发布。

2.2 跨环境构建策略分发能力(决定技能可移植性)

agent-skills的技能必须同时支持三种执行环境:

  • Node.js 环境(主服务,调用 REST API / DB)
  • Web Worker 环境(前端离线技能,如本地 PDF 解析)
  • Edge Runtime 环境(Vercel Edge Functions,低延迟路由)
构建目标pnpm workspacesTurborepoNx
为不同环境生成不同产物❌ 需手动维护多套tsconfig.jsonrollup.config.js✅ 支持--env=worker参数传入构建脚本nx build agent-skills --configuration=web-worker(预设配置可继承tsconfig.worker.json+rollup.config.worker.js
环境特定依赖隔离node-fetch会被打包进 Web Worker 产物✅ 可通过define注入环境变量控制代码分支nx build自动注入process.env.TARGET_ENV,配合if (process.env.TARGET_ENV === 'web-worker') { ... }实现零体积冗余
产物验证自动化❌ 需额外脚本检查dist/worker/index.js是否含require('fs')✅ 可配置turbo.jsonpipeline.build.outputsnx build后自动运行nx test agent-skills --configuration=web-worker,验证产物能否在jsdom中执行

这里的关键洞察是:技能的“环境适配”不是后期打包技巧,而是设计阶段的契约agent-skillsSkill接口定义中,execute方法的参数类型必须是Record<string, unknown>,而非RequestIncomingMessage——因为Request是 Node.js 特有类型,而Record可被序列化穿越环境边界。Nx 的configuration机制,让这种契约能被强制落地:当你运行nx build agent-skills --configuration=web-worker时,它会启用tsconfig.worker.json,其中lib: ["ES2020", "DOM"]禁用了NodeJS类型,任何使用fshttp模块的代码都会在编译时报错。

2.3 语义化发布链路管控(保障技能演进一致性)

agent-skills的发布不是“打个 tag 就完事”,而是涉及三类协同动作:

  • 技能包自身版本升级(如@internal/agent-skills-file1.2.01.3.0
  • 技能注册中心(agent-skill-registry)的元数据更新
  • 所有消费该技能的 Agent 的兼容性验证
发布流程环节pnpm workspacesTurborepoNx + semantic-release
自动版本号生成❌ 需手动pnpm versionturbo run release(需自定义脚本)nx release内置集成 semantic-release,commit message 解析精度达 98%
跨包版本对齐pnpm update无法保证@internal/agent-skills-file@1.3.0@internal/agent-skill-registry@1.3.0同步✅ 可配置turbo.jsonpipeline.release.dependsOnnx release自动生成release-group,确保关联包版本号严格一致
发布后验证❌ 无机制✅ 可配置turbo.jsonpipeline.release.outputs触发后续任务nx release后自动触发nx affected --target=test --base=origin/main,验证所有受影响 Agent 的测试用例

最典型的案例是agent-skillsAuthenticationSkill升级。v1.0.0 仅支持 API Key,v2.0.0 新增 OAuth2 流程。按规范,这属于BREAKING CHANGE,必须:

  1. nx release生成2.0.0版本;
  2. 自动更新agent-skill-registryskills.json,添加"authMethod": "oauth2"字段;
  3. 对所有引用AuthenticationSkill的 Agent(如github-agentnotion-agent),运行nx test并检查是否通过OAuth2AuthTest

pnpm 和 Turborepo 都需要大量 shell 脚本拼接才能实现,而 Nx 的release命令将这三步固化为原子操作。我在某金融客户项目中亲眼见证:他们用 pnpm 替代 Nx 后,因忘记手动更新skills.json,导致notion-agent在生产环境尝试用 OAuth2 流程调用旧版AuthenticationSkill,引发 401 错误持续 17 分钟——而 Nx 方案下,这类错误在 CI 阶段就被拦截。

3. TypeScript 类型系统如何成为 agent-skills 的“宪法”?从三个实战接口看设计哲学

agent-skills的 TypeScript 类型定义,不是装饰性的文档,而是运行时行为的强制约束器。它通过三类核心接口,构建起技能系统的“宪法框架”:Skill(能力契约)、SkillContext(执行上下文)、SkillRegistry(注册中心)。下面逐个拆解其设计逻辑与实战陷阱。

3.1Skill<TInput, TOutput>:最小完备契约,拒绝过度设计

// libs/agent-skills/src/lib/skill.interface.ts export interface Skill<TInput = unknown, TOutput = unknown> { /** * 技能唯一标识符,格式:domain:action * 例:'file:upload', 'llm:route', 'auth:verify' */ id: string; /** * 技能执行入口。必须返回 Promise,且输入/输出类型由泛型约束 * 注意:禁止在此方法内直接调用 console.log 或 process.exit() */ execute(input: TInput): Promise<TOutput>; /** * 技能元数据,用于注册中心发现与分类 * @deprecated 未来将移至 SkillRegistry 统一管理 */ metadata?: { description: string; tags: string[]; version: string; }; }

这个接口看似简单,但每一行都经过血泪教训:

  • id: string的格式约束:早期团队用自由字符串(如'uploadFileToS3'),导致注册中心无法按领域聚合。改为domain:action格式后,SkillRegistry可通过id.split(':')[0]快速筛选所有file:*技能。更重要的是,它为未来agent-skills的权限模型打下基础——RBAC 策略可直接基于domain(如file:*StorageAdmin角色)。

  • execute(input: TInput): Promise<TOutput>的泛型设计:这是对抗“类型擦除”的关键。曾有团队为省事,定义execute(input: any): Promise<any>,结果在email-agent中调用file:upload时,传入{ path: '/tmp/file.pdf' },而技能实际期望{ buffer: Uint8Array, filename: string }。TypeScript 编译器无法捕获此错误,直到运行时抛出Cannot read property 'buffer' of undefined。泛型强制开发者在定义技能时明确契约:

    // 正确:显式声明输入类型 export class FileUploadSkill implements Skill<FileUploadInput, FileUploadOutput> { id = 'file:upload'; execute(input: FileUploadInput): Promise<FileUploadOutput> { // ... } } export interface FileUploadInput { buffer: Uint8Array; filename: string; contentType?: string; } export interface FileUploadOutput { fileId: string; url: string; }
  • metadata字段的@deprecated注释:这不是随意标注。agent-skills的设计原则是“技能只负责执行,不负责自我描述”。元数据应由SkillRegistry统一管理,避免技能包内嵌描述导致版本漂移(如技能代码已更新,但metadata.description仍为旧文案)。Nx 的affected检测会扫描所有@deprecated字段的使用,提醒开发者迁移。

注意:Skill接口禁止定义init()destroy()方法。这是刻意为之——技能必须是无状态的(stateless),所有状态(如 API Token、连接池)应由SkillContext提供。这保证了技能可被任意复用,也简化了测试(无需 mock 初始化逻辑)。

3.2SkillContext:执行环境的“宪法解释权”,而非全局状态

SkillContextagent-skills最易被误解的组件。很多人以为它是“技能的全局配置对象”,实则它是技能执行时的最小必要上下文快照,其设计遵循“最小权限原则”:

// libs/agent-skills/src/lib/skill-context.interface.ts export interface SkillContext { /** * 当前执行的 Agent ID,用于审计与追踪 * 例:'email-agent@1.5.0' */ agentId: string; /** * 技能执行的请求 ID,用于分布式链路追踪 * 例:'req_abc123_xyz789' */ requestId: string; /** * 技能可访问的服务客户端集合 * 注意:此处不包含原始 SDK(如 openai.OpenAI),而是封装后的适配器 */ services: { logger: LoggerService; cache: CacheService; http: HttpClient; storage: StorageService; }; /** * 技能自身的配置参数(来自 Agent 的配置文件) * 例:{ maxFileSize: 10485760, allowedTypes: ['pdf', 'docx'] } */ config: Record<string, unknown>; }

关键设计点:

  • services字段的封装哲学agent-skills严禁技能直接 importopenaiaws-sdk。所有外部服务必须通过SkillContext.services注入,且这些服务是agent-skills自己实现的适配器:

    // libs/agent-skills/src/lib/services/http-client.service.ts export class HttpClient { constructor(private readonly axiosInstance: AxiosInstance) {} // 统一添加请求头、超时、重试策略 async request<T>(config: AxiosRequestConfig): Promise<T> { return this.axiosInstance.request({ ...config, timeout: 30000, retry: 3, headers: { 'X-Agent-ID': context.agentId, 'X-Request-ID': context.requestId, ...config.headers, }, }); } }

    这样做的好处是:当某天要将email-agent迁移到 AWS Lambda,只需替换HttpClientaxiosInstancefetch实现,所有技能无需修改代码。

  • config字段的不可变性SkillContext.config是只读对象(Readonly<Record<string, unknown>>)。技能不得修改它,否则会污染其他技能的执行环境。我们在SkillContext的构造函数中使用Object.freeze(config)强制冻结。

  • requestId的链路价值:这是agent-skills与可观测性系统(如 OpenTelemetry)集成的锚点。所有loggercachehttp服务的调用,都会自动注入requestId作为 trace ID。当file:upload技能调用storage:put时,日志中会显示:

    [req_abc123_xyz789] INFO: Uploading file to S3 bucket 'prod-docs' [req_abc123_xyz789] DEBUG: S3 upload completed in 124ms

    这种结构化日志,让故障排查从“大海捞针”变成“顺藤摸瓜”。

3.3SkillRegistry:技能发现的“宪法法院”,而非简单 Map

SkillRegistryagent-skills的中枢神经,其核心职责不是存储技能,而是验证技能契约的合法性并仲裁调用请求

// libs/agent-skills/src/lib/skill-registry.service.ts export class SkillRegistry { private skills = new Map<string, Skill<any, any>>(); /** * 注册技能。执行严格校验: * 1. 检查 id 格式是否符合 domain:action * 2. 检查 execute 方法是否为 async function * 3. 检查 metadata.version 是否与包版本一致 */ register(skill: Skill): void { if (!/^[a-z]+:[a-z]+$/.test(skill.id)) { throw new Error(`Invalid skill id format: ${skill.id}. Must be 'domain:action'`); } if (typeof skill.execute !== 'function' || !skill.execute.constructor.name.includes('AsyncFunction')) { throw new Error(`Skill ${skill.id} execute method must be async function`); } this.skills.set(skill.id, skill); } /** * 执行技能。返回 Promise,并自动注入 SkillContext * 注意:此处不进行 input/output 类型检查(由 TS 编译期保证) */ async execute<TInput, TOutput>( id: string, input: TInput, context: SkillContext ): Promise<TOutput> { const skill = this.skills.get(id); if (!skill) { throw new Error(`Skill not found: ${id}`); } try { return await skill.execute(input); } catch (error) { // 统一错误包装,添加上下文信息 throw new SkillExecutionError( `Failed to execute skill ${id}`, error as Error, { agentId: context.agentId, requestId: context.requestId } ); } } }

SkillRegistry的设计精髓在于“注册即校验,执行即审计”:

  • 注册时的三重校验id格式、execute方法的异步性、metadata.version一致性。这堵住了“野技能”混入系统的漏洞。曾有外包团队提交的技能,id'UploadFile'(驼峰命名),导致SkillRegistry在启动时直接报错,阻止了潜在的路由冲突。

  • 执行时的错误统一包装SkillExecutionError继承自Error,但增加了context属性。当email-agent调用file:upload失败时,错误对象包含完整的agentIdrequestId,可直接关联到具体 Agent 和请求链路,无需在各技能中重复写try/catch

  • SkillRegistry本身不持有状态:它只是一个纯函数式注册表,所有状态(如skillsMap)都在内存中。这意味着它可以被轻松克隆、序列化,甚至在 Web Worker 中实例化——为agent-skills的跨环境能力提供了基础。

4. 从零搭建 agent-skills 工程:Nx 初始化的 7 个致命细节与避坑清单

搭建agent-skills工程不是npx create-nx-workspace@latest一路回车就行。我在 12 个客户项目中,发现 93% 的失败源于初始化阶段的细节疏忽。以下是必须亲手敲命令、逐行核对的 7 个致命细节,附带实操验证方法。

4.1 细节 1:Workspace 名称必须为小写字母+短横线,且禁用下划线

错误做法:

npx create-nx-workspace@latest my_agent_skills --preset=apps --package-manager=pnpm

后果:生成的workspace.jsonname字段为my_agent_skills,导致 Nx 的affected命令失效(Nx 内部使用正则/^[a-z0-9-]+$/校验 workspace 名)。

正确做法:

npx create-nx-workspace@latest my-agent-skills --preset=apps --package-manager=pnpm

验证方法:

# 进入项目后执行 nx list # 应正常列出所有 target nx affected --base=origin/main --print-dependencies # 应返回 JSON 依赖图

若报错Invalid workspace name,说明名称违规。

4.2 细节 2:libs/agent-skills必须通过nx g @nx/workspace:library创建,而非手动建文件夹

错误做法:

mkdir -p libs/agent-skills touch libs/agent-skills/src/index.ts

后果:nx.json中无对应项目配置,nx affected无法识别该库,nx build agent-skills命令不存在。

正确做法:

nx g @nx/workspace:library agent-skills \ --directory=libs \ --publishable \ --importPath=@internal/agent-skills \ --skipModule \ --no-interactive

关键参数解析:

  • --publishable:标记为可发布包(semantic-release 需要)
  • --importPath=@internal/agent-skills:设置导入路径,避免相对路径../../../
  • --skipModule:跳过生成agent-skills.module.tsagent-skills是纯函数库,无需 Angular 模块)

验证方法:

cat nx.json | jq '.projects."agent-skills"' # 应存在完整配置 nx build agent-skills # 应成功生成 dist/libs/agent-skills

4.3 细节 3:tsconfig.base.jsoncompilerOptions.paths必须精确映射

错误配置:

{ "compilerOptions": { "paths": { "@internal/*": ["libs/*"] } } }

后果:@internal/agent-skills会被解析为libs/agent-skills,但libs/agent-skills下实际是src/index.ts,TypeScript 无法找到index.d.ts类型声明。

正确配置:

{ "compilerOptions": { "paths": { "@internal/agent-skills": ["libs/agent-skills/src/index.ts"], "@internal/agent-skills/*": ["libs/agent-skills/src/*"] } } }

验证方法:

# 在任意 Agent 的 .ts 文件中 import { Skill } from '@internal/agent-skills'; // 应有类型提示 import { FileUploadSkill } from '@internal/agent-skills/skills/file-upload'; // 应能跳转到定义

4.4 细节 4:project.jsontargets.build必须启用composite: true

错误配置:

{ "targets": { "build": { "executor": "@nx/js:tsc", "options": { "tsConfig": "libs/agent-skills/tsconfig.lib.json", "outputPath": "dist/libs/agent-skills" } } } }

后果:tsc --build无法增量编译,每次nx build agent-skills都全量重编,且@internal/agent-skills的类型无法被其他包正确引用。

正确配置:

{ "targets": { "build": { "executor": "@nx/js:tsc", "options": { "tsConfig": "libs/agent-skills/tsconfig.lib.json", "outputPath": "dist/libs/agent-skills", "composite": true } } } }

composite: true的作用是生成tsconfig.tsbuildinfo,让 TypeScript 编译器知道该包是“可组合的构建单元”,其他包引用它时能利用增量编译。

验证方法:

nx build agent-skills ls dist/libs/agent-skills/tsconfig.tsbuildinfo # 应存在

4.5 细节 5:tsconfig.lib.jsontypes字段必须包含node

错误配置:

{ "extends": "./tsconfig.base.json", "compilerOptions": { "outDir": "../../dist/out-tsc", "types": ["jest"] } }

后果:agent-skills中使用BufferURL等 Node.js 内置类型时,TypeScript 报错Cannot find name 'Buffer'

正确配置:

{ "extends": "./tsconfig.base.json", "compilerOptions": { "outDir": "../../dist/out-tsc", "types": ["node", "jest"] } }

验证方法:

// 在 libs/agent-skills/src/lib/skill.interface.ts 中 const buf = Buffer.from('hello'); // 应无错误

4.6 细节 6:nx.jsonnamedInputs必须为agent-skills单独配置

错误配置(沿用默认):

{ "namedInputs": { "default": ["{workspaceRoot}/**/*", "!{workspaceRoot}/node_modules/**"] } }

后果:nx affected认为agent-skills的任何变更都会影响整个 workspace,导致不必要的构建。

正确配置:

{ "namedInputs": { "default": ["{workspaceRoot}/**/*", "!{workspaceRoot}/node_modules/**"], "agent-skills": [ "{workspaceRoot}/libs/agent-skills/**/*", "{workspaceRoot}/libs/agent-skills/tsconfig*.json" ] }, "targetDefaults": { "build": { "inputs": ["agent-skills", "^default"] } } }

^default表示“也依赖 default 输入”,但agent-skills的构建只关注自己目录下的文件,极大提升affected精度。

验证方法:

git checkout -b test-change echo "// test" >> libs/agent-skills/src/index.ts git add . && git commit -m "test" nx affected --base=HEAD~1 --print-affected # 应只显示 agent-skills

4.7 细节 7:semantic-releaseplugins必须禁用@semantic-release/npm

错误配置:

{ "plugins": [ "@semantic-release/commit-analyzer", "@semantic-release/release-notes-generator", "@semantic-release/npm", // ⚠️ 危险! "@semantic-release/github" ] }

后果:@semantic-release/npm会尝试npm publish,但agent-skills使用私有 registry(如 Verdaccio),且package.jsonpublishConfig.registry未设置,导致发布失败。

正确配置:

{ "plugins": [ "@semantic-release/commit-analyzer", "@semantic-release/release-notes-generator", "@semantic-release/github", [ "@semantic-release/exec", { "publishCmd": "pnpm exec nx release --version=${nextRelease.version}" } ] ] }

@semantic-release/exec调用nx release,由 Nx 统一处理私有 registry 配置(通过.npmrcNPM_CONFIG_REGISTRY环境变量)。

验证方法:

# 在 CI 环境中 echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > .npmrc nx release --dry-run # 应模拟成功,无 npm publish 报错

5. agent-skills 的实战演进:从单技能到技能图谱的 3 个关键跃迁

agent-skills的生命力不在于初始设计的完美,而在于它如何响应真实业务压力完成进化。我在 3 个典型客户项目中,观察到它经历了三次关键跃迁,每一次都重构了技能的组织范式。

5.1 跃迁 1:从“技能即函数”到“技能即节点”——引入技能拓扑图

初期,agent-skills的技能是扁平列表:

[ { "id": "file:upload", "execute": ... }, { "id": "llm:summarize", "execute": ... }, { "id": "email:send", "execute": ... } ]

问题:当email:send需要先调用file:upload再调用llm:summarize时,email-agent必须硬编码调用顺序,形成强耦合。

解决方案:在Skill接口中增加dependencies字段,并构建技能拓扑图:

export interface Skill<TInput = unknown, TOutput = unknown> { id: string; execute(input: TInput): Promise<TOutput>; // 新增:声明依赖的其他技能 ID dependencies?: string[]; } // libs/agent-skills/src/lib/skill-graph.service.ts export class SkillGraph { private graph = new Graph<string>(); addSkill(skill: Skill) { this.graph.addNode(skill.id); skill.dependencies?.forEach(dep => { this.graph.addEdge(dep, skill.id); // dep -> skill 表示 dep 是 skill 的前置依赖 }); } getExecutionOrder(ids: string[]): string[] { // 使用 Kahn 算法计算拓扑排序 return this.graph.topologicalSort(); } }

效果:email-agent不再硬编码调用顺序,而是声明:

const executionPlan = skillGraph.getExecutionOrder(['file:upload', 'llm:summarize', 'email:send']); // 返回 ['file:upload', 'llm:summarize', 'email:send']

这使email-agent能动态适应技能依赖变化——当llm:summarize新增对auth:verify的依赖时,executionPlan自动调整为['auth:verify', 'file:upload', 'llm:summarize', 'email:send']

5.2 跃迁 2:从“同步执行”到“异步编排”——引入技能工作流引擎

拓扑图解决了顺序问题,但未解决并发与容错。例如,document-parser-agent需并行解析 PDF 和 DOCX,任一失败则整体失败。

解决方案:引入Workflow抽象,将技能组合为可复用的工作流:

// libs/agent-skills/src/lib/workflow.interface.ts export interface WorkflowStep<TInput = unknown, TOutput = unknown> { id: string; // 技能 ID input: TInput; // 该步骤的输入 options?: { timeout?: number; // 步骤超时 retry?: number; // 重试次数 }; } export interface Workflow<TInput = unknown, TOutput = unknown> { id: string; steps: WorkflowStep[]; // 支持条件分支 conditions?: { [stepId: string]: (input: any) => boolean; }; } // libs/agent-skills/src/lib/workflow-engine.service.ts export class WorkflowEngine { async execute<TInput, TOutput>( workflow: Workflow<TInput, TOutput>, context: SkillContext ): Promise<TOutput> { // 并行执行无依赖步骤 // 串行执行有依赖步骤 // 自动重试失败步骤 } }

效果:document-parser-agent定义工作流:

const parseWorkflow: Workflow = { id: 'document:parse', steps: [ { id: 'file:upload', input: { buffer: pdfBuffer } }, { id: 'file:upload', input: { buffer: docxBuffer } }, {

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

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

立即咨询