مدیریت درخواست ها با Dotprompt

Firebase Genkit افزونه Dotprompt و قالب متنی را برای کمک به شما در نوشتن و سازماندهی اعلان‌های هوش مصنوعی تولیدی خود ارائه می‌کند.

Dotprompt با این فرض طراحی شده است که دستورات کد هستند . شما درخواست‌های خود را در فایل‌هایی با فرمت خاص به نام فایل‌های dotprompt می‌نویسید و نگهداری می‌کنید، تغییرات آن‌ها را با استفاده از سیستم کنترل نسخه مشابهی که برای کد خود استفاده می‌کنید، ردیابی می‌کنید، و آنها را همراه با کدی که مدل‌های هوش مصنوعی تولیدی شما را فراخوانی می‌کند، مستقر می‌کنید.

برای استفاده از 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 است. می توانید از if , unless , و each کمک کننده برای اضافه کردن بخش های شرطی به درخواست خود یا تکرار از طریق محتوای ساختاریافته استفاده کنید. فرمت فایل از YAML frontmatter برای ارائه ابرداده برای یک خط مستقیم با الگو استفاده می کند.

تعریف طرحواره های ورودی/خروجی با 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 پشتیبانی می کند. برای اشیاء، آرایه‌ها و فهرست‌ها پس از نام فیلد با پرانتزی نشان داده می‌شوند.

اشیاء تعریف شده توسط Picoschema دارای تمام ویژگی های مورد نیاز هستند مگر اینکه با علامت اختیاری مشخص شوند ? و اجازه ی خواص اضافی را نمی دهد. وقتی یک ویژگی به‌عنوان اختیاری علامت‌گذاری می‌شود، آن را نیز باطل می‌کند تا به جای حذف یک فیلد، نرم‌افزاری بیشتری برای LLM‌ها فراهم کند تا بتوانند null را برگردانند.

در تعریف یک شی، از کلید ویژه (*) می توان برای اعلام تعریف فیلد "wildcard" استفاده کرد. این با هر ویژگی اضافی که توسط یک کلید صریح ارائه نشده است مطابقت دارد.

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" می سازد. برخی از اعلان‌ها به بهترین وجه به صورت ترکیبی از پیام‌های متعدد، مانند اعلان سیستم، بیان می‌شوند.

{% verbatim %}{% endverbatim %} کمک کننده {% verbatim %}{% endverbatim %} یک راه ساده برای ساخت اعلان های چند پیام ارائه می دهد:

---
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}}

درخواست های چند وجهی

برای مدل‌هایی که از ورودی چندوجهی پشتیبانی می‌کنند، مانند تصاویر در کنار متن، می‌توانید از {% verbatim %}{% endverbatim %} استفاده کنید. {% verbatim %}{% endverbatim %} کمک کننده {% verbatim %}{% endverbatim %} :

---
model: vertexai/gemini-1.5-flash
input:
  schema:
    photoUrl: string
---

Describe this image in a detailed paragraph:

{{media url=photoUrl}}

URL می تواند https:// یا 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 : اعلان "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 مقایسه و مقایسه کنید.