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")
אפשר להפעיל את method 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
.
באובייקטים, במערכים ובמשתני enum, הם מסומנים בסוגריים אחרי שם השדה.
אובייקטים שמוגדרים על ידי Picoschema כוללים את כל המאפיינים הנדרשים, אלא אם הם מסומנים כאופציונליים באמצעות ?
, והם לא מאפשרים להוסיף מאפיינים. כשמאפיין מסומן כאופציונלי, הוא הופך גם לאפשרי לקבל ערך null כדי לספק גמישות רבה יותר ל-LLMs להחזיר ערך 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"
. חלק מההנחיות הכי טוב להציג כשיילוב של כמה הודעות, כמו הנחיה של מערכת.
בעזרת ה-helper {{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}}
כתובת ה-URL יכולה להיות מזהי URI מסוג https://
או data:
בקידוד base64 לשימוש בתמונות 'מוטבעות'. בקוד, זה ייראה כך:
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,
)
וריאציות של הנחיות
קובצי ה-prompt הם פשוט טקסט, ולכן אפשר (וצריך!) לבצע עליהם commit במערכת לניהול גרסאות, כדי שתוכלו להשוות בקלות בין השינויים לאורך זמן. לרוב, אפשר לבדוק גרסאות משופרות של הנחיות רק בסביבת ייצור לצד גרסאות קיימות. Dotprompt תומך בכך באמצעות התכונה וריאנטים שלו.
כדי ליצור וריאנט, צריך ליצור קובץ [name].[variant].prompt
. לדוגמה, אם השתמשתם ב-Gemini 1.5 Flash בהנחיה אבל רציתם לבדוק אם הביצועים של Gemini 1.5 Pro טובים יותר, תוכלו ליצור שני קבצים:
my_prompt.prompt
: ההנחיה 'baseline'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 trace inspector.