☰
Agent Skills 实战:从工具调用到可复用能力模块的智能体开发
2026/10/7 18:16:35 网站建设 项目流程

1. 从"skills"这个热词说起:它到底指什么

最近一段时间,"skills"这个词在技术社区里出现的频率明显高了起来。如果你只是偶尔刷到,可能会觉得它说的是"技能"这个泛泛的概念,没什么特别的。但如果你稍微留意一下上下文,就会发现大家讨论的"skills"其实指向一个很具体的东西——Agent Skills,也就是围绕智能体(Agent)构建的一套可复用能力模块。

我最早接触这个概念是在折腾 Google Cloud 上的一些智能体项目时。当时的需求很明确:我手头有一个基于 Genkit 搭建的对话流程,想让它在特定场景下调用外部工具、执行多步推理、并且能稳定地返回结构化结果。一开始我的做法是把所有逻辑都塞进一个巨大的提示词里,结果就是提示词越写越长,维护起来极其痛苦,改一个地方就牵一发而动全身。后来接触到 Agent Skills 的思路,才意识到问题的本质:我缺的不是更强的模型,而是一套把能力拆解、封装、按需加载的机制。

所以这篇内容,我想从一个实际做过智能体项目的人的角度,把 skills 这件事讲透。它适合几类人看:一是正在用 Google Cloud、GKE、Genkit 这类工具做智能体应用的开发者;二是听说过 Agent Skills 但还没搞明白它和普通函数调用、工具调用有什么区别的人;三是想给自己的项目引入一套可维护能力体系、但不知道从哪下手的人。我会尽量把原理、设计取舍、实操步骤和踩过的坑都摊开来讲,而不是停留在概念层面。

需要先说明一点:skills 这个概念在不同平台、不同框架下的具体实现细节是有差异的。我下面讲的内容,一部分来自我自己在 Google Cloud 生态里的实践,一部分是基于"一个合格从业者在做智能体能力封装时最可能采用的合理方案"做的补充推演。你在自己的项目里落地时,要结合所用框架的实际 API 来调整。

2. Agent Skills 和普通工具调用的本质区别

2.1 为什么"工具调用"不够用了

很多人第一次接触智能体开发,学到的第一个概念就是"工具调用"(tool calling / function calling)。模型根据用户输入,决定调用哪个函数,传什么参数,然后拿到返回值继续推理。这套机制本身没问题,但当你把项目做大之后,会撞上几堵墙。

第一堵墙是上下文膨胀。每个工具都要把它的名称、描述、参数 schema 塞进系统提示词里。工具有十个的时候还好,到三五十个的时候,光是工具定义就占掉大量 token,而且模型在这么多工具里做选择的准确率会明显下降。第二堵墙是能力边界模糊。一个"工具"往往只做一件事,但真实任务需要的是"一组相关的操作加上判断逻辑"。比如"处理一份合同"这件事,涉及读取、抽取关键条款、比对模板、生成风险提示,你不可能把它拆成四个孤立工具让模型自己串,那样出错率极高。

第三堵墙是复用和版本管理。工具散落在代码各处,没有统一的注册、发现、加载机制,换个项目就得重写一遍。

Agent Skills 要解决的就是这几个问题。它把"一组相关的工具 + 判断逻辑 + 领域知识"打包成一个可命名、可描述、可按需加载的能力单元。模型平时不需要知道这个 skill 内部的细节,只在需要的时候把它"激活",加载对应的指令和工具集。

2.2 一个生活化的类比

你可以把普通工具调用想象成一个工具箱,里面堆满了各种螺丝刀、扳手、钳子,每次干活你都得把整个箱子搬到桌上,然后在一堆工具里找。而 Agent Skills 更像是分门别类的工具包:电工包、木工包、水管包,每个包上贴着标签说明它解决什么问题。你需要修电路的时候,只把电工包拿过来,里面的工具和说明书都是配套的。

这个类比的关键在于"配套"两个字。skill 不只是工具的集合,它还带着使用说明——也就是告诉模型"在什么情况下用这个 skill、用的顺序是什么、有哪些注意事项"。这部分说明通常以结构化的指令形式存在,是 skill 区别于普通工具包的核心。

2.3 关键差异对照

