深度定制 Genkit 中间件:用 generateMiddleware 构建可复用、可插拔的生成管线(Genkit JS)

发布时间:2026/9/14 19:20:20

深度定制 Genkit 中间件:用 generateMiddleware 构建可复用、可插拔的生成管线(Genkit JS) 深度定制 Genkit 中间件用 generateMiddleware 构建可复用、可插拔的生成管线Genkit JS【免费下载链接】skillsAgent Skills for Google products and technologies项目地址: https://gitcode.com/GitHub_Trending/skills29/skills导读在 GenkitGoogle 出品的 AI 应用开发框架中中间件是横切关注点cross-cutting concerns的统一承载机制重试、降级、注入工具、改写请求/响应等能力都可以通过中间件挂载到生成流程上。本篇以 skills/cloud/genkit-js/references/middleware-custom.md 为骨架系统讲解如何用generateMiddleware编写命名、可复用、带 Zod 配置校验的自定义中间件并把它通过.plugin()注册为 Genkit 插件让它在ai.generate、可执行 Prompt 和 Agent 上统一生效同时能被 Genkit Dev UI 识别与可视化。中间件机制一览use: [...]数组在深入自定义之前先明确中间件挂载的基本方式。Genkit 中间件通过use: [...]数组附着到生成调用上该数组在ai.generate/ai.generateStream、可执行 PromptdefinePrompt和 AgentdefineAgent上都受支持见 使用中间件import { retry } from genkit-ai/middleware; const res await ai.generate({ model: googleAI.model(gemini-flash-latest), prompt: Say hello, use: [retry({ maxRetries: 2 })], }); // Prompt 与 Agent 上使用同样的数组 const myPrompt ai.definePrompt({ name: p, prompt: ..., use: [retry()] }); const myAgent ai.defineAgent({ name: a, system: ..., use: [retry()] });注意这里的关键形态中间件本身是一个可配置的工厂函数如retry()/artifacts()调用它返回一个供use: [...]使用的引用。genkit-ai/middleware包中的七个现成中间件retry、fallback、artifacts、agents、filesystem、skills、toolApproval都是这种工厂形态而generateMiddleware正是用来构建这一类自定义工厂的底层工具——这正是本篇文章的核心。用 generateMiddleware 定义命名中间件generateMiddleware是自定义中间件的入口它负责两件事声明中间件的元信息name与description后者用于 Dev UI 与调试展示以及可选的configSchema返回一个工厂函数调用后得到一个可放进use: [...]的引用工厂内部可拿到用户传入的config以及 Genkit 的ai实例。原文档给出了一个完整的timing.ts示例——一个记录模型调用耗时的中间件// timing.ts import { generateMiddleware, z } from genkit; const OptionsSchema z.object({ label: z.string().optional() }); export const timing generateMiddleware( { name: timing, description: Logs how long the model call takes., configSchema: OptionsSchema, }, ({ config, ai }) { // Runs once per generate() call. Return any of the hooks below. return { model: async (req, ctx, next) { const start Date.now(); const res await next(req, ctx); console.log([${config?.label ?? timing}] ${Date.now() - start}ms); return res; }, }; } );关键点拆解configSchema与 ZodconfigSchema使用 Zod schema 定义工厂的入参。用户调用timing({ label: gen })时传入的对象会被校验不合法时抛错从而让中间件的配置在编译期和运行期都是类型安全的。原文档用z.object({ label: z.string().optional() })声明了一个可选字符串参数这也呼应了 setup.md 中推荐的“schema 优先”工程实践——Genkit 中无论是 Flow 输入输出、Prompt 输入还是工具参数都统一使用zZod声明。工厂回调的时机注释明确指出工厂回调({ config, ai }) ...在每次generate()调用时执行一次它返回的 hooks 集合定义了这一轮生成中中间件介入的具体位置。ai实例在回调中可用这意味着中间件内部还可以进一步调用ai.generate、读取注册表等实现更复杂的能力编排。与内置中间件的同构性generateMiddleware产出的工厂形态与genkit-ai/middleware包内的中间件完全一致因此自定义中间件与内置中间件在use: [...]中可以无缝混用、按序执行。注册为插件让中间件进入 Dev UI自定义中间件拿到.plugin()方法可以直接注册进genkit({ plugins: [...] })。这是推荐做法——不注册时中间件依然能在use: [...]中工作但无法被 Genkit Dev UI 识别与可视化import { genkit } from genkit; import { googleAI } from genkit-ai/google-genai; import { timing } from ./timing.js; export const ai genkit({ plugins: [googleAI(), timing.plugin()], }); // Then use the factory in use: [...]: await ai.generate({ model: googleAI.model(gemini-flash-latest), prompt: Hi, use: [timing({ label: gen })], });这与内置中间件的注册方式完全一致。以retry为例使用中间件 中的标准做法是export const ai genkit({ plugins: [googleAI(), retry.plugin(), artifacts.plugin()], });注册带来的额外收益Prompt frontmatter 中的use注册后中间件不仅限于代码内使用还可以在 Dotprompt 的 frontmatter 中通过名称引用。在 dotprompt.md 中可以看到.prompt文件的use字段接受中间件名裸字符串或{ name, config }映射名称会解析到已注册在 Genkit 实例上的中间件use: - name: retry # bare string also works: - retry config: maxRetries: 4要让名称可解析前提同样是先注册中间件插件const ai genkit({ plugins: [googleAI(), retry.plugin()], promptDir: ./prompts, });这意味着你的自定义中间件只要通过.plugin()注册就能同样在.prompt文件里以use: - name: timing的方式声明式挂载这大大提升了中间件的复用范围。四个可用 Hook 详解generateMiddleware的实例化回调返回一个GenerateMiddlewareDef可以选择性地包含以下任意子集Hook包裹的对象典型用途入参类型generate(envelope, ctx, next)整个 generate 动作注入请求参数、后处理响应、跨工具循环捕获错误envelope携带{ request, currentTurn, messageIndex }model(req, ctx, next)底层模型调用缓存、重试、请求/响应改写req为GenerateRequesttool(req, ctx, next)单个工具调用校验输入、缓存或覆盖工具输出req为ToolRequestPart返回ToolResponsePart \| undefinedtools: ToolAction[]静态注入工具中间件激活时向模型注入能力artifacts()/filesystem()正是这样注入工具的ToolAction[]一个同时声明全部 hooks 的骨架示例generateMiddleware({ name: example }, ({ ai }) ({ generate: async (envelope, ctx, next) next(envelope, ctx), model: async (req, ctx, next) next(req, ctx), tool: async (req, ctx, next) next(req, ctx), tools: [ /* ToolAction[] */ ], }));Hook 的链式语义每个 hook 都接受next(...)来继续调用链——可以传入被修改后的 request/envelope并在await之后对结果做变换再返回。这种洋葱模型onion model与 Node.js 中间件一脉相承也是genkit-ai/middleware中内置中间件的实现基础。以仓库中agents()中间件多 Agent 编排为例可以直观看到tools静态注入 hook 的实际用途agents()为每个子 Agent 注入一个delegate_to_name工具并在系统提示词后追加sub-agents块模型调用委托工具时中间件运行子 Agent 并把其响应作为工具结果返回。同样artifacts()中间件Artifacts 用法通过静态注入write_artifact/read_artifact两个工具并每轮注入artifacts清单让 Agent 在会话中产出命名交付物。这些能力都是“在tools: ToolAction[]中返回工具定义 在系统提示词层面做注入”的组合拳自定义中间件完全可以按同样的模式实现。如何选择合适的 Hook原文档给出了非常清晰的决策指南需要转换整个回合的 prompt/messages 或最终结果→ 选generate。例如跨整个工具循环的统一错误处理、结果后处理、在请求中注入全局参数需要缓存 / 重试 / 改写单次模型往返→ 选model。这是性能类中间件如内置的retry的主战场需要门控或记忆化工具执行→ 选tool。例如校验工具入参、对高频工具结果做缓存需要为模型提供额外能力→ 选tools。静态注入一组ToolAction让模型在中间件激活期间总是能看到这些工具。值得注意的是内置核心中间件也遵循这一模型。在genkit核心无需额外安装包从genkit/model/middleware导入中simulateConstrainedGeneration、validateSupport、augmentWithContext等中间件都是通过改写模型请求或结果来实现能力的例如import { simulateConstrainedGeneration } from genkit/model/middleware; await ai.generate({ model: someModel, prompt: ..., use: [simulateConstrainedGeneration()], });理解了 hook 分工你就能判断某个横切需求该落到哪个层级而不是一律堆在generate上。最佳实践与注意事项始终通过.plugin()注册Reminder: register custom middleware via.plugin()(see above). It works inuse: [...]without registering, but unregistered middleware is not visible to the Genkit Dev UI.原文档的提醒值得再次强调不注册也能工作但 Dev UI 看不到它。Genkit Dev UI 的中间件可视化、trace 展示和调试体验都依赖于注册信息因此生产级代码中请务必把每个自定义中间件都加入plugins: [...]。与内置中间件协同自定义中间件与genkit-ai/middleware包的内置中间件可以自由组合。例如在多 Agent 编排场景中一个典型组合是use: [ agents({ agents: [researcher, coder], artifactStrategy: session }), artifacts({ readonly: true }), retry(), ];你的自定义中间件可以作为这个链条中的一员与内置中间件一起按use数组的顺序依次执行。关注配置的校验与默认值利用configSchema对工厂参数做 Zod 校验并在工厂回调内部给config提供合理默认值如config?.label ?? timing可以让中间件的调用方只传必要的参数符合 Genkit “Be Minimal”只指定与默认值不同的选项的工程约定见 SKILL.md。小结generateMiddleware把“定义命名中间件 → 注册为插件 → 在use: [...]/ Prompt frontmatter 中使用”这一完整链路收拢成一个清晰的 API用元信息声明身份用configSchema保证配置安全用四个 hooksgenerate/model/tool/tools在正确的层级注入横切逻辑最后通过.plugin()让中间件成为 Genkit 实例的一等公民。掌握这套机制后你不仅能消费内置中间件还能像retry、artifacts、agents那样构建自己的可复用能力让重试、观测、工具注入等逻辑以统一、可组合、可调试的方式贯穿整个生成管线。【免费下载链接】skillsAgent Skills for Google products and technologies项目地址: https://gitcode.com/GitHub_Trending/skills29/skills创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/14 19:15:20

