news 2026/9/17 13:08:38

Genkit Model Action 规范全解:从 GenerateRequest 到流式响应的模型契约与实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Genkit Model Action 规范全解:从 GenerateRequest 到流式响应的模型契约与实现

Genkit Model Action 规范全解:从 GenerateRequest 到流式响应的模型契约与实现

【免费下载链接】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(由 Google 构建并用于生产环境的开源 AI 应用框架,支持 JavaScript、Go、Dart 与 Python)将“模型”统一抽象为一种特殊的 Action。本文以仓库 docs/model-spec.md 为核心骨架,结合 JavaScript 与 Go 两套实现的源码证据,系统讲解模型动作的输入输出契约、Part 统一内容模型、元数据能力声明,以及系统消息、配置透传、工具调用、结构化输出等实现要求。读完本文,你将掌握在 Genkit 中定义一个新模型插件、实现流式响应与多轮工具循环的全部规范细节,并能对照源码理解这些契约在框架内部是如何被校验与执行的。

模型动作(Model Action)定义

在 Genkit 中,一个模型就是一个 Action,它具备以下固定特征(见 docs/model-spec.md):

特征取值
Action 类型(Action Type)model
输入 Schema(Input Schema)GenerateRequest
输出 Schema(Output Schema)GenerateResponse
流式 Schema(Streaming Schema)GenerateResponseChunk

在 JavaScript 实现中,这一契约被建模为 model.ts 中的ModelAction类型:

export type ModelAction<CustomOptionsSchema extends z.ZodTypeAny = z.ZodTypeAny> = Action< typeof GenerateRequestSchema, // 输入:GenerateRequest typeof GenerateResponseSchema, // 输出:GenerateResponse typeof GenerateResponseChunkSchema // 流式:GenerateResponseChunk > & { __configSchema: CustomOptionsSchema; };

创建模型动作有两种方式:defineModel()(注册到 registry,供应用查找)和model()(仅创建不注册,适合插件作者从 resolver 返回模型动作)。两者最终都会调用modelActionOptions(),把输入输出 schema 与元数据打包成标准 Action 参数(model.ts):

return { actionType: 'model', name: options.name, description: label, inputSchema: GenerateRequestSchema, outputSchema: GenerateResponseSchema, metadata: { model: { label, customOptions, versions, supports } }, };

在 Go 实现中,对应的是 gen.go 中的ModelAction(内嵌core.Action[*ModelRequest, *ModelResponse, *ModelResponseChunk])与 generate.go 中的Model接口——Generate(ctx, req *ModelRequest, cb ModelStreamCallback)同时承担普通调用与流式回调。

模型元数据(Metadata)

模型动作通过metadata.model声明自身能力,供框架、开发者工具(如 CLI)和上层应用做能力发现与校验。规范定义的字段如下:

  • label:人类可读名称,例如"Google AI - Gemini Pro"
  • versions:支持的版本字符串数组。
  • supports:能力声明对象:
    • multiturn:是否支持多轮历史消息;
    • media:是否支持多模态输入;
    • tools:是否支持工具调用;
    • systemRole:是否支持system角色消息;
    • output:支持的输出格式数组(如['json', 'text']);
    • contentType:支持的输出内容类型数组;
    • context:是否原生支持文档上下文(RAG grounding);
    • constrained:原生约束生成支持级别,枚举'none'/'all'/'no-tools'
    • toolChoice:是否支持强制指定工具选择;
    • longRunning:是否支持长时运行操作。
  • stage:开发阶段,枚举'featured'/'stable'/'unstable'/'legacy'/'deprecated'
  • customOptions:模型特有配置的 JSON Schema,在请求中通过config暴露。

Go 端结构体ModelInfoModelSupports完整对应了上述字段,且为stageconstrained定义了具名常量(ModelStageFeatured…、ConstrainedSupportNone/All/NoTools),见 gen.go。

能力声明如何被框架使用

supports并非摆设,它在 model/middleware.ts 中被两类内置中间件消费:

  1. validateSupport:在请求进入模型前做能力预检——例如supports.media === false时请求中若出现 media part、supports.tools === false时请求若带 tools、supports.multiturn === false时若传入多条消息,都会直接抛错,错误信息中会完整回显请求体,便于排查。
  2. getModelMiddleware(model.ts):当模型未声明context支持时自动挂载augmentWithContext();当constrained'none'、或为'no-tools'且请求携带工具时,自动挂载simulateConstrainedGeneration(),用提示词模拟约束生成。

