Firebase Genkit udostępnia wtyczkę Dotprompt i format tekstowy, aby ułatwić Ci pisanie i porządkowanie promptów generatywnej AI.
Dotprompt opiera się na założeniu, że prompty są kodem. Ty piszesz i przechowywać prompty w specjalnie sformatowanych plikach zwanych plikami kropkaprompt, śledzić przy użyciu tego samego systemu kontroli wersji, którego używasz w przypadku w kodzie, w którym wdrażasz je razem z kodem wywołującym generatywną AI modeli ML.
Aby używać Dotprompt, najpierw utwórz katalog prompts
w katalogu głównym projektu i
a następnie utwórz w nim plik .prompt
. Oto prosty przykład,
może zadzwonić do użytkownika 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}}.
Aby użyć tego promptu, zainstaluj wtyczkę dotprompt
i zaimportuj funkcję prompt
z
biblioteka @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 Dotprompt opiera się na kierunkach obsługi.
język szablonowy. Możesz użyć pomocników if
, unless
i each
, aby dodać
albo części warunkowe promptu
lub powtarzaj to, wykorzystując uporządkowane treści.
format pliku korzysta z interfejsu YAML do dostarczania metadanych dla wbudowanego promptu
zgodnie z szablonem.
Definiowanie schematów wejściowych/wyjściowych
Dotprompt zawiera kompaktowy, zoptymalizowany pod kątem YAML format definicji schematu o nazwie schemat Picoschema ułatwiający zdefiniowanie najważniejszych atrybutów schematu do wykorzystania LLM. Oto przykładowy schemat 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
extra?: any, arbitrary extra data
(*): string, wildcard field
Powyższy schemat jest odpowiednikiem poniższego interfejsu 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 obsługuje typy skalarne string
, integer
, number
, boolean
i any
.
Obiekty, tablice i wyliczenia są oznaczane w nawiasach po nazwie pola.
Obiekty zdefiniowane przez Picoschema mają wszystkie wymagane właściwości, chyba że są oznaczone jako opcjonalne
do ?
i nie zezwalaj na dodatkowe właściwości. Jeśli właściwość jest oznaczona jako opcjonalna,
ma też wartość null, aby ułatwić LLM zwracanie wartości null zamiast
z pominięciem pola.
W definicji obiektu można użyć klucza specjalnego (*)
do zadeklarowania symbolu wieloznacznego
definicji pola. Spowoduje to dopasowanie wszystkich dodatkowych właściwości, które nie zostały podane przez
jawny klucz.
Picoschema nie obsługuje wielu możliwości pełnego schematu JSON. Jeśli wymagają bardziej zaawansowanych schematów, możesz zamiast tego podać schemat JSON:
output:
schema:
type: object
properties:
field1:
type: number
minimum: 20
Wykorzystywanie schematów wielokrotnego użytku
Oprócz bezpośrednio definiowania schematów w pliku .prompt
możesz też odwoływać się
schemat zarejestrowany według nazwy w defineSchema
. Aby zarejestrować schemat:
import { defineSchema } from '@genkit-ai/core';
import { z } from 'zod';
const MySchema = defineSchema(
'MySchema',
z.object({
field1: z.string(),
field2: z.number(),
})
);
W prompcie możesz podać nazwę zarejestrowanego schematu:
# myPrompt.prompt
---
model: vertexai/gemini-1.5-flash
output:
schema: MySchema
---
Biblioteka Dotprompt automatycznie zidentyfikuje nazwę na podstawie i zarejestrowano schemat Zod. Możesz wtedy użyć tego schematu, aby dokładnie wpisać wynik działania prompta 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();
Zastępowanie metadanych promptu
Z kolei pliki .prompt
umożliwiają umieszczanie metadanych, takich jak konfiguracja modelu, w
w samym pliku, możesz też zastąpić te wartości dla poszczególnych wywołań:
const result = await greetingPrompt.generate({
model: 'vertexai/gemini-1.5-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 do wymuszania na 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.
Podczas generowania promptu z uporządkowanymi danymi wyjściowymi użyj elementu pomocniczego output()
, aby
pobierz i sprawdź:
const createMenuPrompt = await prompt('create_menu');
const menu = await createMenuPrompt.generate({
input: {
theme: 'banana',
},
});
console.log(menu.output());
Zgodność danych wyjściowych jest osiągana przez wstawienie dodatkowych instrukcji do
. Domyślnie jest on dodawany na końcu ostatniej wygenerowanej wiadomości.
za pomocą prompta. Możesz ręcznie zmienić jej położenie za pomocą {{section "output"}}
jako pomoc.
This is a prompt that manually positions output instructions.
== Output Instructions
{{section "output"}}
== Other Instructions
This will come after the output instructions.
Prompty zawierające wiele wiadomości
Domyślnie Dotprompt tworzy jedną wiadomość z przypisaną rolą "user"
. Niektóre
prompty najlepiej wyrażać jako połączenie kilku wiadomości, np.
komunikatora systemowego.
Pomocnik {{role}}
pozwala w prosty sposób tworzyć prompty zawierające wiele wiadomości:
---
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}}
Prompty i historia wieloetapów
Dotprompt obsługuje prompty wieloetapowe, przekazując opcję history
do funkcji
Metoda generate
:
const result = await multiTurnPrompt.generate({
history: [
{ role: 'user', content: [{ text: 'Hello.' }] },
{ role: 'model', content: [{ text: 'Hi there!' }] },
],
});
Domyślnie historia jest wstawiana przed ostatnią wiadomością wygenerowaną przez
pojawi się prośba. Możesz jednak ręcznie pozycjonować historię za pomocą funkcji {{history}}
pomocnik:
{{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.
Prompty multimodalne
W przypadku modeli obsługujących multimodalne dane wejściowe, np. obrazy obok tekstu, możesz
użyj aplikacji pomocniczej {{media}}
:
---
model: vertexai/gemini-1.5-flash
input:
schema:
photoUrl: string
---
Describe this image in a detailed paragraph:
{{media url=photoUrl}}
Adres URL może być identyfikatorem URI data:
zakodowanym w formacie https://
lub w standardzie base64. obraz
i ich wykorzystaniu. W kodzie będzie to:
const describeImagePrompt = await prompt('describe_image');
const result = await describeImagePrompt.generate({
input: {
photoUrl: 'https://example.com/image.png',
},
});
console.log(result.text());
Częściowe
Częściowe części to szablony wielokrotnego użytku, które można uwzględnić w każdym prompcie. Częściowe może być szczególnie przydatne w przypadku powiązanych promptów o typowym działaniu.
Podczas wczytywania katalogu promptów każdy plik z prefiksem _
jest uważany za
częściową. Plik _personality.prompt
może więc zawierać:
You should speak like a {{#if style}}{{style}}{{else}}helpful assistant.{{/else}}.
Możesz to potem uwzględnić w innych promptach:
---
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}}
Fragmenty są wstawiane przy użyciu składni {{>NAME_OF_PARTIAL args...}}
. Jeśli nie
argumentów zostanie podana do części, będzie ona wykonywana z tym samym kontekstem
na urządzeniu nadrzędnym.
Częściowe argumenty przyjmują oba argumenty nazwane jak powyżej lub jeden argument pozycjonujący co reprezentuje kontekst. Może to być pomocne np. dodawania członków listy do listy.
# _destination.prompt
- {{name}} ({{country}})
# chooseDestination.prompt
Help the user decide between these vacation destinations:
{{#each destinations}}
{{>destination this}}{{/each}}
Definiowanie częściowych fragmentów w kodzie
Możesz również zdefiniować części kodu za pomocą parametru definePartial
:
import { definePartial } from '@genkit-ai/dotprompt';
definePartial(
'personality',
'Talk like a {{#if style}}{{style}}{{else}}helpful assistant{{/if}}.'
);
Części zdefiniowane za pomocą kodu są dostępne we wszystkich promptach.
Warianty promptu
Ponieważ pliki promptów mają postać tekstową, możesz (– a powinien!) system kontroli wersji, który pozwala łatwo porównywać zmiany w czasie. Często dopracowane wersje promptów można w pełni przetestować środowiska produkcyjnego i istniejących wersji. Obsługiwany jest kropka to za pomocą funkcji wariantów.
Aby utworzyć wariant, utwórz plik [name].[variant].prompt
. Jeśli na przykład
używasz w prompcie Gemini 1.5 Flash, ale chcesz sprawdzić, czy Gemini 1.5
Wersja Pro działa lepiej, ale możesz utworzyć 2 pliki:
my_prompt.prompt
: wartość bazowa promptmy_prompt.gemini15pro.prompt
: wariant o nazwie „gemini15pro”.
Aby użyć wariantu promptu, podczas wczytywania określ opcję variant
:
const myPrompt = await prompt('my_prompt', { variant: 'gemini15pro' });
Nazwa wariantu jest zawarta w metadanych logów czasu generowania, więc może porównywać rzeczywistą skuteczność różnych wariantów w zrzucie danych Genkit i inspektor.
Definiowanie niestandardowych pomocników
Możesz zdefiniować niestandardowych pomocników do przetwarzania danych i zarządzania nimi w prompcie. Pomocnicy
są zarejestrowane na całym świecie przy użyciu defineHelper
:
import { defineHelper } from '@genkit-ai/dotprompt';
defineHelper('shout', (text: string) => text.toUpperCase());
Zdefiniowanego asystenta możesz używać w dowolnym prompcie:
---
model: vertexai/gemini-1.5-flash
input:
schema:
name: string
---
HELLO, {{shout name}}!!!
Więcej informacji o argumentach przekazanych do pomocy znajdziesz w Dokumentacja tworzenia za pomocą kierownicy z niestandardowymi aplikacjami pomocniczymi.
Alternatywne sposoby wczytywania i definiowania promptów
Metoda Dotprompt jest zoptymalizowana pod kątem organizacji w katalogu promptów. Istnieje jednak Oto kilka innych sposobów wczytywania i definiowania promptów:
loadPromptFile
: wczytaj prompt z pliku w katalogu promptów.loadPromptUrl
: wczytaj prompt 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.5-flash',
input: {
schema: z.object({
name: z.string(),
}),
},
},
`Hello {{name}}, how are you today?`
);