Управление подсказками с помощью Dotprompt

Firebase Genkit предоставляет плагин Dotprompt и текстовый формат, которые помогут вам писать и организовывать генеративные подсказки ИИ.

Dotprompt разработан на основе предположения, что подсказки — это код . Вы пишете и поддерживаете свои подсказки в файлах специального формата, называемых файлами dotprompt, отслеживаете изменения в них, используя ту же систему контроля версий, которую вы используете для своего кода, и развертываете их вместе с кодом, который вызывает ваши генеративные модели ИИ.

Чтобы использовать Dotprompt, сначала создайте каталог prompts в корне вашего проекта, а затем создайте в этом каталоге файл .prompt . Вот простой пример, который вы можете назвать greeting.prompt :

---
model: vertexai/gemini-1.0-pro
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 для предоставления метаданных для подсказки, встроенной в шаблон.

Определение схем ввода/вывода с помощью 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

Приведенная выше схема эквивалентна следующему интерфейсу TypeScript:

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

Пикосхема поддерживает скалярные типы: string , integer , number и boolean . Для объектов, массивов и перечислений они обозначаются круглыми скобками после имени поля.

Объекты, определенные Picoschema, имеют все требуемые свойства, если не указано иное как ? и не разрешать дополнительные свойства.

Picoschema не поддерживает многие возможности полной схемы JSON. Если вам нужны более надежные схемы, вы можете вместо этого предоставить схему JSON:

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

Переопределение метаданных подсказки

Хотя файлы .prompt позволяют встраивать метаданные, такие как конфигурация модели, в сам файл, вы также можете переопределить эти значения для каждого вызова:

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

Структурированный вывод

Вы можете установить формат и схему вывода приглашения для преобразования в JSON:

---
model: vertexai/gemini-1.0-pro
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());

Подсказки с несколькими сообщениями

По умолчанию Dotprompt создает одно сообщение с ролью "user" . Некоторые подсказки лучше всего выражать в виде комбинации нескольких сообщений, например системное приглашение.

Помощник {% verbatim %}{% endverbatim %} предоставляет простой способ создания подсказок с несколькими сообщениями:

---
model: vertexai/gemini-1.0-pro
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 %} :

---
model: vertexai/gemini-1.0-pro-vision
input:
  schema:
    photoUrl: string
---

Describe this image in a detailed paragraph:

{{media url=photoUrl}}

URL-адрес может быть https:// или data: URI для «встроенного» использования изображений. В коде это будет:

const describeImagePrompt = await prompt('describe_image');

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

console.log(result.text());

Подскажите варианты

Поскольку файлы подсказок представляют собой просто текст, вы можете (и должны!) зафиксировать их в своей системе контроля версий, что позволит вам легко сравнивать изменения с течением времени. Зачастую измененные версии подсказок можно полностью протестировать только в производственной среде параллельно с существующими версиями. Dotprompt поддерживает это через функцию вариантов .

Чтобы создать вариант, создайте файл [name].[variant].prompt . Например, если вы использовали Gemini 1.0 Pro в своем приглашении, но хотели посмотреть, будет ли Gemini 1.5 Pro работать лучше, вы можете создать два файла:

  • my_prompt.prompt : «базовое» приглашение
  • my_prompt.gemini15.prompt : вариант под названием «gemini».

Чтобы использовать вариант подсказки, укажите вариант variant при загрузке:

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

Загрузчик приглашений попытается загрузить вариант с этим именем и вернется к базовому состоянию, если такового не существует. Это означает, что вы можете использовать условную загрузку на основе любых критериев, имеющих смысл для вашего приложения:

const myPrompt = await prompt('my_prompt', {
  variant: isBetaTester(user) ? 'gemini15' : null,
});

Имя варианта включается в метаданные трассировки генерации, поэтому вы можете сравнивать и сопоставлять фактическую производительность между вариантами в инспекторе трассировки Genkit.

Альтернативные способы загрузки и определения подсказок

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.0-pro',
    input: {
      schema: z.object({
        name: z.string(),
      }),
    },
  },
  `Hello {{name}}, how are you today?`
);