إدارة الطلبات باستخدام 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 ثم استيراد الدالة prompt من مكتبة @genkit-ai/dotprompt:

import { dotprompt, prompt } from '@genkit-ai/dotprompt';

configureGenkit({ plugins: [dotprompt()] });

بعد ذلك، حمِّل الطلب باستخدام prompt('file_name'):

const greetingPrompt = await prompt('greeting');

const result = await greetingPrompt.generate({
  input: {
    location: 'the beach',
    style: 'a fancy pirate',
  },
});

console.log(result.text());

تستند بنية Dotprompt إلى Handlebars. لغة النماذج. يمكنك استخدام مساعدي if وunless وeach لإضافة الأجزاء الشرطية إلى طلبك أو تكرار المحتوى المنظم. تشير رسالة الأشكال البيانية يستخدم تنسيق ملف الأمر لغة YAML الأمامية لتقديم بيانات وصفية لطلب مضمّن مع القالب.

تعريف مخططات الإدخال/الإخراج

تشتمل Dotprompt على تنسيق تعريف مخطّط مدمج ومحسّن لترميز YAML يسمى Picoschema لتسهيل تحديد أهم السمات في المخطط لاستخدام النماذج اللغوية الكبيرة. وفي ما يلي مثال على مخطط لمقالة:

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

يكافئ المخطط أعلاه واجهة TypeScript التالية:

interface Article {
  title: string;
  subtitle?: string | null;
  /** true when in draft state */
  draft?: boolean | null;
  /** approval status */
  status?: 'PENDING' | 'APPROVED' | null;
  /** the date of publication e.g. '2024-04-09' */
  date: string;
  /** relevant tags for article */
  tags: string[];
  authors: {
    name: string;
    email?: string | null;
  }[];
  metadata?: {
    /** ISO timestamp of last update */
    updatedAt?: string | null;
    /** id of approver */
    approvedBy?: number | null;
  } | null;
  /** arbitrary extra data */
  extra?: any;
  /** wildcard field */

}

يتوافق Picoschema مع الأنواع العددية string وinteger وnumber وboolean وany. بالنسبة إلى الكائنات والمصفوفات والتعدادات، يُشار إليها بأقواس بعد اسم الحقل.

تتضمَّن الكائنات المحدّدة بواسطة Picoschema جميع السمات على النحو المطلوب ما لم تكن يُشار إليها على أنّها اختيارية. من خلال ?، وعدم السماح بالمواقع الإضافية. عندما يتم تمييز خاصية على أنها اختيارية، يصبح أيضًا قابلاً للإلغاء لتوفير مزيد من التساهل لإرجاع النماذج اللغوية الكبيرة القيمة "فارغ" بدلاً من حذف حقل.

في تعريف الكائن، يمكن استخدام المفتاح الخاص (*) للإشارة إلى "حرف بدل". تحديد الحقل. سيؤدي هذا إلى مطابقة أي خصائص إضافية غير مقدمة من المفتاح الصريح.

لا يتيح Picoschema استخدام الكثير من إمكانات مخطط JSON الكامل. إذا كنت تتطلب مخططات أكثر فعالية، فيمكنك توفير مخطط JSON بدلاً من ذلك:

output:
  schema:
    type: object
    properties:
      field1:
        type: number
        minimum: 20

الاستفادة من المخططات القابلة لإعادة الاستخدام

بالإضافة إلى تحديد المخططات مباشرةً في ملف .prompt، يمكنك الرجوع إلى مخططًا مسجَّلاً في defineSchema حسب الاسم. لتسجيل مخطط:

import { defineSchema } from '@genkit-ai/core';
import { z } from 'zod';

const MySchema = defineSchema(
  'MySchema',
  z.object({
    field1: z.string(),
    field2: z.number(),
  })
);

يمكنك إدخال اسم المخطط المسجَّل ضمن طلبك:

# myPrompt.prompt
---
model: vertexai/gemini-1.5-flash
output:
  schema: MySchema
---

ستحل مكتبة Dotprompt تلقائيًا الاسم إلى المعرّف الأساسي. مخطط Zod المسجل. ويمكنك بعد ذلك استخدام المخطط لكتابة ناتج طلب Dotprompt:

import { prompt } from "@genkit-ai/dotprompt";

const myPrompt = await prompt("myPrompt");

const result = await myPrompt.generate<typeof MySchema>({...});

// now strongly typed as MySchema
result.output();

إلغاء البيانات الوصفية للطلب