维度普通工具调用Agent Skills
粒度单个函数一组相关能力 + 指令
加载方式通常全量注入按需激活、渐进式加载
上下文占用随工具数量线性增长未激活时占用极小
复用性跨项目需重写可打包分发、版本化
领域知识靠提示词硬塞内聚在 skill 内部
适用场景简单、少量工具复杂、多步骤、多领域任务

这张表不是绝对的,很多框架在两者之间有过渡形态。但理解这个差异,能帮你在设计时想清楚:我到底该写一个工具,还是封装一个 skill。

3. 在 Google Cloud 与 Genkit 体系里落地 skills 的思路

3.1 为什么选 Genkit 作为切入点

Genkit 是 Google 推出的一个用于构建 AI 应用的框架,它的定位是"把模型调用、工具、流程编排、可观测性整合到一起"。我选它作为讲 skills 落地的载体,原因有三个。

一是它对工具定义和流程编排的支持比较自然,你可以用声明式的方式定义工具,然后用 flow 把多步逻辑串起来,这正好对应 skill 内部"工具 + 判断逻辑"的结构。二是它和 Google Cloud 的其它服务(比如部署、日志、监控)衔接顺畅,skill 做完之后能比较方便地放到 GKE 上跑。三是它的抽象层次适中,不像某些框架那样把一切都藏起来,你还能看清楚底层发生了什么,这对理解 skills 的运行机制很有帮助。

3.2 skill 的目录结构设计

一个可维护的 skill,我建议按下面的结构组织。这不是官方强制规范,而是我在实际项目里摸索出来、觉得比较顺手的方案:

skills/ contract-review/ manifest.json # skill 元信息:名称、描述、触发条件 instructions.md # 给模型的指令:何时用、怎么用、注意事项 tools/ extract_clauses.js # 具体工具实现 compare_template.js resources/ template.json # skill 依赖的静态资源

这里有几个设计取舍值得说清楚。

manifest.json 和 instructions.md 分开,是因为它们的消费者不同。manifest 是给系统看的,用来做 skill 的注册、发现、路由;instructions 是给模型看的,用来指导它在激活 skill 之后怎么行动。混在一起会导致两边都不好维护。

tools 目录下的工具是 skill 私有的,不对外暴露。这一点很重要。如果工具全局注册,那又回到了上下文膨胀的老路。skill 的价值就在于把工具的可见性限制在 skill 内部,只有 skill 被激活时,这些工具才进入模型的视野。

resources 目录放静态依赖,比如模板文件、配置、词表。这些东西如果塞进提示词会非常浪费 token,放在文件里按需读取更合理。

3.3 manifest 里该写什么

manifest 是整个 skill 的入口,它决定了系统怎么找到并加载这个 skill。我一般会包含这几个字段:

{ "name": "contract-review", "version": "1.2.0", "description": "审查合同文本,抽取关键条款并与标准模板比对,输出风险提示", "triggers": [ "用户上传合同并要求审查", "用户询问合同中的风险条款" ], "entrypoint": "instructions.md", "tools": ["extract_clauses", "compare_template"] }

description和triggers是给路由层用的。当用户输入进来,系统先拿这些信息做一次轻量的匹配,判断要不要激活这个 skill。注意这里不要写得太宽泛,否则会导致 skill 被频繁误激活,反而增加开销。我踩过的坑就是把 triggers 写成了"涉及合同的问题",结果用户随便问一句"合同一般包括哪些内容"也会触发整个 skill 加载,纯属浪费。

version字段别省。skill 是要迭代的,没有版本号,出了问题你都不知道线上跑的是哪一版。

4. skill 的加载机制:渐进式披露为什么重要

4.1 全量加载的问题

假设你有 20 个 skill,每个 skill 平均包含 5 个工具和 500 字的指令。如果全量加载,光是 skill 相关的定义就接近上万 token。这不仅烧钱,更要命的是会稀释模型的注意力——上下文里塞了太多无关信息,模型在真正需要判断的地方反而容易出错。

我在早期项目里就吃过这个亏。当时为了图省事,把所有 skill 的指令拼成一个大提示词,结果模型经常"串台",用 A skill 的规则去处理 B skill 的任务。后来改成按需加载,准确率立刻上了一个台阶。

4.2 渐进式披露的三个层次

渐进式披露(progressive disclosure)是 Agent Skills 的核心设计思想,我把它拆成三个层次来理解。

