使用 Dotprompt 管理提示

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 模板语言。您可以使用 ifunlesseach 辅助函数向提示添加条件部分,或迭代结构化内容。该文件格式利用 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 标量类型 stringintegernumberbooleanany。对于对象、数组和枚举,它们在字段名称后用英文括号表示。

由 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 跟踪记录检查器中比较和对比变体之间的实际效果。