تتيح لك ملفات .prompt تضمين البيانات الوصفية، مثل إعدادات النموذج، في الملف نفسه، يمكنك أيضًا إلغاء هذه القيم على أساس كل مكالمة:

const result = await greetingPrompt.generate({
  model: 'vertexai/gemini-1.5-pro',
  config: {
    temperature: 1.0,
  },
  input: {
    location: 'the beach',
    style: 'a fancy pirate',
  },
});

إخراج منظَّم

يمكنك ضبط التنسيق ومخطط الإخراج للطلب لإجباره على تنسيق JSON:

---
model: vertexai/gemini-1.5-flash
input:
  schema:
    theme: string
output:
  format: json
  schema:
    name: string
    price: integer
    ingredients(array): string
---

Generate a menu item that could be found at a {{theme}} themed restaurant.

عند إنشاء طلب باستخدام نتائج منظَّمة، استخدِم مساعد "output()" من أجل لاسترداده والتحقق من صحته:

const createMenuPrompt = await prompt('create_menu');

const menu = await createMenuPrompt.generate({
  input: {
    theme: 'banana',
  },
});

console.log(menu.output());

ويتم تحقيق التوافق مع الإخراج من خلال إدخال تعليمات إضافية في مطالبة. يتم إلحاقه تلقائيًا بنهاية آخر رسالة تم إنشاؤها حسب المطالبة. يمكنك تغيير موضعه يدويًا باستخدام {{section "output"}}. .

This is a prompt that manually positions output instructions.

== Output Instructions

{{section "output"}}

== Other Instructions

This will come after the output instructions.

الطلبات المتعددة الرسائل

تنشئ Dotprompt رسالة واحدة تلقائيًا بدور "user". بعض الإشعارات يتم التعبير عن الطلبات بأفضل شكل في صورة مجموعة من الرسائل المتعددة، مثل رسالة مطالبة من النظام.

يوفّر مساعد {{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}}

المطالبات متعددة الأدوار والتاريخ

تتوافق ميزة Dotprompt مع الطلبات المتعددة الأدوار من خلال تمرير خيار history إلى طريقة generate:

const result = await multiTurnPrompt.generate({
  history: [
    { role: 'user', content: [{ text: 'Hello.' }] },
    { role: 'model', content: [{ text: 'Hi there!' }] },
  ],
});

سيتم تلقائيًا إدراج السجلّ قبل الرسالة النهائية التي يتم إنشاؤها بواسطة المطالبة. ومع ذلك، يمكنك تحديد موضع السجلّ يدويًا باستخدام {{history}} مساعد:

{{role "system"}}
This is the system prompt.
{{history}}
{{role "user"}}
This is a user message.
{{role "model"}}
This is a model message.
{{role "user"}}
This is the final user message.

الطلبات المتعدّدة النماذج

بالنسبة إلى النماذج التي تتيح إدخال متعدد الوسائط مثل الصور إلى جانب النص، يمكنك استخدام مساعد {{media}}:

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

Describe this image in a detailed paragraph:

{{media url=photoUrl}}

يمكن أن يكون عنوان URL https:// أو معرِّفات الموارد المنتظمة (URI) بترميز base64 للنوع "مضمّن".data: مصوّر الاستخدام. في التعليمات البرمجية، سيكون هذا كالتالي:

const describeImagePrompt = await prompt('describe_image');

const result = await describeImagePrompt.generate({
  input: {
    photoUrl: 'https://example.com/image.png',
  },
});

console.log(result.text());

جزئي

الأجزاء الجزئية هي نماذج قابلة لإعادة الاستخدام يمكن تضمينها في أي طلب. جزئي ويمكن أن يكون مفيدًا بشكل خاص للطلبات ذات الصلة التي تشترك في السلوك.

عند تحميل دليل طلب، أي ملف يبدأ بـ _ يعتبر ملفًّا جزئية. لذلك قد يحتوي الملف _personality.prompt على:

