news 2026/10/6 4:21:54

Agent Skills 实战:用 Genkit 和 Gemini 在 GKE 上构建可维护的 AI Agent 能力单元

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Agent Skills 实战:用 Genkit 和 Gemini 在 GKE 上构建可维护的 AI Agent 能力单元

1. 从"skills"这个标题说起:Agent Skills 到底在解决什么问题

第一次看到"skills"这个标题,很多人会以为是某个技能树、能力清单或者培训课程。但结合热搜词里的 Agent Skills、Google Cloud、GKE、Genkit、Gemini 来看,这里的 skills 指向的是一个更具体的东西:给 AI Agent 装配可复用、可组合、可独立部署的能力单元。换句话说,它不是教人怎么用 AI,而是教开发者怎么把"一个 Agent 能干什么"这件事拆成一块块可以插拔的积木。

我在实际接触这类项目时最大的感受是:大部分人做 Agent 的第一反应是写一个巨大的 prompt,把所有能力塞进一段系统提示里,然后祈祷模型每次都能正确调用。这种做法在 demo 阶段没问题,一旦要上线、要多人协作、要迭代,就会迅速崩掉。Agent Skills 这套思路的核心价值,就是把这个"巨型 prompt"拆解成一个个独立的 skill,每个 skill 有自己的描述、输入输出契约、执行逻辑,Agent 在运行时根据任务动态选择调用哪个 skill。

这个项目适合谁看?三类人最需要:第一类是正在用 Gemini 或类似大模型做 Agent 应用、但被 prompt 维护成本折磨的开发者;第二类是想把 Agent 部署到 Google Cloud 上、需要一套工程化能力管理方案的团队;第三类是刚接触 Genkit 这类框架、想搞清楚"skill 和 tool 到底有什么区别"的入门者。我会从概念拆解、框架选型、落地步骤、踩坑经验几个角度,把这件事讲透。

需要先明确一个前提:Agent Skills 不是某个单一产品的名字,而是一种架构模式。Google 在 Genkit 和 Gemini 生态里推的这套东西,本质上是把"函数调用(function calling)"进一步抽象成"技能注册与发现"。理解这一点,后面所有的工程细节才站得住脚。

2. Skill、Tool、Function 三者到底差在哪

2.1 从一次真实的调用链说起

假设你做一个"帮我订会议室"的 Agent。用户说"下周三下午两点,帮我订个能坐 8 个人的会议室"。这条指令背后,Agent 需要做几件事:解析时间、查询可用会议室、检查人数容量、执行预订、返回确认。如果把这些都写成一个 tool,那这个 tool 会非常臃肿,参数一大堆,模型很容易填错。

Agent Skills 的做法是拆开:一个parse_timeskill 负责把自然语言时间转成结构化时间;一个query_roomskill 负责按条件查会议室;一个book_roomskill 负责执行预订。每个 skill 只做一件事,参数少、语义清晰,模型调用时的准确率会明显提升。这就是 skill 和 tool 最直观的区别——tool 是能力接口,skill 是能力单元,一个 tool 可以内部编排多个 skill,也可以一个 skill 直接暴露成一个 tool。

再往深一层,function 是编程语言层面的概念,是 skill 的实现载体。你写一个 Python 函数,用 Genkit 的装饰器把它注册成 skill,框架再把它暴露给模型作为可调用的 tool。三者是"实现 → 注册 → 暴露"的递进关系,不是并列关系。很多人搞混,是因为文档里经常混用这几个词。

2.2 为什么"可发现性"是 skill 设计的命门

Skill 和普通函数最大的不同,在于它必须能被 Agent自动发现并正确选择。这就引出一个关键设计点:每个 skill 都需要一份高质量的元数据描述,包括它叫什么、干什么、什么时候该用、输入输出长什么样。这份描述直接决定了模型能不能在几十个 skill 里挑对那一个。

我踩过的坑是:早期给 skill 写的描述太笼统,比如"处理用户请求",结果模型在多个 skill 之间反复横跳,调用链乱成一团。后来改成"当用户提供自然语言时间表达(如'下周三下午两点')时,将其转换为 ISO 8601 格式的时间对象",准确率立刻上来了。skill 描述要写得像给一个新同事交代任务,具体到触发条件和边界,这是最容易被忽视但最影响效果的一环。

