Firebase Genkit fornisce il plug-in Dotprompt e il formato di testo per aiutarti a scrivere e organizzare i prompt di IA generativa.
Dotprompt è progettato sulla base del presupposto che i prompt sono codice. Scrivi e scrivi gestire i tuoi prompt in file appositamente formattati chiamati file dotprompt, monitorare e le modifiche utilizzando lo stesso sistema di controllo della versione utilizzato ed eseguire il deployment insieme al codice che chiama la tua IA generativa di grandi dimensioni.
Per utilizzare Dotprompt, crea prima una directory prompts
nella directory principale del progetto e poi un file .prompt
in quella directory. Ecco un semplice esempio
potrebbe chiamare 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}}.
Per utilizzare questo prompt, installa il plug-in dotprompt
:
go get github.com/firebase/genkit/go/plugins/dotprompt
Carica quindi il prompt utilizzando 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")
Puoi chiamare il metodo Generate
del prompt per eseguire il rendering del modello e passarlo
all'API del modello in un solo passaggio:
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())
In alternativa, esegui il rendering del modello in una stringa:
renderedPrompt, err := prompt.RenderText(map[string]any{
"location": "a restaurant",
"style": "a pirate",
})
La sintassi di Dotprompt si basa sul parametro Handlebars
per i modelli di machine learning. Puoi utilizzare gli aiuti if
, unless
e each
per aggiungere
parti condizionali al prompt o eseguire l'iterazione dei contenuti strutturati. La
utilizza la frontmatter YAML per fornire metadati per una
con il modello.
Definizione di schemi di input/output con Picoschema
Dotprompt include un formato di definizione dello schema compatto basato su YAML chiamato Picoschema per semplificare la definizione degli attributi più importanti di uno schema per l'utilizzo di LLM. Ecco un esempio di schema per un articolo:
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
Lo schema precedente è equivalente al seguente schema 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 supporta i tipi scalari string
, integer
, number
, boolean
e any
.
Per oggetti, array ed enum, sono indicati tra parentesi dopo il nome del campo.
Gli oggetti definiti da Picoschema hanno tutte le proprietà obbligatorie, a meno che non siano indicati come facoltativi
entro il giorno ?
e non consentire altre proprietà. Se una proprietà è contrassegnata come facoltativa,
viene inoltre reso nullo per consentire agli LLM di restituire un valore nullo anziché
omettere un campo.
In una definizione di oggetto, la chiave speciale (*)
può essere utilizzata per dichiarare una definizione di campo "wildcard". Corrisponderà a qualsiasi proprietà aggiuntiva non fornita da un
una chiave esplicita.
Picoschema non supporta molte delle funzionalità dello schema JSON completo. Se hai bisogno di schemi più solidi, puoi fornire uno schema JSON:
output:
schema:
type: object
properties:
field1:
type: number
minimum: 20
Override dei metadati dei prompt
Sebbene i file .prompt
ti consentano di incorporare metadati come la configurazione del modello nel
file stesso, puoi anche sostituire questi valori in base alla chiamata:
// 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,
)
Prompt con più messaggi
Per impostazione predefinita, Dotprompt crea un singolo messaggio con un ruolo "user"
. Alcune
di prompt vengono espressi al meglio come una combinazione di più messaggi, ad esempio
di un prompt di sistema.
L'helper {{role}}
fornisce un modo semplice per creare prompt con più messaggi:
---
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}}
Prompt multimodali
Per i modelli che supportano input multimodali, come immagini insieme a testo, puoi utilizzare l'helper {{media}}
:
---
model: vertexai/gemini-1.5-flash
input:
schema:
photoUrl: string
---
Describe this image in a detailed paragraph:
{{media url=photoUrl}}
L'URL può essere un URI https://
o data:
con codifica Base64 per l'utilizzo di immagini "in linea". In codice, sarà:
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,
)
Varianti del prompt
Poiché i file dei prompt sono solo testo, puoi (e devi) assegnarli al tuo di controllo della versione, che consentono di confrontare facilmente le modifiche apportate nel tempo. Spesso, le versioni modificate dei prompt possono essere testate completamente solo in un ambiente di produzione, affiancate alle versioni esistenti. La richiesta di punti supporta tramite la funzionalità relativa alle varianti.
Per creare una variante, crea un file [name].[variant].prompt
. Ad esempio, se
nel prompt stavi utilizzando Gemini 1.5 Flash, ma volevi vedere se Gemini 1.5
Pro avrebbe prestazioni migliori. Potresti creare due file:
my_prompt.prompt
: la "base di riferimento" richiestamy_prompt.geminipro.prompt
: una variante denominata "geminipro"
Per utilizzare una variante del prompt, specificala al momento del caricamento:
describeImagePrompt, err := dotprompt.OpenVariant(g, "describe_image", "geminipro")
Il caricatore del prompt tenterà di caricare la variante di quel nome e di fare fallback rispetto alla base di riferimento se non ne esiste. Ciò significa che puoi utilizzare il caricamento condizionale in base ai criteri più adatti alla tua applicazione:
var myPrompt *dotprompt.Prompt
if isBetaTester(user) {
myPrompt, err = dotprompt.OpenVariant(g, "describe_image", "geminipro")
} else {
myPrompt, err = dotprompt.Open(g, "describe_image")
}
Il nome della variante è incluso nei metadati delle tracce di generazione, quindi può confrontare il rendimento effettivo delle varianti nella traccia Genkit controllore.