
1. 从“skills”这个热词说起它到底是什么为什么突然火了最近几个月不管是在技术社区、开发者群聊还是在做AI应用的朋友圈子里“skills”这个词出现的频率高得离谱。有人把它翻译成“技能包”有人叫它“能力插件”还有人直接管它叫“AI的手和脚”。如果你只是偶尔刷到可能会觉得这又是一个新造的概念过两个月就凉了。但如果你真正动手搭过几个Agent或者用Google Cloud上的Genkit、GKE跑过一些自动化流程你就会明白skills这个东西不是噱头它解决的是一个非常具体、非常痛的问题。我先用一句话把它的核心说清楚skills是一套让AI Agent能够稳定、可复用、可组合地完成特定任务的封装单元。你可以把它理解成给AI准备的“工具箱”每个skill就是一把螺丝刀、一个扳手AI需要拧螺丝的时候就调用拧螺丝的skill需要量尺寸的时候就调用量尺寸的skill而不是每次都从零开始“想”怎么拧螺丝。那为什么是现在火因为过去一年大模型的能力已经足够强了强到可以理解复杂指令、可以写代码、可以做推理。但问题也随之而来你让模型直接去操作一个真实系统它很容易“自由发挥”今天用A方法明天用B方法结果不可复现调试起来极其痛苦。skills的出现本质上是把“怎么做”这件事从模型的即兴发挥里抽出来变成显式的、可版本管理的、可测试的资产。这就像你带团队你不会让每个新人自己琢磨怎么发版而是给他一份标准操作手册skills就是那份手册的代码化形态。从热搜词也能看出来大家关心的方向非常集中Google Cloud、Agent Skills、GKE、Genkit这几个词频繁出现说明skills和云原生、和Agent框架的结合是当前的主流落地路径。而“claude agent skills: a first principles deep dive”“codex skills”“skills开发”“skills安装”这些词则反映出不同技术栈的开发者都在往这个方向靠。有人想找现成的skills下载有人想自己写skills有人想知道怎么在本地环境里把skills跑起来。我写这篇东西就是想把这几个问题一次性讲透从设计思路到实操细节再到踩坑经验尽量让不同基础的人都能拿走能用的东西。2. 核心设计思路拆解为什么是“技能”而不是“函数”或“插件”2.1 从函数调用到技能封装中间差了什么很多人第一次接触skills的时候会问这不就是function calling吗我直接给模型定义几个函数让它调不就完了这个问题问得特别好因为它正好点到了skills和传统function calling的本质区别。传统的function calling你定义的是一个接口函数名、参数、返回值。模型看到这个接口决定要不要调、怎么传参。但问题在于函数只定义了“做什么”没有定义“怎么做”。比如你有一个函数叫deploy_to_gke参数是集群名和镜像地址。模型知道要调这个函数但它不知道部署之前要先检查镜像是否存在、部署之后要等rollout完成、失败了要怎么回滚。这些“怎么做”的知识要么散落在你的prompt里要么靠模型自己猜。skills的做法是把“做什么”和“怎么做”打包在一起。一个skill通常包含几个部分元数据描述这个skill是干什么的、什么时候用、执行逻辑具体的步骤和判断、依赖声明需要哪些工具或权限、以及验证逻辑怎么判断执行成功了。这四样东西合在一起才构成一个完整的skill。你可以把它类比成一份“带操作步骤的SOP文档”而不是一个光秃秃的API。注意如果你只是把原来的函数换个名字叫skill那本质上没有区别。skills的价值在于把隐性知识显性化把“模型需要猜的东西”变成“写死在skill里的确定性逻辑”。2.2 为什么Google Cloud和Genkit在这个话题里频繁出现热搜词里Google Cloud、GKE、Genkit三个词绑在一起出现不是偶然。Genkit是Google推出的一个用于构建AI应用的框架它原生支持Agent和工具调用的概念。而GKE是Google Kubernetes Engine是跑容器化工作负载的地方。这三者组合起来形成了一条很清晰的链路用Genkit定义Agent和skills用GKE跑Agent的运行时用Google Cloud的其他服务比如Cloud Run、Cloud Functions作为skill的实际执行后端。为什么这条链路受欢迎因为skills本质上是一种“可执行的配置”它需要有一个稳定的运行时来承载。你不可能在本地笔记本上跑一个需要调用十几个云服务的Agent然后指望它稳定。GKE提供了弹性伸缩、服务发现、健康检查这些基础设施让skills的调用不会因为某个后端挂了就整个崩掉。而Genkit则提供了开发期的抽象让你用比较少的代码就能把skill注册到Agent上。我自己的经验是如果你只是做demo本地跑跑没问题。但一旦你要把Agent放到生产环境让它在没人盯着的情况下处理真实任务那GKE这类编排平台几乎是绕不开的。skills的调用链路越长对底层稳定性的要求就越高。2.3 技能的组合性与可测试性才是长期价值单独一个skill能做的事很有限比如“查天气”或者“发邮件”。但skills真正的威力在于组合。你可以定义一个“处理客户投诉”的skill它内部会依次调用“查询订单状态”“判断是否符合退款条件”“生成回复邮件”“记录处理日志”这几个子skill。每个子skill都可以独立测试、独立替换整个流程又是可追踪的。这种设计带来的好处是调试变得极其简单。如果客户投诉处理错了你不需要去翻模型的对话记录猜它哪一步想歪了你只需要看每个子skill的输入输出很快就能定位到是“判断退款条件”那个skill的逻辑写错了还是“查询订单状态”返回了脏数据。可测试性是skills区别于“让模型自由发挥”的最大优势。而且skills是可以版本化的。你今天写了一个v1版本的“生成周报”skill下周发现格式要调整你改一版v2旧版本还能继续用新版本可以灰度发布。这种工程化的管理方式是让AI应用从“玩具”走向“工具”的关键一步。3. 核心细节解析一个skill到底由哪些部分组成3.1 元数据让Agent知道“什么时候该用我”元数据是skill的“自我介绍”。它通常包括几个字段name技能名、description自然语言描述、trigger_conditions触发条件、input_schema输入参数定义、output_schema输出格式定义。其中最重要的是description和trigger_conditions因为Agent就是靠这两样东西来判断当前任务该不该调用这个skill。我见过很多新手写skilldescription写得特别随意比如“处理数据”。这种描述对Agent来说几乎没有信息量它不知道“处理”是指清洗、转换还是分析也不知道什么场景下该用。好的description应该是具体的、场景化的比如“当用户提供一份CSV文件并要求按指定列去重时使用此技能返回去重后的文件路径和重复行数”。trigger_conditions则更进一步它可以用结构化的方式定义触发规则。比如你可以写“当输入中包含‘去重’关键词且文件扩展名为.csv时触发”。这样Agent在规划任务时就能更准确地匹配到正确的skill而不是靠猜。实操心得description不要写得太短也不要写得太长。太短信息不足太长会占用宝贵的上下文窗口。我的经验是控制在50到150个词之间把“做什么、输入什么、输出什么、什么场景用”这四件事说清楚就够了。3.2 执行逻辑确定性优先模型兜底执行逻辑是skill的核心。这里有一个非常重要的设计原则能写死的逻辑就不要交给模型。比如“先检查文件是否存在如果不存在就报错”这种步骤完全可以用代码写死不需要模型来判断。模型只应该用在那些真正需要理解、推理、生成的地方比如“根据用户反馈判断情绪倾向”或者“生成一段自然语言的回复”。一个典型的skill执行逻辑通常包含这几个阶段前置校验检查输入是否合法、主流程核心操作步骤、异常处理出错时怎么办、后置校验确认输出符合预期。每个阶段都可以用代码实现也可以用模型辅助但边界要清晰。我举个例子。假设你要写一个“自动回复客户咨询”的skill。前置校验阶段你可以用代码检查输入里有没有客户ID和咨询内容。主流程阶段你可以先调用一个“查询历史订单”的子skill然后把订单信息和咨询内容一起交给模型生成回复。异常处理阶段如果查询订单失败你可以让skill返回一个“转人工”的信号而不是让模型硬编一个回复。后置校验阶段你可以检查生成的回复里有没有包含敏感词或者错误的价格信息。这种结构化的写法比让模型从头到尾自由发挥要可靠得多。而且每个阶段都可以单独测试出了问题也容易定位。3.3 依赖声明别让skill变成“隐式耦合”的重灾区依赖声明是很多人容易忽略的部分。一个skill可能依赖外部API、数据库、文件系统、或者其他skill。如果你不把这些依赖显式声明出来就会出现一种情况skill在开发环境跑得好好的一上生产就挂因为生产环境没有某个环境变量或者某个服务没开。我的做法是每个skill都必须声明三类依赖运行时依赖需要哪些库或服务、权限依赖需要哪些IAM角色或API密钥、数据依赖需要访问哪些数据源。这些声明不一定要很复杂但必须存在而且要在skill加载的时候做检查。如果依赖不满足skill应该直接拒绝加载而不是等到执行到一半才报错。在GKE上跑的时候我通常会把这些依赖声明和Kubernetes的ConfigMap或者Secret绑定起来。skill启动时先读配置确认所有依赖都就绪再注册到Agent上。这样能避免很多“运行时才发现缺东西”的尴尬。3.4 验证逻辑怎么判断skill真的执行成功了验证逻辑是skill的“验收标准”。很多skill只定义了怎么执行没定义怎么判断执行结果对不对。这会导致一个问题skill返回了一个结果但Agent不知道这个结果是不是可信的只能默认它是对的。如果skill内部出了bug返回了错误的结果Agent可能会基于错误结果继续往下走最后整个任务失败但你很难追溯是哪一步出的问题。好的验证逻辑应该包含格式验证输出是否符合schema、业务验证结果是否满足业务规则、以及一致性验证多次执行结果是否稳定。格式验证可以用JSON Schema来做业务验证需要你根据具体场景写规则一致性验证则可以通过重复执行或者对比历史数据来实现。比如一个“生成报价单”的skill格式验证检查返回的JSON里有没有必需的字段业务验证检查报价金额是否在合理范围内一致性验证可以对比同一产品在不同时间的报价是否波动过大。这三层验证做完你才能比较放心地说这个skill是可靠的。4. 实操过程从零搭建一个可用的skill并部署到GKE4.1 环境准备与项目初始化先说环境。我假设你已经有基本的Node.js或Python开发环境并且有一个Google Cloud项目。如果你还没有去Google Cloud控制台建一个然后启用GKE API和Genkit相关的API。这一步没什么好省的该开的服务都要开。项目初始化我推荐用Genkit的CLI来做因为它会帮你生成一套比较规范的项目结构。命令大概是这样的npm install -g genkit-cli genkit init my-skill-project cd my-skill-project初始化完之后你会看到一个skills目录和一个agents目录。skills目录就是放各个skill定义的地方agents目录是放Agent配置的地方。这种分离的结构很好因为skill是可以跨Agent复用的你不应该把skill的逻辑写死在某个Agent里。接下来安装依赖。除了Genkit本身你还需要装一些用于验证和测试的库比如zod用于schema定义jest或vitest用于单元测试。这些不是必须的但强烈建议加上后面会省很多事。4.2 定义第一个skill从“查询订单状态”开始我拿一个最简单的例子来演示一个查询订单状态的skill。这个skill的输入是订单ID输出是订单状态和预计送达时间。虽然简单但麻雀虽小五脏俱全元数据、执行逻辑、依赖声明、验证逻辑都会涉及到。先定义schema。用zod写的话大概是这样import { z } from zod; export const OrderStatusInput z.object({ orderId: z.string().describe(订单的唯一标识符), }); export const OrderStatusOutput z.object({ status: z.enum([pending, shipped, delivered, cancelled]), estimatedDelivery: z.string().optional(), lastUpdated: z.string(), });然后写skill的定义。在Genkit里一个skill通常是一个对象包含name、description、inputSchema、outputSchema和一个execute函数。execute函数就是执行逻辑的入口。import { defineSkill } from genkit/skill; import { OrderStatusInput, OrderStatusOutput } from ./schemas; import { fetchOrderFromDB } from ../services/orderService; export const orderStatusSkill defineSkill({ name: queryOrderStatus, description: 根据订单ID查询订单的当前状态和预计送达时间。当用户询问订单进度时使用此技能。, inputSchema: OrderStatusInput, outputSchema: OrderStatusOutput, async execute(input) { // 前置校验 if (!input.orderId || input.orderId.length 6) { throw new Error(订单ID格式不正确); } // 主流程 const order await fetchOrderFromDB(input.orderId); if (!order) { throw new Error(未找到该订单); } // 后置校验 const result { status: order.status, estimatedDelivery: order.estimatedDelivery, lastUpdated: new Date().toISOString(), }; // 用schema验证输出 OrderStatusOutput.parse(result); return result; }, });这段代码里前置校验检查了订单ID的基本格式主流程从数据库拉数据后置校验用schema验证了输出。异常处理是通过抛错来实现的Agent捕获到错误后可以决定是重试还是转人工。注意事项execute函数里尽量不要做太重的操作。如果查询订单需要调用一个很慢的外部API最好加一个超时设置并且考虑用缓存。skill的执行时间直接影响Agent的响应速度太慢的skill会让整个Agent变得不可用。4.3 把skill注册到Agent并配置触发规则skill写好了接下来要把它注册到Agent上。在Genkit里Agent的配置通常是一个单独的文件你可以在里面列出这个Agent可以使用的所有skill。import { defineAgent } from genkit/agent; import { orderStatusSkill } from ../skills/orderStatus; export const customerServiceAgent defineAgent({ name: customerService, description: 处理客户咨询的Agent可以查询订单状态、处理退款申请等。, skills: [orderStatusSkill], // 其他配置... });注册完之后Agent在规划任务时就会把orderStatusSkill纳入考虑范围。但这里有一个关键点Agent怎么知道什么时候该用这个skill这就回到前面说的trigger_conditions。在Genkit里你可以通过description和skill的元数据来影响Agent的决策也可以显式地定义触发规则。我的经验是对于简单的skill把description写好就够了。对于复杂的skill或者多个skill功能有重叠的情况最好显式定义触发条件。比如你可以写“当用户输入包含‘订单’和‘状态’两个关键词时优先使用queryOrderStatus技能”。这种规则虽然看起来笨但在实际运行中能显著提高准确率。4.4 本地测试与调试技巧在部署到GKE之前一定要在本地把skill跑通。Genkit提供了一个开发服务器可以让你在本地模拟Agent的调用。启动命令大概是genkit start -- npm run dev然后你会看到一个本地URL打开后可以手动输入测试用例观察Agent的决策过程和skill的执行结果。这个界面对于调试非常有用因为你可以看到Agent为什么选择了某个skill以及skill返回了什么。我通常会准备一组测试用例覆盖正常情况、边界情况和异常情况。比如订单ID正常、订单ID不存在、订单ID格式错误、数据库连接失败等等。每个用例都跑一遍确认skill的行为符合预期。实操心得本地测试的时候把日志打详细一点。特别是skill的输入输出一定要打出来。很多时候问题不是出在skill逻辑本身而是出在Agent传给skill的参数不对。如果你能看到每次调用的实际参数定位问题会快很多。4.5 部署到GKE容器化与配置管理本地跑通之后就可以往GKE上部署了。部署的第一步是容器化。你需要写一个Dockerfile把Node.js应用打包成镜像。这里有一个坑不要把开发依赖打进生产镜像。用多阶段构建可以解决这个问题。FROM node:20-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build FROM node:20-alpine WORKDIR /app COPY --frombuilder /app/dist ./dist COPY --frombuilder /app/node_modules ./node_modules COPY package*.json ./ CMD [node, dist/index.js]镜像构建好之后推送到Google Cloud的容器仓库然后在GKE上创建一个Deployment。这里的关键是配置管理。skill可能依赖一些环境变量比如数据库连接串、API密钥等。这些不要硬编码在代码里也不要用明文写在Deployment的YAML里。用Kubernetes的Secret来管理敏感信息用ConfigMap来管理非敏感的配置。apiVersion: apps/v1 kind: Deployment metadata: name: skill-runtime spec: replicas: 2 selector: matchLabels: app: skill-runtime template: metadata: labels: app: skill-runtime spec: containers: - name: runtime image: gcr.io/my-project/skill-runtime:latest envFrom: - configMapRef: name: skill-config - secretRef: name: skill-secrets resources: requests: memory: 256Mi cpu: 250m limits: memory: 512Mi cpu: 500m资源限制这一块不要省。我见过太多因为没设limits导致一个skill把整个节点拖垮的案例。256Mi到512Mi的内存对于大多数skill来说够用了如果你的skill需要处理大文件或者做复杂计算再往上调。4.6 监控与日志上线之后怎么知道skill跑得好不好部署完成只是开始上线之后的监控才是重头戏。你需要关注几个指标skill的调用次数、成功率、平均执行时间、以及错误分布。这些指标可以帮助你快速发现异常。比如某个skill的成功率突然从99%掉到80%那肯定是出了问题可能是依赖的外部服务挂了也可能是输入数据格式变了。在GKE上你可以用Cloud Monitoring来采集这些指标用Cloud Logging来收集日志。我通常会在skill的execute函数里加一些结构化的日志比如console.log(JSON.stringify({ skill: queryOrderStatus, orderId: input.orderId, status: started, timestamp: Date.now(), }));执行完成后再打一条完成的日志带上耗时和结果状态。这样在Cloud Logging里就可以很方便地过滤和统计。注意事项日志里不要打敏感信息比如用户的完整订单详情、支付信息等。如果需要追踪用脱敏后的ID来代替。这不仅是合规要求也是保护用户隐私的基本操作。5. 常见问题与排查技巧实录5.1 Agent不调用skill或者调用了错误的skill这是最常见的问题没有之一。表现是Agent要么完全忽略某个skill要么在应该用A skill的时候用了B skill。排查思路分三步走。第一步检查skill的description和trigger_conditions。很多时候问题就出在这里描述写得太模糊Agent无法区分。你可以试着把description改得更具体加入更多的场景关键词。比如把“查询订单”改成“当用户提供订单ID并询问订单状态、物流进度或预计送达时间时使用此技能”。第二步检查Agent的prompt。Agent的决策很大程度上受系统prompt的影响。如果prompt里没有明确告诉Agent“你有这些技能可用”它可能根本不知道去调用。你可以在prompt里加一段“你可以使用以下技能来完成任务queryOrderStatus查询订单状态、applyRefund申请退款……”。把技能列表和简要说明写进去能显著提高调用准确率。第三步如果前两步都没问题那可能是模型本身的能力限制。不同的模型在工具调用上的表现差异很大。你可以试着换一个更强的模型或者调整temperature参数。temperature太高会导致决策随机性增加调低一点通常能让调用更稳定。5.2 skill执行超时或返回结果不稳定超时问题通常有两个原因依赖的外部服务太慢或者skill内部逻辑有性能瓶颈。排查的时候先看日志确认是哪一步耗时最长。如果是外部服务慢考虑加缓存或者设置更合理的超时时间。如果是内部逻辑慢看看有没有可以优化的地方比如减少不必要的循环、用更高效的数据结构等。结果不稳定则更隐蔽一些。可能的原因包括依赖的数据源在变化、模型生成的中间结果有随机性、或者并发调用导致了竞态条件。我的做法是给skill加上幂等性保证同样的输入应该得到同样的输出。如果做不到完全幂等至少要把不确定性控制在可接受的范围内并且在输出里标注哪些部分是可能变化的。5.3 部署到GKE后skill无法加载或报权限错误这个问题通常和配置有关。GKE上的Pod和本地环境最大的区别是Pod里的服务账号和权限是受控的。如果你的skill需要访问某个Google Cloud服务比如Cloud SQL或者Cloud Storage你需要确保Pod使用的Kubernetes Service Account绑定了正确的IAM角色。排查步骤先看Pod的日志确认报错信息是什么。如果是“permission denied”或者“403”那就是IAM权限问题。去Google Cloud控制台检查对应的Service Account有没有缺少角色。如果是“connection refused”或者“timeout”那可能是网络策略或者防火墙规则的问题检查VPC配置和NetworkPolicy。还有一个容易忽略的点是Secret的挂载。如果你用Secret来管理API密钥确认Secret已经正确创建并且Pod的envFrom或volumeMounts引用了正确的Secret名称。我遇到过好几次因为Secret名字拼错导致skill加载失败的情况排查了半天才发现是个低级错误。5.4 常见问题速查表问题现象可能原因排查方向解决建议Agent不调用skilldescription模糊、prompt未提及、模型能力不足检查skill元数据、Agent prompt、模型选择细化description、在prompt中列出技能、换更强模型调用错误的skill多个skill功能重叠、触发条件不明确对比skill的description和trigger_conditions显式定义触发规则、合并相似skillskill执行超时外部服务慢、内部逻辑性能差查看日志中的耗时分布加缓存、设超时、优化逻辑结果不稳定数据源变化、模型随机性、竞态条件对比多次执行的输入输出保证幂等性、固定随机种子、加锁GKE上加载失败IAM权限不足、Secret配置错误、网络策略查看Pod日志、检查Service Account和Secret补IAM角色、修正Secret引用、调整网络策略日志中缺少关键信息日志级别设置过高、未打结构化日志检查日志配置和代码中的日志语句调整日志级别、补充结构化日志5.5 几个我踩过的坑和对应的技巧第一个坑是skill的粒度问题。一开始我把skill写得太细一个skill只做一件事结果Agent需要调用十几个skill才能完成一个任务调用链太长出错概率大增。后来我调整了粒度把经常一起出现的操作合并成一个skill调用链缩短了稳定性明显提升。我的经验是一个skill最好对应一个“用户可感知的完整操作”而不是一个技术步骤。第二个坑是过度依赖模型生成。有些skill的逻辑里我让模型来生成中间结果比如“根据用户描述生成一个查询条件”。结果发现模型生成的查询条件经常不符合数据库的schema导致查询失败。后来我改成让模型生成结构化的JSON然后用代码校验和转换成功率从70%提升到了95%以上。能约束的就约束别让模型自由发挥。第三个坑是忽略冷启动。在GKE上如果Pod缩容到零下次请求来的时候需要冷启动skill的加载时间会很长。对于延迟敏感的场景我建议保持至少一个副本常驻或者用minReplicas来设置最小副本数。虽然会增加一点成本但用户体验会好很多。6. 技能生态的扩展思路从单点skill到技能市场6.1 skill的复用与组合策略当你写了几个skill之后很自然会想到复用。比如“查询订单状态”这个skill在客服Agent里能用在物流Agent里也能用。这时候你需要考虑的是怎么让skill跨Agent复用而不是每个Agent都复制一份。我的做法是把skill做成独立的包用npm或者私有registry来管理。每个skill有自己的版本号、依赖声明和测试用例。Agent通过依赖声明来引用skill而不是直接把代码拷过来。这样当skill更新时所有引用它的Agent都能受益而且可以通过版本号来控制升级节奏。组合方面我建议定义一些“复合skill”也就是内部调用其他skill的skill。比如“处理退货”这个复合skill内部会调用“查询订单”“判断退货资格”“生成退货单”“通知物流”这几个子skill。复合skill的好处是它把业务流程固化下来了Agent不需要自己去规划这些步骤只需要调用一个复合skill就能完成整个流程。这大大降低了Agent的决策复杂度。6.2 技能市场与发现机制热搜词里有“skills大全”“skills推荐”“skills下载平台”这些词说明大家对于现成skill的需求很旺盛。目前确实有一些平台在尝试做skill的分享和分发但整体还处于早期阶段。如果你要自己搭建一个内部的skill市场有几个关键点要注意。首先是发现机制。skill多了之后怎么让开发者快速找到需要的skill光靠名字搜索是不够的你需要有分类、标签、评分、使用量统计这些元数据。我通常会要求每个skill在注册时填写分类比如“订单管理”“客户服务”“数据分析”和标签这样搜索和推荐会准确很多。其次是质量把控。开放的skill市场很容易出现质量参差不齐的情况。我的建议是引入审核机制和测试覆盖率要求。一个skill要上架至少要有完整的单元测试覆盖率不低于80%并且要通过一组标准的集成测试。这样才能保证上架的skill是可靠的。最后是版本管理。skill的更新可能会破坏依赖它的Agent所以必须要有语义化版本控制。破坏性变更要升主版本号并且要提供迁移指南。Agent在引用skill时可以指定版本范围比如“^1.0.0”表示接受1.x的所有版本但不接受2.0。6.3 安全与权限skill不能是“万能钥匙”skill的权限管理是一个容易被忽视但极其重要的问题。一个skill如果权限过大比如可以访问所有数据库、可以调用所有API那一旦被恶意利用或者出现bug后果会很严重。我的原则是最小权限每个skill只拥有完成它任务所必需的最小权限。具体怎么做在GKE上你可以为不同的skill分配不同的Kubernetes Service Account每个Service Account只绑定必要的IAM角色。比如“查询订单”的skill只需要数据库的只读权限“申请退款”的skill需要数据库的写权限和支付网关的调用权限。这样即使某个skill被攻破影响范围也被限制在它的权限范围内。另外skill的输入输出也要做校验。输入要防止注入攻击输出要防止敏感信息泄露。我通常会在skill的入口和出口加一层校验逻辑入口检查输入是否符合schema并且没有恶意内容出口检查输出是否包含敏感字段比如完整的信用卡号、密码等如果有就脱敏或者拒绝返回。提示不要为了方便给skill开太大的权限。我见过一个团队为了省事给所有skill都绑定了项目级的Editor角色结果一个skill的bug导致整个项目的资源被误删。这种教训一次就够了。7. 我个人的一些实操体会写了这么多最后说几点我自己的真实感受。skills这个东西入门容易写好难。你花半个小时就能写出一个能跑的skill但要写出一个在生产环境稳定运行、能被多个Agent复用、出了问题能快速定位的skill需要花的心思远超你的预期。我最大的体会是skill的质量取决于你对业务的理解深度。如果你对业务流程本身就不清楚写出来的skill一定是漏洞百出的。所以在动手写skill之前先花时间把业务流程梳理清楚把每个步骤的输入输出、异常情况、边界条件都列出来。这份梳理的功夫比写代码本身重要得多。另一个体会是不要追求一步到位。我一开始总想写一个“完美”的skill把所有可能的情况都覆盖到。结果写了很久测试的时候发现很多情况根本不会发生而真正高频的场景反而没处理好。后来我改变了策略先写一个覆盖核心场景的v1版本上线跑一段时间根据实际日志和反馈再迭代。这种小步快跑的方式效率高很多。还有一点测试用例要跟着skill一起写。我见过太多人skill写完了才想起来补测试结果测试写得很敷衍根本起不到验证作用。我的习惯是写skill之前先把测试用例列出来包括正常情况、边界情况、异常情况。然后写skill的时候每完成一个逻辑分支就跑一遍对应的测试。这样写出来的skill质量有保证后续修改也不容易引入回归问题。最后如果你刚开始接触skills我建议从最简单的场景入手比如“查询天气”或者“发送通知”这种。先把整个流程跑通理解skill的元数据、执行逻辑、依赖声明、验证逻辑是怎么配合的。然后再逐步挑战更复杂的场景。skills的生态还在快速演进现在投入时间学习后面会越来越顺手。