2.3 一张表看清三者的边界

维度FunctionSkillTool
本质代码实现能力单元 + 元数据暴露给模型的接口
关注点逻辑正确可发现、可组合参数契约
粒度任意单一职责可粗可细
谁消费开发者Agent 运行时大模型
典型数量无限制中等(10-50)少而精

这张表是我自己在做架构评审时常用的对照工具。核心结论是:skill 的数量可以比 tool 多,但每个 skill 必须足够"窄"。窄意味着模型选择时的歧义小,组合时的灵活性高。

3. 用 Genkit 把 skill 跑起来:环境到第一个可用 Agent

3.1 环境准备里最容易被忽略的两件事

Genkit 的安装本身不复杂,npm install -g genkit或者用项目级依赖都行。但有两个细节新手几乎必踩。第一是运行时版本,Genkit 对 Node 版本有要求,版本太低会在初始化时报一些看不懂的模块错误,建议直接用当前 LTS。第二是模型访问凭证的配置方式,很多人把密钥硬编码在代码里,这在本地跑没问题,一上 GKE 就出安全事故。正确做法是用环境变量或云平台的密钥管理服务,代码里只读不写。

我建议在动手写 skill 之前,先跑通一个最小的"hello agent",确认模型能正常响应。这一步能帮你排除掉 80% 的环境问题,避免后面把环境问题和逻辑问题混在一起排查。

3.2 定义第一个 skill 的完整流程

一个 skill 的定义通常包含四部分:名称、描述、输入 schema、执行函数。用 Genkit 的风格大致是这样:

