Firebase Genkit bietet das Dotprompt-Plug-in und das Textformat zum Schreiben und organisieren Sie Ihre generativen KI-Prompts.
Dotprompt basiert auf der Prämisse, dass Prompts Code sind. Sie schreiben und verwalten Ihre Prompts in speziell formatierten Dateien, sogenannten Dotprompt-Dateien, verfolgen Änderungen daran mit demselben Versionskontrollsystem, das Sie für Ihren Code verwenden, und stellen sie zusammen mit dem Code bereit, der Ihre generativen KI-Modelle aufruft.
Wenn Sie Dotprompt verwenden möchten, erstellen Sie zuerst ein prompts
-Verzeichnis im Stammverzeichnis Ihres Projekts und dann eine .prompt
-Datei in diesem Verzeichnis. Hier ist ein einfaches Beispiel,
kann greeting.prompt
aufrufen:
---
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}}.
Installieren Sie das Plug-in dotprompt
, um diesen Prompt zu verwenden:
go get github.com/firebase/genkit/go/plugins/dotprompt
Laden Sie dann die Aufforderung mit Open
:
import "github.com/firebase/genkit/go/plugins/dotprompt"
g, err := genkit.Init(ctx, genkit.WithPromptDir("prompts"))
if err != nil {
log.Fatal(err)
}
prompt, err := dotprompt.Open(g, "greeting")
Sie können die Generate
-Methode des Prompts aufrufen, um die Vorlage zu rendern und in einem Schritt an die Modell-API zu übergeben:
ctx = context.Background()
// Default to the project in GCLOUD_PROJECT and the location "us-central1".
vertexai.Init(ctx, g, nil)
// The .prompt file specifies vertexai/gemini-2.0-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-2.0-flash", &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, g,
dotprompt.WithInput(GreetingPromptInput{
Location: "the beach",
Style: "a fancy pirate",
Name: "Ed",
}),
nil,
)
if err != nil {
return err
}
fmt.Println(response.Text())
Oder rendern Sie die Vorlage einfach in einen String:
renderedPrompt, err := prompt.RenderText(map[string]any{
"location": "a restaurant",
"style": "a pirate",
})
Die Syntax von Dotprompt basiert auf dem Handlebars
der Vorlagensprache. Sie können die Helper „if
“, „unless
“ und „each
“ verwenden,
bedingte Abschnitte zu deinem Prompt hinzufügen oder strukturierte Inhalte iterieren. Das Dateiformat verwendet YAML-Frontmatter, um Metadaten für einen Prompt inline in der Vorlage bereitzustellen.
Eingabe-/Ausgabeschemas mit Picoschema definieren
Dotprompt enthält ein kompaktes, YAML-basiertes Schemadefinitionformat namens Picoschema, mit dem sich die wichtigsten Attribute eines Schemas für die Verwendung in LLM-Umgebungen ganz einfach definieren lassen. Hier ist ein Beispiel für ein Schema für einen Artikel:
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
Das obige Schema entspricht dem folgenden JSON-Schema:
{
"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 unterstützt die skalaren Typen string
, integer
, number
, boolean
und any
.
Objekte, Arrays und Enums werden durch eine Klammer nach dem Feldnamen gekennzeichnet.
Von Picoschema definierte Objekte haben alle erforderlichen Eigenschaften, sofern nicht als optional gekennzeichnet
von ?
und lassen keine zusätzlichen Eigenschaften zu. Wenn eine Eigenschaft als optional gekennzeichnet ist,
Es ist auch für Nullwerte möglich, damit LLMs nachsichtiger Null anstelle von
das Auslassen eines Feldes.
In einer Objektdefinition kann der Spezialschlüssel (*)
verwendet werden, um einen „Platzhalter“ zu deklarieren
Felddefinition. Dabei werden alle zusätzlichen Eigenschaften abgeglichen, die nicht von einem
expliziten Schlüssel enthält.
Picoschema unterstützt viele der Funktionen des vollständigen JSON-Schemas nicht. Wenn Sie robustere Schemas erfordern, können Sie stattdessen ein JSON-Schema angeben:
output:
schema:
type: object
properties:
field1:
type: number
minimum: 20
Prompt-Metadaten überschreiben
Mit .prompt
-Dateien können Sie Metadaten wie die Modellkonfiguration in
in der Datei selbst können Sie diese Werte auch für jeden Aufruf überschreiben:
// Make sure you set up the model you're using.
vertexai.DefineModel(g, "gemini-2.0-flash", nil)
response, err := prompt.Generate(
context.Background(),
g,
dotprompt.WithInput(GreetingPromptInput{
Location: "the beach",
Style: "a fancy pirate",
Name: "Ed",
}),
dotprompt.WithModelName("vertexai/gemini-2.0-flash"),
dotprompt.WithConfig(&ai.GenerationCommonConfig{
Temperature: 1.0,
}),
nil,
)
Prompts für mehrere Nachrichten
Standardmäßig erstellt Dotprompt eine einzelne Nachricht mit der Rolle "user"
. Einige
Prompts lassen sich am besten in einer Kombination aus mehreren Nachrichten wie
Systemaufforderung.
Mit dem Helper {{role}}
können Sie ganz einfach Prompts für mehrere Nachrichten erstellen:
---
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}}
Multimodale Prompts
Bei Modellen, die multimodale Eingaben wie Bilder neben Text unterstützen, können Sie
Verwenden Sie den Helper {{media}}
:
---
model: vertexai/gemini-1.5-flash
input:
schema:
photoUrl: string
---
Describe this image in a detailed paragraph:
{{media url=photoUrl}}
Bei der URL kann es sich um https://
- oder base64-codierte data:
-URIs für „inline“ handeln Bild
Nutzung. Im Code würde das so aussehen:
ctx := context.Background()
g, err := genkit.Init(ctx, genkit.WithPromptDir("prompts"))
if err != nil {
log.Fatal(err)
}
describeImagePrompt, err := dotprompt.Open(g, "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(), g,
dotprompt.WithInput(DescribeImagePromptInput{
PhotoUrl: dataURI,
}),
nil,
)
Prompt-Varianten
Da Prompt-Dateien nur Text sind, können (und sollten!) Sie sie in Ihren Versionsverwaltungssystem, mit dem sich Änderungen über einen bestimmten Zeitraum leicht vergleichen lassen. Oft können angepasste Prompts nur in einer Produktionsumgebung zusammen mit vorhandenen Versionen vollständig getestet werden. Dotprompt unterstützt dies über die Funktion Varianten.
Wenn Sie eine Variante erstellen möchten, erstellen Sie eine [name].[variant].prompt
-Datei. Wenn beispielsweise
Sie haben Gemini 1.5 Flash in Ihrem Prompt verwendet, wollten aber wissen, ob Gemini 1.5
Pro würde eine bessere Leistung erzielen, wenn Sie zwei Dateien erstellen:
my_prompt.prompt
: „baseline“my_prompt.geminipro.prompt
: eine Variante mit dem Namen „geminipro“
Wenn Sie eine Promptvariante verwenden möchten, geben Sie sie beim Laden an:
describeImagePrompt, err := dotprompt.OpenVariant(g, "describe_image", "geminipro")
Der Prompt-Lademechanismus versucht, die Variante dieses Namens zu laden, und greift auf die Baseline zurück, falls keine vorhanden ist. Das bedeutet, dass Sie das bedingte Laden anhand von Kriterien verwenden können, die für Ihre Anwendung sinnvoll sind:
var myPrompt *dotprompt.Prompt
if isBetaTester(user) {
myPrompt, err = dotprompt.OpenVariant(g, "describe_image", "geminipro")
} else {
myPrompt, err = dotprompt.Open(g, "describe_image")
}
Der Name der Variante ist in den Metadaten der generierten Traces enthalten. So können Sie die tatsächliche Leistung der Varianten im Genkit-Trace-Inspector vergleichen.