从相机标定到全景拼接:基于OpenCV的AVM环视系统实战解析

以前做倒车影像的时候,我一直在琢磨一个问题:为什么我们逼着车头一点一点挪进窄车位的时候,就不能有个视角直接从上往下看着整车,像打游戏一样把车挪进去?后来才知道,这种技术在车载领域早就有了官方名字&a…

2026/9/14 19:15:20

从航拍到三维重建:构建上帝视角的完整技术路径

1. 内容整体设计与思路拆解1.1 "上帝视角"到底在解决什么问题"gods-eye-view"这个词,这两年听得越来越多。不管是无人机航拍、三维重建、自动驾驶的BEV感知,还是项目管理里的全局决策,大家都在追求同一个东西——跳出局部…

2026/9/14 19:15:20

上帝视角实景三维系统实战:从倾斜摄影到CesiumJS渲染全流程

1. 为什么"gods-eye-view"突然成了硬需求:从炫技到刚需的转变先说个我最近的实际感受。以前提到上帝视角,大家第一反应是游戏里的俯视镜头,或者大疆无人机那种从天上往下看的航拍画面。但最近两年,我在GIS圈、智慧城市项…

2026/9/14 19:35:21

LangGraph子图设计与模块化AI系统开发实践

1. LangGraph子图设计基础与核心概念在构建复杂AI系统时,模块化设计是提升可维护性和扩展性的关键。LangGraph作为基于图的编程框架,其子图(Subgraph)功能允许我们将大型工作流分解为可重用的独立组件。这种设计模式特别适合需要多步骤推理和决策的AI应用…