import { genkit, z } from 'genkit'; import { googleAI } from '@genkit-ai/googleai'; const ai = genkit({ plugins: [googleAI()] }); const parseTimeSkill = ai.defineTool( { name: 'parseTime', description: '将自然语言时间表达转换为 ISO 8601 时间对象,例如"下周三下午两点"', inputSchema: z.object({ text: z.string() }), outputSchema: z.object({ iso: z.string() }), }, async ({ text }) => { // 实际解析逻辑,可调用模型或规则引擎 return { iso: '2025-01-08T14:00:00+08:00' }; } );

注意description的写法——它同时是给模型看的"使用说明",也是给人看的"文档"。我习惯把触发条件写在最前面,因为模型在选择 skill 时最先匹配的就是这部分语义。

3.3 让 Agent 真正"会用"这些 skill

定义完 skill 只是第一步,关键是让 Agent 在对话中自动调用。Genkit 的generate接口支持传入 tools 数组,模型会根据用户输入决定是否调用、调用哪个。这里有个实操技巧:先用少量 skill 验证调用链,再逐步增加。一次性塞 20 个 skill 进去,模型的选择准确率会断崖式下降,而且你很难定位是哪个 skill 的描述有问题。

验证时我习惯打开 Genkit 的开发者 UI,它能可视化展示每一次调用的输入输出和决策路径。这个 UI 在排查"模型为什么没调用我预期的 skill"时特别有用,比看日志高效得多。

3.4 从本地到 GKE 的部署差异

本地跑通不代表能上生产。部署到 GKE 时,几个点必须提前处理:skill 执行函数如果是 IO 密集型的,要考虑并发和超时;模型调用有配额限制,要做限流和降级;日志要结构化,方便在云平台上检索。我见过太多项目本地 demo 完美,一上集群就因为超时和配额问题频繁失败。

提示:在 GKE 上部署 Agent 服务时,建议把 skill 执行和模型调用分成两个独立的服务,这样模型侧扩容和 skill 侧扩容可以解耦,成本也更可控。

4. Skill 编排:当单个 skill 不够用时怎么办

4.1 编排的两种思路:链式与路由

单个 skill 只能解决原子任务,真实业务往往是多步的。编排有两种主流思路。链式编排是把 skill 按固定顺序串起来,前一个的输出是后一个的输入,适合流程确定的场景,比如"解析时间 → 查会议室 → 预订"。路由编排是先判断任务类型,再分发给对应的 skill 子集,适合任务类型多样的场景,比如一个客服 Agent 要同时处理退款、查询、投诉。

选择哪种,取决于你的任务是否可预测。可预测就用链式,简单可靠;不可预测就用路由,灵活但需要更强的意图识别能力。我个人的经验是:能用链式就别用路由,因为链式的调试成本低得多,每一步的输入输出都是确定的。

4.2 用 Genkit Flow 固化编排逻辑

Genkit 提供了 Flow 的概念,可以把一段编排逻辑封装成一个可复用、可观测的单元。这比在 prompt 里让模型自己决定调用顺序要可靠得多。下面是一个链式编排的简化示例:

import { defineFlow } from '@genkit-ai/flow'; export const bookRoomFlow = defineFlow( { name: 'bookRoom' }, async (userInput) => { const time = await parseTimeSkill({ text: userInput }); const rooms = await queryRoomSkill({ time: time.iso, capacity: 8 }); if (rooms.length === 0) return { status: 'no_room' }; return await bookRoomSkill({ roomId: rooms[0].id, time: time.iso }); } );

Flow 的好处是它把编排逻辑从"模型决策"变成了"代码决策",确定性和可测试性都大幅提升。模型只负责它擅长的部分——理解自然语言,剩下的交给代码。

4.3 编排中的错误处理与重试

多步编排里,任何一步都可能失败。我的做法是给每个 skill 定义明确的错误类型,编排层根据错误类型决定是重试、降级还是直接返回。比如查询会议室超时,可以重试一次;预订失败,则必须返回明确原因,不能静默吞掉。

这里有个反直觉的点:不要让模型来决定重试。模型对"失败"的理解往往不准确,它可能把一次正常的空结果当成失败去重试,浪费配额。重试逻辑应该写在代码里,模型只负责生成最终的用户回复。

5. 那些文档不会告诉你的踩坑记录

5.1 skill 描述写得太"聪明"反而坏事

我一开始喜欢在 skill 描述里写很多"高级"的语义,比如"智能识别用户意图并优雅处理"。结果模型完全抓不住重点。后来改成大白话,把触发条件、输入格式、输出格式一条条列清楚,效果立竿见影。给模型看的描述,要像给机器看的规格说明,不要像给人类看的营销文案。

5.2 参数 schema 太宽松导致模型乱填

用z.string()这种宽松类型时,模型经常填出意料之外的值。比如时间参数,它可能填"下午"而不是具体时间。解决办法是尽量用枚举、正则约束、必填校验把 schema 收紧。schema 越严格,模型犯错的空间越小。这一点和传统 API 设计是相通的——契约越明确,调用方越不容易出错。

5.3 本地能跑、线上报错的典型原因

最常见的是环境变量缺失和网络策略限制。本地开发时你可能直接用了个人凭证,线上服务账号没有对应权限,调用就失败了。排查这类问题,第一步永远是看服务账号的权限和网络出口策略,而不是怀疑代码逻辑。

5.4 关于 Gemini 账号资格问题的说明

热搜里出现了"your account is not eligible for gemini code assist for individuals at this time"这类词,说明不少人在配置阶段卡在了账号资格上。这类问题通常和账号类型、地区、订阅状态有关。我的建议是:先确认你使用的账号类型是否符合对应服务的要求,再检查是否需要通过组织管理员开通权限。遇到资格提示时,不要反复重试,先去看官方文档里关于账号类型和可用区域的说明,能省下大量时间。

6. 把 skills 做成可维护资产:命名、版本与测试

6.1 命名规范决定团队协作效率

Skill 一多,命名混乱就是灾难。我坚持的规范是:动词开头、领域前缀、语义唯一。比如room.queryAvailable、room.book、time.parse。这样在几十个 skill 里检索和归类都很清晰。避免用handle、process这种万能动词,它们等于没命名。

6.2 给 skill 加版本,别怕麻烦

Skill 的描述和 schema 一旦变更,模型的行为可能跟着变。给 skill 加版本号(如room.book.v2),可以在不影响线上 Agent 的前提下灰度测试新版本。这个习惯在多人协作时尤其重要,否则你改一个描述,别人的 Agent 可能就崩了。

6.3 测试 skill 的三个层次

第一层是单元测试,验证执行函数的逻辑正确;第二层是契约测试,验证输入输出符合 schema;第三层是调用测试,用真实或模拟的模型输入,验证模型能否正确选中这个 skill。第三层最容易被忽略,但恰恰是 Agent 场景下最关键的。我通常会准备一组"意图样本",每次改动 skill 描述后跑一遍,看选中率有没有下降。

测试层次验证目标工具建议
单元测试执行逻辑正确常规测试框架
契约测试schema 合规schema 校验库
调用测试模型选中率意图样本集 + 自动化

6.4 监控上线后的 skill 表现

上线不是终点。要监控每个 skill 的调用频次、成功率、平均耗时,以及"未被调用但预期应被调用"的情况。后者往往意味着描述有问题。我习惯每周看一次 skill 调用分布,异常波动通常能提前暴露问题。

7. 我对 Agent Skills 这套模式的实际体会

做了几个基于 Genkit 和 Gemini 的 Agent 项目之后,我最大的体会是:Agent 的可靠性不取决于模型多强,而取决于你把能力拆得多清楚。模型再聪明,面对一个描述模糊、职责不清的 skill 集合,也会表现得像个新手。反过来,即使模型能力一般,只要 skill 设计得当、编排逻辑清晰,整体表现也能很稳。

另一个体会是关于"克制"。刚开始做 Agent 的人总想让它什么都能干,于是不断加 skill、加能力。但每加一个 skill,模型的选择负担就增加一分。我现在更倾向于先做减法:这个 skill 能不能合并?这个能力是不是根本不需要?少而精的 skill 集合,比大而全的能力库更容易维护,也更容易调优。

最后分享一个实用习惯:把每个 skill 的"设计意图"和"已知边界"写在一个单独的文档里,和代码放在一起。半年后你回头看,或者新人接手时,这份文档比任何注释都值钱。Agent 项目迭代快,唯一能对抗遗忘的,就是当时留下的清晰记录。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/6 4:21:17

Ponytail:面向开发者的轻量级AI Agent CLI工作台

1. 项目概述:Ponytail 是什么,它解决的不是“技术问题”,而是“人机协作断层”Ponytail 这个名字乍一听像发型,但放在当前 AI 工具链生态里,它代表的是一类正在快速成型的新范式——面向终端开发者的轻量级 AI Agent 框…

作者头像 李华
网站建设 2026/10/6 4:21:16

从概念到落地:智能体架构、平台选型与安全验证指南

简介:这是一份系统讲解华为“智能体”参考架构的PDF电子文档,面向智慧城市、数字经济、新基建、AI落地等领域的政企决策者、云解决方案架构师及相关技术爱好者,也适合作为相关培训的入门知识补充。文档以智能体概述为起点,完整介绍…

作者头像 李华
网站建设 2026/10/6 4:21:03

深入理解Android AppOps:权限之上的执行闸门与系统服务解析

做 Android 开发越久,越会发现权限体系不是我们平时看到的“允许/拒绝”那么简单。系统设置里的开关只管一部分,真正在背后记录每一次调用、控制每一次访问的,是一个叫 AppOps 的系统服务。我第一次认真研究它,是想做一个权限使用…

作者头像 李华
网站建设 2026/10/6 4:20:34

OpenShell终端工作台:从部署配置到插件扩展的完整实践指南

1. 项目概述与设计思路1.1 OpenShell到底解决了什么问题OpenShell,初见这个名字我以为是又一个套壳终端的练手项目,直到自己在开源的仓库里翻到它,才意识到这个工具定位有点意思——它不是一个单纯模拟终端的玩具,而是把“Shell工…

作者头像 李华
网站建设 2026/10/6 4:20:31

上下文模式(Context-Mode)设计与落地:从状态隔离到模式切换全指南

做了这么多年系统设计和底层框架,我越来越觉得“上下文模式”这件事被严重低估了。很多人把 context-mode 简单理解成“多轮对话里传历史消息”,或者“保留几个全局变量”,但真正到了复杂业务场景里,你会发现这远远不够。今天想结…

作者头像 李华
网站建设 2026/10/6 4:19:46

从零掌握AI Agent Skills:核心原理、开发实战与避坑指南

1. 从“skills”这个热词说起:它到底是什么,为什么突然火了最近几个月,不管是在技术社区、开发者群聊,还是在做AI应用的朋友圈子里,“skills”这个词出现的频率高得离谱。有人把它翻译成“技能包”,有人叫它…

作者头像 李华