第一层是元信息层。系统始终持有所有 skill 的 name、description、triggers,但只有这些,非常轻量。这一层的作用是让路由层能快速判断"当前任务可能和哪些 skill 相关"。

第二层是指令层。当某个 skill 被判定为相关,系统加载它的 instructions.md,把详细的操作指南注入上下文。这时候模型知道了"该怎么做",但还不知道"能用哪些工具"。

第三层是工具层。只有当模型明确要执行某个操作时,对应的工具定义才被加载进来。这一层是真正干活的。

这个分层的好处是:上下文占用随任务复杂度动态变化,而不是随 skill 总数变化。你有 100 个 skill,但一次任务可能只激活 1 个,那实际开销就只和这 1 个 skill 有关。

4.3 路由判断怎么做才准

路由判断是渐进式披露的第一道关卡,做不好整个机制就废了。我的经验是不要只靠模型判断,而是模型判断 + 规则兜底结合。

规则兜底指的是:用关键词、正则、甚至简单的分类器先做一轮粗筛,把明显相关的 skill 挑出来,再交给模型做精细判断。这样做的好处是可控——你可以在规则层设置硬性条件,避免模型"想太多"。

举个具体例子。对于"合同审查"这个 skill,我可以先设一条规则:如果输入里包含"合同""条款""甲方乙方"这类词,就把它列入候选。然后再让模型在候选里判断到底该激活哪个。纯靠模型的话,有时候用户只是随口提一句"合同",模型就兴师动众地激活整个 skill,体验反而不好。

提示:路由判断的准确率是可以量化的。建议你在项目里埋点,记录每次激活的 skill 和最终任务是否匹配,跑一段时间后统计误激活率和漏激活率,再针对性调整 triggers 和规则。

5. 把 skill 部署到 GKE 上的实操要点

5.1 为什么考虑 GKE

skill 本身是逻辑单元,跑在哪都行。但当你的智能体应用要对外提供服务,就需要考虑部署、扩缩容、可观测性这些工程问题。GKE(Google Kubernetes Engine)是 Google Cloud 上的托管 Kubernetes 服务,用它来跑智能体应用有几个实际好处:容器化的 skill 可以独立扩缩容;不同 skill 之间资源隔离;日志和监控统一接入。

不过我要先泼盆冷水:不是所有项目都值得上 GKE。如果你只是做个原型、验证一下 skills 的思路,本地跑跑就够了,上 K8s 纯属给自己找麻烦。GKE 适合的是那种已经有明确流量、需要稳定服务、团队有一定运维能力的场景。

5.2 容器化 skill 的注意事项

把 skill 打包成容器时,有几个点容易踩坑。

第一,skill 的静态资源要打进镜像。前面说的 resources 目录,如果放在容器外挂载,部署时会多一层依赖,容易出问题。直接 COPY 进镜像最省心。

第二,工具的外部依赖要显式声明。skill 里的工具可能依赖某些库或外部服务,这些必须在 Dockerfile 里写清楚。我见过有人本地跑得好好的,一上容器就报错,最后发现是某个隐式依赖没装。

第三,镜像要分层。skill 的指令和资源变动频繁,工具实现相对稳定,基础镜像最稳定。分层构建能让每次更新只重建变动的那一层,加快部署速度。

一个简化的 Dockerfile 大概长这样:

FROM node:20-slim WORKDIR /app COPY package*.json ./ RUN npm ci --production COPY skills/ ./skills/ COPY src/ ./src/ CMD ["node", "src/server.js"]

5.3 扩缩容策略怎么定

skill 的负载特征和普通 Web 服务不太一样。普通服务请求比较均匀,skill 的调用往往是突发性的——可能几分钟没请求,然后突然来一批。所以扩缩容策略要偏向"快速响应"而不是"平稳"。

我的做法是设置较低的缩容阈值和较快的扩容触发。具体参数要看你的实际流量,但思路是:宁可多留一点冗余,也别让请求排队。因为智能体任务本身耗时较长,一旦排队,用户等待时间会成倍增加。

另外,不同 skill 的资源需求差异很大。有的 skill 只是调几个 API,很轻;有的 skill 要做大量文本处理,很重。如果全部塞在一个 Deployment 里,资源分配会很难受。可以考虑按 skill 的资源特征分组部署,重的和轻的分开。