2026/9/14 19:35:21

网络原理-HTTP

我们已经知道了网络协议栈,接下来就学习一下每个层中的关键协议吧(重点内容)先来介绍应用层1 应用层的协议应用层是程序员打交道最多的层次,是和应用程序直接相关的,程序员写的代码只要涉及到网络通信,都可…

2026/9/14 19:35:21

Spring Boot图书借阅管理系统开发实践

1. 项目概述"springboot105图书借阅管理系统617w1"是一个基于Spring Boot框架开发的图书借阅管理平台。这个系统主要面向学校图书馆、社区图书室等场景,提供完整的图书管理、借阅、归还、查询等功能。从项目编号来看,这很可能是一个课程设计或…

2026/9/14 19:35:21

Windows系统多版本JDK共存配置与切换指南

1. 问题现象与背景分析最近在Windows 10系统上遇到了一个典型的多版本JDK共存问题:原本已经安装了JDK 8用于老项目维护,现在需要为新的Spring Boot 3.x项目配置OpenJDK 17。按照常规流程安装并配置环境变量后,命令行执行java -version却依然显…

2026/9/14 19:30:21

ArmorPaint:开源PBR贴图绘制实战,替代Substance Painter的轻量工作流

做 3D 美术或者独立游戏的朋友应该都有类似的体会:模型雕刻完、UV 展开好,最头疼的就是贴图绘制这一环。用 Substance Painter 确实舒服,但订阅价格摆在那里,个人项目或者刚入门的同学很难说服自己掏这个钱。我后来换到 armorpain…

2026/9/14 2:17:50

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/14 0:03:22

KCF目标跟踪算法与OTB工程实现:毕业设计实战解析

简介:这是一份基于KCF核相关滤波算法、融合尺度池与抗遮挡处理的目标检测跟踪MATLAB完整源码,主要面向计算机相关专业准备毕业设计、课程设计或期末大作业的学生,也适合需要项目实战练习的初学者。源码在OTB数据集上完成验证,能够…

2026/9/14 0:03:22

语音情感识别实战:Keras实现LSTM、CNN、SVM与MLP多模型对比

简介:面向语音情感识别入门与进阶开发者,这份基于Keras的项目源码完整实现了LSTM、CNN、SVM、MLP四种模型,兼容Python3.8与Keras/TensorFlow2环境。压缩包内含49个文件,大小约70.31MB,主体包括Python脚本、yaml/json配…

2026/9/14 11:59:31

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/14 13:53:59

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/14 11:22:57

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码