ניהול הנחיות באמצעות Dotprompt

Firebase Genkit מספק את הפלאגין Dotprompt ואת פורמט הטקסט שיעזרו לכם לכתוב ולארגן את ההנחיות של ה-AI הגנרטיבי.

Dotprompt מעוצבת סביב ההנחה שהודעות הן קוד. אתם כותבים ו לשמור את ההנחיות בקבצים בעיצוב מיוחד שנקרא קובצי נקודהprompt, לעקוב לשנות אותן באמצעות אותה מערכת לניהול גרסאות שבה אתם משתמשים ופורסים אותם יחד עם הקוד שקורא לבינה המלאכותית הגנרטיבית למשימות ספציפיות.

כדי להשתמש ב-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"
g, err := genkit.Init(ctx, genkit.WithPromptDir("prompts"))
if err != nil {
	log.Fatal(err)
}
prompt, err := dotprompt.Open(g, "greeting")

אפשר לקרוא ל-method Generate של ההנחיה כדי לעבד את התבנית ולהעביר אותה ל-API של המודל בשלב אחד:

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())

אפשר גם להציג את התבנית כמחרוזת:

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 כדי לספק יותר זמן כדי שמודלים מסוג 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(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,
)

הנחיות לכמה הודעות

כברירת מחדל, 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}}

כתובת האתר יכולה להיות https:// או מזהי data: בקידוד base64 עבור "inline" קובץ אימג' בשימוש. בקוד, זה יהיה:

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,
)

וריאנטים של הנחיות

מכיוון שקובצי הנחיות הם רק טקסט, אתם יכולים (וכדאי!) לשמור אותם לניהול גרסאות, המאפשרת להשוות שינויים לאורך זמן בקלות. לרוב, אפשר לבדוק גרסאות משופרות של הנחיות רק בסביבת ייצור לצד גרסאות קיימות. תמיכה ב-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(g, "describe_image", "geminipro")

הכלי לטעינת הנחיות ינסה לטעון את הווריאנט של השם הזה ולחזור אם לא קיים כזה, לערך הבסיס. כלומר, אפשר להשתמש בחיבור מותנה על סמך כל קריטריון שמתאים לאפליקציה שלכם:

var myPrompt *dotprompt.Prompt
if isBetaTester(user) {
	myPrompt, err = dotprompt.OpenVariant(g, "describe_image", "geminipro")
} else {
	myPrompt, err = dotprompt.Open(g, "describe_image")
}

שם הווריאנט נכלל במטא-נתונים של נתוני המעקב אחרי היצירה, כך שתוכלו להשוות בין הביצועים בפועל של הווריאנטים השונים ב-Genkit trace inspector.

Code-first framework for orchestrating, deploying, and monitoring generative AI workflows.

עדכון אחרון: Jul 16, 2024

Code-first framework for orchestrating, deploying, and monitoring generative AI workflows.

עדכון אחרון: Nov 6, 2024

Code-first framework for orchestrating, deploying, and monitoring generative AI workflows.

עדכון אחרון: Aug 1, 2024