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
插件:
go get github.com/firebase/genkit/go/plugins/dotprompt
然后,使用 Open
加载提示:
import "github.com/firebase/genkit/go/plugins/dotprompt"
dotprompt.SetDirectory("prompts")
prompt, err := dotprompt.Open("greeting")
您可以调用提示的 Generate
方法来呈现模板,并在一步中将其传递给模型 API:
ctx := context.Background()
// Default to the project in GCLOUD_PROJECT and the location "us-central1".
vertexai.Init(ctx, nil)
// The .prompt file specifies vertexai/gemini-1.5-flash, which is
// automatically defined by Init(). However, if it specified a model that
// isn't automatically loaded (such as a specific version), you would need
// to define it here:
// vertexai.DefineModel("gemini-1.0-pro-002", &ai.ModelCapabilities{
// Multiturn: true,
// Tools: true,
// SystemRole: true,
// Media: false,
// })
type GreetingPromptInput struct {
Location string `json:"location"`
Style string `json:"style"`
Name string `json:"name"`
}
response, err := prompt.Generate(
ctx,
&dotprompt.PromptRequest{
Variables: GreetingPromptInput{
Location: "the beach",
Style: "a fancy pirate",
Name: "Ed",
},
},
nil,
)
if err != nil {
return err
}
fmt.Println(response.Text())
或者,只需将模板呈现给字符串:
renderedPrompt, err := prompt.RenderText(map[string]any{
"location": "a restaurant",
"style": "a pirate",
})
Dotprompt 的语法基于 Handlebars 模板语言。您可以使用 if
、unless
和 each
辅助函数向提示添加条件部分,或迭代结构化内容。该文件格式利用 YAML 前处理为内嵌在模板中的提示提供元数据。
使用 Picoschema 定义输入/输出架构
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
上述架构等效于以下 JSON 架构:
{
"properties": {
"metadata": {
"properties": {
"updatedAt": {
"type": "string",
"description": "ISO timestamp of last update"
},
"approvedBy": {
"type": "integer",
"description": "id of approver"
}
},
"type": "object"
},
"title": {
"type": "string"
},
"subtitle": {
"type": "string"
},
"draft": {
"type": "boolean",
"description": "true when in draft state"
},
"date": {
"type": "string",
"description": "the date of publication e.g. '2024-04-09'"
},
"tags": {
"items": {
"type": "string"
},
"type": "array",
"description": "relevant tags for article"
},
"authors": {
"items": {
"properties": {
"name": {
"type": "string"
},
"email": {
"type": "string"
}
},
"type": "object",
"required": ["name"]
},
"type": "array"
}
},
"type": "object",
"required": ["title", "date", "tags", "authors"]
}
Picoschema 标量类型 string
、integer
、number
、boolean
和 any
。对于对象、数组和枚举,它们在字段名称后用英文括号表示。
由 Picoschema 定义的对象具有所有必需的属性(除非由 ?
表示为可选属性),并且不允许添加额外的属性。当某个属性被标记为可选属性时,它也会设为可为 null,以便 LLM 更宽松地返回 null,而不是省略某个字段。
在对象定义中,特殊键 (*)
可用于声明“通配符”字段定义。这将匹配显式键未提供的任何其他属性。
Picoschema 不支持完整 JSON 架构的许多功能。如果您需要更强大的架构,可以改为提供 JSON 架构:
output:
schema:
type: object
properties:
field1:
type: number
minimum: 20
替换提示元数据
虽然 .prompt
文件允许您在文件本身中嵌入元数据(例如模型配置),但您也可以在每次调用时替换这些值:
// Make sure you set up the model you're using.
vertexai.DefineModel("gemini-1.5-flash", nil)
response, err := prompt.Generate(
context.Background(),
&dotprompt.PromptRequest{
Variables: GreetingPromptInput{
Location: "the beach",
Style: "a fancy pirate",
Name: "Ed",
},
Model: "vertexai/gemini-1.5-flash",
Config: &ai.GenerationCommonConfig{
Temperature: 1.0,
},
},
nil,
)
多消息提示
默认情况下,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}}
多模态提示
对于支持多模态输入(例如图片和文本)的模型,您可以使用 {{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。在代码中,应如下所示:
dotprompt.SetDirectory("prompts")
describeImagePrompt, err := dotprompt.Open("describe_image")
if err != nil {
return err
}
imageBytes, err := os.ReadFile("img.jpg")
if err != nil {
return err
}
encodedImage := base64.StdEncoding.EncodeToString(imageBytes)
dataURI := "data:image/jpeg;base64," + encodedImage
type DescribeImagePromptInput struct {
PhotoUrl string `json:"photo_url"`
}
response, err := describeImagePrompt.Generate(
context.Background(),
&dotprompt.PromptRequest{Variables: DescribeImagePromptInput{
PhotoUrl: dataURI,
}},
nil,
)
提示变体
由于提示文件只是文本,因此您可以(并且应该)将提示文件提交到版本控制系统,以便您轻松比较一段时间内的更改。通常,调整后的提示版本只能在生产环境中与现有版本并排进行全面测试。Dotprompt 通过其变体功能支持此功能。
如需创建变体,请创建 [name].[variant].prompt
文件。例如,如果您在提示中使用了 Gemini 1.5 Flash,但想了解 Gemini 1.5 Pro 的表现是否更好,则可以创建两个文件:
my_prompt.prompt
:“基准”提示my_prompt.geminipro.prompt
:名为“geminipro”的变体
如需使用提示变体,请在加载时指定相应变体:
describeImagePrompt, err := dotprompt.OpenVariant("describe_image", "geminipro")
提示加载器会尝试加载该名称的变体,如果不存在,则回退为使用基准。这意味着,您可以根据对您的应用有意义的条件使用条件加载:
var myPrompt *dotprompt.Prompt
var err error
if isBetaTester(user) {
myPrompt, err = dotprompt.OpenVariant("describe_image", "geminipro")
} else {
myPrompt, err = dotprompt.Open("describe_image")
}
变体的名称包含在生成跟踪记录的元数据中,因此您可以在 Genkit 跟踪记录检查器中比较和对比变体之间的实际效果。