You should speak like a {{#if style}}{{style}}{{else}}helpful assistant.{{/else}}.

ويمكن بعد ذلك تضمين ذلك في الطلبات الأخرى:

---
model: vertexai/gemini-1.5-flash
input:
  schema:
    name: string
    style?: string
---

{{ role "system" }}
{{>personality style=style}}

{{ role "user" }}
Give the user a friendly greeting.

User's Name: {{name}}

يتم إدراج الأجزاء الجزئية باستخدام البنية {{>NAME_OF_PARTIAL args...}}. إذا كانت الإجابة "لا" يتم تقديم الوسيطات إلى الجزء الجزئي، ويتم تنفيذها مع السياق نفسه مثل طلب من أحد الوالدين

تقبل القيم الجزئية كلاً من الوسيطات المُسمّاة كما هو مذكور أعلاه أو وسيطة موضعية واحدة. لتمثيل السياق. ويمكن أن يكون هذا مفيدًا على سبيل المثال: تعرض أعضاء القائمة.

# _destination.prompt
- {{name}} ({{country}})

# chooseDestination.prompt
Help the user decide between these vacation destinations:
{{#each destinations}}
{{>destination this}}{{/each}}

تعريف الأجزاء الجزئية في التعليمة البرمجية

ويمكنك أيضًا تحديد الرموز الجزئية باستخدام الرمز definePartial:

import { definePartial } from '@genkit-ai/dotprompt';

definePartial(
  'personality',
  'Talk like a {{#if style}}{{style}}{{else}}helpful assistant{{/if}}.'
);

تتوفّر الأجزاء الجزئية المحدّدة بالرمز في جميع الطلبات.

صيغ الطلب

نظرًا لأن ملفات المطالبة ما هي إلا ملفات نصية، يمكنك (ويجب عليك) فرضها في نظام التحكم في الإصدار، مما يسمح لك بمقارنة التغييرات بمرور الوقت بسهولة. في كثير من الأحيان، لا يمكن اختبار الإصدارات المعدّلة من الطلبات بشكل كامل إلا من خلال بيئة الإنتاج جنبًا إلى جنب مع الإصدارات الحالية. توافق Dotprompt ذلك من خلال ميزة خيارات المنتج.

لإنشاء صيغة، أنشِئ ملف [name].[variant].prompt. على سبيل المثال، إذا كنت تستخدم Gemini 1.5 Flash في طلبك، لكنك أردت معرفة ما إذا كان Gemini 1.5 سيعمل Pro بشكل أفضل، يمكنك إنشاء ملفين:

  • my_prompt.prompt: "المرجع" إشعار
  • my_prompt.gemini15pro.prompt: خيار منتج باسم "gemini15pro"

لاستخدام صيغة طلب، حدِّد الخيار variant عند التحميل:

const myPrompt = await prompt('my_prompt', { variant: 'gemini15pro' });

يتم تضمين اسم الصيغة في البيانات الوصفية لتتبُّع الإنشاء، وبالتالي إمكانية مقارنة الأداء الفعلي بين الصيغ في تتبع Genkit الجديد.

تحديد المساعدة المخصّصة

يمكنك تحديد أدوات مساعدة مخصّصة لمعالجة البيانات وإدارتها داخل الطلب. مساعدو أن تكون مسجَّلة عالميًا باستخدام defineHelper:

import { defineHelper } from '@genkit-ai/dotprompt';

defineHelper('shout', (text: string) => text.toUpperCase());

بعد تحديد المساعد، يمكنك استخدامه في أي طلب:

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

HELLO, {{shout name}}!!!

لمزيد من المعلومات حول الوسيطات التي يتم تمريرها إلى المساعدة، اطلع على مستندات عن الأسماء المعرِّفة حول إنشاء تطبيقات المساعدة المخصّصة.

طرق بديلة لتحميل الطلبات وتحديدها

تم تحسين Dotprompt للمؤسسة في دليل الطلب. ومع ذلك، تتوفّر بعض الطرق الأخرى لتحميل الطلبات وتحديدها:

  • loadPromptFile: تحميل طلب من ملف في دليل الطلب
  • loadPromptUrl: تحميل طلب من عنوان URL
  • defineDotprompt: تحديد طلب في الرمز

أمثلة:

import {
  loadPromptFile,
  loadPromptUrl,
  defineDotprompt,
} from '@genkit-ai/dotprompt';
import path from 'path';
import { z } from 'zod';

// Load a prompt from a file
const myPrompt = await loadPromptFile(
  path.resolve(__dirname, './path/to/my_prompt.prompt')
);

// Load a prompt from a URL
const myPrompt = await loadPromptUrl('https://example.com/my_prompt.prompt');

// Define a prompt in code
const myPrompt = defineDotprompt(
  {
    model: 'vertexai/gemini-1.5-flash',
    input: {
      schema: z.object({
        name: z.string(),
      }),
    },
  },
  `Hello {{name}}, how are you today?`
);