使用 AI 模型生成内容

生成式 AI 的核心是 AI 模型。目前,Google 搜索的 例如,大语言模型 (LLM) 和图片生成模型 生成模型。这些模型会接收称为提示(最常见的是 文本、图片或两者的组合),并从中生成输出文本, 图片甚至音频或视频

这些模型的输出可能令人惊讶,LLM 可生成文本 看起来像是由人写的, 可以生成非常接近真实照片或 人类创作的艺术作品。

此外,事实证明,LLM 能够完成简单的文本生成之外的任务:

  • 编写计算机程序
  • 规划完成较大型任务所需的子任务
  • 整理未整理的数据
  • 理解和提取文本语料库中的信息数据
  • 根据以下文字描述,跟踪并执行自动化活动: 活动

我们为您提供了许多模型,它们来自多个不同的提供商。每个 模型各有优缺点,一个模型可能在一项任务中表现出色 但在其他方面却不尽如人意使用生成式 AI 的应用通常 而能够根据当下的任务使用多个不同的模型。

作为应用开发者,您通常不与生成式 AI 互动 而是通过以 Web API 的形式提供的服务进行构建。 虽然这些服务通常具有相似的功能,但它们都提供 通过不同且不兼容的 API 实现如果您想使用多个 必须使用其专有 SDK, 彼此不兼容。如果您想从一个模型升级到 那么您可能需要在整个开发过程中 。

Genkit 能够解决这一难题,它提供了一个可以 获取潜在任何生成式 AI 模型服务的详细访问信息, 已经提供了多个预构建的实现。打造 AI 赋能的产品 Genkit 应用简化了首次生成式 AI 调用的流程 无论是组合多个模型,还是将一个模型 新模式的出现。

准备工作

如果您要运行此页面上的代码示例,请先完成 使用入门指南。所有示例都假定您 已将 Genkit 作为依赖项安装在您的项目中。

Genkit 支持的模型

Genkit 设计非常灵活,可以使用任何生成式 AI 模型服务。其核心库定义了用于 模型插件定义处理 特定模型及其 API。

Genkit 团队负责维护可与 Vertex AI、 Google 生成式 AI 和 Ollama:

  • Gemini 系列中的 LLM Google Cloud Vertex AI 插件
  • 通过 Google AI 插件使用 Gemini 系列 LLM
  • Imagen2 和 Imagen3 图片生成模型(通过 Google Cloud Vertex AI 实现)
  • 通过 Google Cloud Vertex AI 的模型,Anthropic 的 Claude 3 系列 LLM 花园
  • Gemma 2、Llama 3 以及其他许多开放模型, 插件(您必须自行托管 Ollama 服务器)

此外,还有几个社区支持的插件, 这些模型的接口:

您可以通过在genkit-model npmjs.org

加载和配置模型插件

在使用 Genkit 开始生成内容之前,您需要 配置模型插件。如果您正在浏览入门指南 您就已经这样做了否则,请参阅入门指南 指南或各个插件的文档,并按照说明 继续。

generate() 函数

Genkit - 供您与生成式 AI 互动的主要界面 是 generate() 函数。

最简单的 generate() 调用会指定您要使用的模型和一个文本 提示:

import { generate } from '@genkit-ai/ai';
import { configureGenkit } from '@genkit-ai/core';
import { gemini15Flash } from '@genkit-ai/googleai';

configureGenkit(/* ... */);

(async () => {
  const llmResponse = await generate({
    model: gemini15Flash,
    prompt: 'Invent a menu item for a pirate themed restaurant.',
  });

  console.log(await llmResponse.text());
})();

运行这个简短的示例时,它会输出一些调试信息 然后是 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.

再次运行该脚本,您会得到不同的输出。

上述代码示例使用导出的模型引用指定了模型 由模型插件触发。您还可以使用字符串标识符指定模型:

const llmResponse = await generate({
  model: 'googleai/gemini-1.5-flash-latest',
  prompt: 'Invent a menu item for a pirate themed restaurant.',
});

模型字符串标识符类似于 providerid/modelid,其中提供商 ID (在本例中为 googleai)标识插件,模型 ID 是 模型特定版本的插件特定字符串标识符。

有些模型插件(如 Ollama 插件)可能会提供 数十个不同的模型,因此无需导出单个模型 参考。在这些情况下,您只能使用以下代码,将模型指定为 generate() 其字符串标识符:

const llmResponse = await generate({
  model: 'ollama/gemma2',
  prompt: 'Invent a menu item for a pirate themed restaurant.',
});

