AI 模型是生成式 AI 的核心。目前,生成模型的两个最突出的示例是大语言模型 (LLM) 和图片生成模型。这些模型会接受称为“提示”的输入(通常为文本、图片或二者结合),并据此生成文本、图片,甚至音频或视频输出。
这些模型的输出效果令人惊艳:LLM 生成的文本几乎可以乱真,图片生成模型也能生成逼真的照片或近似人类创作的艺术作品。
此外,LLM 还能胜任简单文本生成以外的任务:
- 编写计算机程序
- 规划完成复杂任务所需的各个子任务
- 整理杂乱无序的数据
- 理解并提取文本语料库中的信息数据
- 根据活动的文字说明跟踪和执行自动化活动
您可以从多家不同的提供商处获得多种模型。每种模型都有其优势和局限,一种模型可能在某项任务中表现突出,在其他任务中则相对逊色。利用生成式 AI 的应用通常可以根据当前任务使用多个不同的模型。
作为应用开发者,您通常不会直接与生成式 AI 模型互动,而是通过以 Web API 形式提供的服务进行互动。虽然这些服务通常功能类似,但它们通过各自不同且不兼容的 API 提供这些功能。如果您希望使用多种模型服务,就必须使用它们各自的专有 SDK,而这些 SDK 可能不兼容。如果您希望将模型升级为最新且功能更强的版本,可能需要从头构建该集成。
Genkit 通过提供一个单一接口来解决此难题,该接口可抽象出访问可能的任何生成式 AI 模型服务的详细信息,并且已经提供了多种预构建实现。围绕 Genkit 构建 AI 赋能的应用可简化首次生成式 AI 调用流程,并可轻松组合多个模型或在出现新模型时将一个模型换成另一个模型。
准备工作
如果您想运行本页面中的代码示例,请先完成使用入门指南中的步骤。所有示例都假定您已在项目中将 Genkit 作为依赖项进行安装。
Genkit 支持的模型
Genkit 的设计具备足够灵活性,可支持使用任何可能的生成式 AI 模型服务。其核心库定义了用于处理模型的通用接口,而模型插件定义了用于处理特定模型及其 API 的实现细节。
Genkit 团队会维护用于处理 Vertex AI、Google 生成式 AI 和 Ollama 提供的模型的插件:
- Gemini 系列 LLM,通过 Google Cloud Vertex AI 插件
- Gemini 系列 LLM,通过 Google AI 插件
- 通过 Google Cloud Vertex AI 使用 Imagen2 和 Imagen3 图片生成模型
- Anthropic 的 Claude 3 系列 LLM,通过 Google Cloud Vertex AI 的 Model Garden
- 通过 Ollama 插件使用 Gemma 2、Llama 3 以及更多开放式模型(您必须自行托管 Ollama 服务器)
此外,还有一些由社区支持的插件可提供这些模型的接口:
- Claude 3 系列 LLM,通过 Anthropic 插件
- GPT 系列 LLM,通过 OpenAI 插件
- GPT 系列 LLM,通过 Azure OpenAI 插件
- 通过 Cohere 插件控制 R 系列 LLM
- Mistral 系列 LLM,通过 Mistral 插件
- 通过 Groq 插件使用 Gemma 2、Llama 3 以及更多托管在 Groq 上的开放式模型
您可以在 npmjs.org 上搜索标记为 genkit-model
的软件包,了解更多信息。
加载和配置模型插件
在使用 Genkit 开始生成内容之前,您需要加载并配置模型插件。如果您是从“使用入门”指南中过来的,那么您已经完成了此步骤。否则,请参阅使用入门指南或各插件文档,并在继续操作前完成相关步骤。
generate() 方法
在 Genkit 中,您与生成式 AI 模型互动的主要接口是 generate()
方法。
最简单的 generate()
调用会指定您要使用的模型和文本提示:
import { googleAI } from '@genkit-ai/googleai';
import { genkit } from 'genkit';
const ai = genkit({
plugins: [googleAI()],
model: googleAI.model('gemini-2.0-flash'),
});
async function main() {
const { text } = await ai.generate(
'Invent a menu item for a pirate themed restaurant.'
);
console.log(text);
}
main();
运行此简短示例时,它会输出一些调试信息,然后输出 generate()
调用的输出(通常是 Markdown 文本),如以下示例所示:
## The Blackheart's Bounty
**A hearty stew of slow-cooked beef, spiced with rum and molasses, served in a
hollowed-out cannonball with a side of crusty bread and a dollop of tangy
pineapple salsa.**
**Description:** This dish is a tribute to the hearty meals enjoyed by pirates
on the high seas. The beef is tender and flavorful, infused with the warm spices
of rum and molasses. The pineapple salsa adds a touch of sweetness and acidity,
balancing the richness of the stew. The cannonball serving vessel adds a fun and
thematic touch, making this dish a perfect choice for any pirate-themed
adventure.
再次运行该脚本时,您将会看到不同的输出结果。
上述代码示例将生成请求发送到了您在配置 Genkit 实例时指定的默认模型。
您还可以为单个 generate()
调用指定模型:
const { text } = await ai.generate({
model: googleAI.model('gemini-2.0-flash'),
prompt: 'Invent a menu item for a pirate themed restaurant.',
});
此示例使用模型插件提供的模型引用函数。模型引用包含有关模型及其选项的静态类型信息,这些信息对 IDE 中的代码补全和编译时代码补全都很有用。许多插件都使用此模式,但并非全部。如果您的插件不使用此模式,请参阅其文档,了解创建函数引用的最佳方式。
有时,您可能会看到将模型引用作为常量导入的代码示例:
import { googleAI, gemini20Flash } from "@genkit-ai/googleai";
const ai = genkit({
plugins: [googleAI()],
model: gemini20Flash,
});
某些插件可能仍在使用此模式。对于已改用新语法的插件,这些常量仍然存在并继续有效,但未来可能不会为新的模型添加新的常量。
另一种方法是使用字符串标识符指定模型。无论插件选择如何处理类型化模型引用,此方法都适用于所有插件。不过,您将无法获得静态类型检查的帮助:
const { text } = await ai.generate({
model: 'googleai/gemini-2.0-flash-001',
prompt: 'Invent a menu item for a pirate themed restaurant.',
});
模型字符串标识符的格式为 providerid/modelid
,其中提供方 ID(在本例中为 googleai
)用于标识插件,而模型 ID 则是特定模型版本的插件专用字符串标识符。
某些模型插件(例如 Ollama 插件)可提供对数十种不同模型的访问权限,因此不会导出单个模型引用。在这些情况下,您只能使用字符串标识符向 generate()
指定模型。
这些示例还说明了一个重要要点:当您使用 generate()
进行生成式 AI 模型调用时,更改要使用的模型只需向模型参数传递不同的值即可。通过使用 generate()
替代原生模型 SDK,您可以更灵活地在应用中集成多个不同模型,并在未来轻松切换所用模型。
到目前为止,您只看到了最简单的 generate()
调用的示例。不过,generate()
还提供了一个接口,用于与生成模型进行更高级的交互,您将在后续部分看到该接口。
系统提示
某些模型支持提供系统提示,以告知模型您希望它如何响应来自用户的消息。您可以使用系统提示来指定您希望模型采用的角色、其回答的语气、回答的格式等等。
如果您使用的模型支持系统提示,您可以使用 system
参数提供一个提示:
const { text } = await ai.generate({
system: 'You are a food industry marketing consultant.',
prompt: 'Invent a menu item for a pirate themed restaurant.',
});
模型参数
generate()
函数接受 config
参数,您可以通过该参数指定可选设置,以控制模型生成内容的方式:
const { text } = await ai.generate({
prompt: 'Invent a menu item for a pirate themed restaurant.',
config: {
maxOutputTokens: 400,
stopSequences: ['<end>', '<fin>'],
temperature: 1.2,
topP: 0.4,
topK: 50,
},
});
支持的确切参数取决于各个模型和模型 API。不过,上例中的参数对几乎所有模型都适用。以下是这些参数的说明:
用于控制输出长度的参数
maxOutputTokens
LLM 对称为 token 的单元进行操作。token 通常会映射到特定字符序列,但并非总是如此。当您将提示传递给模型时,模型首先要做的一件事就是将提示字符串词元化成一系列 token。然后,LLM 会根据已词元化的输入生成一系列 token。最后,token 序列会转换回文本,即输出内容。
输出 token 数上限参数仅用于设置使用 LLM 生成的 token 数上限。每个模型都可能使用不同的词元化器,但一个很好的经验法则是,将单个英语单词视为由 2 到 4 个 token 组成。
如前所述,某些 token 可能并不映射到字符序列。例如,通常有一个 token 表示序列的结束:当 LLM 生成此 token 时,它会停止生成更多 token。因此,LLM 生成的 token 数量通常会少于最大值,因为它生成了“stop”token。
stopSequences
您可以使用此参数设置 token 或 token 序列,以在生成时指示 LLM 输出结束。此处要使用的正确值通常取决于模型的训练方式,并且通常由模型插件设置。不过,如果您已提示模型生成其他 stop 序列,则可以在此处指定该序列。
请注意,您指定的是字符序列,而不是真正的 token 本体。在大多数情况下,您需要指定一个字符序列,以便模型的词元化器将其映射到单个 token。
用于控制“创意”的参数
温度、Top-P 和 Top-K 参数共同控制您希望模型的“创意”程度。下面简要介绍了这些参数的含义,但更重要的一点是:这些参数用于调整 LLM 输出的风格特性。这些参数的最佳值取决于您的目标和偏好,并且可能只有通过实验才能找到。
temperature
LLM 从根本上说是 token 预测机器。对于给定的 token 序列(例如提示),LLM 会针对其词汇表中的每个 token 预测该 token 在序列中出现的可能性。温度是一个缩放比例,用于在将这些预测结果归一化为介于 0 到 1 之间的概率之前对其进行除法运算。
低温值(介于 0.0 到 1.0 之间)会放大 token 之间可能性的差异,导致模型更不可能生成它已评估为不太可能的 token。这通常被认为是缺乏创意的输出。虽然从技术上讲 0.0 并非有效值,但许多模型会将其视为一种指示,让模型以确定性方式运行,并仅考虑最有可能的那个 token。
高温度值(大于 1.0)会压缩不同 token 的可能性差异,从而导致模型更有可能生成之前评估为不太可能的 token。这通常被视为更有创意的输出。某些模型 API 会设置一个最高温度,通常为 2.0。
topP
Top-p 是一个介于 0.0 到 1.0 之间的值,用于通过指定 token 的累计概率来控制您希望模型考虑的可能 token 的数量。例如,值为 1.0 表示考虑所有可能的 token(但仍会考虑每个 token 的概率)。值为 0.4 表示仅考虑概率总和为 0.4 的最可能的 token,并排除其他 token。
topK
Top-k 是一个整数值,它同样控制您希望模型考虑的可能 token 的数量,但这次是通过明确指定 token 数量上限来控制。指定值 1 表示模型应以确定的方式运行。
对模型参数进行实验
您可以使用开发者界面,试验这些参数对不同模型和提示组合生成的输出的影响。使用 genkit start
命令启动开发者界面,它将自动加载项目中配置的插件定义的所有模型。您可以快速尝试不同的提示和配置值,而无需在代码中反复进行这些更改。
结构化输出
在应用中将生成式 AI 作为组件使用时,您通常希望输出的格式不是纯文本。即使只是生成面向用户展示的内容,您也可以借助结构化输出,以更具吸引力的方式呈现。但对于更高级的生成式 AI 应用(例如以程序化方式使用模型输出,或将一个模型的输出作为输入传递给另一个模型),结构化输出是必不可少的。
在 Genkit 中,您可以在调用 generate()
时指定架构,以便向模型请求结构化输出:
import { z } from 'genkit'; // Import Zod, which is re-exported by Genkit.
const MenuItemSchema = z.object({
name: z.string(),
description: z.string(),
calories: z.number(),
allergens: z.array(z.string()),
});
const { output } = await ai.generate({
prompt: 'Invent a menu item for a pirate themed restaurant.',
output: { schema: MenuItemSchema },
});
模型输出架构使用 Zod 库指定。除了架构定义语言之外,Zod 还提供运行时类型检查,可弥合静态 TypeScript 类型与生成式 AI 模型不可预测的输出之间的差距。借助 Zod,您可以编写代码,并可依赖于成功的生成调用始终会返回符合 TypeScript 类型的输出这一事实。
当您在 generate()
中指定架构时,Genkit 会在后台执行多项操作:
- 在提示中添加有关所需输出格式的更多指导。这还会附带一个效果,即向模型明确指定您希望生成的具体内容(例如,不仅要建议菜单项,还要生成描述、过敏原列表等)。
- 将模型输出解析为 JavaScript 对象。
- 验证输出是否符合架构。
如需从成功的生成调用中获取结构化输出,请使用响应对象的 output
属性:
if (output) {
const { name, description, calories, allergens } = output;
}
处理错误
请注意,在上一个示例中,output
属性可以是 null
。如果模型未能生成符合架构的输出,就可能会发生这种情况。处理此类错误的最佳策略取决于您的确切用例,但以下是一些常规提示:
尝试使用其他模型。为了成功生成结构化输出,模型必须能够以 JSON 格式生成输出。像 Gemini 和 Claude 这样功能强大的 LLM 足够灵活,可以做到这一点;但较小的模型(例如您在 Ollama 中使用的某些本地模型)如果未经专门训练,往往无法稳定生成结构化输出。
利用 Zod 的强制转换功能:您可以在架构中指定 Zod 应尝试将不合规的类型强制转换为架构指定的类型。如果您的架构包含字符串以外的原始类型,使用 Zod 强制转换可以减少遇到的
generate()
失败次数。以下版本的MenuItemSchema
使用类型强制转换来自动更正模型以字符串(而非数字)形式生成卡路里信息的情况:const MenuItemSchema = z.object({ name: z.string(), description: z.string(), calories: z.coerce.number(), allergens: z.array(z.string()), });
重试 generate() 调用。如果您选择的模型通常能够生成符合规范的输出,您可以将此类错误视为网络连接错误处理,并通过某种增量退避策略重试请求。
流式
在生成大量文本时,您可以通过在生成输出时显示输出(对输出进行流式传输)来改善用户体验。在大多数 LLM 聊天应用中,流式传输的典型示例是:用户可以在模型生成回答消息的同时实时读取内容,从而提升应用的响应感知,并增强与智能体对话的沉浸感。
在 Genkit 中,您可以使用 generateStream()
方法对输出进行流式传输。其语法与 generate()
方法类似:
const { response, stream } = ai.generateStream(
'Suggest a complete menu for a pirate themed restaurant.'
);
响应对象具有 stream
属性,您可以使用该属性在请求生成流式输出时对其进行迭代:
for await (const chunk of stream) {
console.log(chunk.text);
}
您还可以获取请求的完整输出,就像非流式请求一样:
const completeText = (await response).text;
流式传输也适用于结构化输出:
const MenuSchema = z.object({
starters: z.array(MenuItemSchema),
mains: z.array(MenuItemSchema),
desserts: z.array(MenuItemSchema),
});
const { response, stream } = await ai.generateStream({
prompt: 'Suggest a complete menu for a pirate themed restaurant.',
output: { schema: MenuSchema },
});
for await (const chunk of stream) {
// `output` is an object representing the entire output so far.
console.log(chunk.output);
}
// Get the completed output.
const { output } = await response;
流式结构化输出与流式文本的运作方式略有不同:响应分块的 output
属性是通过累积到目前为止生成的分块构建的对象,而不是表示单个分块的对象(单个分块本身可能无效)。从某种意义上讲,结构化输出的每个分块都会替换之前的分块。
例如,前面的示例的前五个输出可能如下所示:
null
{ starters: [ {} ] }
{
starters: [ { name: "Captain's Treasure Chest", description: 'A' } ]
}
{
starters: [
{
name: "Captain's Treasure Chest",
description: 'A mix of spiced nuts, olives, and marinated cheese served in a treasure chest.',
calories: 350
}
]
}
{
starters: [
{
name: "Captain's Treasure Chest",
description: 'A mix of spiced nuts, olives, and marinated cheese served in a treasure chest.',
calories: 350,
allergens: [Array]
},
{ name: 'Shipwreck Salad', description: 'Fresh' }
]
}
多模态输入
到目前为止,您看到的示例都使用文本字符串作为模型提示。虽然这仍然是提示生成式 AI 模型的最常用方式,但许多模型也可以接受其他媒体作为提示。媒体提示通常与文本提示结合使用,以指示模型对媒体执行某些操作,例如为图片添加说明或将录音转录为文字。
模型是否支持媒体输入以及可接受的媒体类型,完全由该模型及其 API 决定。例如,Gemini 1.5 系列模型可以接受图片、视频和音频作为提示。
如需向支持媒体提示的模型提供媒体提示,请传递一个由媒体部分和文本部分组成的数组,而不是将简单的文本提示传递给 generate
:
const { text } = await ai.generate([
{ media: { url: 'https://example.com/photo.jpg' } },
{ text: 'Compose a poem about this image.' },
]);
在上面的示例中,您使用可公开访问的 HTTPS 网址指定了图片。您还可以通过将媒体数据编码为数据网址来直接传递媒体数据。例如:
import { readFile } from 'node:fs/promises';
const b64Data = await readFile('photo.jpg', { encoding: 'base64url' });
const dataUrl = `data:image/jpeg;base64,${b64Data}`;
const { text } = await ai.generate([
{ media: { url: dataUrl } },
{ text: 'Compose a poem about this image.' },
]);
所有支持媒体输入的模型均可识别数据网址和 HTTPS 网址,部分模型插件还扩展了对其他媒体来源的支持。例如,借助 Vertex AI 插件,您还可以使用 Cloud Storage (gs://
) 网址。
生成媒体
到目前为止,本页上的大多数示例都涉及使用 LLM 生成文本。不过,Genkit 还可与图像生成模型搭配使用。将 generate()
与图片生成模型搭配使用与使用 LLM 类似。例如,如需通过 Vertex AI 使用 Imagen2 模型生成图片,请执行以下操作:
Genkit 使用
data:
网址作为生成的媒体的标准输出格式。这是一种标准格式,有许多库可用于处理它们。以下示例使用jsdom
中的data-urls
软件包:npm i --save data-urls
npm i --save-dev @types/data-urls
如需生成图片并将其保存到文件中,请调用
generate()
,指定图片生成模型和输出格式的媒体类型:import { vertexAI } from '@genkit-ai/vertexai'; import parseDataURL from 'data-urls'; import { genkit } from 'genkit'; import { writeFile } from 'node:fs/promises'; const ai = genkit({ plugins: [vertexAI({ location: 'us-central1' })], }); async function main() { const { media } = await ai.generate({ model: vertexAI.model('imagen-3.0-fast-generate-001'), prompt: 'photo of a meal fit for a pirate', output: { format: 'media' }, }); if (media === null) throw new Error('No media generated.'); const data = parseDataURL(media.url); if (data === null) throw new Error('Invalid "data:" URL.'); await writeFile(`output.${data.mimeType.subtype}`, data.body); } main();
后续步骤
详细了解 Genkit
- 作为应用开发者,您影响生成式 AI 模型输出的主要方式是通过提示。请阅读提示管理,了解 Genkit 如何帮助您在代码库中开发有效的提示并对其进行管理。
- 虽然
generate()
是所有由生成式 AI 赋能应用的核心,但在实际应用中,通常需要在调用生成式 AI 模型前后执行配套处理。为反映这一点,Genkit 引入了 flow 的概念,工作流的定义方式与函数类似,但增加了可观测性和简化部署等额外功能。如需了解详情,请参阅定义工作流。
高级 LLM 用法
- 增强 LLM 功能的一种方法是,向 LLM 提示一系列方式,让其向您请求更多信息,或请求您执行某些操作。这称为“工具调用”或“函数调用”。经过训练以支持此功能的模型可以使用格式特殊的回答来回答提示,该响应会向调用应用指明应执行某些操作并将结果连同原始提示一起发送回 LLM。Genkit 提供库函数,可自动完成工具调用实现中的提示生成和调用-回答循环元素。如需了解详情,请参阅工具调用。
- 检索增强生成 (RAG) 是一种技术,用于将特定于某个领域的信息引入模型的输出中。这通常通过在将提示传递给语言模型之前插入相关信息来实现。完整的 RAG 实现需要集成多种技术:文本嵌入生成模型、向量数据库和大语言模型。如需了解 Genkit 如何简化协调这些各种元素的过程,请参阅检索增强生成 (RAG)。
测试模型输出
作为软件工程师,您可能习惯了确定性系统,在这种系统中,相同的输入始终会产生相同的输出。不过,由于 AI 模型是概率性的,因此输出可能会因输入中的细微差异、模型的训练数据,甚至温度等参数故意引入的随机性而异。
Genkit 的评估器采用结构化方式,使用多种策略来评估 LLM 的回答质量。如需了解详情,请参阅评估页面。