Firebase Genkit 提供 Dotprompt 插件和文本格式,可帮助您编写和整理生成式 AI 提示。
Dotprompt 的设计基于提示即代码这一前提。您可以在格式特殊的文件(称为 dotprompt 文件)中编写和维护提示,使用您为代码所用的同一版本控制系统跟踪对提示的更改,然后将提示与调用生成式 AI 模型的代码一起部署。
如需使用 Dotprompt,请先在项目根目录中创建 prompts
目录,然后在该目录中创建 .prompt
文件。以下是您可以调用 greeting.prompt
的简单示例:
---
model: vertexai/gemini-1.5-flash
config:
temperature: 0.9
input:
schema:
location: string
style?: string
name?: string
default:
location: a restaurant
---
You are the world's most welcoming AI assistant and are currently working at {{location}}.
Greet a guest{{#if name}} named {{name}}{{/if}}{{#if style}} in the style of {{style}}{{/if}}.
如需使用此提示,请安装 dotprompt
插件,然后从中导入 promptRef
函数
@genkit-ai/dotprompt
库:
import { dotprompt, promptRef } from '@genkit-ai/dotprompt';
configureGenkit({ plugins: [dotprompt()] });
然后,使用 promptRef('file_name')
加载提示:
const greetingPrompt = promptRef('greeting');
const result = await greetingPrompt.generate({
input: {
location: 'the beach',
style: 'a fancy pirate',
},
});
console.log(result.text());
Dotprompt 的语法基于 Handlebars 模板语言。您可以使用 if
、unless
和 each
辅助函数向提示添加条件部分,或迭代结构化内容。该文件格式利用 YAML 前处理为内嵌在模板中的提示提供元数据。
定义输入/输出架构
Dotprompt 包含一种针对 YAML 优化的紧凑架构定义格式,称为 Picoschema,可让您轻松定义架构中最重要的属性 了解 LLM 的使用。下面是一个文章的架构示例:
schema:
title: string # string, number, and boolean types are defined like this
subtitle?: string # optional fields are marked with a `?`
draft?: boolean, true when in draft state
status?(enum, approval status): [PENDING, APPROVED]
date: string, the date of publication e.g. '2024-04-09' # descriptions follow a comma
tags(array, relevant tags for article): string # arrays are denoted via parentheses
authors(array):
name: string
email?: string
metadata?(object): # objects are also denoted via parentheses
updatedAt?: string, ISO timestamp of last update
approvedBy?: integer, id of approver
extra?: any, arbitrary extra data
(*): string, wildcard field
上面的架构等效于以下 TypeScript 接口:
interface Article {
title: string;
subtitle?: string | null;
/** true when in draft state */
draft?: boolean | null;
/** approval status */
status?: 'PENDING' | 'APPROVED' | null;
/** the date of publication e.g. '2024-04-09' */
date: string;
/** relevant tags for article */
tags: string[];
authors: {
name: string;
email?: string | null;
}[];
metadata?: {
/** ISO timestamp of last update */
updatedAt?: string | null;
/** id of approver */
approvedBy?: number | null;
} | null;
/** arbitrary extra data */
extra?: any;
/** wildcard field */
}
Picoschema 标量类型 string
、integer
、number
、boolean
和 any
。对于对象、数组和枚举,它们在字段名称后用英文括号表示。
由 Picoschema 定义的对象具有所有必需的属性(除非由 ?
表示为可选属性),并且不允许添加额外的属性。当某个属性被标记为可选属性时,它也会设为可为 null,以便 LLM 更宽松地返回 null,而不是省略某个字段。
在对象定义中,特殊键 (*)
可用于声明“通配符”字段定义。这将匹配显式键未提供的任何其他属性。
Picoschema 不支持完整 JSON 架构的许多功能。如果您需要更强大的架构,可以改为提供 JSON 架构:
output:
schema:
type: object
properties:
field1:
type: number
minimum: 20
利用可重复使用的架构
除了在 .prompt
文件中直接定义架构之外,您还可以引用
按名称在 defineSchema
中注册的架构。如需注册架构,请执行以下操作:
import { defineSchema } from '@genkit-ai/core';
import { z } from 'zod';
const MySchema = defineSchema(
'MySchema',
z.object({
field1: z.string(),
field2: z.number(),
})
);
在提示中,您可以提供已注册架构的名称:
# myPrompt.prompt
---
model: vertexai/gemini-1.5-flash
output:
schema: MySchema
---
Dotprompt 库会自动将该名称解析为 已注册 Zod 架构。然后,您可以利用架构 Dotprompt 的 输出:
import { promptRef } from "@genkit-ai/dotprompt";
const myPrompt = promptRef("myPrompt");
const result = await myPrompt.generate<typeof MySchema>({...});
// now strongly typed as MySchema
result.output();
替换提示元数据
虽然 .prompt
文件允许您在文件本身中嵌入元数据(例如模型配置),但您也可以在每次调用时替换这些值:
const result = await greetingPrompt.generate({
model: 'vertexai/gemini-1.5-pro',
config: {
temperature: 1.0,
},
input: {
location: 'the beach',
style: 'a fancy pirate',
},
});
结构化输出
您可以将提示的格式和输出架构设置为强制转换为 JSON:
---
model: vertexai/gemini-1.5-flash
input:
schema:
theme: string
output:
format: json
schema:
name: string
price: integer
ingredients(array): string
---
Generate a menu item that could be found at a {{theme}} themed restaurant.
使用结构化输出生成提示时,可以使用 output()
辅助程序
检索并验证它:
const createMenuPrompt = promptRef('create_menu');
const menu = await createMenuPrompt.generate({
input: {
theme: 'banana',
},
});
console.log(menu.output());
在
提示。默认情况下,它附加到最后生成的消息的末尾。
输入的信息。您可以使用 {{section "output"}}
手动重新调整其位置
帮助程序。
This is a prompt that manually positions output instructions.
== Output Instructions
{{section "output"}}
== Other Instructions
This will come after the output instructions.
多消息提示
默认情况下,Dotprompt 会构造包含 "user"
角色单条消息。某些提示最好以多条消息的组合表示,例如系统提示。
{{role}}
辅助函数提供了一种构造多消息提示的简单方法:
---
model: vertexai/gemini-1.5-flash
input:
schema:
userQuestion: string
---
{{role "system"}}
You are a helpful AI assistant that really loves to talk about food. Try to work
food items into all of your conversations.
{{role "user"}}
{{userQuestion}}
多轮提示和历史记录
Dotprompt 支持多轮提示,只需将 history
选项传递到
generate
方法:
const result = await multiTurnPrompt.generate({
history: [
{ role: 'user', content: [{ text: 'Hello.' }] },
{ role: 'model', content: [{ text: 'Hi there!' }] },
],
});
默认情况下,历史记录将插入
提示。不过,您可以使用 {{history}}
手动调整历史记录的位置
帮助程序:
{{role "system"}}
This is the system prompt.
{{history}}
{{role "user"}}
This is a user message.
{{role "model"}}
This is a model message.
{{role "user"}}
This is the final user message.
多模态提示
对于支持多模态输入(例如图片和文本)的模型,您可以使用 {{media}}
辅助函数:
---
model: vertexai/gemini-1.5-flash
input:
schema:
photoUrl: string
---
Describe this image in a detailed paragraph:
{{media url=photoUrl}}
网址可以是 https://
或用于“内嵌”图片且采用 base64 编码的 data:
URI。在代码中,应如下所示:
const describeImagePrompt = promptRef('describe_image');
const result = await describeImagePrompt.generate({
input: {
photoUrl: 'https://example.com/image.png',
},
});
console.log(result.text());
部分内容
部分内容是可重复使用的模板,可以包含在任何提示中。部分内容 对于具有共同行为的相关提示特别有用。
加载提示目录时,任何前缀为 _
的文件都会被视为
partial。因此,文件 _personality.prompt
可能包含以下内容:
You should speak like a {{#if style}}{{style}}{{else}}helpful assistant.{{/else}}.
然后,可以在其他提示中添加此信息:
---
model: vertexai/gemini-1.5-flash
input:
schema:
name: string
style?: string
---
{{ role "system" }}
{{>personality style=style}}
{{ role "user" }}
Give the user a friendly greeting.
User's Name: {{name}}
使用 {{>NAME_OF_PARTIAL args...}}
语法插入部分内容。如果拒绝
部分参数提供给部分,它会在与
。
部分接受上述命名参数或单个位置参数 表示上下文。这一功能非常有用,例如:呈现列表中的成员。
# _destination.prompt
- {{name}} ({{country}})
# chooseDestination.prompt
Help the user decide between these vacation destinations:
{{#each destinations}}
{{>destination this}}{{/each}}
在代码中定义部分内容
您还可以使用 definePartial
在代码中定义部分:
import { definePartial } from '@genkit-ai/dotprompt';
definePartial(
'personality',
'Talk like a {{#if style}}{{style}}{{else}}helpful assistant{{/if}}.'
);
所有提示中均提供代码定义的部分。
提示变体
由于提示文件只是文本,因此您可以(并且应该)将提示文件提交到版本控制系统,以便您轻松比较一段时间内的更改。通常,调整后的提示版本只能在生产环境中与现有版本并排进行全面测试。Dotprompt 通过其变体功能支持此功能。
如需创建变体,请创建 [name].[variant].prompt
文件。例如,如果您在提示中使用了 Gemini 1.5 Flash,但想了解 Gemini 1.5 Pro 的表现是否更好,则可以创建两个文件:
my_prompt.prompt
:“基准”提示my_prompt.gemini15pro.prompt
:名为“gemini15pro”的变体
如需使用提示变体,请在加载时指定 variant
选项:
const myPrompt = promptRef('my_prompt', { variant: 'gemini15pro' });
变体的名称包含在生成跟踪记录的元数据中,因此您可以在 Genkit 跟踪记录检查器中比较和对比变体之间的实际效果。
定义自定义帮助程序
您可以定义自定义帮助程序,以处理和管理提示中的数据。帮助程序
使用 defineHelper
在全局范围内注册:
import { defineHelper } from '@genkit-ai/dotprompt';
defineHelper('shout', (text: string) => text.toUpperCase());
定义帮助程序后,您可以在任何提示中使用它:
---
model: vertexai/gemini-1.5-flash
input:
schema:
name: string
---
HELLO, {{shout name}}!!!
如需详细了解传递到帮助程序中的参数,请参阅 标识名文档 自定义帮助程序。
加载和定义提示的备用方法
Dotprompt 针对提示目录中的组织结构进行了优化。不过, 下面列出了加载和定义提示的一些其他方法:
loadPromptFile
:从提示目录中的文件加载提示。loadPromptUrl
:从网址加载提示。defineDotprompt
:在代码中定义提示。
示例:
import {
loadPromptFile,
loadPromptUrl,
defineDotprompt,
} from '@genkit-ai/dotprompt';
import path from 'path';
import { z } from 'zod';
// Load a prompt from a file
const myPrompt = await loadPromptFile(
path.resolve(__dirname, './path/to/my_prompt.prompt')
);
// Load a prompt from a URL
const myPrompt = await loadPromptUrl('https://example.com/my_prompt.prompt');
// Define a prompt in code
const myPrompt = defineDotprompt(
{
model: 'vertexai/gemini-1.5-flash',
input: {
schema: z.object({
name: z.string(),
}),
},
},
`Hello {{name}}, how are you today?`
);