
1. 从“skills”这个标题说起它到底指什么第一次看到“skills”这个标题很多人会以为是某个泛泛而谈的能力清单或者一份简历上的技能罗列。但结合热搜词里的 Google Cloud、Agent Skills、GKE、Genkit 这些关键词方向就非常明确了——这里说的 skills是围绕 AI Agent 构建的一套可插拔能力模块也就是让智能体真正“会做事”的那些具体技能单元。我在实际接触这套东西之前也走过一段弯路。最开始我以为 Agent 就是写一个很长的系统提示词把角色、任务、输出格式全塞进去然后调用大模型就完事了。结果做出来的东西只能聊天一旦让它去查数据库、调接口、生成文件、跑部署流程立刻就露馅。后来才明白提示词解决的是“怎么表达”而 skills 解决的是“怎么执行”。这两件事完全不在一个层面上。所谓 Agent Skills你可以把它理解成给智能体准备的“工具箱加操作手册”。一个 skill 通常包含三部分一段描述这个技能能干什么的元数据、一套指导模型如何调用它的指令、以及真正执行动作的代码或工具链。模型看到用户请求后先判断该用哪个 skill再按照 skill 里定义的流程去调用外部能力最后把结果组织成自然语言返回。整个过程里模型负责决策和编排skill 负责落地执行。这套机制解决的核心问题是让大模型从“只会说”变成“能动手”。以前你要做一个自动巡检 GKE 集群并生成报告的助手得写一大堆胶水代码把模型输出解析成结构化指令再手动路由到不同函数。现在把这些逻辑封装成一个个 skill模型自己就能根据上下文选择调用哪个组合起来完成复杂任务。对于做后端、做运维、做全栈的开发者来说这意味着你可以把精力放在业务逻辑本身而不是浪费在反复调教模型输出格式上。适合看这篇内容的人我大致分三类。第一类是有一定开发基础想把自己的服务接入 AI Agent 体系的工程师比如你已经在用 Google Cloud 跑服务想让它和 Genkit 配合起来做智能编排。第二类是对 Agent 架构感兴趣但还没动手实践过的技术爱好者你至少需要了解基本的 API 调用和命令行操作。第三类是做技术选型和方案评估的架构师你需要判断 skills 这套模式在你们团队现有技术栈里能不能落地、成本如何、维护起来麻不麻烦。如果你完全没写过代码也没接触过云服务那这篇内容可能会有点吃力建议先补一下基础再回来看。2. 整体设计思路为什么是“技能”而不是“大提示词”2.1 从单体提示词到模块化技能的演进逻辑早期做 Agent 应用主流做法是写一个超长的系统提示词把角色设定、任务说明、输出格式、边界条件全部塞进去。这种做法在任务简单时还能凑合一旦任务变复杂问题就集中爆发了。首先是提示词长度膨胀模型注意力被稀释关键指令容易被忽略。其次是维护困难改一个子任务的逻辑可能影响其他任务的输出。最后是无法复用你在 A 项目里写好的数据库查询逻辑到 B 项目里只能复制粘贴改一处就得同步改多处。Skills 的思路完全不同。它把每个独立能力拆成一个自包含的模块每个模块有自己的描述、指令和执行体。模型在运行时根据用户意图动态选择加载哪个 skill而不是一次性把所有指令都塞进上下文。这样做的好处非常直接上下文更干净模型决策更准确每个 skill 可以独立开发、测试、版本管理同一个 skill 可以在不同 Agent 之间共享复用。我打个比方。单体提示词就像一本厚厚的员工手册新员工入职第一天要全部读完但实际工作中只用得到其中几页。Skills 就像公司内部的知识库每个技能是一篇独立文档员工遇到具体问题时去查对应那篇就行。显然后者更高效也更符合实际工作方式。2.2 为什么选择 Google Cloud 与 Genkit 作为落地载体热搜词里出现了 Google Cloud、GKE、Genkit这不是偶然。Google Cloud 提供的是底层基础设施GKE 负责容器编排和运行环境Genkit 则是面向 AI 应用的开发框架。这三者组合起来刚好覆盖了 Agent Skills 从开发到部署的完整链路。Genkit 的定位很关键。它提供了一套标准化的方式来定义工具、编排流程、管理模型调用。你可以把每个 skill 写成一个 Genkit 的 tool然后用 Genkit 的 flow 把多个 tool 串起来。Genkit 会自动处理模型与工具之间的交互协议包括函数调用格式、参数校验、错误传递这些琐碎但容易出错的环节。没有这层框架你就得自己实现一套工具注册和调度机制工作量不小而且容易在边界情况上翻车。GKE 的价值在于运行环境。Agent Skills 里的执行体往往需要访问外部服务、读写数据库、调用内部 API这些操作对网络隔离、权限控制、弹性伸缩都有要求。GKE 提供的容器化运行环境让你可以把每个 skill 的执行体打包成独立容器按需扩缩容同时通过 Kubernetes 的 RBAC 和 Network Policy 控制访问权限。相比在本地或单台服务器上跑GKE 的方案在稳定性和安全性上高出一个量级。至于为什么不用其他云平台我的看法是如果你已经在用 Google Cloud 的生态比如 BigQuery、Cloud Run、Vertex AI那整套 skills 体系可以无缝对接省去大量适配工作。如果你是从零开始那选择哪个平台主要看团队熟悉度和成本预算技术原理是相通的。2.3 技能拆分粒度多细才算合适这是实操中最容易纠结的问题。拆得太粗一个 skill 干太多事模型选择时容易混淆维护起来也麻烦。拆得太细skill 数量爆炸模型每次决策要扫描的选项太多反而降低准确率。我的经验是遵循“单一职责加可组合”原则。每个 skill 只做一件事但这件事的边界要清晰到模型能准确判断什么时候该用它。比如“查询 GKE 集群节点状态”是一个合适的粒度“运维 GKE 集群”就太宽泛了“获取节点 CPU 使用率”又太细了因为通常你还需要内存、磁盘等信息才能做判断。另一个实用技巧是看调用频率和参数复杂度。如果一个操作几乎每次都要和其他操作一起出现那可以考虑合并成一个 skill。如果某个 skill 的参数超过五六个而且不同参数组合对应不同场景那可能需要拆成多个 skill每个接受更少的参数。3. 核心细节解析一个 Skill 到底由什么组成3.1 元数据层让模型知道“有这个技能”元数据是 skill 的身份证。它通常包括技能名称、功能描述、适用场景、输入输出格式说明。这部分内容会被注入到模型的上下文中让模型在决策时知道有哪些技能可用。名称要简短且语义明确。我见过有人把 skill 命名为doStuff或helper这种名字对模型来说毫无信息量等于没写。好的命名像queryGkeNodeStatus、generateDeploymentReport模型一看就知道这个技能是干什么的。描述部分要写清楚三件事这个技能解决什么问题、什么情况下应该使用它、调用后会产生什么效果。我通常会加一句“当用户询问……时使用此技能”给模型一个明确的触发条件。描述不要写太长两三句话足够太长了反而稀释关键信息。输入输出格式说明经常被忽略但非常重要。你需要告诉模型这个技能接受哪些参数、每个参数是什么类型、是否必填、取值范围是什么。如果输出是结构化的也要说明字段含义。这些信息直接影响模型能否正确构造调用参数。3.2 指令层告诉模型“怎么用这个技能”指令层是给模型看的操作指南。它描述的是调用这个技能的标准流程包括前置条件检查、参数准备、调用方式、结果处理。前置条件检查经常被跳过但实际运行中很多错误都源于条件不满足就强行调用。比如一个 skill 需要先获取集群凭证才能查询节点状态那指令里就要写明“调用前确认已通过认证”。模型看到这条指令后会在调用前先检查认证状态避免无效调用。参数准备部分要说明每个参数从哪里来。有些参数直接从用户输入提取有些需要从上下文推断有些需要先调用其他技能获取。把这些来源写清楚模型才能正确组装参数。结果处理部分要说明调用成功后如何解读返回数据以及调用失败时如何处理。比如返回的是 JSON 格式的节点列表指令里要说明如何提取关键字段、如何判断节点是否健康。失败处理要区分可重试错误和不可重试错误给出不同的应对策略。3.3 执行层真正干活的代码执行层是 skill 的实体通常是一个函数或一段脚本。它接收模型传来的参数执行具体操作返回结果。执行层的第一原则是幂等性。同一个请求调用多次结果应该一致不能产生副作用。比如“创建集群”这种操作如果模型因为重试机制调用了两次不应该创建出两个集群。实现幂等性的常见做法是使用唯一请求 ID服务端根据 ID 去重。第二原则是错误处理要完善。执行层抛出的异常要包含足够的信息让模型能判断是参数错误、权限不足、服务不可用还是其他问题。错误信息不要直接抛原始堆栈要转换成模型能理解的描述。比如“403 Forbidden”要转换成“当前凭证没有执行此操作的权限请检查 IAM 角色绑定”。第三原则是超时控制。外部调用一定要设超时避免模型等待过久。超时时间根据操作类型设定查询类操作通常 10 到 30 秒创建类操作可以放宽到几分钟。超时后要返回明确的超时提示让模型决定是否重试。3.4 技能间的依赖与编排单个 skill 能做的事有限真正复杂的任务需要多个 skill 协作完成。这时候编排逻辑就很重要。最简单的编排是串行调用A 完成后调用 BB 完成后调用 C。Genkit 的 flow 天然支持这种模式你只需要定义好每个步骤的输入输出框架会自动处理数据传递。复杂一点的是条件分支根据 A 的结果决定调用 B 还是 C。这需要在 flow 里写判断逻辑或者让模型根据 A 的返回自行决策。我的建议是能用代码判断的就不要交给模型因为代码判断更稳定、更可预测。再复杂的是并行调用B 和 C 互不依赖可以同时执行。这在需要聚合多个数据源时很有用比如同时查询节点状态和 Pod 状态最后合并成一份报告。并行调用要注意错误处理如果其中一个失败是整体失败还是部分成功继续需要提前定义好策略。4. 实操过程从零搭建一个可用的 Skill4.1 环境准备与依赖安装假设你已经在 Google Cloud 上有一个项目并且本地安装了 gcloud CLI 和 kubectl。第一步是启用必要的 APIgcloud services enable \ container.googleapis.com \ aiplatform.googleapis.com \ run.googleapis.com \ cloudbuild.googleapis.com这几个 API 分别对应 GKE、Vertex AI、Cloud Run 和 Cloud Build。Genkit 本身不依赖特定云服务但如果你要用 Google 的模型服务aiplatform 是必须的。接下来安装 Genkit 的 CLI 和 Node.js 依赖。我习惯用 Node.js 做 Genkit 开发因为生态最成熟npm install -g genkit-cli npm init -y npm install genkit genkit-ai/googleai如果你用 Python也有对应的 genkit 包安装方式类似。选哪个语言主要看团队技术栈功能上没有本质差异。4.2 定义第一个 Skill查询 GKE 节点状态我们从最简单的开始。这个 skill 接收集群名称和区域返回节点列表及状态。先定义元数据和指令import { defineTool } from genkit; export const queryGkeNodeStatus defineTool( { name: queryGkeNodeStatus, description: 查询指定 GKE 集群的节点状态包括节点名称、状态、CPU 和内存使用率。当用户询问集群节点健康状况时使用此技能。, inputSchema: { type: object, properties: { clusterName: { type: string, description: GKE 集群名称 }, location: { type: string, description: 集群所在区域或可用区 }, }, required: [clusterName, location], }, outputSchema: { type: object, properties: { nodes: { type: array, items: { type: object, properties: { name: { type: string }, status: { type: string }, cpuUsage: { type: string }, memoryUsage: { type: string }, }, }, }, }, }, }, async (input) { // 执行层逻辑 } );执行层我用 gcloud 命令获取节点信息然后解析输出async (input) { const { clusterName, location } input; const { execSync } require(child_process); try { const result execSync( gcloud container clusters describe ${clusterName} --location ${location} --format json, { timeout: 30000, encoding: utf-8 } ); const cluster JSON.parse(result); const nodes (cluster.nodePools || []).flatMap(pool (pool.instanceGroupUrls || []).map((url, idx) ({ name: ${pool.name}-node-${idx}, status: pool.status || UNKNOWN, cpuUsage: N/A, memoryUsage: N/A, })) ); return { nodes }; } catch (error) { if (error.message.includes(not found)) { throw new Error(集群 ${clusterName} 在 ${location} 未找到请检查名称和区域是否正确); } if (error.message.includes(permission)) { throw new Error(当前账号没有查询集群的权限请确认已绑定 container.clusters.get 角色); } throw new Error(查询集群失败${error.message}); } }这里有几个细节值得注意。超时设了 30 秒因为 gcloud 命令偶尔会慢。错误处理区分了“未找到”和“权限不足”两种情况分别给出可操作的提示。节点信息从 nodePools 里提取实际生产环境你可能需要调用 Kubernetes API 获取更详细的资源使用率但作为示例这样已经够用。4.3 注册 Skill 并接入模型定义好 skill 后需要在 Genkit 应用里注册它并配置模型import { genkit } from genkit; import { googleAI } from genkit-ai/googleai; import { queryGkeNodeStatus } from ./skills/queryGkeNodeStatus; const ai genkit({ plugins: [googleAI()], model: googleai/gemini-2.0-flash, }); ai.defineFlow( { name: gkeAssistant, inputSchema: { type: string }, outputSchema: { type: string }, }, async (userInput) { const response await ai.generate({ prompt: userInput, tools: [queryGkeNodeStatus], }); return response.text; } );这段代码做了三件事初始化 Genkit 并指定模型、注册 skill 作为可用工具、定义一个 flow 接收用户输入并返回模型响应。模型在生成回复时如果判断需要查询节点状态会自动调用 queryGkeNodeStatus拿到结果后再组织语言返回。4.4 本地测试与调试启动 Genkit 开发服务器genkit start -- npx tsx src/index.ts这会打开一个本地调试界面你可以直接输入问题测试。我通常会准备几个测试用例“帮我看看 my-cluster 在 us-central1 的节点状态”“my-cluster 的节点都健康吗”“查询一下 us-central1 区域所有集群的节点”前两个应该能正确触发 skill第三个可能因为参数不完整而失败这正好用来测试错误处理是否到位。调试时重点关注模型是否在正确的时机调用了 skill。如果模型没有调用通常是描述写得不够明确或者用户输入和描述之间的语义差距太大。这时候需要调整描述增加更多触发词和场景说明。4.5 部署到 GKE 并配置权限本地测试通过后就可以部署到 GKE 了。先把应用打包成容器FROM node:20-slim WORKDIR /app COPY package*.json ./ RUN npm ci --production COPY . . RUN npm run build CMD [node, dist/index.js]构建并推送到 Artifact Registrygcloud builds submit --tag us-central1-docker.pkg.dev/PROJECT_ID/skills-repo/gke-assistant:latest然后创建 GKE 部署apiVersion: apps/v1 kind: Deployment metadata: name: gke-assistant spec: replicas: 2 selector: matchLabels: app: gke-assistant template: metadata: labels: app: gke-assistant spec: serviceAccountName: gke-assistant-sa containers: - name: app image: us-central1-docker.pkg.dev/PROJECT_ID/skills-repo/gke-assistant:latest ports: - containerPort: 3000 resources: requests: memory: 256Mi cpu: 250m limits: memory: 512Mi cpu: 500m关键点是 serviceAccountName。你需要创建一个 Kubernetes Service Account并绑定 Google Cloud IAM 角色让 Pod 里的应用有权限调用 GKE API。具体做法是用 Workload Identity 把 KSA 和 GSA 关联起来然后给 GSA 授予 container.clusters.get 权限。这一步不做的话部署上去的应用调用 gcloud 命令会直接报权限错误。5. 常见问题与排查技巧实录5.1 模型不调用 Skill 怎么办这是最高频的问题。模型收到用户请求后直接用自己的知识回答完全没有触发 skill 调用。原因通常有三个描述不够明确、参数 schema 有问题、模型能力不足。排查顺序是这样的。先看描述把用户可能的各种问法都列出来确保描述里覆盖了这些场景的关键词。比如用户可能说“节点怎么样”“机器健康吗”“集群状态”描述里就要包含“节点状态”“健康状况”“集群”这些词。再看参数 schema。如果必填参数太多模型可能因为无法确定所有参数而放弃调用。这时候可以把部分参数设为可选让模型先调用再补充或者提供默认值。最后考虑换模型。不同模型对工具调用的支持程度差异很大。Gemini 2.0 Flash 在工具调用上表现不错但如果你的场景特别复杂可能需要上更强的模型。实测下来模型能力对工具调用成功率的影响能到 30% 以上。5.2 参数提取错误怎么修模型调用 skill 时传错了参数比如把集群名称和区域搞反了或者漏传了必填参数。这种问题通常源于参数描述不够清晰。我的做法是在参数描述里加示例。比如 clusterName 的描述写成“GKE 集群名称例如 my-production-cluster”location 写成“集群所在区域例如 us-central1 或 asia-east1”。有了具体示例模型提取参数时准确率明显提升。另一个技巧是在指令层加参数校验步骤。让模型在调用前先确认参数是否完整、格式是否正确。这相当于加了一道人工检查虽然多了一步但能大幅降低错误率。5.3 执行超时与重试策略外部调用超时是另一个常见问题。gcloud 命令、API 请求、数据库查询都可能超时。如果 skill 没有超时控制模型会一直等待用户体验很差。我的策略是分层设置超时。skill 执行层设一个总超时比如 30 秒。内部每个外部调用再设更细的超时比如 API 请求 10 秒数据库查询 5 秒。这样即使某个环节慢也不会拖垮整个 skill。重试方面只对幂等操作开启自动重试。查询类操作可以重试创建类操作要谨慎。重试次数不要超过 3 次间隔用指数退避避免给下游服务造成压力。如果重试后仍然失败返回明确的错误信息让模型决定是否告知用户稍后再试。5.4 权限与网络隔离的坑部署到 GKE 后最常见的错误是权限不足。Pod 里的应用调用 Google Cloud API 时用的是节点默认服务账号这个账号通常权限很大但不一定包含你需要的特定权限。正确做法是创建专用 GSA按最小权限原则授予必要角色然后通过 Workload Identity 绑定到 KSA。网络隔离方面如果 GKE 集群启用了私有节点Pod 没有公网 IP调用外部 API 需要配置 Cloud NAT 或者 Private Google Access。这个坑我在第一次部署时踩过本地测试一切正常上集群后所有外部调用都超时排查了半天才发现是网络出口的问题。5.5 常见问题速查表问题现象可能原因排查方法解决方案模型不调用 skill描述不明确检查描述是否覆盖用户问法补充触发词和场景说明参数提取错误参数描述模糊查看模型实际传入的参数增加参数示例和格式说明执行超时外部调用过慢查看各环节耗时分层设置超时优化慢查询权限不足服务账号角色缺失查看错误信息中的权限名绑定对应 IAM 角色网络不通私有集群无出口检查 Pod 网络配置配置 Cloud NAT 或 Private Google Access结果格式错误输出 schema 不匹配对比实际输出和 schema调整 schema 或增加后处理6. 进阶技巧让 Skills 更好用的几个实践6.1 技能组合与流程编排单个 skill 用起来简单但真正体现价值的是多个 skill 组合完成复杂任务。比如一个“集群健康巡检”流程可以串起查询节点状态、查询 Pod 状态、检查资源配额、生成报告四个 skill。Genkit 的 flow 支持这种编排。你定义一个主 flow在里面依次调用各个 skill把前一个的输出作为后一个的输入。模型在这个过程中扮演的是决策者角色判断是否需要执行整个流程以及如何处理中间结果。我建议把常用的组合固化成 flow而不是每次都让模型临时决定调用顺序。固化流程更稳定也更容易测试和优化。模型只在流程内部做局部决策比如根据节点状态判断是否需要进一步查询 Pod。6.2 技能版本管理与灰度发布生产环境里 skill 会不断迭代新版本可能引入不兼容的变更。直接全量替换风险太大需要版本管理和灰度发布机制。我的做法是给每个 skill 加版本号比如 queryGkeNodeStatus_v1、queryGkeNodeStatus_v2。新版本上线后先让一小部分流量走新版本观察错误率和延迟指标。如果一切正常再逐步扩大流量比例直到全量切换。Genkit 本身不直接提供灰度能力但你可以通过部署多个 flow 版本在上层用负载均衡或特性开关来控制流量分配。这需要一些额外的工程投入但对于核心 skill 来说是值得的。6.3 技能的可观测性建设Skill 上线后你需要知道它被调用了多少次、成功率多少、平均耗时多少、哪些参数组合最容易出错。这些数据是优化的依据。基础的做法是在 skill 执行层加日志记录每次调用的输入、输出、耗时、错误信息。日志格式要结构化方便后续用 BigQuery 或 Cloud Logging 做分析。进阶做法是接入 OpenTelemetry把 skill 调用作为 span 上报和整个请求链路关联起来。这样你能看到一次用户请求触发了哪些 skill、每个 skill 耗时多少、瓶颈在哪里。Genkit 对 OpenTelemetry 有内置支持配置起来不算复杂。6.4 安全边界与输入校验Skill 执行层直接操作外部系统安全边界必须清晰。我的原则是永远不信任模型传来的参数所有输入都要校验。校验包括类型检查、范围检查、格式检查。比如集群名称只允许字母数字和连字符区域必须在预定义的列表里参数长度不能超过限制。校验不通过直接返回错误不要尝试修复或猜测。另一个安全措施是限制 skill 的操作范围。查询类 skill 只读不写创建类 skill 限制可创建的资源类型和数量。敏感操作加二次确认比如删除集群前要求模型先调用一个确认 skill拿到确认令牌后才能执行删除。7. 我个人在实际操作中的体会这套 skills 体系我用下来最大的感受是它把 AI Agent 从“演示品”变成了“生产力工具”。以前做 demo 很惊艳一上生产就各种问题。现在有了标准化的 skill 定义、执行、编排机制至少工程上的坑少了一大半。但我也要提醒一句skills 不是银弹。它解决的是执行层面的问题决策层面的问题依然存在。模型选错 skill、传错参数、误解结果这些情况仍然会发生。所以生产环境里一定要有兜底机制关键操作要有人工确认环节不能完全放手让模型自己跑。另外skill 的维护成本不要低估。每个 skill 都需要测试、监控、版本管理、权限配置数量多了之后管理复杂度是指数级上升的。我的建议是从最核心的两三个 skill 开始跑通整个链路后再逐步扩展不要一上来就铺开做几十个。最后分享一个小技巧给每个 skill 写一个“负面清单”明确列出这个 skill 不做什么。比如查询节点状态的 skill负面清单里写“不负责修改节点配置、不负责重启节点、不负责调整资源配额”。这个清单会注入到模型上下文里帮助模型更准确地判断边界减少误用。实测下来加了负面清单后模型误调用率能降低不少。