DotPrompt adalah pustaka sederhana yang memungkinkan Anda membuat prompt menggunakan sintaks berbasis konfigurasi, tanpa perlu menyematkannya ke dalam aplikasi Anda. Ini mendukung pembuatan templat untuk perintah melalui bahasa templating Fluid, memungkinkan Anda untuk menggunakan kembali perintah yang sama dan meneruskan nilai yang berbeda pada waktu proses.
File prompt hanyalah file apa pun yang diakhiri dengan ekstensi .prompt
. File sebenarnya itu sendiri adalah file konfigurasi YAML, dan ekstensinya memungkinkan perpustakaan dengan cepat mengidentifikasi file untuk tujuan yang dimaksudkan.
Ada masalah umum dengan file .prompt
yang menyebabkan perilaku tidak biasa pada alat seperti Rider dan IntelliJ. Anda dapat mengatasinya dengan menonaktifkan plugin Terminal atau menggunakan editor lain untuk memodifikasi file.
Isi file prompt berisi beberapa properti identifikasi tingkat atas, diikuti dengan informasi konfigurasi dan terakhir prompt.
File prompt lengkap akan terlihat seperti ini.
nama: Contohmodel: gpt-4oconfig: outputFormat: teks suhu: 0,9 maxToken: 500 masukan:parameter: topik: gaya string?: stringdefault: topik: perintah media sosial: sistem: | Anda adalah asisten peneliti yang sangat membantu yang akan memberikan tanggapan deskriptif untuk topik tertentu dan bagaimana dampaknya terhadap masyarakat pengguna: | Jelaskan dampak {{ topik }} terhadap cara kita berinteraksi dengan teknologi sebagai masyarakat {% if style -%} Bisakah Anda menjawab dengan gaya {{ style }} {% endif -%}fewShots: - pengguna: Apa itu respons Bluetooth: Bluetooth adalah standar teknologi nirkabel jarak pendek yang digunakan untuk bertukar data antara perangkat tetap dan seluler dalam jarak pendek dan membangun jaringan area pribadi. - pengguna: Apa perbedaan pembelajaran mesin dengan pemrograman tradisional? Tanggapan: Pembelajaran mesin memungkinkan algoritme belajar dari data dan berkembang seiring waktu tanpa diprogram secara eksplisit. - pengguna: Bisakah Anda memberikan contoh AI dalam kehidupan sehari-hari? Tanggapan: AI digunakan dalam asisten virtual seperti Siri dan Alexa, yang memahami dan merespons perintah suara.
name
bersifat opsional dalam konfigurasi, jika tidak disediakan maka nama diambil dari nama file dikurangi ekstensinya. Jadi file bernama gen-lookup-code.prompt
akan diberi nama gen-lookup-code
. Ini tidak berperan dalam pembuatan prompt itu sendiri (walaupun pembaruan di masa mendatang mungkin terjadi), namun memungkinkan Anda mengidentifikasi sumber prompt saat masuk, dan memilih prompt dari pengelola prompt.
Jika Anda menggunakan properti ini maka ketika file dimuat, namanya diubah menjadi huruf kecil dan spasi diganti dengan tanda hubung. Jadi nama My cool Prompt
akan menjadi my-cool-prompt
. Hal ini dilakukan untuk memastikan nama mudah diakses dari kode.
Ini adalah item opsional lain dalam konfigurasi, namun memberikan informasi kepada pengguna file perintah model mana (atau penerapan untuk Azure Open AI) yang harus digunakan. Karena ini bisa menjadi nol jika tidak ditentukan, konsumen harus memastikan untuk memeriksanya sebelum penggunaan. Misalnya:
var model = promptFile.Model ?? "default saya";
Namun, menggunakan opsi ini memungkinkan teknisi yang cepat untuk menjelaskan secara eksplisit model mana yang ingin mereka gunakan untuk memberikan hasil terbaik.
Bagian config
memiliki beberapa item tingkat atas yang disediakan untuk digunakan klien dalam panggilan LLM mereka untuk mengatur opsi pada setiap panggilan. Properti outputFormat
mengambil nilai text
atau json
bergantung pada bagaimana LLM dimaksudkan untuk merespons permintaan. Jika menentukan json
maka beberapa LLM memerlukan sistem atau perintah pengguna untuk menyatakan bahwa keluaran yang diharapkan adalah JSON juga. Jika perpustakaan tidak mendeteksi istilah JSON
di prompt maka perpustakaan akan menambahkan pernyataan kecil ke prompt sistem yang meminta respons dalam format JSON.
Bagian input
berisi detail tentang parameter yang diberikan ke prompt. Ini tidak diperlukan dan Anda dapat membuat perintah yang tidak memiliki nilai apa pun yang diteruskan sama sekali. Namun jika Anda melakukannya maka inilah yang Anda butuhkan.
Di bawah input
adalah bagian parameters
yang berisi daftar pasangan kunci-nilai di mana kuncinya adalah nama parameternya, dan nilainya adalah jenisnya. Jika Anda menambahkan tanda tanya pada nama parameter (misalnya style?
) maka parameter tersebut dianggap sebagai parameter opsional dan tidak akan error jika Anda tidak memberikan nilainya.
Jenis yang didukung adalah:
Tipe Parameter | Jenis jaringan titik | Setara dengan C# |
---|---|---|
rangkaian | Sistem.String | rangkaian |
bodoh | Sistem.Boolean | bodoh |
tanggalwaktu | Sistem.DateTimeOffset | Sistem.DateTimeOffset |
nomor | Sistem.Byte Sistem.SByte Sistem.UInt16 Sistem.Int16 Sistem.UInt32 Sistem.Int32 Sistem.UInt64 Sistem.Int64 Sistem.Tunggal Sistem.Ganda Sistem.Desimal | byte sbyte pendek pendek tidak ke dalam ulong panjang mengambang dobel desimal |
obyek | Sistem.Objek | obyek |
4 yang pertama digunakan sebagaimana disediakan. Objek yang diteruskan ke prompt akan dipanggil metode ToString
untuk digunakan dalam prompt.
Tipe datetime
dapat ditampilkan dengan representasi ToString
defaultnya, atau Anda dapat menggunakan filter Fluid untuk menentukan formatnya, mengubah zona waktu, dan banyak lagi.
Jika Anda memberikan nilai untuk parameter yang tidak sesuai dengan tipe yang ditentukan maka kesalahan akan terjadi.
Juga di input
adalah bagian default
. Bagian ini memungkinkan Anda menentukan nilai default untuk parameter mana pun. Jadi jika parameter tidak disediakan dalam aplikasi Anda maka nilai default akan digunakan.
Bagian prompts
berisi templat untuk sistem dan petunjuk pengguna. Meskipun perintah pengguna diperlukan, Anda tidak perlu menentukan perintah sistem.
Baik perintah system
maupun user
merupakan nilai string dan dapat ditentukan dengan cara apa pun yang didukung YAML. Contoh di atas menggunakan string multiline di mana hasil pengangkutan dipertahankan.
YAML memiliki dukungan besar untuk nilai string multiline melalui Block Scalars. Dengan ini ia mendukung string literal dan terlipat . Dengan string literal, karakter baris baru dalam string masukan dipertahankan dan string tetap persis seperti yang tertulis. Dengan dilipat, karakter baris baru akan diciutkan dan diganti dengan karakter spasi, memungkinkan Anda menulis string yang sangat panjang dalam beberapa baris. Menggunakan dilipat, jika Anda menggunakan dua karakter baris baru, maka baris baru ditambahkan ke string.
# Contoh dilipat: > Kapal-kapal yang digantung di langit sama seperti batu bata tidak# Menghasilkan:# Kapal-kapal yang digantung di langit sama seperti batu bata tidak
#contoh literal: | Kapal-kapal yang digantung di langit sama seperti batu bata yang tidak# Menghasilkan:# Kapal-kapal yang digantung# di langit sama seperti batu bata yang tidak
Sintaks petunjuknya menggunakan bahasa templating Fluid, yang didasarkan pada Liquid yang dibuat oleh Shopify. Bahasa templating ini memungkinkan kita untuk menentukan perintah pengguna yang dapat berubah bergantung pada nilai yang diteruskan ke parser templat.
Pada contoh di atas Anda dapat melihat {{ topic }}
yang merupakan pengganti nilai yang diteruskan, dan akan langsung diganti ke dalam templat. Ada juga bagian {% if style -%} ... {% endif -%}
yang memberitahu parser untuk hanya menyertakan bagian ini jika parameter style
memiliki nilai. -%}
di akhir penanda berisi simbol tanda hubung yang memberi tahu parser bahwa ia harus menciutkan baris kosong.
Ada tutorial bagus tentang menulis template dengan Fluid yang tersedia online.
Saat Anda membuat prompt, itu tidak menggantikan templat, hanya memberi Anda keluaran yang dihasilkan. Ini berarti Anda dapat membuat prompt sebanyak yang Anda inginkan dengan nilai input berbeda.
fewShots
adalah bagian yang memungkinkan penulis prompt memberikan teknik prompt beberapa kali untuk solusinya. Saat membuat prompt, Anda akan menyertakan ini, bersama dengan prompt sistem Anda, dan kemudian prompt pengguna, ini memberikan contoh tentang bagaimana LLM harus merespons prompt pengguna. Jika Anda menggunakan OpenAI atau Azure OpenAI maka Anda dapat menggunakan metode ekstensi (lihat nanti) yang akan membuatkan semua pesan untuk Anda.
File prompt dapat diakses secara langsung. Jika Anda hanya memiliki beberapa file atau ingin segera mengujinya maka ini adalah cara yang cukup sederhana untuk melakukannya.
menggunakan DotPrompt;var promptFile = PromptFile.FromFile("path/to/prompt-file.prompt");var systemPrompt = promptFile.GetSystemPrompt(null);var userPrompt = promptFile.GetUserPrompt(Kamus baru<string, objek>{{ " topik", "bluetooth" },{ "gaya", "penjual mobil bekas" }});
Jika file prompt berisi contoh di atas, maka akan menghasilkan yang berikut ini.
System Prompt:
You are a helpful research assistant who will provide descriptive responses for a given topic and how it impacts society
User Prompt:
Explain the impact of bluetooth on how we engage with technology as a society
Can you answer in the style of a used car salesman
Hal ini mungkin mengakibatkan respon dari LLM yang terlihat seperti ini (maaf)
Hadirin sekalian, berkumpullah dan izinkan saya memberi tahu Anda tentang keajaiban teknologi modern yang merevolusi cara kita terhubung dengan gadget—saya sedang berbicara tentang Bluetooth! Bluetooth adalah pahlawan tanpa tanda jasa, saus rahasia yang membuat hidup kita lebih nyaman, lebih terhubung, dan tentunya lebih berteknologi tinggi. Bayangkan ini: komunikasi tanpa batas dan tanpa kabel antar perangkat favorit Anda. Tidak ada lagi kabel yang kusut, tidak ada lagi kekacauan. Ini seperti mendapat tiket VIP ke barisan depan masa depan!
...
Manajer prompt adalah metode pilihan untuk menangani file prompt Anda. Ini memungkinkan Anda memuatnya dari suatu lokasi, mengaksesnya berdasarkan nama, dan kemudian menggunakannya dalam aplikasi Anda.
Default untuk manajer prompt adalah mengakses file di folder prompts
lokal, meskipun Anda dapat menentukan jalur yang berbeda jika Anda mau.
// Muat dari lokasi default direktori `prompts`var promptManager = new PromptManager();var promptFile = promptManager.GetPromptFile("example");// Gunakan foldervar promptManager = new PromptManager("another-location"); var promptFile = promptManager.GetPromptFile("example");// Daftar semua perintah yang dimuatvar promptNames = promptManager.ListPromptFileNames();
Manajer prompt mengimplementasikan antarmuka IPromptManager
, jadi jika Anda ingin menggunakannya melalui wadah DI, atau pola IoC, Anda dapat dengan mudah menyediakan versi tiruan untuk pengujian.
Manajer prompt juga dapat mengambil contoh IPromptStore
yang memungkinkan Anda membangun penyimpanan kustom yang mungkin tidak berbasis file (lihat Membuat penyimpanan prompt kustom). Hal ini juga memungkinkan untuk menyediakan antarmuka tiruan sehingga Anda dapat menulis pengujian unit yang tidak bergantung pada mekanisme penyimpanan.
Menggunakan manajer perintah untuk membaca perintah dan kemudian menggunakannya dalam panggilan ke titik akhir Azure OpenAI.
NB Contoh ini mengasumsikan bahwa ada direktori prompts
dengan file prompt yang tersedia.
menggunakan System.ClientModel;menggunakan Azure.AI.OpenAI;menggunakan DotPrompt;var openAiClient = new(new Uri("https://endpoint"), new ApiKeyCredential("abc123"));var promptManager = new PromptManager();var promptFile = promptManager.GetPromptFile("example");// Metode prompt sistem dan prompt pengguna menggunakan kamus yang berisi nilai yang diperlukan untuk // templat. Jika tidak ada yang diperlukan, Anda cukup memasukkan null.var systemPrompt = promptFile.GetSystemPrompt(null);var userPrompt = promptFile.GetUserPrompt(new Dictionary<string, object>{{ "topic", "bluetooth" },{ "style" , "penjual mobil bekas" }});var client = openAiClient.GetChatClient(promptFile.Model ?? "default-model");var penyelesaian = menunggu client.CompleteChatAsync([SystemChatMessage(systemPrompt) baru,UserChatMessage(userPrompt)] baru,ChatCompletionOptions(ResponseFormat = promptFile.OutputFormat == OutputFormat.Json ? ChatResponseFormat.JsonObject : ChatResponseFormat.Text,Temperature = promptFile.Config.Temperature,MaxTokens = promptFile.Config.MaxTokens));
Atau, menggunakan metode ekstensi yang disediakan OpenAI.
menggunakan System.ClientModel;menggunakan Azure.AI.OpenAI;menggunakan DotPrompt;menggunakan DotPrompt.Extensions.OpenAi;var openAiClient = new(new Uri("https://endpoint"), new ApiKeyCredential("abc123"));var promptManager = new PromptManager();var promptFile = promptManager.GetPromptFile("example");var promptValues = baru Kamus<string, objek>{{ "topik", "bluetooth" },{ "gaya", "penjual mobil bekas" }};var client = openAiClient.GetChatClient(promptFile.Model ?? "default-model");var selesai = menunggu client.CompleteChatAsync(promptFile.ToOpenAiChatMessages(promptValues),promptFile.ToOpenAiChatCompletionOptions());var respon = penyelesaian.Value;Console.WriteLine(response.Content[0].Text);
Dan sekarang, jika kita perlu memodifikasi prompt kita, kita cukup mengubah file prompt dan membiarkan kode kita sendiri (dengan asumsi parameternya tidak berubah).
Gambar di atas menunjukkan bagaimana Anda dapat menggunakan DotPrompt untuk membaca file prompt dari disk. Namun bagaimana jika Anda memiliki situasi di mana Anda ingin perintah Anda berada di tempat yang lebih terpusat, seperti layanan penyimpanan cloud, atau database? Nah, Manajer prompt dapat mengambil contoh IPromptStore
sebagai argumen. Dalam semua contoh di atas, ini menggunakan FilePromptStore
yang disertakan, tetapi Anda juga dapat membuatnya sendiri. Itu hanya perlu mengimplementasikan antarmuka dan selesai.
Sebagai contoh, berikut adalah implementasi sederhana yang menggunakan Penyimpanan Tabel Azure Storage untuk menyimpan detail perintah.
/// <summary>/// Implementasi IPromptStore untuk Tabel Azure Storage/// </summary>kelas publik AzureTablePromptStore : IPromptStore{/// <summary>/// Memuat perintah dari penyimpanan tabel/// < /ringkasan>IEnumerable publik<PromptFile> Load(){var tableClient = GetTableClient();var promptEntities = tableClient.Query<PromptEntity>(e => e.PartitionKey == "DotPromptTest");var promptFiles = promptEntities.Select(pe => pe.ToPromptFile()).ToList();return promptFiles;}/// <ringkasan >/// Mendapatkan klien tabel/// </ringkasan>TableClient statis pribadi GetTableClient(){// Ganti item konfigurasi di sini dengan nilai Anda atau beralih ke menggunakan// Klien otentikasi berbasis Entra = new TableServiceClient(new Uri($"https://{Configuration.StorageAccountName}.table.core.windows.net/"),new TableSharedKeyCredential(Configuration.StorageAccountName, Configuration.StorageAccountKey ));var tableClient = client.GetTableClient("prompts");tableClient.CreateIfNotExists();return tableClient;}}/// <summary>/// Mewakili catatan yang disimpan di tabel penyimpanan /// </summary>public class PromptEntity : ITableEntity{ /// <summary>/// Gets, menyetel kunci partisi untuk record/// </summary>public string PartitionKey { get; mengatur; } = string.Empty;/// <summary>/// Gets, menyetel kunci baris untuk record/// </summary>public string RowKey { get; mengatur; } = string.Empty;/// <summary>/// Mendapatkan, menetapkan stempel waktu entri/// </summary>public DateTimeOffset? Stempel waktu { dapatkan; mengatur; }/// <summary>/// Mendapat, menetapkan catatan nilai ETag/// </summary>public ETag ETag { get; mengatur; }/// <summary>/// Mendapatkan, menyetel model untuk menggunakan /// </summary>string publik? Model { dapatkan; mengatur; }/// <summary>/// Mendapat, mengatur format output/// </summary>public string OutputFormat { get; mengatur; } = string.Empty;/// <summary>/// Mendapat, menetapkan jumlah maksimum token/// </summary>public int MaxTokens { get; mengatur; }/// <summary>/// Gets, menyetel informasi parameter yang disimpan sebagai nilai string JSON /// </summary>public string Parameters { get; mengatur; } = string.Empty;/// <summary>/// Gets, menyetel nilai default yang disimpan sebagai nilai string JSON /// </summary>public string Default { get; mengatur; } = string.Empty;/// <summary>/// Gets, menyetel template prompt sistem/// </summary>public string SystemPrompt { get; mengatur; } = string.Empty;/// <summary>/// Mendapat, menyetel template prompt pengguna/// </summary>public string UserPrompt { get; mengatur; } = string.Empty;/// <summary>/// Mengembalikan rekaman entitas prompt ke dalam instance <see cref="PromptFile"/>/// </summary>/// <returns></returns>public PromptFile ToPromptFile(){var parameter = new Dictionary<string, string>();var defaults = new Dictionary<string, object>();// Jika ada nilai parameter, konversikan ke dalam kamusif (!string.IsNullOrEmpty(Parameters)){var entitasParameters = (JsonObject)JsonNode.Parse(Parameter)!;foreach (var (prop, propType) di entitasParameters){parameters.Add(prop, propType?.AsValue().ToString () ?? string.Empty);}}// Jika ada nilai default, ubahlah menjadi kamusif (!string.IsNullOrEmpty(Default)){var entitasDefaults = (JsonObject)JsonNode.Parse(Default)!;foreach (var (prop, defaultValue) di entitasDefaults){defaults.Add(prop, defaultValue?.AsValue().GetValue <objek>() ?? string.Empty);}}// Hasilkan prompt baru filevar promptFile = new PromptFile{Name = RowKey,Model = Model,Config = new PromptConfig{OutputFormat = Enum.Parse<OutputFormat>(OutputFormat, true),MaxTokens = MaxTokens,Input = new InputSchema{Parameter = parameter,Default = defaults}},Permintaan = Perintah baru{Sistem = SystemPrompt,Pengguna = UserPrompt}};kembalikan promptFile;}}
Dan kemudian untuk menggunakan ini kita akan melakukan hal berikut
var promptManager = PromptManager baru(AzureTablePromptStore());var promptFile = promptManager.GetPromptFile("contoh");
Masih ada ruang untuk pekerjaan yang harus dilakukan di sini dan beberapa hal yang sedang kami pertimbangkan termasuk
Opsi konfigurasi tambahan
Teknik dorongan tambahan
Terbuka terhadap masukan. Apakah ada sesuatu yang ingin Anda lihat? Beri tahu kami