Funkcje promptu oparte na plikach w Semantic Kernel
W poprzednich artykułach omówiliśmy podstawowe aspekty korzystania z Semantic Kernel
oraz sposób tworzenia i uruchamiania promptów inline. Dziś skupimy się na bardziej zaawansowanym podejściu — funkcjach promptów opartych na plikach. Dzięki temu możesz przenieść swoje prompty do dedykowanych plików i używać ich wielokrotnie, co ułatwia zarządzanie i poprawia czytelność projektu. W tym artykule dowiesz się, jak w praktyce wykorzystać takie podejście i dlaczego warto to zrobić.
Zalety funkcji promptów opartych na plikach
Stosowanie funkcji promptów opartych na plikach niesie ze sobą liczne korzyści:
- Modularność i Przejrzystość: Przechowywanie promptów w osobnych plikach pozwala na oddzielenie logiki od danych, co zwiększa przejrzystość i organizację kodu.
- Łatwość Aktualizacji: Aktualizowanie promptów w jednym centralnym miejscu sprawia, że zmiany są automatycznie stosowane tam, gdzie prompt jest używany, eliminując potrzebę modyfikacji wielu miejsc w kodzie.
- Re-używalność: Pliki z promptami mogą być wykorzystywane w różnych 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, zespół może łatwo współdzielić je w repozytorium, zapewniając jednolite standardy i ułatwiając pracę zespołową.
Elementy Składowe funkcji promptów opartych na plikach
Przechowywanie funkcji promptów w systemie plików opiera się na stworzeniu dwóch kluczowych plików:
- skprompt.txt: To zwykły plik tekstowy, w którym definiujemy treść promptu, czyli to, co model ma zrobić. Możemy w nim zawrzeć zarówno konkretne instrukcje, jak i zmienne.
- config.json: Plik konfiguracyjny, który określa parametry modelu oraz definiuje zmienne używane w promptach, co czyni naszą funkcję bardziej elastyczną.
W pliku skprompt.txt
zapisujemy definicję promptu, która może także zawierać dynamiczne zmienne. Dzięki temu możemy łatwo dostosować działanie do konkretnych potrzeb.
Przykładowo, możemy stworzyć prompt, który instruuje model, aby przetłumaczył tekst z jednego języka na inny:
Translate the following text from {{$source_language}} to {{$target_language}}: "{{$text_to_translate}}"
W powyższym przykładzie użyliśmy zmiennych takich jak {{$source_language}}
, {{$target_language}}
, oraz {{$text_to_translate}}
. Są one dynamiczne i mogą być zastępowane odpowiednimi wartościami podczas wywoływania funkcji, co umożliwia szerokie zastosowanie tego samego promptu w różnych kontekstach, bez konieczności każdorazowej jego edycji.
Plik config.json
odgrywa kluczową rolę w określeniu konfiguracji działania modelu. Zawiera parametry, takie jak maksymalna liczba tokenów czy temperatura, które sterują sposobem generowania odpowiedzi przez model. Ponadto, w tym pliku definiujemy zmienne używane w pliku skprompt.txt
, zapewniając ich zgodność i dynamiczne zastosowanie.
Poniżej znajduje się przykładowy plik config.json
:
{
"schema": 1,
"description": "Translate text.",
"default_services": [
"gpt-4o-mini"
],
"execution_settings": {
"default": {
"max_tokens": 1000,
"temperature": 0.5
}
},
"input_variables": [
{
"name": "$source_language",
"description": "Language from which the text will be translated.",
"required": true
},
{
"name": "$target_language",
"description": "Language into which the text will be translated.",
"required": true
},
{
"name": "$text_to_translate",
"description": "The text that needs to be translated.",
"required": true
}
]
}
W powyższym przykładzie, execution_settings
określa ustawienia działania, takie jak liczba tokenów (max_tokens
) oraz temperatura (temperature
), które wpływają na sposób generowania odpowiedzi — im wyższa temperatura, tym bardziej kreatywne będą wyniki. W sekcji input_variables
definiujemy zmienne, które zostały wcześniej użyte w skprompt.txt
, takie jak $source_language
, $target_language
, oraz $text_to_translate
. Każda z tych zmiennych ma szczegółowy opis, co ułatwia ich użycie i zrozumienie przez innych programistów.
Czas połączyć wszystkie elementy razem i uruchomić nasz prompt. Poniższy kod w języku C# pokazuje, jak wykorzystać funkcje promptów oparte na plikach.
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");
var prompts = kernel.CreatePluginFromPromptDirectory(path);
var result = await kernel.InvokeAsync(prompts["Translate"], 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();
Na początku kodu tworzony jest ConfigurationBuilder
, który odpowiada za zbudowanie konfiguracji aplikacji, w tym uzyskanie klucza API z UserSecrets
. To pozwala na bezpieczne przechowywanie danych uwierzytelniających. Następnie, używając Kernel.CreateBuilder()
, tworzymy instancję kernel
z dodanym wsparciem dla modelu OpenAI, używając klucza API (configuration["apiKey"]!
). Dzięki temu nasz model (gpt-4o-mini
) jest gotowy do generowania odpowiedzi.
Kolejnym krokiem jest załadowanie promptów z systemu plików. Ścieżka do katalogu z plikami promptów jest ustalana za pomocą Path.Combine()
, co umożliwia załadunek ich przy użyciu kernel.CreatePluginFromPromptDirectory(path)
. W ten sposób pliki promptów stają się częścią środowiska Semantic Kernel jako pluginy, które można wywoływać w kodzie. Funkcje promptu są umieszczone w katalogu źródłowym Prompts/Translate
, gdzie Translate
jest nazwą funkcji promptu.
W następnej części kodu wykorzystujemy kernel.InvokeAsync()
, aby uruchomić prompt Translate
. Przekazywane są do niego zmienne, takie jak source_language
(język źródłowy), target_language
(język docelowy) oraz text_to_translate
(tekst do przetłumaczenia). W tym przypadku chcemy przetłumaczyć zdanie z polskiego na angielski. Przekazane zmienne dynamicznie zastępują te użyte w definicji promptu w pliku skprompt.txt
, co umożliwia elastyczne użycie tego samego promptu w różnych kontekstach.
Na koniec wynik tłumaczenia jest wyświetlany na ekranie konsoli za pomocą Console.WriteLine(result)
. Console.ReadLine()
zatrzymuje program, aby użytkownik mógł przeanalizować wynik przed zakończeniem działania aplikacji. Ten kod pokazuje, jak łatwo połączyć konfigurację, prompty i wywoływanie funkcji w sposób modularny, co sprawia, że zarządzanie kodem jest bardziej efektywne i przejrzyste.
Zakończenie
Przechowywanie funkcji promptów w plikach to niezwykle praktyczne podejście, które zwiększa modularność, elastyczność i efektywność pracy z Semantic Kernel
. Dzięki oddzieleniu treści promptów od kodu możemy łatwiej zarządzać projektami, ułatwić współpracę w zespole i zapewnić spójność w różnych aplikacjach. Takie rozwiązanie pozwala na dynamiczne i skalowalne tworzenie interakcji z modelami AI, co jest kluczowe w szybko rozwijającym się środowisku sztucznej inteligencji. Zachęcam do wypróbowania tego podejścia w swoich projektach, by przekonać się o jego zaletach w praktyce.
Do zobaczenia w kolejnych postach!