Firebase Genkit udostępnia wtyczkę Dotprompt i format tekstowy, które ułatwiają pisanie i organizowanie promptów generatywnej AI.
Działanie Dotprompt opiera się na założeniu, że potwierdzenia to kod. Możesz zapisywać i obsługiwać prompty w specjalnie sformatowanych plikach zwanych plikami dotprompt, śledzisz ich zmiany za pomocą tego samego systemu kontroli wersji, którego używasz w przypadku kodu, oraz wdrażasz je razem z kodem, który wywołuje Twoje modele generatywnej AI.
Aby używać Dotprompt, najpierw utwórz katalog prompts
w katalogu głównym projektu, a potem utwórz w nim plik .prompt
. Oto prosty przykład, który możesz wywołać 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}}.
Aby użyć tego promptu, zainstaluj wtyczkę dotprompt
i zaimportuj funkcję prompt
z biblioteki @genkit-ai/dotprompt
:
import { dotprompt, prompt } from '@genkit-ai/dotprompt';
configureGenkit({ plugins: [dotprompt()] });
Następnie wczytaj prompt za pomocą polecenia 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());
Składnia instrukcji Dotprompt opiera się na języku szablonów Handlebars. Aby dodać części warunkowe do promptu lub powtórzyć uporządkowane treści, możesz użyć pomocników if
, unless
i each
. Format pliku wykorzystuje interfejs YAML do przekazywania metadanych promptu wbudowanego w szablon.
Definiowanie schematów wejściowych/wyjściowych za pomocą Picoschema
Dotprompt zawiera kompaktowy, zoptymalizowany pod kątem YAML format definicji schematu o nazwie Piicoschema, który ułatwia definiowanie najważniejszych atrybutów schematu na potrzeby wykorzystania LLM. Oto przykład schematu artykułu:
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
Powyższy schemat jest odpowiednikiem tego interfejsu 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;
};
}
Schemat Picoschema obsługuje typy skalarne string
, integer
, number
i boolean
. W przypadku obiektów, tablic i wyliczeń po nazwie pola oznacza je nawias.
Obiekty zdefiniowane przez Picoschema mają wszystkie wymagane właściwości, chyba że są oznaczone jako opcjonalne w elemencie ?
, i nie zezwalają na dodatkowe właściwości.
Schemat Picoschema nie obsługuje wielu funkcji pełnego schematu JSON. Jeśli potrzebujesz bardziej zaawansowanych schematów, możesz podać schemat JSON:
output:
schema:
type: object
properties:
field1:
type: number
minimum: 20
Zastępowanie metadanych promptu
Pliki .prompt
umożliwiają umieszczenie metadanych, takich jak konfiguracja modelu, w samym pliku, ale możesz też zastąpić te wartości dla poszczególnych wywołań:
const result = await greetingPrompt.generate({
model: 'google-genai/gemini-pro',
config: {
temperature: 1.0,
},
input: {
location: 'the beach',
style: 'a fancy pirate',
},
});
Uporządkowane dane wyjściowe
Możesz ustawić format i schemat wyjściowy promptu, aby przekształcić je w format 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.
Podczas generowania promptu z uporządkowanymi danymi wyjściowymi użyj elementu pomocniczego output()
, aby go pobrać i zweryfikować:
const createMenuPrompt = await prompt('create_menu');
const menu = await createMenuPrompt.generate({
input: {
theme: 'banana',
},
});
console.log(menu.output());
Prompty z wieloma wiadomościami
Domyślnie Dotprompt tworzy pojedynczą wiadomość z rolą "user"
. Niektóre prompty najlepiej wyrażać jako kombinację różnych komunikatów, np. promptów systemowych.
Asystent {{role}}
pozwala w prosty sposób tworzyć prompty z wieloma wiadomościami:
---
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}}
Prompty wielomodalne
W przypadku modeli obsługujących multimodalne dane wejściowe, takich jak obrazy obok tekstu, możesz użyć elementu pomocniczego {{media}}
:
---
model: vertexai/gemini-1.0-pro-vision
input:
schema:
photoUrl: string
---
Describe this image in a detailed paragraph:
{{media url=photoUrl}}
Adres URL może być identyfikatorem URI data:
zakodowanym w https://
lub base64 na potrzeby wykorzystania obrazu w treści. W kodzie będzie to wyglądać tak:
const describeImagePrompt = await prompt('describe_image');
const result = await describeImagePrompt.generate({
input: {
photoUrl: 'https://example.com/image.png',
},
});
console.log(result.text());
Warianty promptów
Pliki promptów są tylko tekstem, więc możesz (i powinien!) zatwierdzić je w swoim systemie kontroli wersji, co umożliwi łatwe porównywanie zmian z upływem czasu. Często zmienione wersje promptów można w pełni przetestować tylko w środowisku produkcyjnym obok istniejących wersji. Dotprompt obsługuje to za pomocą funkcji wariantów.
Aby utworzyć wariant, utwórz plik [name].[variant].prompt
. Jeśli np. w prompcie używasz Gemini 1.0 Pro, ale chcesz sprawdzić, czy Gemini 1.5 Pro będzie skuteczniejsze, możesz utworzyć 2 pliki:
my_prompt.prompt
: prompt „odniesienie”my_prompt.gemini15.prompt
: odmiana o nazwie „gemini”
Aby użyć wariantu promptu, podczas wczytywania wybierz opcję variant
:
const myPrompt = await prompt('my_prompt', { variant: 'gemini15' });
Narzędzie ładujące prompty podejmie próbę wczytania wariantu o tej nazwie i powrót do wersji bazowej, jeśli nie istnieje. Oznacza to, że możesz używać wczytywania warunkowego na podstawie dowolnych kryteriów pasujących do Twojej aplikacji:
const myPrompt = await prompt('my_prompt', {
variant: isBetaTester(user) ? 'gemini15' : null,
});
Nazwa wariantu jest zawarta w metadanych logów czasu generowania, dzięki czemu możesz porównywać rzeczywistą wydajność między wariantami w inspektorze logu czasu Genkit.
Alternatywne sposoby wczytywania i definiowania promptów
Parametr Dotprompt jest zoptymalizowany pod kątem organizacji w katalogu promptów. Istnieje jednak kilka innych sposobów wczytywania i definiowania promptów:
loadPromptFile
: wczytaj prompt z pliku w katalogu promptów.loadPromptUrl
: wczytanie promptu z adresu URL.defineDotprompt
: zdefiniuj prompt w kodzie.
Przykłady:
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?`
);