前面的所有示例还说明了一个重要点:当您使用 generate(),用于进行生成式 AI 模型调用,从而更改要 只需向模型参数传递不同的值即可。修改者 使用 generate() 而不是原生模型 SDK,则可以自行指定 从而更轻松地在应用中使用多个不同的模型并更改 生成模型。

到目前为止,您只看到了最简单的 generate() 调用示例。不过, generate() 还提供了一个接口,用于实现更高级的 生成模型,我们将在后面的部分中加以介绍。

模型参数

generate() 函数接受 config 形参,您可以通过该形参 指定用于控制模型如何生成内容的可选设置:

const llmResponse = await generate({
  prompt: "Suggest an item for the menu of a pirate themed restaurant",
  model: gemini15Flash,
  config: {
    maxOutputTokens: 400,
    stopSequences: ["<end>", "<fin>"],
    temperature: 1.2,
    topP: 0.4,
    topK: 50,
  },
});

支持的具体参数取决于具体的模型和模型 API。不过,上一个示例中的参数几乎对所有 模型。以下是对这些参数的说明:

用于控制输出长度的参数

maxOutputTokens

LLM 基于称为词元的单元运行。令牌通常会出现, 会映射到特定字符序列。将提示传递到 模型,首先需要执行的步骤之一是对提示字符串进行词元化 形成一个词元序列。然后,LLM 会根据 词元化输入。最后,词元序列会转换回文本, 这就是您的输出。

“最大输出词元数”参数只是设定了 使用 LLM 生成文本。每个模型可能使用不同的标记生成器, 较好的做法是将一个英语单词视为由 2 到 4 构成 词元。

如前所述,某些词法单元可能不会映射到字符序列。其中之一 例如,通常会有一个表示序列结束的词元: 当 LLM 生成这个词元时,它会停止生成更多词元。因此, LLM 生成的词元数量可能少于 因为它生成了“停止”令牌。

stopSequences

您可以使用此参数设置词元或词元序列, 指示 LLM 输出的结尾。应在此处使用的正确值 通常取决于模型的训练方式,并且通常由模型设定 插件。不过,如果您已提示模型再次生成经停点, 则可以在此处指定

请注意,您指定的是字符序列,而不是词元本身。大多数 您需要指定模型分词器映射到的字符序列 生成单个词元。

用于控制“创意”的参数

temperaturetop-ptop-k 参数可共同控制 “广告素材”模型。下面简要说明了 这些参数的含义,但更需要注意的是: 用于调整 LLM 输出的字符。最优 客户的价值取决于您的目标和偏好,并且很有可能 只有通过实验才能找到。

温度

从根本上讲,LLM 是一种词元预测机器。对于给定的词元序列 LLM 会预测词汇表中的每个词元, 序列中下一个词元的可能性。当前温度为 在归一化为这些预测之前所依据的缩放比例 介于 0 到 1 之间的概率。

低温值(在 0.0 和 1.0 之间)会放大 这样一来,模型就能够 来生成已评估为不可能出现的词元。这通常是 则会被认为是创意不足的输出内容。尽管从技术上来讲,0.0 并不是 许多模型都将其视为指示模型的行为方式, 并且只考虑概率最高的一个词元。

高温度值(大于 1.0)会压缩 词元之间的概率差异,结果是 更有可能生成之前被评估为 不太可能。这通常被认为是更具创造性的输出内容。某个型号 API 会施加一个最高温度(通常为 2.0)。

topP

Top-p 是一个介于 0.0 和 1.0 之间的值,用于控制可能的 您希望模型考虑的词元数量,只需指定累积概率 词元数量。例如,1.0 表示考虑所有可能的 词元(但仍需考虑每个词元的概率)。值为 0.4 表示只考虑概率最高的词元,其概率总和为 0.4,将其余词元从考虑范围中排除。

topK

Top-k 是一个整数值,该值也可以控制 但这次只需明确指定 词元数量。指定值 1 表示模型的行为 更新。

使用模型参数进行实验

您可以试验这些参数对所生成输出的影响 来根据不同的模型和提示组合进行微调。启动 genkit start 命令,它会自动加载所有 。您可以快速 尝试不同的提示和配置值,而不必反复 更改代码

结构化输出

在应用中使用生成式 AI 作为组件时,您通常需要 以纯文本以外的格式输出。即使您只是生成内容 而结构化输出则仅对 以便对用户更具吸引力但对于更高级的 生成式 AI 的应用,例如以编程方式使用模型的输出, 或者将一个模型的输出馈送到另一个模型中,结构化输出是必须的。

