ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

AI Agent Skills实战:基于Google Cloud、GKE与Genkit构建可复用技能模块

2026/10/7 7:46:50 拓冰建站 浏览量
AI Agent Skills实战:基于Google Cloud、GKE与Genkit构建可复用技能模块 1. 从“skills”这个标题说起它到底指什么第一次看到“skills”这个标题很多人会以为是某个泛泛而谈的能力清单或者一份简历上的技能罗列。但结合热搜词里的 Agent Skills、Google Cloud、GKE、Genkit 这些关键词方向就非常明确了——这里说的 skills是围绕 AI Agent 构建的一套可复用能力模块也就是让智能体真正“会做事”的那些封装好的技能单元。我在实际接触这套东西之前也走过一段弯路。最开始我以为 Agent 就是写一段提示词把角色设定好把任务描述清楚它就能自己跑起来。结果真到落地的时候发现提示词只能解决“说什么”解决不了“怎么做”。比如你要让一个 Agent 去查数据库、调接口、生成报告、再把结果写回某个存储光靠提示词是撑不起来的。这时候 skills 就登场了。skills 的本质是把一个具体的、可复用的操作能力封装成 Agent 可以识别、可以调用、可以组合的模块。它有点像给 Agent 准备的“工具箱”每个 skill 就是一把螺丝刀或者一个扳手。Agent 拿到任务之后自己判断该用哪个工具、按什么顺序用、用完怎么把结果串起来。这个思路一旦跑通Agent 的能力边界就从“聊天”扩展到了“干活”。这套东西适合谁来参考我的判断是三类人第一类是已经在做 AI 应用开发、想让自己的产品从“能对话”升级到“能执行”的工程师第二类是在云平台上做部署和运维、需要把 AI 能力接进现有系统的架构师第三类是对 Agent 感兴趣、想自己动手搭一个能跑通闭环的爱好者。不管你是哪一类只要你想让 AI 真正替你完成一串有依赖关系的操作skills 这套机制就值得花时间吃透。接下来我会从整体设计思路、核心细节、实操过程、常见问题几个层面把这套东西拆开讲清楚。里面会涉及 Google Cloud、GKE、Genkit 这些具体工具的选择理由和配置方式也会分享一些我在实际搭建过程中踩过的坑和总结出来的技巧。2. 整体设计与思路拆解为什么是 skills 而不是别的方案2.1 从“单体提示词”到“技能模块化”的演进逻辑早期做 Agent大家习惯把所有指令塞进一个巨大的系统提示词里。任务简单的时候没问题一旦任务变复杂提示词就会膨胀到几千甚至上万字维护起来非常痛苦。改一个环节可能影响其他环节加一个新功能得重新梳理整个提示词的结构。更麻烦的是这种单体提示词很难复用——A 项目里写好的逻辑搬到 B 项目基本要重写。skills 的思路正好相反。它把每个独立的能力拆出来单独定义输入、输出、执行逻辑和依赖关系。Agent 在运行时根据任务需要动态加载和调用这些 skill。这样做的好处有几个一是可复用一个查天气的 skill 可以在多个 Agent 里直接用二是可测试每个 skill 可以单独验证不用把整个 Agent 跑起来才能测三是可组合复杂任务可以拆成多个 skill 的编排像搭积木一样拼起来。我自己的体会是这种模块化带来的最大收益不是开发效率而是调试效率。以前 Agent 出错你得从头到尾排查提示词很难定位是哪句话导致的问题。现在每个 skill 有明确的边界出错的时候直接看是哪个 skill 的输入不对、还是输出格式不对、还是执行超时排查路径清晰很多。2.2 为什么选 Google Cloud GKE Genkit 这套组合热搜词里出现了 Google Cloud、GKE、Genkit这不是偶然。这套组合在当前 Agent 开发场景里确实有它的合理性。Google Cloud 提供的是底层基础设施包括计算、存储、网络、鉴权这些。GKE 是 Google Kubernetes Engine负责容器编排。为什么 Agent 需要容器编排因为一个稍微像样的 Agent 系统往往不是单个服务而是多个 skill 服务、一个调度服务、一个状态管理服务、可能还有缓存和消息队列。这些服务需要部署、扩缩容、健康检查、滚动更新Kubernetes 在这方面是成熟方案。Genkit 是 Google 推出的 AI 应用开发框架它的定位是帮开发者把 AI 能力接进应用里。它提供了模型调用、提示词管理、工具调用、流程编排这些基础能力。用 Genkit 来写 skill好处是它天然支持工具调用tool calling的模式和 skills 的思路非常契合。你可以把一个 skill 定义成一个 Genkit 的 tool然后让模型在需要的时候自动调用。这套组合的逻辑是Genkit 负责 skill 的定义和编排GKE 负责 skill 的部署和运行Google Cloud 提供底层的算力和服务。三层各司其职整体比较清晰。2.3 方案选型时的几个关键取舍在实际选型的时候有几个点需要想清楚。第一个取舍是skill 的粒度怎么定。粒度太粗一个 skill 干太多事复用性就差粒度太细skill 数量爆炸编排复杂度上升。我的经验是一个 skill 最好对应一个“原子操作”比如“查询用户订单”“发送邮件”“生成 PDF”而不是“处理用户请求”这种模糊的复合操作。第二个取舍是skill 的执行是同步还是异步。同步调用简单直接但遇到耗时操作会阻塞异步调用灵活但需要额外的状态管理。我一般建议快速操作走同步超过几秒的操作走异步并且把任务 ID 返回给调用方让调用方轮询或者等回调。第三个取舍是skill 的鉴权和隔离怎么做。不同 skill 可能需要访问不同的资源权限不能一刀切。在 GKE 里可以用 Service Account 配合 RBAC 来做细粒度控制每个 skill 服务用独立的 Service Account只授予它需要的权限。3. 核心细节解析与实操要点skill 的定义、注册与调用3.1 一个 skill 的最小结构长什么样一个规范的 skill至少包含这几个部分名称、描述、输入参数定义、输出格式定义、执行逻辑、错误处理。名称和描述是给 Agent 看的Agent 靠这些信息判断该不该调用这个 skill。输入输出定义是给编排层看的用来做参数校验和结果传递。执行逻辑是实际干活的代码。错误处理决定 skill 失败时怎么反馈。用 Genkit 来写的话一个 skill 大概是这样定义的import { genkit, z } from genkit; import { googleAI } from genkit-ai/googleai; const ai genkit({ plugins: [googleAI()], model: googleai/gemini-2.0-flash, }); export const queryOrderSkill ai.defineTool( { name: queryOrder, description: 根据订单号查询订单的详细信息包括状态、金额、创建时间, inputSchema: z.object({ orderId: z.string().describe(订单号格式为 ORD 开头加 12 位数字), }), outputSchema: z.object({ orderId: z.string(), status: z.string(), amount: z.number(), createdAt: z.string(), }), }, async (input) { // 实际查询逻辑 const order await fetchOrderFromDB(input.orderId); if (!order) { throw new Error(订单 ${input.orderId} 不存在); } return { orderId: order.id, status: order.status, amount: order.amount, createdAt: order.created_at, }; } );这段代码里name和description非常关键。Agent 在决定调用哪个 skill 的时候主要依据就是这两个字段。描述写得越清楚Agent 判断越准确。我见过很多 skill 调用失败根本原因就是描述太模糊Agent 不知道该在什么场景下用它。3.2 skill 的注册与发现机制定义好 skill 之后需要把它注册到 Agent 可以访问的地方。Genkit 的做法是把 skill 作为 tool 传给模型模型在生成回复的时候如果判断需要调用某个 tool就会输出一个 tool call 请求框架拦截这个请求执行对应的 skill再把结果喂回模型。在 GKE 上部署的时候我通常会把一组相关的 skill 打包成一个服务通过 HTTP 或者 gRPC 暴露出去。然后有一个统一的 skill registry 服务记录所有可用 skill 的地址和元信息。Agent 启动的时候从 registry 拉取 skill 列表运行时根据任务需要调用对应的 skill 服务。这里有个细节值得注意skill 的发现不一定要全量加载。如果 skill 数量很多全量加载会让模型的上下文变得很长影响判断准确率。更好的做法是按需加载比如根据当前任务类型只加载相关的 skill 子集。这个可以通过给 skill 打标签、按标签过滤来实现。3.3 参数校验与错误处理的实操要点skill 的输入参数校验我建议用 schema 来做不要靠人工判断。Genkit 集成了 Zod可以直接用 Zod 定义输入输出的结构。这样做的好处是参数不对的时候框架会自动拦截不会让错误参数进入执行逻辑。错误处理方面有几个原则。第一skill 内部要捕获可预期的异常比如网络超时、资源不存在转换成结构化的错误信息返回。第二不可预期的异常要记录日志方便排查。第三错误信息要足够具体让 Agent 或者上层编排逻辑知道该怎么处理。比如“订单不存在”和“数据库连接失败”是两种完全不同的错误前者可能让 Agent 换个订单号重试后者可能需要触发告警。注意skill 的错误信息不要直接暴露给最终用户里面可能包含内部实现细节。建议在编排层做一层错误转换把技术错误转成用户能理解的提示。4. 实操过程与核心环节实现从零搭一个可用的 skill 系统4.1 环境准备与依赖安装先说一下基础环境。我用的 Node.js 版本是 20 LTSGenkit 对 Node 版本有要求太老的版本会报错。安装 Genkit 和相关依赖npm install genkit genkit-ai/googleai genkit-ai/express zod如果要用 Google Cloud 的其他服务比如 Cloud SQL、Cloud Storage还需要装对应的客户端库npm install google-cloud/sql google-cloud/storageGKE 那边需要提前准备好集群。如果只是本地开发测试可以用 minikube 或者 kind 起一个本地集群不用一上来就买云资源。等 skill 逻辑跑通了再往真实集群上部署。4.2 定义第一个 skill 并本地验证我建议从最简单的 skill 开始比如一个“获取当前时间”的 skill。别看它简单它能帮你把整条链路跑通定义、注册、调用、返回结果。export const getCurrentTimeSkill ai.defineTool( { name: getCurrentTime, description: 获取当前服务器时间返回 ISO 格式字符串, inputSchema: z.object({}), outputSchema: z.object({ time: z.string(), }), }, async () { return { time: new Date().toISOString() }; } );定义好之后写一个简单的测试脚本让模型调用这个 skillconst response await ai.generate({ prompt: 现在几点了, tools: [getCurrentTimeSkill], }); console.log(response.text);如果模型正确调用了 skill 并返回了时间说明基础链路是通的。这一步看起来简单但能帮你提前发现配置问题比如 API key 没设对、模型名称写错、网络不通等等。4.3 把 skill 部署到 GKE 的完整流程本地验证通过之后就可以往 GKE 上部署了。流程大致是写 Dockerfile、构建镜像、推送到镜像仓库、写 Kubernetes 部署文件、应用部署、验证服务。Dockerfile 大概长这样FROM node:20-slim WORKDIR /app COPY package*.json ./ RUN npm ci --onlyproduction COPY . . EXPOSE 8080 CMD [node, server.js]Kubernetes 部署文件里有几个地方需要特别注意。一是资源限制skill 服务通常不需要太多 CPU 和内存但要根据实际负载调整。二是健康检查要配置 liveness 和 readiness 探针否则服务假死的时候 Kubernetes 不会自动重启。三是环境变量API key 这类敏感信息不要写进镜像用 Secret 挂载。apiVersion: apps/v1 kind: Deployment metadata: name: skill-service spec: replicas: 2 selector: matchLabels: app: skill-service template: metadata: labels: app: skill-service spec: containers: - name: skill-service image: gcr.io/your-project/skill-service:latest ports: - containerPort: 8080 resources: requests: memory: 256Mi cpu: 250m limits: memory: 512Mi cpu: 500m livenessProbe: httpGet: path: /health port: 8080 initialDelaySeconds: 10 periodSeconds: 30 readinessProbe: httpGet: path: /ready port: 8080 initialDelaySeconds: 5 periodSeconds: 10 env: - name: GOOGLE_API_KEY valueFrom: secretKeyRef: name: api-secrets key: google-api-key部署命令kubectl apply -f deployment.yaml kubectl get pods -l appskill-service kubectl logs -f pod-name4.4 多 skill 编排的实操示例单个 skill 跑通之后真正的价值在于多 skill 编排。比如一个“处理退款申请”的任务可能需要依次调用查询订单 skill、验证退款资格 skill、计算退款金额 skill、发起退款 skill、发送通知 skill。在 Genkit 里可以用 flow 来编排export const refundFlow ai.defineFlow( { name: refundFlow, inputSchema: z.object({ orderId: z.string() }), outputSchema: z.object({ success: z.boolean(), message: z.string() }), }, async (input) { const order await queryOrderSkill.run({ orderId: input.orderId }); const eligible await checkRefundEligibilitySkill.run({ order }); if (!eligible.canRefund) { return { success: false, message: eligible.reason }; } const amount await calculateRefundSkill.run({ order }); const result await initiateRefundSkill.run({ orderId: input.orderId, amount }); await sendNotificationSkill.run({ orderId: input.orderId, status: refunded }); return { success: true, message: 退款 ${amount} 元已发起 }; } );这种编排方式的好处是每个步骤的输入输出都是明确的出错的时候能精确定位到是哪一步的问题。而且每个 skill 可以独立测试不用每次都跑完整流程。5. 常见问题与排查技巧实录5.1 skill 调用失败的高频原因速查问题现象可能原因排查方法解决方式Agent 不调用 skillskill 描述不清晰检查 description 是否说明了使用场景补充描述明确触发条件调用参数格式错误schema 定义与实际不符打印实际传入参数修正 schema 或调用方skill 执行超时内部逻辑耗时过长加日志看卡在哪一步优化逻辑或改异步返回结果解析失败输出格式与 schema 不匹配对比实际输出和 schema修正输出或 schema权限不足Service Account 权限不够查看 GKE 事件日志补充 RBAC 权限服务无法访问网络策略或端口配置错误检查 Service 和 Ingress修正网络配置5.2 几个我踩过的坑和对应的解法第一个坑是 skill 描述写得太技术化。我一开始写描述的时候习惯用“调用 XX 接口返回 XX 数据”这种表述。结果 Agent 经常不调用因为它不理解这个 skill 在什么业务场景下有用。后来改成“当用户询问订单状态时使用”调用准确率明显提升。描述要站在 Agent 的角度写告诉它“什么时候用”而不是“这个 skill 做了什么”。第二个坑是 skill 之间共享状态。我一开始想让多个 skill 共享一个数据库连接池结果发现 GKE 里 Pod 是分布式的每个 Pod 有自己的连接池共享不了。后来改成每个 skill 服务独立管理自己的连接通过外部存储来共享状态。这个坑的本质是不要把单机思维带到分布式环境里。第三个坑是错误信息太笼统。早期我的 skill 出错都返回“操作失败”Agent 拿到这个信息完全不知道该怎么办。后来改成返回具体的错误码和描述比如“ORDER_NOT_FOUND”“INSUFFICIENT_BALANCE”Agent 就能根据错误类型决定是重试、换参数、还是上报。错误信息是 Agent 做决策的重要依据不能敷衍。5.3 性能优化的几个实用技巧skill 系统的性能瓶颈通常不在计算而在网络往返和模型调用。优化方向有几个。一是减少不必要的 skill 调用。有些 skill 的结果可以缓存比如配置类、字典类的查询没必要每次都调。在 skill 内部加一层缓存能显著降低延迟。二是并行化独立的 skill。如果两个 skill 之间没有依赖关系可以并行调用而不是串行等待。Genkit 的 flow 支持并行执行用Promise.all就能实现。三是控制 skill 返回的数据量。有些 skill 返回一大堆字段但 Agent 实际只用其中几个。返回数据太大会占用上下文窗口影响模型判断。建议只返回必要字段或者提供分页机制。四是合理设置超时。每个 skill 调用都要设超时避免一个慢 skill 拖垮整个流程。超时时间根据 skill 的实际耗时来定一般设成 P99 耗时的 1.5 到 2 倍。6. skill 系统的扩展与维护经验6.1 skill 版本管理与灰度发布skill 一旦上线就会被多个 Agent 或者流程依赖。直接改线上 skill 风险很大可能影响正在运行的任务。我的做法是给 skill 加版本号新版本先灰度发布观察一段时间没问题再全量。在 GKE 里可以用两个 Deployment 分别跑新旧版本通过 Service 的标签选择器控制流量比例。或者用 Istio 这类服务网格做更精细的流量切分。关键是skill 的接口要保持向后兼容不能因为加了个参数就让老调用方挂掉。6.2 监控与告警的配置要点skill 系统跑起来之后必须要有监控。我关注几个核心指标调用次数、成功率、P50/P95/P99 延迟、错误分布。这些指标可以用 Google Cloud 的 Operations Suite 来采集和展示。告警方面我设了两条线一是成功率低于 95% 持续 5 分钟就告警二是 P99 延迟超过阈值持续 10 分钟就告警。告警不要设得太敏感否则会被噪音淹没也不要太迟钝否则出了问题半天才发现。日志方面每个 skill 调用都要记录调用时间、输入参数脱敏后、输出结果脱敏后、耗时、是否成功。这些日志在排查问题的时候非常有用。但要注意日志里不要记录敏感信息比如用户密码、支付凭证。6.3 skill 复用与组合的进阶思路当 skill 积累到一定数量之后可以考虑做 skill 的组合封装。比如把“查询订单 验证资格 计算金额”这三个 skill 组合成一个“退款预检”skill对外只暴露一个接口。这样上层编排会更简洁但底层还是复用了原有的原子 skill。另一个思路是让 Agent 自己组合 skill。给 Agent 一批原子 skill让它根据任务目标自己决定调用顺序。这种方式灵活度高但可控性差适合探索性任务。对于流程固定的业务场景还是用预定义的 flow 更稳妥。我在实际项目里的做法是混合使用核心业务流程用预定义 flow保证稳定性和可预测性辅助性的、探索性的任务让 Agent 自由组合 skill发挥灵活性。两者结合既能保证主干流程可靠又能应对长尾需求。6.4 安全与权限的实操建议skill 系统涉及多个服务之间的调用安全不能忽视。几个基本要求服务间通信用 mTLS不要裸奔每个 skill 服务用独立的 Service Account权限最小化敏感配置用 Secret 管理不要硬编码对外暴露的接口要有鉴权和限流。在 GKE 里可以用 Workload Identity 把 Kubernetes 的 Service Account 和 Google Cloud 的 IAM 绑定这样 Pod 访问云资源的时候不用管理密钥文件安全性更高。网络策略方面用 NetworkPolicy 限制 Pod 之间的访问只允许必要的通信。提示skill 的输入参数里如果包含用户可控的内容一定要做校验和转义防止注入类问题。尤其是拼接 SQL、调用外部命令的场景要格外小心。7. 我对这套东西的真实体会折腾了这么久我最大的感受是skills 这套机制的价值不在于技术有多新而在于它把 Agent 的开发从“写提示词”变成了“搭系统”。提示词是模糊的、难以测试的、难以复用的skill 是明确的、可测试的、可复用的。这个转变让 Agent 从玩具变成了工具。另一个体会是skill 的设计比实现更重要。我见过太多人花大量时间写 skill 的执行逻辑却忽略了 skill 的描述、输入输出定义、错误处理。结果 skill 本身能跑但 Agent 不会用、用不对、出错不知道怎么处理。skill 是给 Agent 用的不是给人用的设计的时候要站在 Agent 的角度想问题。最后分享一个小技巧如果你刚开始接触这套东西不要一上来就搞复杂的多 skill 编排。先写一个最简单的 skill把定义、注册、调用、返回这条链路跑通。然后再加第二个、第三个逐步体会 skill 之间怎么协作。这个过程比看十篇文档都管用。