İstem mühendisliği, uygulama geliştirici olarak üretken yapay zeka modellerinin çıkışını etkilemenin birincil yoludur. Örneğin, LLM'leri kullanırken modellerin yanıtlarının üslubunu, biçimini, uzunluğunu ve diğer özelliklerini etkileyen istemler oluşturabilirsiniz.
Bu istemleri yazma şekliniz, kullandığınız modele bağlıdır. Bir model için yazılmış bir istem, başka bir modelde kullanıldığında iyi performans göstermeyebilir. Benzer şekilde, belirlediğiniz model parametreleri (sıcaklık, en iyi k vb.) de çıkışı modele bağlı olarak farklı şekilde etkiler.
Bu faktörlerin üçünün de (model, model parametreleri ve istem) birlikte çalışarak istediğiniz çıktıyı oluşturması nadiren önemsiz bir süreçtir ve genellikle önemli miktarda yineleme ve deneme gerektirir. Genkit, bu iterasyonu daha hızlı ve daha kullanışlı hale getirmeyi amaçlayan Dotprompt adlı bir kitaplık ve dosya biçimi sağlar.
Dotprompt, istemlerin kod olduğu ilkesine göre tasarlanmıştır. İstemlerinizi, amaçlanan modeller ve model parametreleriyle birlikte uygulama kodunuzdan ayrı olarak tanımlarsınız. Ardından, siz (veya uygulama kodu yazmakla hiç ilgilenmeyen biri) Genkit geliştirici kullanıcı arayüzünü kullanarak istemler ve model parametreleri üzerinde hızlıca iterasyon yapabilirsiniz. İstemleriniz istediğiniz şekilde çalışmaya başladıktan sonra bunları uygulamanıza aktarabilir ve Genkit'i kullanarak çalıştırabilirsiniz.
İstem tanımlarınızın her biri .prompt
uzantılı bir dosyaya yerleştirilir. Bu dosyaların nasıl göründüğüne dair bir örnek aşağıda verilmiştir:
---
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}}.
Üçlü kısa çizgiler içindeki kısım, GitHub Markdown ve Jekyll tarafından kullanılan ön metin biçimine benzer bir YAML ön metindir. Dosyanın geri kalanı ise isteğe bağlı olarak Handlebars şablonlarını kullanabilen istemdir. Aşağıdaki bölümlerde, .prompt
dosyasını oluşturan bölümlerin her biri ve bunların nasıl kullanılacağı hakkında daha ayrıntılı bilgi verilmektedir.
Başlamadan önce
Bu sayfayı okumadan önce Yapay zeka modelleriyle içerik oluşturma sayfasında ele alınan içerik hakkında bilgi sahibi olmanız gerekir.
Bu sayfadaki kod örneklerini çalıştırmak istiyorsanız önce Başlangıç kılavuzundaki adımları tamamlayın. Tüm örneklerde, Genkit'i projenize bağımlı olarak yüklemiş olduğunuz varsayılmaktadır.
İstem dosyaları oluşturma
Dotprompt, istem oluşturmak ve yüklemek için birkaç farklı yöntem sunsa da istemlerini tek bir dizinde (veya alt dizinlerinde) .prompt
dosyaları olarak düzenleyen projeler için optimize edilmiştir. Bu bölümde, önerilen kurulumu kullanarak istemlerin nasıl oluşturulacağı ve yükleneceği gösterilmektedir.
İstem dizini oluşturma
Dotprompt kitaplığı, istemlerinizi proje kök dizininizdeki bir dizinde bulmayı bekler ve burada bulduğu tüm istemleri otomatik olarak yükler. Bu dizin varsayılan olarak prompts
olarak adlandırılır. Örneğin, varsayılan dizin adını kullanarak proje yapınız şöyle görünebilir:
your-project/
├── lib/
├── node_modules/
├── prompts/
│ └── hello.prompt
├── src/
├── package-lock.json
├── package.json
└── tsconfig.json
Farklı bir dizin kullanmak istiyorsanız Genkit'i yapılandırırken bunu belirtebilirsiniz:
const ai = genkit({
promptDir: './llm_prompts',
// (Other settings...)
});
İstem dosyası oluşturma
.prompt
dosyası oluşturmanın iki yolu vardır: metin düzenleyici veya geliştirici kullanıcı arayüzü.
Metin düzenleyicisi kullanma
Metin düzenleyici kullanarak istem dosyası oluşturmak istiyorsanız istemler dizininizde .prompt
uzantılı bir metin dosyası oluşturun. Örneğin, prompts/hello.prompt
.
İstem dosyasına dair basit bir örnek aşağıda verilmiştir:
---
model: vertexai/gemini-1.5-flash
---
You are the world's most welcoming AI assistant. Greet the user and offer your assistance.
Tire işaretleri içindeki kısım, GitHub markdown ve Jekyll tarafından kullanılan ön metin biçimine benzer bir YAML ön metindir. Dosyanın geri kalanı ise isteğe bağlı olarak Handlebars şablonları kullanabilen istemdir. Ön bilgiler bölümü isteğe bağlıdır ancak çoğu istem dosyası en azından bir modeli belirten meta veriler içerir. Bu sayfanın geri kalanında, bunun ötesine nasıl geçeceğiniz ve istem dosyalarınızda Dotprompt'ın özelliklerinden nasıl yararlanacağınız gösterilmektedir.
Geliştirici kullanıcı arayüzünü kullanma
Geliştirici kullanıcı arayüzündeki model çalıştırıcıyı kullanarak da istem dosyası oluşturabilirsiniz. Genkit kitaplığını içe aktaran ve ilgilendiğiniz model eklentisini kullanacak şekilde yapılandıran uygulama kodundan başlayın. Örneğin:
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=...
}),
],
});
Dosyada başka kodlar varsa sorun olmaz ancak gereken tek şey yukarıdaki koddur.
Geliştirici kullanıcı arayüzünü aynı projeye yükleyin:
genkit start -- tsx --watch src/your-code.ts
Modeller bölümünde, eklenti tarafından sağlanan model listesinden kullanmak istediğiniz modeli seçin.
Ardından, memnun olduğunuz sonuçları elde edene kadar istemi ve yapılandırmayı deneyin. Hazır olduğunuzda Dışa Aktar düğmesine basın ve dosyayı istemler dizininize kaydedin.
İstemleri çalıştırma
İstem dosyalarını oluşturduktan sonra bunları uygulama kodunuzdan veya Genkit tarafından sağlanan araçları kullanarak çalıştırabilirsiniz. İstemlerinizi nasıl çalıştırmak istediğinizden bağımsız olarak, öncelikle Genkit kitaplığını ve ilgilendiğiniz model eklentilerini içe aktaran uygulama kodundan başlayın. Örneğin:
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=...
}),
],
});
Dosyada başka kodlar varsa sorun olmaz ancak gereken tek şey yukarıdaki koddur. İstemlerinizi varsayılan dizinden farklı bir dizinde saklıyorsunuzdur. Genkit'i yapılandırırken bunu belirtmeyi unutmayın.
Koddan istemleri çalıştırma
İstemleri kullanmak için önce prompt('file_name')
yöntemini kullanarak yükleyin:
const helloPrompt = ai.prompt('hello');
Yüklendikten sonra istemi bir işlev gibi çağırabilirsiniz:
const response = await helloPrompt();
// Alternatively, use destructuring assignments to get only the properties
// you're interested in:
const { text } = await helloPrompt();
Çağırılabilir istem iki isteğe bağlı parametre alır: istemin girişi (giriş şemalarını belirtme ile ilgili aşağıdaki bölüme bakın) ve generate()
yöntemine benzer bir yapılandırma nesnesi. Örneğin:
const response2 = await helloPrompt(
// Prompt input:
{ name: 'Ted' },
// Generation options:
{
config: {
temperature: 0.4,
},
}
);
İstem çağrısına ilettiğiniz tüm parametreler, istem dosyasında belirtilen parametreleri geçersiz kılar.
Kullanılabilir seçeneklerin açıklamaları için Yapay zeka modelleriyle içerik oluşturma başlıklı makaleyi inceleyin.
Geliştirici kullanıcı arayüzünü kullanma
Uygulamanızın istemlerini hassaslaştırırken, istemler ve model yapılandırmaları üzerinde uygulama kodunuzdan bağımsız olarak hızlıca iterasyon yapmak için bunları Genkit geliştirici kullanıcı arayüzünde çalıştırabilirsiniz.
Geliştirici kullanıcı arayüzünü proje dizininizden yükleyin:
genkit start -- tsx --watch src/your-code.ts
İstemleri geliştirici kullanıcı arayüzüne yükledikten sonra farklı giriş değerleriyle çalıştırabilir ve istem metninde veya yapılandırma parametrelerinde yapılan değişikliklerin model çıktısını nasıl etkilediğini deneyebilirsiniz. Sonuçtan memnun kaldığınızda, değiştirilen istemi proje dizininize kaydetmek için İsteği dışa aktar düğmesini tıklayabilirsiniz.
Model yapılandırması
İstem dosyalarınızın ön kısım bloğunda, isteminizle ilgili model yapılandırma değerlerini isteğe bağlı olarak belirtebilirsiniz:
---
model: googleai/gemini-1.5-flash
config:
temperature: 1.4
topK: 50
topP: 0.4
maxOutputTokens: 400
stopSequences:
- "<end>"
- "<fin>"
---
Bu değerler doğrudan çağrılabilir istem tarafından kabul edilen config
parametresiyle eşlenir:
const response3 = await helloPrompt(
{},
{
config: {
temperature: 1.4,
topK: 50,
topP: 0.4,
maxOutputTokens: 400,
stopSequences: ['<end>', '<fin>'],
},
}
);
Kullanılabilir seçeneklerin açıklamaları için Yapay zeka modelleriyle içerik oluşturma başlıklı makaleyi inceleyin.
Giriş ve çıkış şemaları
İsteminiz için giriş ve çıkış şemalarını ön kısım bölümünde tanımlayarak belirtebilirsiniz:
---
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.
Bu şemalar, generate()
isteğine veya akış tanımına iletilenlerle hemen hemen aynı şekilde kullanılır. Örneğin, yukarıda tanımlanan istem yapılandırılmış bir çıkış oluşturur:
const menuPrompt = ai.prompt('menu');
const { data } = await menuPrompt({ theme: 'medieval' });
const dishName = data['dishname'];
const description = data['description'];
.prompt
dosyasında şemaları tanımlamak için birkaç seçeneğiniz vardır: Dotprompt'ın kendi şema tanımlama biçimi olan Picoschema; standart JSON şeması veya uygulama kodunuzda tanımlanan şemalara referans olarak. Aşağıdaki bölümlerde bu seçeneklerin her biri ayrıntılı olarak açıklanmıştır.
Picoschema
Yukarıdaki örnekteki şemalar, Picoschema adlı bir biçimde tanımlanmıştır. Picoschema, LLM kullanımı için bir şemanın en önemli özelliklerini tanımlamayı kolaylaştıran, YAML için optimize edilmiş kompakt bir şema tanımı biçimidir. Aşağıda, bir uygulamanın bir makale hakkında saklayabileceği bilgileri belirten daha uzun bir şema örneği verilmiştir:
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
Yukarıdaki şema, aşağıdaki TypeScript arayüzüne eşdeğerdir:
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
ve any
skaler türlerini destekler. Nesneler, diziler ve enum'lar, alan adından sonra parantez içinde gösterilir.
Picoschema tarafından tanımlanan nesneler, ?
ile isteğe bağlı olarak belirtilmediği sürece gerekli tüm özelliklere sahiptir ve ek özelliklere izin vermez. Bir özellik isteğe bağlı olarak işaretlendiğinde, LLM'lerin bir alanı atlamak yerine null döndürmesi için daha fazla esneklik sağlamak amacıyla null olarak da ayarlanır.
Bir nesne tanımında, "wildcard" alan tanımı beyan etmek için özel anahtar (*)
kullanılabilir. Bu, açık bir anahtarla sağlanmayan tüm ek özelliklerle eşleşir.
JSON şeması
Picoschema, tam JSON şemasının birçok özelliğini desteklemez. Daha güçlü şemalara ihtiyacınız varsa bunun yerine bir JSON şeması sağlayabilirsiniz:
output:
schema:
type: object
properties:
field1:
type: number
minimum: 20
Kodda tanımlanan Zod şemaları
Şemaları .prompt
dosyasında doğrudan tanımlamanın yanı sıra, defineSchema()
'a kayıtlı bir şemaya adla referans verebilirsiniz. TypeScript kullanıyorsanız bu yaklaşım, istemlerle çalışırken dilin statik tür denetimi özelliklerinden yararlanmanıza olanak tanır.
Şema kaydetmek için:
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()),
})
);
İsteminizde, kayıtlı şemanın adını belirtin:
---
model: googleai/gemini-1.5-flash-latest
output:
schema: MenuItemSchema
---
Dotprompt kitaplığı, adı otomatik olarak temel kayıtlı Zod şemasına çözer. Ardından, Dotprompt'ın çıkışını güçlü bir şekilde yazı tipi için şemayı kullanabilirsiniz:
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;
İstem şablonları
.prompt
dosyasının ön bilgileri (varsa) izleyen kısmı, modele iletilecek istemdir. Bu istem basit bir metin dizesi olsa da genellikle istemde kullanıcı girişini kullanmak istersiniz. Bunu yapmak için Handlebars şablonlama dilini kullanarak isteminizi belirtebilirsiniz.
İstem şablonları, isteminizin giriş şeması tarafından tanımlanan değerlere atıfta bulunan yer tutucular içerebilir.
Bunu giriş ve çıkış şemalarıyla ilgili bölümde zaten görmüştünüz:
---
model: googleai/gemini-1.5-flash
config:
temperature: 1.4
topK: 50
topP: 0.4
maxOutputTokens: 400
stopSequences:
- "<end>"
- "<fin>"
---
Bu örnekte, istemi çalıştırdığınızda {{theme}}
Handlebars ifadesi, girişin theme
mülkünün değerine çözümlenir. İsteme giriş aktarmak için istemi aşağıdaki örnekte gösterildiği gibi çağırın:
const menuPrompt = ai.prompt('menu');
const { data } = await menuPrompt({ theme: 'medieval' });
Giriş şeması theme
özelliğini isteğe bağlı olarak tanımladığı ve varsayılan bir değer sağladığı için özelliği atlayabileceğinizi ve istemin varsayılan değer kullanılarak çözüleceğini unutmayın.
Handlebars şablonları, bazı sınırlı mantıksal yapıları da destekler. Örneğin, varsayılan değer sağlamaya alternatif olarak, Handlebars'ın #if
yardımcısını kullanarak istemi tanımlayabilirsiniz:
---
model: googleai/gemini-1.5-flash
input:
schema:
theme?: string
---
Invent a menu item for a {{#if theme}}{{theme}} themed{{/if}} restaurant.
Bu örnekte, theme
mülkü belirtilmediğinde istem "Restoran için bir menü öğesi oluşturun" şeklinde oluşturulur.
Yerleşik tüm mantıksal yardımcılar hakkında bilgi edinmek için Handlebars belgelerine bakın.
Şablonlarınız, giriş şemanız tarafından tanımlanan özelliklere ek olarak Genkit tarafından otomatik olarak tanımlanan değerlere de referans verebilir. Sonraki birkaç bölümde, bu otomatik olarak tanımlanmış değerler ve bunları nasıl kullanabileceğiniz açıklanmaktadır.
Birden fazla mesaj istemi
Dotprompt varsayılan olarak "kullanıcı" rolüne sahip tek bir mesaj oluşturur. Ancak bazı istemler, sistem istemi gibi birden fazla mesajın bir kombinasyonu olarak en iyi şekilde ifade edilir.
{{role}}
yardımcısı, çok mesajlı istemler oluşturmanın basit bir yolunu sunar:
---
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}}
Çok modlu istemler
Metinle birlikte resimler gibi çoklu formatlı girişleri destekleyen modeller için {{media}}
yardımcısını kullanabilirsiniz:
---
model: vertexai/gemini-1.5-flash
input:
schema:
photoUrl: string
---
Describe this image in a detailed paragraph:
{{media url=photoUrl}}
URL, "satır içi" resim kullanımı için https:
veya Base64 olarak kodlanmış data:
URI'leri olabilir.
Kodda bu şöyle görünür:
const multimodalPrompt = ai.prompt('multimodal');
const { text } = await multimodalPrompt({
photoUrl: 'https://example.com/photo.jpg',
});
data:
URL'si oluşturma örneği için Modeller sayfasındaki Çoklu formatlı giriş bölümüne de bakın.
Kısmi
Kısmi şablonlar, herhangi bir istemin içine dahil edilebilecek yeniden kullanılabilir şablonlardır. Kısmi veriler, özellikle ortak davranışları paylaşan ilgili istemler için yararlı olabilir.
İstem dizini yüklenirken ön ekinde kısa çizgi (_
) bulunan dosyalar kısmi olarak kabul edilir. Bu nedenle, _personality.prompt
dosyası şunları içerebilir:
You should speak like a {{#if style}}{{style}}{{else}}helpful assistant.{{/else}}.
Bu, diğer istemlere eklenebilir:
---
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}}
Kısmiler {{>NAME_OF_PARTIAL args...}}
söz dizimi kullanılarak eklenir. Kısmi bağımsız değişkene bağımsız değişken sağlanmazsa üst istemle aynı bağlamda yürütülür.
Kısmiler, hem yukarıdaki gibi adlandırılmış bağımsız değişkenleri hem de bağlamı temsil eden tek bir konumsal bağımsız değişkeni kabul eder. Bu, bir listenin üyelerini oluşturma gibi görevler için yararlı olabilir.
_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}}
Kodda kısmi tanımlama
definePartial
kullanarak kısmi ifadeleri kodda da tanımlayabilirsiniz:
ai.definePartial(
'personality',
'Talk like a {{#if style}}{{style}}{{else}}helpful assistant{{/if}}.'
);
Kodla tanımlanan kısmi ifadeler tüm istemlerde kullanılabilir.
Özel Yardımcı Programları Tanımlama
İstem içindeki verileri işlemek ve yönetmek için özel yardımcılar tanımlayabilirsiniz.
Yardımcılar, defineHelper
kullanılarak dünya genelinde kaydedilir:
ai.defineHelper('shout', (text: string) => text.toUpperCase());
Tanımladığınız yardımcıları herhangi bir istemde kullanabilirsiniz:
---
model: googleai/gemini-1.5-flash
input:
schema:
name: string
---
HELLO, {{shout name}}!!!
İstem varyantları
İstem dosyaları yalnızca metin olduğundan bunları sürüm denetimi sisteminize gönderebilir (ve göndermeniz gerekir) ve böylece zaman içindeki değişiklikleri kolayca karşılaştırabilirsiniz. İstemlerin değiştirilmiş sürümleri genellikle yalnızca üretim ortamında mevcut sürümlerle birlikte tam olarak test edilebilir. Dotprompt, varyantlar özelliği aracılığıyla bunu destekler.
Varyant oluşturmak için bir [name].[variant].prompt
dosyası oluşturun. Örneğin, isteminizde Gemini 1.5 Flash kullanıyorsanız ancak Gemini 1.5 Pro'nun daha iyi performans gösterip göstermeyeceğini görmek istiyorsanız iki dosya oluşturabilirsiniz:
my_prompt.prompt
: "Referans" istemimy_prompt.gemini15pro.prompt
:gemini15pro
adlı bir varyant
İstem varyantı kullanmak için yükleme sırasında varyant seçeneğini belirtin:
const myPrompt = ai.prompt('my_prompt', { variant: 'gemini15pro' });
Varyantın adı, oluşturma izlemelerinin meta verilerine dahil edilir. Böylece, Genkit izleme denetleyicisinde varyantlar arasındaki gerçek performansı karşılaştırabilirsiniz.
Kodda istemleri tanımlama
Şimdiye kadar ele alınan tüm örneklerde, istemlerinizin tek bir dizinde (veya alt dizinlerinde) ayrı .prompt
dosyalarında tanımlandığı ve uygulamanızın çalışma zamanında bu dosyalara erişebildiği varsayılmıştır. Dotprompt bu kurulum etrafında tasarlanmıştır ve yazarları bu deneyimi genel olarak en iyi geliştirici deneyimi olarak değerlendirmektedir.
Ancak bu kurulum tarafından iyi desteklenmeyen kullanım alanlarınız varsa definePrompt()
işlevini kullanarak istemleri kodda da tanımlayabilirsiniz:
Bu işlevin ilk parametresi, bir .prompt
dosyasının ön kısım bloğuna benzer; ikinci parametre, istem dosyasında olduğu gibi bir Handlebars şablon dizesi veya GenerateRequest
döndüren bir işlev olabilir:
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?` }],
},
],
};
}
);