6. 开发一个 skill 的完整流程与踩坑记录

6.1 从需求到 skill 的拆解

假设我要做一个"论文辅助写作"的 skill。需求是:用户给一个主题,skill 能帮忙找相关文献、整理提纲、检查引用格式。

第一步是判断这该不该做成一个 skill。判断标准是:这个任务是不是多步骤的?是不是需要一组相关工具?是不是有领域知识要内聚?三个都是"是",那就适合做成 skill。

第二步是拆工具。找文献是一个工具,整理提纲是一个工具,检查引用格式是一个工具。注意这里不要拆得太细,比如"检查引用格式"内部又分 APA、MLA、Chicago,这些应该是同一个工具的不同参数,而不是三个工具。

第三步是写指令。指令要回答几个问题:什么时候用这个 skill?用的顺序是什么?每个工具的输出怎么处理?有哪些常见错误要避免?

6.2 指令写作的坑

指令写得好不好,直接决定 skill 好不好用。我踩过的坑主要有这几个。

坑一:指令太抽象。比如写"根据用户需求选择合适的工具",这种话等于没说。模型需要的是具体判断依据,比如"如果用户提供了主题但没有文献列表,先调用 find_references;如果已有文献列表,直接进入 outline 步骤"。

坑二:指令太长。有人觉得写得越详细越好,结果 instructions.md 写了三千字,模型读到后面忘了前面。我的经验是控制在 500 到 800 字,把最关键的判断逻辑和顺序写清楚,细节交给工具自己处理。

坑三:没有错误处理指引。工具调用失败怎么办?返回结果不符合预期怎么办?这些必须在指令里说明。比如"如果 find_references 返回空结果,不要直接告诉用户没找到,而是尝试用更宽泛的关键词重试一次"。

6.3 测试 skill 的方法

skill 的测试和普通代码测试不一样,因为它的行为有随机性。我的做法是构造一批典型场景,人工评估输出质量,而不是追求自动化断言。

具体来说,我会准备三类测试用例:正常场景(用户需求明确、工具都能正常工作)、边界场景(用户需求模糊、工具返回空或异常)、干扰场景(用户输入里混入了和 skill 无关的内容)。每类准备五到十个,跑完之后看 skill 的激活是否正确、工具调用是否合理、最终输出是否满足需求。

这个过程很费时间,但非常值得。我见过太多 skill 在 demo 时表现完美,一上真实场景就各种翻车,根本原因就是测试用例太单一。

注意:skill 的测试要覆盖"不该激活"的情况。很多时候问题不是 skill 没被激活,而是被错误激活了。专门准备一批"看起来相关但其实不该触发"的输入,能帮你发现 triggers 设计的问题。

7. 关于 skills 生态的一些观察和判断

7.1 skills 的复用与分发

skills 这个概念之所以有意思,很大程度上是因为它天然适合复用和分发。一个写好的 skill,理论上可以打包给任何人用。这催生了一些讨论,比如"skills 市场""skills 推荐"这类话题。

我的判断是:通用型 skill 的价值有限,垂直型 skill 才是重点。像"文本摘要""翻译"这种通用能力,模型本身就很强,封装成 skill 意义不大。真正有价值的是那些包含特定领域知识、特定流程、特定数据的 skill,比如某个行业的合规审查、某类文档的处理、某个系统的操作流程。这些东西模型不知道,必须靠 skill 补上。

7.2 不要为了 skills 而 skills

最后说一个我观察到的现象:有些团队一听说 skills 这个概念,就急着把现有功能全部改造成 skill,结果改完之后发现复杂度不降反升。

skills 是一种组织复杂性的手段,它的前提是你确实有复杂性要组织。如果你的应用只有三五个工具、逻辑很直白,那老老实实写函数调用就行,套一层 skill 的壳纯属增加负担。判断标准很简单:当你觉得提示词越来越难维护、工具越来越多、上下文越来越挤的时候,才是引入 skills 的时机。

我在实际项目里的体会是,skills 最大的价值不在于技术本身有多新,而在于它强迫你把"能力"当成一等公民来设计——给它命名、写文档、定版本、做测试。这个思维方式的转变,比任何具体实现都重要。

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

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

立即咨询