也就是说:模型作者只需如实声明能力,框架会自动补齐“不支持能力”的降级路径,这正是 Model Action 规范的价值所在。

数据契约:GenerateRequest 与 GenerateResponse

GenerateRequest(模型动作输入)

字段类型说明
messagesMessage[](必填)会话历史消息列表
configany模型特有配置(如 temperature、topK),按模型 config schema 校验
toolsToolDefinition[]可供模型调用的工具列表
toolChoiceenum工具选择策略:'auto''required''none'
outputOutputConfig期望输出格式/结构的配置
docsDocumentData[]作为上下文使用的检索文档

JS 端对应 model-types.ts 中的ModelRequestSchema/GenerateRequestSchema(后者额外保留了一个已被废弃的candidates字段,注释明确说明“所有响应现在只返回单一候选”,可作为版本演进线索)。Go 端对应 gen.go 中的ModelRequest结构体。

toolChoice的三个取值在GenerateActionOptionsSchema的注释中有精确语义:auto让模型自行决定是否使用工具,required强制模型选择一个工具,none强制模型不使用任何工具,默认auto

OutputConfig

字段类型说明
formatstring期望格式(如'json''text'
schemaRecord<string, any>定义期望输出结构的 JSON Schema
constrainedboolean是否原生强制 schema 约束
contentTypestring输出的具体内容类型

JS 实现OutputConfigSchema位于 model-types.ts。此外框架内部还有更丰富的GenerateActionOutputConfig(含instructionsjsonSchema),供上层 generate action 使用。

GenerateResponse(模型动作输出)

字段类型说明
messageMessage生成的消息
finishReasonenum结束原因:'stop''length''blocked''interrupted''other''unknown''failed'
finishMessagestring结束原因的补充信息
errorRuntimeErrorfinishReason'failed'(或被中止的模型停止)时的分类失败信息;'blocked'时不存在
usageGenerationUsageToken 与字符用量统计
latencyMsnumber生成耗时(毫秒)
customany模型特有附加信息
requestGenerateRequest触发本次响应的请求

值得注意的是,latencyMs并非由插件手工填充,而是defineModel/model在 runner 外层用performance.now()自动计时的(model.ts),插件只需返回普通响应即可。

finishReason在 JS 端为FinishReasonSchema枚举(model-types.ts,实际枚举含'aborted'共 8 项)。Go 端在 generate.go 中定义了isAbnormal()辅助方法:blockedabortedfailedinterruptedother均视为异常结束,驱动多轮工具循环的提前终止与错误归因。

usageGenerationUsageSchema非常完整:除了 input/output/total tokens,还统计字符数、图片数、视频数、音频文件数,以及thoughtsTokenscachedContentTokens和自定义custom计数。

GenerateResponseChunk(流式响应块)

字段类型说明
roleRole正在生成消息的角色(通常为'model'
indexnumber响应中消息的索引(通常为 0)
contentPart[](必填)本块包含的内容 parts
aggregatedboolean为 true 时,本块包含到目前为止的全部累计内容
customany模型特有附加信息

JS 实现ModelResponseChunkSchemaGenerateResponseChunkSchema为其别名)位于 model-types.ts,注释明确了aggregated与增量(incremental)两种语义。

统一内容模型:Message 与 Part

Message

字段类型说明
roleenum(必填)消息发送者角色:'system''user''model''tool'
contentPart[](必填)消息内容,由一个或多个 part 组成
metadataRecord<string, any>与消息关联的任意元数据

RoleSchema = z.enum(['system', 'user', 'model', 'tool'])MessageSchema见 model-types.ts。

Part:统一的内容单元

Genkit 用统一的Part结构表示不同类型的内容,Part 是若干具体 part 类型的联合。JS 端的完整定义见 parts.ts,PartSchema由 8 种 part 联合而成(比规范文档多出resource类型)。

文本 Part(Text Part)

{ "text": "Hello, world!" }

媒体 Part(Media Part)——多模态内容,内联数据应编码为data:URI(base64)。

图片:

{ "media": { "url": "data:image/jpeg;base64,/9j/4AAQSkZJRg...", "contentType": "image/jpeg" } }

音频:

{ "media": { "url": "data:audio/L16;codec=pcm;rate=24000;base64,AAAAAA...", "contentType": "audio/L16;codec=pcm;rate=24000" } }

视频:

{ "media": { "url": "https://example.com/video.mp4", "contentType": "video/mp4" } }

所有 part 都可携带metadata,用于存放放不进主 schema 的提供者特有信息。常见用途包括图片/视频的mediaResolution、视频的videoMetadata(如时长、偏移量),或内部签名如thoughtSignature

{ "media": { "url": "..." }, "metadata": { "mediaResolution": { "level": "MEDIA_RESOLUTION_HIGH" }, "videoMetadata": { "startOffset": { "seconds": 10 } } } }

工具请求 Part(Tool Request Part)——模型请求执行某个工具:

{ "toolRequest": { "name": "weatherTool", "ref": "call_123", "input": { "city": "New York" } } }

JS 端ToolRequestSchema还包含partial: boolean可选字段,用于流式工具调用的部分请求(见下文“部分工具请求”)。

工具响应 Part(Tool Response Part)——工具执行结果回传给模型:

{ "toolResponse": { "name": "weatherTool", "ref": "call_123", "output": { "temperature": 72 }, "content": [ ] } }

注意ref必须与请求的 ref 匹配;output通常是结构化 JSON;content为可选内容 parts(例如工具返回图片等富内容)。JS 实现ToolResponseSchema支持{ output, content, metadata }的多部件(multipart)结构(parts.ts)。

自定义 Part(Custom Part)——表示未被其他类型覆盖的提供者特有内容,典型场景是服务端工具(如代码执行)的结果返回:

{ "custom": { "executableCode": { "code": "print('Hello World')", "language": "PYTHON" }, "codeExecutionResult": { "outcome": "OUTCOME_OK", "output": "Hello World\n" } } }

推理 Part(Reasoning Part)——模型提供的思维链(chain-of-thought)或推理文本:

{ "reasoning": "First, I will calculate..." }

数据 Part(Data Part)——规范中标注为“保留供未来使用,目前没有任何已知插件支持”,表示通用结构化数据:

{ "data": { "key": "value" } }

提供者特有功能(Provider-Specific Features)

许多模型提供超出纯文本生成或客户端工具调用的服务端能力,规范要求统一通过config对象或特定 metadata 处理。

服务端工具(Server-Side Tools)

Web Search(Grounding)、Code Execution、URL Context 等通常实现为“服务端工具”——因为客户端不执行它们,所以配置在config中而非tools列表里。

Web Search 配置示例:

{ "config": { "googleSearch": {}, "tools": [{ "googleSearch": {} }] } }

注:googleSearch为提供者特有键;某些提供者可能使用tools配置键。

URL Context 配置示例:

{ "config": { "urlContext": { "urls": ["https://example.com/article"] } } }

编码准则(Encoding Guidelines)

  • 请求侧:启用/配置服务端功能一律使用config;除非客户端确实要执行该工具,否则不要使用ToolRequestPart
  • 响应侧
    • 若服务端工具产生了内容(如代码执行输出),它可以作为TextPart(若已融入回答)或CustomPart出现;
    • 执行相关的元数据(如搜索来源、grounding 元数据)应放在GenerateResponse.custom字段或Message.metadata中。

行为规范(Behavior)

请求处理流程

  1. 校验:模型动作校验GenerateRequest
  2. 上下文:若提供了docs,模型动作应将其纳入上下文,典型做法是增强消息历史。
  3. 工具:若提供了tools,将其转换为底层模型 API 期望的格式。
  4. 配置:应用config选项。

对应地,JS 框架为docs提供了augmentWithContext()中间件:把检索到的上下文文档渲染成文本追加到最后一条 user 消息,默认前言为"\n\nUse the following information to complete your task:\n\n",每条文档按[引用键]: 文本模板渲染(model/middleware.ts)。该中间件仅在模型未声明原生context支持时挂载,这正是规范第 2 条“典型做法是增强消息历史”的框架级实现。

系统消息处理

Genkit 将系统指令标准化为messages数组中的role: 'system'消息。但许多提供者(如 Google GenAI)要求系统指令作为独立配置字段而非会话历史的一部分。

实现要求(MUST):

  • 模型动作必须接受输入messages数组中的role: 'system'消息;
  • 若底层提供者要求独立系统指令:
    1. messages数组中提取系统消息;
    2. 按提供者要求转换/格式化(如systemInstruction字段);
    3. 若提供者不支持历史中的system角色,确保这些消息不会被传入常规会话历史。

框架为不支持原生 system role 的模型提供了simulateSystemPrompt()中间件(model/middleware.ts):把system消息改写成一对 user 消息("SYSTEM INSTRUCTIONS:\n" + 指令)与 model 消息("Understood.")插入历史,实现模拟系统提示。

配置处理:透传模式(Passthrough)

模型插件应遵循“透传”模式处理配置,这样底层模型 API 新增的功能无需更新插件即可被用户立即使用:

  1. 提取已知选项:显式解构已知配置键(如temperaturetopKtopP),按 Genkit 通用 schema 或特定逻辑处理;
  2. 透传其余选项:把所有剩余未知键直接传给底层模型 API 的配置对象。
const { temperature, topK, ...restOfConfig } = request.config || {}; const apiRequest = { model: modelName, temperature: temperature, // 处理已知键 top_k: topK, ...restOfConfig // 透传未知键 };
  1. 合并工具:若提供者支持通过配置传工具(如config.tools),应与标准request.tools合并,让用户能在标准 Genkit 工具之外附带提供者特有的工具定义(如服务端工具):
const tools = request.tools?.map(toProviderTool) || []; if (config.tools) { tools.push(...config.tools); }

JS 框架侧,GenerationCommonConfigSchema(model-types.ts)本身就以.passthrough()声明,已定义versiontemperaturemaxOutputTokenstopKtopPstopSequences(最多 5 条)、apiKey等通用键,其余键原样透传。规范中“已知键按通用 schema 处理、未知键透传”的双层设计,与插件实现侧(如google-genai的 config overrides)配合,形成完整的配置链路。

响应生成

  1. 内容:模型输出被解析为Part对象——文本映射为TextPart,函数调用映射为ToolRequestPart
  2. 流式:流式时模型发出GenerateResponseChunk
    • 理想情况下 chunk 应包含增量更新;
    • 若底层模型在流式时只支持完整响应,则应设置aggregated: true
  3. 结束原因:模型必须把提供者特有的 finish reason 映射为 Genkit 标准枚举。

JS 端defineModel会为响应自动补latencyMsperformance.now()计时),同时modelActionOptions会把configSchema转成 JSON Schema 写入metadata.model.customOptions,供工具链校验用户传入的config

工具处理

工具是 Genkit 模型的核心能力,实现涉及定义转换、请求处理(含流式)与响应处理三部分。

工具定义转换

模型动作必须把 Genkit 的ToolDefinition转换为提供者期望的格式:

  • 名称:若提供者有严格命名规则需做清洗(例如 Gemini 把/替换为__);
  • 输入 Schema:把inputSchema中的 JSON Schema 转换为提供者的 schema 格式;
  • 描述:透传工具描述。

ToolDefinition在 JS 端包含namekeydescriptioninputSchemaoutputSchemametadata(model-types.ts)。

工具请求

当模型决定调用工具时,发出ToolRequestPart

  • ref:若提供者支持,分配稳定的ref(call ID)用于关联响应;
  • input:工具参数。

部分工具请求(流式):部分模型(如 Gemini 3.0)支持流式工具调用,此时模型发出partial: trueToolRequestPart

  • partial请求中的input应包含到目前为止累计的参数(取决于插件状态管理逻辑),或当前 delta;
  • 工具调用的最后一个 chunk 应为partial: false(或省略该字段)。

JS 端ToolRequestSchemapartial字段(parts.ts)正是为这一场景设计的。

工具响应

工具执行结果以role: 'tool'消息中的ToolResponsePart回传给模型:

  • ref:必须匹配对应ToolRequestPartref
  • output:工具执行结果(通常是 JSON 对象);
  • content:可选 parts 列表(如工具返回图片或其他富内容)。
多轮流程(Multi-turn Flow)

支持工具的模型必须处理如下对话循环:

  1. User Message
  2. Model Message(包含ToolRequestPart
  3. Tool Message(包含ToolResponsePart
  4. Model Message(最终回答)

Go 端 generate.go 中实现了完整的工具循环:框架负责执行工具并把结果回填(Response.ToolRequests()FinishReason.isAbnormal()用于判断异常终止),插件只需在一次调用中正确产出ToolRequestPart并在后续收到tool角色消息后给出最终回答。JS 端GenerateActionOptionsSchema中的maxTurns(默认 5)与returnToolRequests则控制了这一循环的迭代上限与是否交由上层手动处理工具请求。

结构化输出(Structured Output)

  • 若提供output.schema,模型应尝试生成匹配该 schema 的内容;
  • output.constrained为 true 且模型支持,则由模型生成过程原生强制 schema;
  • 否则,schema 可被包含在提示词指令中;
  • 结果的结构化数据通常序列化在TextPart中。

框架为不支持原生约束生成的模型提供了simulateConstrainedGeneration()中间件(model/middleware.ts):把 schema 以"Output should be in JSON format and conform to the following schema:\n\n\``\n{...}\n```"的形式注入 user 消息,同时对底层模型关闭constrained标记,实现“模拟约束生成”。而constrained声明为'all'` 的模型则直接透传,由其自身保证 schema 遵守。

跨语言一致性:一份规范,三套实现

规范文档描述的契约在仓库中并非单一语言的孤例,而是通过多语言实现保持一致:

  • JavaScript/TypeScript:model-types.ts 定义全部 Zod schema(GenerateRequestSchemaModelResponseSchemaGenerateResponseChunkSchemaFinishReasonSchemaGenerationUsageSchema等),parts.ts 定义 Part 联合类型,model.ts 定义defineModel/model创建入口,model/middleware.ts 提供能力校验与降级中间件;
  • Go:gen.go 定义ModelInfoModelSupportsModelStageConstrainedSupportModelRequest,generate.go 定义Model接口、ModelAction与多轮工具循环;
  • Pythonpy/packages/genkit包亦实现了同等的模型抽象(如genkit/ai模块),可用于对照阅读。

实战清单:实现一个符合规范的模型插件

综合规范与源码,一个合规的 Genkit 模型插件作者需要落实:

  1. 声明式能力:如实填写labelversionssupports(尤其是constrainedcontext,它们直接决定框架是否挂载模拟中间件)与stage
  2. 配置透传:解构通用键后把剩余配置透传给底层 API,不要拦截未知参数;
  3. Part 双向转换:输入侧把提供者返回的文本/函数调用/媒体映射为TextPart/ToolRequestPart/MediaPart,输出侧把服务端工具内容放入CustomPart
  4. 系统消息适配:接受role: 'system'输入,按提供者要求提取到独立字段;
  5. 流式语义正确:增量时发增量 chunk,只能给整段时设aggregated: true,流式工具调用用partial标记;
  6. finish reason 映射:把提供者结束原因归一化到标准枚举,异常结束(blocked/failed/interrupted等)不要继续走工具循环;
  7. 结构化输出:原生约束按output.constrained透传,否则依赖框架的模拟约束中间件。

对照本文的契约表与源码路径,你可以逐项核对自己的模型实现,确保它能在 Genkit 的 generate action、开发者工具与多语言生态中无缝工作。

【免费下载链接】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),仅供参考

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

MCP Apps远程测试指南:用cloudflared隧道连接Claude.ai

MCP Apps远程测试指南&#xff1a;用cloudflared隧道连接Claude.ai 【免费下载链接】ext-apps Official repo for spec & SDK of MCP Apps protocol - standard for UIs embedded AI chatbots, served by MCP servers 项目地址: https://gitcode.com/GitHub_Trending/ex/…

作者头像 李华
网站建设 2026/9/17 13:04:52

Feast Snowflake 离线存储(Snowflake Offline Store)配置与实战指南

Feast Snowflake 离线存储&#xff08;Snowflake Offline Store&#xff09;配置与实战指南 【免费下载链接】feast The Open Source Feature Store for AI/ML 项目地址: https://gitcode.com/GitHub_Trending/fe/feast 本文围绕 Feast 开源特征平台中面向 Snowflake 的…

作者头像 李华
网站建设 2026/9/17 13:04:04

Win10越用越慢?13种优化方法从启动项到电源策略

Windows 10用久了变慢几乎是躲不掉的事&#xff0c;但十有八九不是硬件真不行&#xff0c;而是系统里堆了太多默认开着、默认运行、默认保留的东西。我手上这台办公本用了四年多&#xff0c;中间只加过一条内存&#xff0c;系统一直没重装&#xff0c;靠的就是隔一段时间按固定…

作者头像 李华
网站建设 2026/9/17 13:02:55

UML用例图从入门到实战:参与者、用例关系与软考考点解析

1. 用例图到底解决什么问题UML设计系列写到这里&#xff0c;前面几篇分别聊了类图、对象图这些偏静态结构的图&#xff0c;这一篇轮到用例图。说实话&#xff0c;用例图经常被当成UML里最“简单”的一张图&#xff0c;很多同学画的时候也就拖几个椭圆、拉几根线&#xff0c;感觉…

作者头像 李华