Genkit Go Skills 中间件实战:从 pirate 技能文件的 SKILL.md 格式到 use_skill 加载机制

发布时间:2026/9/17 19:39:07
Genkit Go Skills 中间件实战:从 pirate 技能文件的 SKILL.md 格式到 use_skill 加载机制 Genkit Go Skills 中间件实战从 pirate 技能文件的 SKILL.md 格式到 use_skill 加载机制【免费下载链接】genkitOpen-source framework for building agentic apps in JavaScript, Go, Dart, and Python, built and used in production by Google项目地址: https://gitcode.com/GitHub_Trending/ge/genkit本文以 Genkit Go 示例库中的 pirate 技能文件 为切入点完整拆解 Genkit Go Skills 中间件的运作方式一个技能文件SKILL.md应如何组织 YAML frontmatter 与正文指令、中间件如何扫描并解析这些文件、又如何通过注入系统提示词与注册use_skill工具让模型在运行时按需加载海盗语气这类人格化指令。读完后你能直接写出自己的技能库并理解其底层加载链路。一、pirate 技能文件一个最小而完整的技能定义Skills 中间件中的技能本质就是一个目录 一个 SKILL.md 文件。pirate 技能位于示例目录go/samples/basic-middleware/skills/skills/下与haiku、shakespeare、eli5三个技能并列见 main.go 头注释。其完整内容如下--- name: pirate description: Respond in the voice of a swashbuckling pirate. --- Ahoy! From here on, ye be speakin only like a proper swashbuckling pirate. Sprinkle in aye, arr, matey, ye, tis, and similar pirate idioms liberally. Refer to problems as troubles at sea, to tasks as quests, and to files or data as treasure. Stay in character for the entire response. Keep it punchy and fun.这份文件由两部分构成两部分对应中间件的两条处理路径YAML frontmatter---围栏之间包含name: pirate与description: Respond in the voice of a swashbuckling pirate.两个字段。描述文本会被写进注入给模型的系统提示词是模型看见这个技能的主要依据——pirate 的 description 一句话点明用途以海盗口吻回应模型据此判断用户请求是否匹配。正文指令frontmatter 之后的 Markdown 文本是技能的真正载荷。pirate 的正文给出了可执行的风格规范全程使用 aye、arr、matey、ye、tis 等海盗习语把问题称为 troubles at sea海上麻烦、把任务称为 quests任务、把文件与数据称为 treasure宝藏并且要求整个回答保持人设、短促有趣。这段正文只有在模型调用use_skill之后才会进入对话上下文这正是 Skills 中间件按需加载设计的核心见下文第四节。二、示例应用如何接入 pirate 技能理解这个技能文件最直接的方式是看消费它的示例程序 basic-middleware/skills/main.go。该程序做了四件事注册 Middleware 插件。genkit.Init时通过genkit.WithPlugins(googlegenai.GoogleAI{}, middleware.Middleware{})挂载内置中间件插件插件在 plugin.go 中暴露了 Retry、Fallback、ToolApproval、Skills、Filesystem 五种中间件其中 Skills 的注册描述为 Expose a local library of skills as loadable system instructions将本地技能库暴露为可加载的系统指令。声明技能库路径。const skillsDir ./skills指向工作目录下的技能库main.go#L62-L64。路径相对于工作目录go run .正好落在该目录因此./skills/下的pirate/、haiku/等子目录都会被扫描到。定义 askFlow 流式流程。流程中通过ai.WithUse(middleware.Skills{SkillPaths: []string{skillsDir}})启用中间件并用ai.WithSystem(...)明确提示模型回答前先判断列出的技能是否匹配匹配则先调用use_skillmain.go#L99-L125。默认问题指向 pirate。AskRequest.Question字段的jsonschema默认值被设为Explain how a rainbow forms in the voice of a pirate.——不带任何请求体的调用就会被导向 pirate 技能返回 Arr, matey! 式的回答而不是普通段落main.go#L66-L70。源码注释还特意提醒jsonschema标签以逗号分隔默认值中不能包含逗号否则值会被静默截断。另外值得注意的是流式回调中的过滤逻辑use_skill那一轮模型调用也会流经流式通道但不产生文本示例用chunk.Text() ! 过滤空块避免回答看起来迟到而非空白main.go#L112-L119。三、SKILL.md 的格式规范目录约定与 frontmatter 解析以下格式约束并非文档约定而是由中间件源码 skills.go 直接实现的扫描与解析行为决定的3.1 目录结构约定每个技能是技能路径下的一个直接子目录目录内必须含有名为SKILL.md的文件缺少该文件的子目录会被跳过。扫描不递归只枚举skills/的一层子目录scanSkills中仅对每个条目检查entry.IsDir()后拼接目录名/SKILL.md见 skills.go#L168-L186。以.开头的隐藏目录被忽略技能名调用use_skill时使用的名称取目录名而非 frontmatter 里的name字段——frontmatter 的name实际上不参与查找写错也不会导致加载失败但description会影响模型的选择判断。未配置SkillPaths时默认扫描skills目录defaultSkillsPath见 skills.go#L32-L33。路径不存在或不可读时会被跳过如果该路径是调用方显式配置的跳过会以warn级别日志提示很可能配错了仅当是未配置时的默认路径则只打debug日志skills.go#L148-L156。3.2 frontmatter 解析规则parseFrontmatterskills.go#L194-L212实现了严格的围栏格式要求文件开头必须是---且其后必须紧跟换行符\n或\r\n允许文件带 BOM会先剥离\ufeff结束围栏是独立成行的---解析器在剩余文本中查找第一个\n---围栏之间的文本按 YAML 解析只提取name与description两个字段无 frontmatter 或解析失败时返回零值不报错——此时技能仍会被暴露给模型只是描述缺省。描述为空时会填充占位文本No description provided.skillsMissingDescription而该占位文本在系统提示词中会被省略只列出技能名skills.go#L229-L236。pirate 的 frontmatter 正是符合这一规范的标准写法两行---之间恰好是name/description两个键值对。四、运行时加载链路从扫描到 use_skill 工具返回中间件在每次ai.Generate调用时完成一次扫描并把结果固化到返回的ai.Hooks中保证WrapGenerate与use_skill工具看到同一份技能集合skills.go#L87-L133。整条链路分为三步4.1 注入 系统提示词buildSkillsPrompt把扫描结果渲染为如下结构的系统提示词片段以示例中四个技能为例按字母序排列skills You have access to a library of skills that serve as specialized instructions/personas. Strongly prefer to use them when working on anything related to them. Only use them once to load the context. Here are the available skills: - eli5 - Explain concepts in very simple terms suitable for a five-year-old. - haiku - Respond as a single traditional haiku with a 5-7-5 syllable structure. - pirate - Respond in the voice of a swashbuckling pirate. - shakespeare - Respond in the style of William Shakespeare — early modern English, poetic cadence. /skills可以看到 pirate 技能暴露给模型的正是其 description 一行。技能按名称排序保证多次运行输出稳定。injectSkillsPromptskills.go#L245-L285负责把该片段放入请求的系统消息中且是幂等的每个注入的文本 Part 都带有Metadata[skills-instructions] true标记skillsMarker后续多轮工具循环重放历史时中间件会原地刷新已存在的标记 Part 而不是重复追加若历史里没有标记 Part则追加到已有的 system 消息末尾或在最前面新建一条 system 消息。这个设计保证了带use_skill工具循环的多轮对话中skills块始终只出现一次。若扫描结果为空没有任何技能wrapGenerate直接放行请求、不做任何注入skills.go#L121-L127。4.2 注册 use_skill 工具中间件同时注册名为use_skill的工具useSkillToolName常量注明其命名刻意与 JS 版实现保持一致便于提示词与评测在两种运行时之间移植。工具接收单个参数skillName执行逻辑非常直接在扫描结果 map 中按名称查找找不到返回skill %q not found错误找到则os.ReadFile读取该技能的 SKILL.md完整原始内容含 frontmatter 在内的全文作为工具输出返回给模型skills.go#L103-L119。由此形成完整的两阶段加载时序模型先看到skills清单只有名称 一行描述这是目录页token 开销极小判断请求匹配后调用use_skill(skillNamepirate)pirate 的 SKILL.md 全文作为工具响应进入对话历史模型基于已加载的正文指令以海盗口吻完成最终回答。4.3 测试用例对行为的印证skills_test.go 中的五个测试覆盖了上述全部行为可视为格式与行为的可执行规范TestSkillsInjectsSystemPrompt断言系统提示词同时包含带描述的python - A python expert skill与无 frontmatter 时仅列名称的javascriptTestSkillsRegistersUseSkillTool模拟模型首轮请求调用use_skill断言工具响应中完整包含 SKILL.md 正文Python prompt contentTestSkillsUnknownSkillReturnsError未知技能名返回包含not found的错误TestSkillsPromptInjectionIsIdempotent重放历史后断言skills块在系统消息中仍然只有 1 个验证原地刷新而非重复注入TestSkillsNoopWhenNoSkillsFound空目录时不注入任何系统消息。五、与其余三个示例技能对照pirate 所在的技能库共有四个技能风格各不相同便于肉眼观察加载效果技能description注入提示词正文指令要点pirate以冒险海盗口吻回应使用 aye/arr/matey 等习语问题称 troubles at sea、任务称 quests、文件数据称 treasure全程保持人设haiku以 5-7-5 音节的传统俳句回应每次只输出俳句三行无前言、标题或解释shakespeare以莎士比亚风格回应早期现代英语使用 thou/thee/hast 等词汇鼓励抑扬格节奏称读者为 gentle readereli5用五岁儿童能懂的语言解释概念短句子、生活化类比、避免术语、全文不超过十句对比可见 pirate 技能的写法特点它的正文不仅定义语气还给出领域词汇映射规则问题→troubles at sea 等这类替换规则比单纯说说海盗话更能约束模型输出的一致性。六、动手运行与 HTTP 调用在示例目录下运行工作目录必须是go/samples/basic-middleware/skills/因为skillsDir ./skills是相对路径go run .服务监听127.0.0.1:8080所有 flow 自动挂载为POST /flow名。要触发 pirate 技能可以不传任何 body默认问题就是海盗口吻问彩虹curl -N -X POST http://localhost:8080/askFlow?streamtrue \ -H Content-Type: application/json \ -d {data: {question: Write a haiku about debugging code.}}把question换成Explain recursion to me like I am five.则会加载 eli5 技能。若要观察use_skill调用本身可用 Genkit CLI 启动 Dev UI 并在http://localhost:4000/traces查看每次运行的 trace启动方式为genkit start -- go run .CLI 一次性安装即可。七、编写自己的 SKILL.md要点清单综合源码行为与 pirate 示例一份健壮的 SKILL.md 应满足目录名即技能名把技能放在skillsDir/技能名/SKILL.md目录名小写、无空格这是模型调用use_skill时使用的唯一标识frontmatter 围栏严格首行---后必须紧跟换行结束---独立成行键值只写name与descriptiondescription 面向选择一句话写清何时该用这个技能它会原样出现在skills清单中是模型决策的唯一线索正文面向执行写可验证的行为规则词汇表、结构约束、长度上限、输出格式正文全文会在use_skill后被逐字读入对话写多少模型就遵守多少控制正文长度正文只在该技能被加载时才进入上下文但这正是按需加载的意义所在——把重指令留在 SKILL.md 里而不是全部塞进常驻系统提示词。小结pirate 技能文件虽然只有十行却完整展示了 Genkit Go Skills 中间件的设计frontmatter 的description构成低成本目录页正文指令通过use_skill工具在模型需要时按需载入对话扫描、解析、幂等注入与工具注册均由 skills.go 实现并经 skills_test.go 全量验证。掌握这一文件约定后你可以为任何模型流程挂上可组合、可版本化的人格/风格库而不必修改流程代码本身。【免费下载链接】genkitOpen-source framework for building agentic apps in JavaScript, Go, Dart, and Python, built and used in production by Google项目地址: https://gitcode.com/GitHub_Trending/ge/genkit创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询