在 Genkit 中,您可以通过指定架构来请求模型的结构化输出 调用 generate() 时:

import { z } from "zod";
const MenuItemSchema = z.object({
  name: z.string(),
  description: z.string(),
  calories: z.number(),
  allergens: z.array(z.string()),
});

const llmResponse = await generate({
  prompt: "Suggest an item for the menu of a pirate themed restaurant",
  model: gemini15Flash,
  output: {
    schema: MenuItemSchema,
  },
});

使用 Zod 指定模型输出架构 库。除了架构定义语言之外,Zoda 还提供 类型检查,在静态 TypeScript 类型和 生成不可预测的生成式 AI 模型输出。Zod 允许您编写代码, 成功的 generate 调用将始终返回 与您的 TypeScript 类型相符。

当您在 generate() 中指定架构时,Genkit 在 场景:

  • 使用有关所需输出格式的额外指导来增强提示。 这也有一个副作用,即为模型指定具体的内容 (例如,您不仅建议一个菜单项, 生成说明、过敏原列表等)。
  • 将模型输出解析为 JavaScript 对象。
  • 验证输出是否符合架构。

如需从成功的生成调用中获取结构化输出,请使用响应 对象的 output() 方法:

type MenuItem = z.infer<typeof MenuItemSchema>;

const output: MenuItem | null = llmResponse.output();

处理错误

请注意,在前面的示例中,输出方法可能会返回 null。这可以 当模型无法生成符合架构的输出时,就会发生这种情况。您 还可以通过捕获 NoValidCandidatesError generate 抛出的异常:

import { NoValidCandidatesError } from "@genkit-ai/ai";
try {
  llmResponse = await generate(/* ... */);
} catch (e) {
  if (e instanceof NoValidCandidatesError) {
    // Output doesn't conform to schema.
  }
}

处理此类错误的最佳策略取决于您的确切用途, 下面提供了一些常用的提示:

  • 请尝试其他型号。为了使结构化输出成功,模型必须 能够以 JSON 格式生成输出。最强大的 LLM,例如 Gemini 和 Claude 有着多种多样的技能,可以做到这一点;然而,一些较小的模型 与 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() 函数类似:

import { generateStream } from "@genkit-ai/ai";
import { GenerateResponseChunk } from "@genkit-ai/ai/lib/generate";
const llmResponseStream = await generateStream({
  prompt: 'Suggest a complete menu for a pirate themed restaurant',
  model: gemini15Flash,
});

不过,此函数会返回响应块的异步可迭代对象。 在各个区块可用时对其进行处理:

for await (const responseChunkData of llmResponseStream.stream()) {
  const responseChunk = responseChunkData as GenerateResponseChunk;
  console.log(responseChunk.text());
}

您仍然可以立即获取完整响应:

const llmResponse = await llmResponseStream.response();

流式处理也适用于结构化输出:

const MenuSchema = z.object({
  starters: z.array(MenuItemSchema),
  mains: z.array(MenuItemSchema),
  desserts: z.array(MenuItemSchema),
});
type Menu = z.infer<typeof MenuSchema>;

const llmResponseStream = await generateStream({
  prompt: "Suggest a complete menu for a pirate themed restaurant",
  model: gemini15Flash,
  output: { schema: MenuSchema },
});

for await (const responseChunkData of llmResponseStream.stream()) {
  const responseChunk = responseChunkData as GenerateResponseChunk<Menu>;
  // output() returns an object representing the entire output so far
  const output: Menu | null = responseChunk.output();
  console.log(output);
}

流式结构化输出与流式文本的工作原理略有不同。时间 调用响应块的 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 一系列模型可以接受图片、视频和音频作为提示。

向支持媒体提示的模型提供媒体提示,而不是传递 简单文本提示,传递一个包含媒体部分和 文本部分:

const llmResponse = await generate({
  prompt: [
    { media: { url: 'https://example.com/photo.jpg' } },
    { text: 'Compose a poem about this image.' },
  ],
  model: gemini15Flash,
});

在上面的示例中,您使用可公开访问的 HTTPS 指定了图片 网址。您还可以将媒体数据编码为数据网址,从而直接传递该数据。例如:

import { readFile } from 'node:fs/promises';
const b64Data = await readFile('output.png', { encoding: 'base64url' });
const dataUrl = `data:image/png;base64,${b64Data}`;

const llmResponse = await generate({
  prompt: [
    { media: { url: dataUrl } },
    { text: 'Compose a poem about this image.' },
  ],
  model: gemini15Flash,
});

