Praca z szablonami promptów YAML w Semantic Kernel
W poprzednim poście omówiłem dodawanie promptów za pomocą plików config.json
oraz skprompt.txt
. To podejście pozwala na lepsze zarządzanie promptami, oddzielając ich definicje od kodu aplikacji. Dziś skupiam się na kolejnym rozwiązaniu tj. szablonach promptów opartych na plikach YAML. Szablony te umożliwiają przechowywanie promptów w dedykowanych plikach, co znacząco ułatwia zarządzanie, poprawia czytelność kodu oraz zwiększa modularność projektu. W tym artykule omówię, jak wykorzystać to podejście w praktyce, jakie niesie korzyści i dlaczego warto go używać.
Przed rozpoczęciem pracy upewnij się, że masz zainstalowane wymagane pakiety: Microsoft.SemanticKernel
oraz Microsoft.SemanticKernel.Yaml
. Teraz przejdźmy do przykładu aplikacji konsolowej w .NET, który pokaże, jak używać tych narzędzi w praktyce.
Poniżej przedstawiam przykładowy kod w C#, który demonstruje, jak wczytać prompt z pliku YAML i użyć go do stworzenia funkcji semantycznej w Semantic Kernel
:
using Microsoft.Extensions.Configuration;
using Microsoft.SemanticKernel;
var builder = new ConfigurationBuilder()
.AddUserSecrets<Program>();
var configuration = builder.Build();
var kernel = Kernel.CreateBuilder()
.AddOpenAIChatCompletion("gpt-4o-mini", configuration["apiKey"]!)
.Build();
var path = Path.Combine(Directory.GetCurrentDirectory(), "..","..","..", "Prompts", "Translate.yaml");
var promptYaml = File.ReadAllText(path);
var translateFunc = kernel.CreateFunctionFromPromptYaml(promptYaml);
var result = await kernel.InvokeAsync(translateFunc, new KernelArguments
{
["source_language"] = "polish",
["target_language"] = "english",
["text_to_translate"] = "Pracuj tak ciężko jak to możliwe, to zwiększa szanse na sukces. Jeśli inni ludzie pracują 40 godzin w tygodniu, a ty 100 godzin, to ty w 4 miesiące osiągniesz to, co innym zajmie rok."
});
Console.WriteLine(result);
Console.ReadLine();
Kod ten najpierw konfiguruje dostęp do klucza API, wykorzystując ConfigurationBuilder
do odczytania poufnych danych z konfiguracji aplikacji za pomocą AddUserSecrets<Program>()
.
W kolejnym kroku tworzona jest instancja jądra Semantic Kernel
za pomocą Kernel.CreateBuilder()
. Następnie wywołujemy metodę AddOpenAIChatCompletion()
, aby umożliwić komunikację z modelem OpenAI za pomocą odpowiedniego klucza API.
Kolejnym krokiem jest odczytanie treści promptu z pliku Translate.yaml
za pomocą File.ReadAllText()
. Ten prompt jest następnie używany do stworzenia funkcji tłumaczącej (translateFunc
) za pomocą CreateFunctionFromPromptYaml()
. Następnie tworzymy obiekt KernelArguments
, który zawiera wartości wejściowe, takie jak język źródłowy, język docelowy oraz tekst do przetłumaczenia.
Na koniec, funkcja tłumacząca jest wywoływana za pomocą kernel.InvokeAsync()
, a wynik tłumaczenia jest wyświetlany w konsoli. Dzięki temu podejściu możemy oddzielić logikę promptów od kodu aplikacji, co znacząco poprawia modularność i zarządzanie projektem.
Plik YAML
W powyższym przykładzie korzystamy z pliku Translate.yaml
, który definiuje treść prompt-a oraz parametry tłumaczenia. Oto przykładowa zawartość pliku YAML:
name: Translate
template: |
Translate the following text from {{$source_language}} to {{$target_language}}: "{{$text_to_translate}}"
description: Translate text.
input_variables:
- name: source_language
description: Language from which the text will be translated.
is_required: true
- name: target_language
description: Language into which the text will be translated.
is_required: true
- name: text_to_translate
description: The text that needs to be translated.
is_required: true
output_variable:
description: Translated sentence.
execution_settings:
default:
max_tokens: 1000
temperature: 0.5
Plik YAML zaczyna się od sekcji name
, która określa nazwę funkcji. Następnie znajduje się template
, czyli właściwy szablon promptu, który posłuży do generowania zapytań dla AI. Szablon ten zawiera miejsca na zmienne, takie jak język źródłowy, język docelowy oraz tekst do przetłumaczenia, co pozwala na łatwe dostosowywanie polecenia do konkretnych potrzeb.
description
to krótki opis funkcji, która jest przekazywana do usługi AI i stanowi informację o tym, co funkcja robi. Jest to przydatne szczególnie wtedy, gdy mamy wiele różnych promptów – taki opis ułatwia szybką orientację w ich przeznaczeniu.
W sekcji input_variables
definiujemy zmienne wejściowe, które służą do dostosowania szablonu promptu do konkretnego przypadku użycia. Każda zmienna jest opisana za pomocą trzech parametrów: name
, czyli nazwy zmiennej, description
, zawierającego opis jej roli, oraz is_required
, który określa, czy dana zmienna jest obowiązkowa. Na przykład source_language
to zmienna określająca język, z którego tekst ma być przetłumaczony, natomiast target_language
definiuje język docelowy. Ostatnia zmienna, text_to_translate
, to tekst, który chcemy przetłumaczyć.
output_variable
opisuje wynik generowany przez usługę AI, w tym przypadku przetłumaczony tekst. Dzięki temu mamy jasność, co stanowi wynik działania funkcji, co jest szczególnie przydatne, gdy pracujemy z bardziej złożonymi szablonami i różnymi typami danych wyjściowych.
Na końcu mamy sekcję execution_settings
, która określa szczegóły techniczne działania promptu. max_tokens
definiuje maksymalną długość odpowiedzi, którą może wygenerować model AI, a temperature
wpływa na kreatywność odpowiedzi – wyższa wartość temperatury sprawia, że model generuje bardziej zróżnicowane i mniej przewidywalne odpowiedzi.
Korzyści z Używania Szablonów Promptów YAML
Modularność i Przejrzystość: Opis promptów w osobnych plikach pozwala oddzielić logikę aplikacji od danych, co zwiększa przejrzystość i organizację kodu. YAML pozwala na lepszą organizację i zarządzanie bardziej złożonymi promptami, wprowadzając porządek tam, gdzie kod inline może stać się trudny do utrzymania.
Łatwość Aktualizacji: Zmiany w promptach można wprowadzać centralnie w jednym miejscu. Takie podejście sprawia, że każda aktualizacja automatycznie jest stosowana wszędzie tam, gdzie prompt jest używany, co eliminuje konieczność modyfikacji wielu miejsc w kodzie.
Re-używalność: Pliki YAML mogą być wykorzystywane wielokrotnie w różnych częściach projektu oraz w innych projektach, co zmniejsza powielanie kodu, a tym samym ryzyko błędów i zapewnia większą spójność.
Lepsza Współpraca: Dzięki przechowywaniu promptów w plikach, cały zespół może łatwo współdzielić je w repozytorium, zapewniając jednolite standardy i ułatwiając współpracę. Pliki YAML są proste do edycji, co wspiera współpracę między programistami i innymi członkami zespołu, nawet jeśli nie mają doświadczenia w programowaniu.
Podsumowanie
Przechowywanie promptów w plikach YAML to skuteczny sposób na uporządkowanie i zwiększenie modularności projektów korzystających z Semantic Kernel
. Jeśli jeszcze nie korzystaliście z tego podejścia, warto je wypróbować, aby uprościć zarządzanie promptami i zredukować złożoność kodu.
Do zobaczenia w kolejnych postach.