Engineering prompt adalah cara utama yang dapat Anda gunakan untuk memengaruhi output model AI generatif sebagai developer aplikasi. Misalnya, saat menggunakan LLM, Anda dapat membuat perintah yang memengaruhi nada, format, panjang, dan karakteristik lainnya dari respons model.
Cara Anda menulis perintah ini akan bergantung pada model yang Anda gunakan; perintah yang ditulis untuk satu model mungkin tidak berperforma baik saat digunakan dengan model lain. Demikian pula, parameter model yang Anda tetapkan (suhu, top-k, dan sebagainya) juga akan memengaruhi output secara berbeda, bergantung pada model.
Mendapatkan ketiga faktor ini—model, parameter model, dan perintah—agar bekerja sama untuk menghasilkan output yang Anda inginkan jarang merupakan proses yang mudah dan sering kali melibatkan iterasi dan eksperimen yang substansial. Genkit menyediakan library dan format file yang disebut Dotprompt, yang bertujuan untuk membuat iterasi ini lebih cepat dan lebih praktis.
Dotprompt dirancang berdasarkan premis bahwa prompt adalah kode. Anda menentukan perintah beserta model dan parameter model yang ditujukan untuknya secara terpisah dari kode aplikasi Anda. Kemudian, Anda (atau, mungkin seseorang yang bahkan tidak terlibat dalam menulis kode aplikasi) dapat melakukan iterasi dengan cepat pada perintah dan parameter model menggunakan UI Developer Genkit. Setelah perintah berfungsi seperti yang Anda inginkan, Anda dapat mengimpornya ke aplikasi dan menjalankannya menggunakan Genkit.
Setiap definisi perintah Anda akan ditempatkan dalam file dengan ekstensi .prompt
. Berikut
contoh tampilan file ini:
---
model: googleai/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}}.
Bagian dalam tiga tanda hubung adalah frontmatter YAML, mirip dengan format front
matter yang digunakan oleh GitHub Markdown dan Jekyll; bagian lain dari file adalah
prompt, yang secara opsional dapat menggunakan
template Handlebars. Bagian
berikut akan membahas lebih lanjut setiap bagian yang membuat
file .prompt
dan cara menggunakannya.
Sebelum memulai
Sebelum membaca halaman ini, Anda harus sudah memahami konten yang dibahas di halaman Membuat konten dengan model AI.
Jika Anda ingin menjalankan contoh kode di halaman ini, selesaikan langkah-langkah dalam panduan Memulai terlebih dahulu. Semua contoh mengasumsikan bahwa Anda telah menginstal Genkit sebagai dependensi dalam project.
Membuat file perintah
Meskipun Dotprompt menyediakan beberapa cara yang berbeda untuk membuat
dan memuat perintah, Dotprompt dioptimalkan untuk project yang mengatur perintahnya sebagai
file .prompt
dalam satu direktori (atau subdirektorinya). Bagian
ini menunjukkan cara membuat dan memuat perintah menggunakan penyiapan yang direkomendasikan ini.
Membuat direktori perintah
Library Dotprompt diharapkan menemukan perintah Anda di direktori di
root project dan otomatis memuat perintah apa pun yang ditemukan di sana. Secara default,
direktori ini diberi nama prompts
. Misalnya, menggunakan nama direktori default, struktur project Anda mungkin terlihat seperti ini:
your-project/
├── lib/
├── node_modules/
├── prompts/
│ └── hello.prompt
├── src/
├── package-lock.json
├── package.json
└── tsconfig.json
Jika ingin menggunakan direktori lain, Anda dapat menentukannya saat mengonfigurasi Genkit:
const ai = genkit({
promptDir: './llm_prompts',
// (Other settings...)
});
Membuat file perintah
Ada dua cara untuk membuat file .prompt
: menggunakan editor teks, atau dengan
UI developer.
Menggunakan editor teks
Jika Anda ingin membuat file perintah menggunakan editor teks, buat file teks dengan
ekstensi .prompt
di direktori perintah: misalnya,
prompts/hello.prompt
.
Berikut adalah contoh minimal file perintah:
---
model: vertexai/gemini-1.5-flash
---
You are the world's most welcoming AI assistant. Greet the user and offer your assistance.
Bagian dalam tanda hubung adalah frontmatter YAML, mirip dengan format frontmatter yang digunakan oleh markdown GitHub dan Jekyll; bagian lain dari file adalah perintah, yang secara opsional dapat menggunakan template Handlebars. Bagian pengantar bersifat opsional, tetapi sebagian besar file perintah setidaknya akan berisi metadata yang menentukan model. Bagian lain dari halaman ini menunjukkan cara melakukan hal-hal di luar ini, dan menggunakan fitur Dotprompt dalam file perintah Anda.
Menggunakan UI developer
Anda juga dapat membuat file perintah menggunakan runner model di UI developer. Mulai dengan kode aplikasi yang mengimpor library Genkit dan mengonfigurasinya untuk menggunakan plugin model yang Anda minati. Contoh:
import { genkit } from 'genkit';
// Import the model plugins you want to use.
import { googleAI } from '@genkit-ai/googleai';
const ai = genkit({
// Initialize and configure the model plugins.
plugins: [
googleAI({
apiKey: 'your-api-key', // Or (preferred): export GOOGLE_GENAI_API_KEY=...
}),
],
});
Tidak masalah jika file berisi kode lain, tetapi kode di atas adalah satu-satunya yang diperlukan.
Muat UI developer dalam project yang sama:
genkit start -- tsx --watch src/your-code.ts
Di bagian Model, pilih model yang ingin Anda gunakan dari daftar model yang disediakan oleh plugin.
Kemudian, bereksperimenlah dengan perintah dan konfigurasi hingga Anda mendapatkan hasil yang memuaskan. Jika sudah siap, tekan tombol Ekspor dan simpan file ke direktori perintah Anda.
Menjalankan perintah
Setelah membuat file perintah, Anda dapat menjalankannya dari kode aplikasi, atau menggunakan alat yang disediakan oleh Genkit. Terlepas dari cara Anda ingin menjalankan perintah, mulailah dengan kode aplikasi yang mengimpor library Genkit dan plugin model yang Anda minati. Contoh:
import { genkit } from 'genkit';
// Import the model plugins you want to use.
import { googleAI } from '@genkit-ai/googleai';
const ai = genkit({
// Initialize and configure the model plugins.
plugins: [
googleAI({
apiKey: 'your-api-key', // Or (preferred): export GOOGLE_GENAI_API_KEY=...
}),
],
});
Tidak masalah jika file berisi kode lain, tetapi kode di atas adalah satu-satunya yang diperlukan. Jika Anda menyimpan perintah di direktori selain default, pastikan untuk menentukannya saat mengonfigurasi Genkit.
Menjalankan perintah dari kode
Untuk menggunakan perintah, muat terlebih dahulu menggunakan metode prompt('file_name')
:
const helloPrompt = ai.prompt('hello');
Setelah dimuat, Anda dapat memanggil perintah seperti fungsi:
const response = await helloPrompt();
// Alternatively, use destructuring assignments to get only the properties
// you're interested in:
const { text } = await helloPrompt();
Perintah yang dapat dipanggil memerlukan dua parameter opsional: input ke perintah (lihat
bagian di bawah tentang menentukan skema input), dan objek
konfigurasi, mirip dengan metode generate()
. Contoh:
const response2 = await helloPrompt(
// Prompt input:
{ name: 'Ted' },
// Generation options:
{
config: {
temperature: 0.4,
},
}
);
Setiap parameter yang Anda teruskan ke panggilan perintah akan menggantikan parameter yang sama yang ditentukan dalam file perintah.
Lihat Membuat konten dengan model AI untuk mengetahui deskripsi opsi yang tersedia.
Menggunakan UI developer
Saat Anda meningkatkan kualitas perintah aplikasi, Anda dapat menjalankannya di UI developer Genkit untuk melakukan iterasi pada perintah dan konfigurasi model dengan cepat, secara independen dari kode aplikasi Anda.
Muat UI developer dari direktori project Anda:
genkit start -- tsx --watch src/your-code.ts
Setelah memuat perintah ke UI developer, Anda dapat menjalankannya dengan parameter input yang berbeda, dan bereksperimen dengan pengaruh perubahan pada kata-kata perintah atau parameter konfigurasi terhadap output model. Jika sudah puas dengan hasilnya, Anda dapat mengklik tombol Export prompt untuk menyimpan perintah yang diubah kembali ke direktori project.
Konfigurasi model
Di blok materi awal file perintah, Anda dapat menentukan nilai konfigurasi model untuk perintah secara opsional:
---
model: googleai/gemini-1.5-flash
config:
temperature: 1.4
topK: 50
topP: 0.4
maxOutputTokens: 400
stopSequences:
- "<end>"
- "<fin>"
---
Nilai ini dipetakan langsung ke parameter config
yang diterima oleh perintah
yang dapat dipanggil:
const response3 = await helloPrompt(
{},
{
config: {
temperature: 1.4,
topK: 50,
topP: 0.4,
maxOutputTokens: 400,
stopSequences: ['<end>', '<fin>'],
},
}
);
Lihat Membuat konten dengan model AI untuk mengetahui deskripsi opsi yang tersedia.
Skema input dan output
Anda dapat menentukan skema input dan output untuk perintah dengan menentukannya di bagian isi awal:
---
model: googleai/gemini-1.5-flash
input:
schema:
theme?: string
default:
theme: "pirate"
output:
schema:
dishname: string
description: string
calories: integer
allergens(array): string
---
Invent a menu item for a {{theme}} themed restaurant.
Skema ini digunakan dengan cara yang sama seperti yang diteruskan ke permintaan
generate()
atau definisi alur. Misalnya, perintah yang ditentukan di atas menghasilkan
output terstruktur:
const menuPrompt = ai.prompt('menu');
const { data } = await menuPrompt({ theme: 'medieval' });
const dishName = data['dishname'];
const description = data['description'];
Anda memiliki beberapa opsi untuk menentukan skema dalam file .prompt
: format definisi skema
Dotprompt sendiri, Picoschema; Skema JSON standar; atau, sebagai
referensi ke skema yang ditentukan dalam kode aplikasi Anda. Bagian berikut
menjelaskan setiap opsi ini secara lebih mendetail.
Picoschema
Skema dalam contoh di atas ditentukan dalam format yang disebut Picoschema. Picoschema adalah format definisi skema ringkas yang dioptimalkan untuk YAML yang memudahkan dalam menentukan atribut skema yang paling penting untuk penggunaan LLM. Berikut adalah contoh skema yang lebih panjang, yang menentukan informasi yang mungkin disimpan aplikasi tentang artikel:
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
Skema di atas setara dengan antarmuka TypeScript berikut:
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 mendukung jenis skalar string
, integer
, number
, boolean
, dan
any
. Objek, array, dan enum dilambangkan dengan tanda kurung setelah nama kolom.
Objek yang didefinisikan oleh Picoschema memiliki semua properti yang disyaratkan, kecuali dilambangkan
sebagai opsional dengan ?
, dan tidak mengizinkan properti tambahan. Jika properti
ditandai sebagai opsional, properti tersebut juga dibuat nullable untuk memberikan lebih banyak kemudahan bagi LLM
agar menampilkan null, bukan menghilangkan kolom.
Dalam definisi objek, kunci khusus (*)
dapat digunakan untuk mendeklarasikan
definisi kolom "karakter pengganti". Hal ini akan cocok dengan semua properti tambahan yang tidak
disediakan oleh kunci eksplisit.
Skema JSON
Picoschema tidak mendukung banyak kemampuan skema JSON lengkap. Jika memerlukan skema yang lebih andal, Anda dapat memberikan Skema JSON:
output:
schema:
type: object
properties:
field1:
type: number
minimum: 20
Skema Zod yang ditentukan dalam kode
Selain menentukan skema secara langsung dalam file .prompt
, Anda dapat
mereferensikan skema yang terdaftar dengan defineSchema()
berdasarkan namanya. Jika Anda menggunakan TypeScript, pendekatan ini akan memungkinkan Anda memanfaatkan fitur pemeriksaan jenis statis bahasa saat Anda menggunakan perintah.
Untuk mendaftarkan skema:
import { z } from 'genkit';
const MenuItemSchema = ai.defineSchema(
'MenuItemSchema',
z.object({
dishname: z.string(),
description: z.string(),
calories: z.coerce.number(),
allergens: z.array(z.string()),
})
);
Dalam perintah Anda, berikan nama skema yang terdaftar:
---
model: googleai/gemini-1.5-flash-latest
output:
schema: MenuItemSchema
---
Library Dotprompt akan otomatis me-resolve nama ke skema Zod yang terdaftar di bawahnya. Kemudian, Anda dapat menggunakan skema untuk mengetik output Dotprompt dengan tegas:
const menuPrompt = ai.prompt<
z.ZodTypeAny, // Input schema
typeof MenuItemSchema, // Output schema
z.ZodTypeAny // Custom options schema
>('menu');
const { data } = await menuPrompt({ theme: 'medieval' });
// Now data is strongly typed as MenuItemSchema:
const dishName = data?.dishname;
const description = data?.description;
Template perintah
Bagian file .prompt
yang mengikuti materi awal (jika ada) adalah
perintah itu sendiri, yang akan diteruskan ke model. Meskipun perintah ini dapat berupa
string teks sederhana, Anda sering kali ingin menyertakan input pengguna ke dalam
perintah. Untuk melakukannya, Anda dapat menentukan perintah menggunakan
bahasa template Handlebars.
Template perintah dapat menyertakan placeholder yang merujuk ke nilai yang ditentukan oleh
skema input perintah Anda.
Anda telah melihat cara kerjanya di bagian skema input dan output:
---
model: googleai/gemini-1.5-flash
config:
temperature: 1.4
topK: 50
topP: 0.4
maxOutputTokens: 400
stopSequences:
- "<end>"
- "<fin>"
---
Dalam contoh ini, ekspresi Handlebars, {{theme}}
,
di-resolve ke nilai properti theme
input saat Anda menjalankan
perintah. Untuk meneruskan input ke perintah, panggil perintah seperti dalam contoh
berikut:
const menuPrompt = ai.prompt('menu');
const { data } = await menuPrompt({ theme: 'medieval' });
Perhatikan bahwa karena skema input mendeklarasikan properti theme
sebagai opsional
dan memberikan default, Anda dapat menghilangkan properti tersebut,
dan perintah akan di-resolve menggunakan nilai default.
Template Handlebars juga mendukung beberapa konstruksi logis terbatas. Misalnya, sebagai alternatif untuk memberikan default, Anda dapat menentukan perintah menggunakan helper #if
Handlebars:
---
model: googleai/gemini-1.5-flash
input:
schema:
theme?: string
---
Invent a menu item for a {{#if theme}}{{theme}} themed{{/if}} restaurant.
Dalam contoh ini, perintah dirender sebagai "Buat item menu untuk restoran"
saat properti theme
tidak ditentukan.
Lihat dokumentasi Handlebars untuk mengetahui informasi tentang semua helper logis bawaan.
Selain properti yang ditentukan oleh skema input, template Anda juga dapat merujuk ke nilai yang ditentukan secara otomatis oleh Genkit. Beberapa bagian berikutnya menjelaskan nilai yang ditentukan secara otomatis ini dan cara menggunakannya.
Prompt multi-pesan
Secara default, Dotprompt membuat satu pesan dengan peran "pengguna". Namun, beberapa perintah sebaiknya dinyatakan sebagai kombinasi dari beberapa pesan, seperti perintah sistem.
Helper {{role}}
menyediakan cara mudah untuk
membuat perintah multi-pesan:
---
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}}
Prompt multi-modal
Untuk model yang mendukung input multimodal, seperti gambar di samping teks, Anda dapat
menggunakan helper {{media}}
:
---
model: vertexai/gemini-1.5-flash
input:
schema:
photoUrl: string
---
Describe this image in a detailed paragraph:
{{media url=photoUrl}}
URL dapat berupa URI https:
atau data:
berenkode base64 untuk penggunaan gambar "inline".
Dalam kode, ini akan menjadi:
const multimodalPrompt = ai.prompt('multimodal');
const { text } = await multimodalPrompt({
photoUrl: 'https://example.com/photo.jpg',
});
Lihat juga Input multimodal, di halaman
Model, untuk mengetahui contoh pembuatan URL data:
.
Parsial
Parsial adalah template yang dapat digunakan kembali dan dapat disertakan di dalam perintah apa pun. Bagian dapat sangat membantu untuk perintah terkait yang memiliki perilaku yang sama.
Saat memuat direktori perintah, setiap file yang diawali dengan garis bawah (_
) dianggap sebagai parsial. Jadi, file _personality.prompt
mungkin berisi:
You should speak like a {{#if style}}{{style}}{{else}}helpful assistant.{{/else}}.
Kemudian, ini dapat disertakan dalam perintah lain:
---
model: googleai/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}}
Bagian disisipkan menggunakan sintaksis {{>NAME_OF_PARTIAL args...}}
. Jika tidak ada argumen yang diberikan ke bagian, argumen akan dieksekusi dengan konteks
yang sama dengan perintah induk.
Bagian menerima argumen bernama seperti di atas atau satu argumen posisional yang mewakili konteks. Hal ini dapat berguna untuk tugas seperti merender anggota daftar.
_destination.prompt
- {{name}} ({{country}})
chooseDestination.prompt
---
model: googleai/gemini-1.5-flash-latest
input:
schema:
destinations(array):
name: string
country: string
---
Help the user decide between these vacation destinations:
{{#each destinations}}
{{>destination this}}
{{/each}}
Menentukan bagian dalam kode
Anda juga dapat menentukan parsial dalam kode menggunakan definePartial
:
ai.definePartial(
'personality',
'Talk like a {{#if style}}{{style}}{{else}}helpful assistant{{/if}}.'
);
Bagian yang ditentukan kode tersedia di semua perintah.
Menentukan Helper Kustom
Anda dapat menentukan helper kustom untuk memproses dan mengelola data di dalam perintah.
Helper didaftarkan secara global menggunakan defineHelper
:
ai.defineHelper('shout', (text: string) => text.toUpperCase());
Setelah helper ditentukan, Anda dapat menggunakannya di perintah apa pun:
---
model: googleai/gemini-1.5-flash
input:
schema:
name: string
---
HELLO, {{shout name}}!!!
Varian perintah
Karena file prompt berupa teks, Anda bisa (dan harus) melakukan commit ke sistem kontrol versi, yang memungkinkan Anda untuk membandingkan perubahan dari waktu ke waktu dengan mudah. Sering kali, versi perintah yang sudah diutak-atik hanya bisa diuji sepenuhnya di lingkungan produksi secara berdampingan dengan versi yang sudah ada. Dotprompt mendukung hal ini melalui fitur variannya.
Untuk membuat varian, buat file [name].[variant].prompt
. Misalnya, jika
Anda menggunakan Gemini 1.5 Flash di prompt, tetapi ingin mengetahui apakah Gemini 1.5 Pro
akan berperforma lebih baik, Anda dapat membuat dua file:
my_prompt.prompt
: prompt "dasar"my_prompt.gemini15pro.prompt
: varian bernamagemini15pro
Untuk menggunakan varian perintah, tentukan opsi varian saat memuat:
const myPrompt = ai.prompt('my_prompt', { variant: 'gemini15pro' });
Nama varian disertakan dalam metadata trace pembuatan, sehingga Anda dapat membandingkan dan membedakan performa sebenarnya di antara varian dalam pemeriksa trace Genkit.
Menentukan perintah dalam kode
Semua contoh yang telah dibahas sejauh ini mengasumsikan bahwa perintah Anda ditentukan
dalam setiap file .prompt
dalam satu direktori (atau subdirektorinya),
yang dapat diakses oleh aplikasi Anda saat runtime. Dotprompt dirancang berdasarkan penyiapan ini, dan
penulisnya menganggapnya sebagai pengalaman developer terbaik secara keseluruhan.
Namun, jika Anda memiliki kasus penggunaan yang tidak didukung dengan baik oleh penyiapan ini,
Anda juga dapat menentukan perintah dalam kode menggunakan fungsi definePrompt()
:
Parameter pertama untuk fungsi ini analog dengan blok materi awal file
.prompt
; parameter kedua dapat berupa string template Handlebars,
seperti dalam file perintah, atau fungsi yang menampilkan GenerateRequest
:
const myPrompt = ai.definePrompt(
{
name: 'myPrompt',
model: 'googleai/gemini-1.5-flash',
input: {
schema: z.object({
name: z.string(),
}),
},
},
'Hello, {{name}}. How are you today?'
);
const myPrompt = ai.definePrompt(
{
name: 'myPrompt',
model: 'googleai/gemini-1.5-flash',
input: {
schema: z.object({
name: z.string(),
}),
},
},
async (input): Promise<GenerateRequest> => {
return {
messages: [
{
role: 'user',
content: [{ text: `Hello, ${input.name}. How are you today?` }],
},
],
};
}
);