所有支持媒体输入的模型都支持数据网址和 HTTPS 网址。部分 模型插件添加对其他媒体来源的支持。例如,Vertex AI 插件还允许您使用 Cloud Storage (gs://) 网址。

正在生成媒体内容

到目前为止,本页中的大部分示例都是介绍如何使用 LLM。不过,Genkit 也可以与图片生成模型搭配使用。使用 将 generate() 用于图像生成模型与使用 LLM 类似。对于 通过 Vertex AI 使用 Imagen2 模型生成图片:

  1. Genkit 使用 data: 网址作为生成的媒体的标准输出格式。 这是一种标准格式,有许多库可用来处理它们。这个 示例使用 jsdom 中的 data-urls 软件包:

    npm i data-urls
    npm i --save-dev @types/data-urls
    
  2. 如需生成图片并将其保存到文件中,请调用 generate(),并指定 输出格式的媒体类型:

    import { generate } from '@genkit-ai/ai';
    import { configureGenkit } from '@genkit-ai/core';
    import { vertexAI, imagen2 } from '@genkit-ai/vertexai';
    import parseDataURL from 'data-urls';
    
    import { writeFile } from 'node:fs/promises';
    
    configureGenkit({
      plugins: [vertexAI({ location: 'us-central1' })],
    });
    
    (async () => {
      const mediaResponse = await generate({
        model: imagen2,
        prompt: 'photo of a meal fit for a pirate',
        output: { format: 'media' },
      });
    
      const media = mediaResponse.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);
    })();
    

消息历史记录

您的许多用户第一次接触大语言模型 花时间通过聊天机器人交流。虽然 LLM 的功能远不止于 仍然是一种熟悉且实用的互动方式。即使 您的用户不会以这种方式直接与模型互动, 提示的对话风格是影响输出结果的有力方式 生成式 AI 模型。

如需根据模型响应生成消息历史记录,请调用 toHistory() 方法:

let response = await generate({
  model: gemini15Flash,
  prompt: "How do you say 'dog' in French?",
});
let history = response.toHistory();

您可以序列化此历史记录,并将其保留在数据库或会话存储空间中。然后,在将来调用 generate() 时传递历史记录和提示:

response = await generate({
  model: gemini15Flash,
  prompt: 'How about in Spanish?',
  history,
});
history = response.toHistory();

如果您使用的模型支持 system 角色,则可以使用初始 history 设置系统消息:

import { MessageData } from "@genkit-ai/ai/model";
let history: MessageData[] = [
  { role: 'system', content: [{ text: 'Talk like a pirate.' }] },
];
let response = await generate({
  model: gemini15Flash,
  prompt: "How do you say 'dog' in French?",
  history,
});

后续步骤

详细了解 Genkit

  • 作为应用开发者,影响生成式 AI 输出结果的主要方式 是通过提示完成的。如需了解具体方法,请参阅提示管理 Genkit 可帮助您开发有效的提示并在代码库中进行管理。
  • 尽管 generate() 是依托于生成式 AI 的所有技术的核心 实际应用通常需要进行额外工作 以及调用生成式 AI 模型后生成的报告。为了反映这一点,Genkit 引入了 的概念,流的定义与函数类似, 可观测性和简化部署等功能。如需了解详情,请参阅 定义工作流

高级 LLM 用法

  • 增强 LLM 能力的一种方法就是提示他们 向您索要更多信息,或要求您执行 执行一些操作这称为“工具调用”或“函数调用”。模型 经过训练支持此功能的员工可以使用 一种特殊格式的响应,它指示调用应用程序 它应执行某项操作,并将结果连同结果一起发回给 LLM 原始提示。Genkit 具有相应的库函数,可自动执行 提示生成和调用 - 响应循环元素的 实施。如需了解详情,请参阅工具调用
  • 检索增强生成 (RAG) 是一种技术,用于 将特定领域的信息整合到模型输出中。这是通过 先将相关信息插入提示,然后再传递给 语言模型。完整的 RAG 实现需要您引入多个 文本嵌入生成模型、矢量数据库和 大型语言模型。请参阅检索增强生成 (RAG), 了解 Genkit 如何简化协调 元素。

测试模型输出

作为软件工程师,您习惯于确定 输入始终生成相同的输出。然而,随着 AI 模型的发展, 输出可能会根据输入、 模型的训练数据,甚至是由参数刻意引入的随机性, 比如温度

Genkit 评估员是评估 LLM 质量的结构化方法 使用各种策略构建响应。阅读更多 评估页面。