Jak tworzyć skuteczne prompt dla LLM i optymalizować ich działanie

Model LLM, jak wspominałem w LLM na co dzień: Co każdy programista powinien wiedzieć, służy do przetwarzania naturalnego języka, co za tym idzie komunikacja może odbywać się w takim sam sposób co z drugim człowiekiem. Aczkolwiek należy pamiętać, że taki typ komunikacji nie zawsze będzie efektywny.

Czym jest prompt engineering?

Właśnie tutaj wkracza prompt engineering, czyli podejście zakładające, że każdy komunikat (prompt) odpowiada konkretnemu celowi. Odpowiednia konstrukcja promptu znacząco wpływa na jakość odpowiedzi generowanej przez model.

Jaki jest najlepszy język LLM?

Logicznym i trafnym jest założenie, że komunikaty powinny być tworzone w języku angielskim. Mimo, że większość topowych modeli wspiera popularne języki, to jednak są one zoptymalizowane pod kątem języka angielskiego.

Poniższy wykres przedstawia skuteczność modelu GPT-4 w kontekście do wykorzystania różnych języków.

źródło: https://cdn.openai.com/papers/gpt-4.pdf

Jak widać na wykresie, skuteczność modelu w języku angielskim jest wyższa niż w innych językach, w tym polskim, o 3.4%.

Dlaczego to ważne?

Różnica ta może znacząco wpłynąć na działanie aplikacji produkcyjnych. Dlatego w takich przypadkach zaleca się używanie języka angielskiego. Natomiast język polski może być z powodzeniem wykorzystywany w mniej krytycznych zastosowaniach, np. do zadań lokalnych czy eksperymentalnych.

Context Window – znaczenie liczby tokenów

Każdy model może przetworzyć ograniczoną liczbę tokenów w jednym zapytaniu. Tokeny obejmują zarówno dane wejściowe (prompt), jak i odpowiedź generowaną przez model. To kluczowa kwestia podczas projektowania efektywnych promptów.

W przypadku zapytań zawierających dokumenty do tłumaczenia lub analizy, musimy upewnić się, że mieszczą się one w ramach „okna kontekstowego”. Dlatego ważnym elementem tworzenia aplikacji opartych na AI jest monitorowanie liczby tokenów. Do tego celu można wykorzystać narzędzia takie jak Tiktokenizer lub bibliotekę Tokenizer od Microsoftu.

Format danych a liczba tokenów

Warto też wiedzieć, że format pliku przesyłany do modelu ma wpływ na liczbę tokenów. Na przykład prosty JSON zawierający informacje o produkcie wygląda następująco:

{
  "product": {
    "id": 101,
    "name": "Smartfon X200",
    "price": 1299.99,
    "availability": "in stock"
  },
  "specifications": {
    "screenSize": "6.5 inches",
    "processor": "Octa-core 2.8GHz",
    "ram": "8GB",
    "battery": "4500mAh"
  },
  "reviews": [
    {
      "rating": 4.5,
      "comment": "Great performance."
    }
  ]
}

Analiza tego pliku przy użyciu Tiktokenizer dla modelu GPT-4 pokazuje następującą liczbę tokenów:

Dla porównania, ten sam plik zapisany w formacie YAML wygląda tak:

Ten przykład doskonale prezentuje jak ważny jest format danych, nie tylko wejściowych ale także wyjściowych. Tylko poprzez zmianę formatu, możemy zaoszczędzić 34 tokeny. Wydaje się to niewiele, ale w produkcyjnej aplikacji, może to być znacząca różnica.

Jak widać, zapis w formacie YAML pozwala zaoszczędzić 34 tokeny w porównaniu z JSON-em. Wynika to z mniejszej liczby znaków wymaganych do reprezentacji danych w YAML-u.

Nawet z pozoru niewielkie oszczędności w liczbie tokenów mogą mieć znaczenie w produkcyjnych aplikacjach, szczególnie w przypadku dużych zapytań lub intensywnego korzystania z modeli AI. Optymalizacja tokenów może przełożyć się na obniżenie kosztów i zwiększenie wydajności.

Jak optymalizować prompt?

Tworząc efektywny prompt musimy zadać sobie trud i wziąć pod uwagę kilka dobrych praktyk.

  1. Ograniczenie kontekstu → Polega na nadaniu modelowi roli, opisie problemu oraz wymagań, tak aby nakierować go na dany sposób myślenia. Przykład: Prezentowany przykład pokazuje w jaki sposób systemowy prompt nakierowuje model na oczekiwaną odpowiedź.
  2. Jasne określenie celu → musimy określić czego oczekujemy od modelu. Może to być bardziej ogólny rezultat lub nawet określenie formatu odpowiedzi. Na przykład “Zwróć listę w formacie JSON, zgodnie z poniższymi zasadami, strukturą i przykładami.”
  3. Określenie zasad → zależnie od rozwiązywanego problemu bardzo często potrzebujemy narzucić odpowiednie zasady na model. Ze względu na czytelność przeważnie będą one w formacie listy, a w nich powinny znaleźć się wymagania co do odpowiedzi i sposobu zachowania się modelu. Do tego powinny zawierać informacje o zachowaniu w tak zwanym happy path lub w sytuacjach brzegowych.
  4. Dostarczenie informacji → w niektórych sytuacjach chcemy przekazać modelowi dodatkowe informacje, na przykład wyniki wyszukiwania lub treść na której ma się opierać podczas wykonywania zadania. W takim przypadku trzeba jasno zaznaczyć daną sekcje w której znajdują się informacje oraz dodać zasadę np. “Odpowiadając bierz pod uwagę treść z sekcji <section_data>.” Dzięki temu model precyzyjnie wie, które dane są istotne dla zadania, co minimalizuje ryzyko błędnej interpretacji.
  5. Przykłady → LLM bardzo dobrze rozpoznają wzorce. Co za tym idzie warto do promptu dodać przykłady oczekiwanej odpowiedzi, uwzględniając warunki brzegowe jak i niepożądane scenariusze.
  6. Przemyślenie → Świetnym podejściem jest pozwolenie modelu na “myślenie” przed udzieleniem odpowiedzi. Ważne, żeby pozwolić mu najpierw pomyśleć a następnie udzielić odpowiedzi. Takie podejście, znane jako chain-of-thought, może znacząco poprawić jakość generowanych wyników.

Jako przykład podam swój prompt ze szkolenia AI Devs, gdzie zadaniem było przyjęcie instrukcji w formacie JSON, przetworzenie jej odpowiednio tak aby poruszyć się po mapie, a następnie zwrócenie informacji co dane pole przedstawia.

Cały przykład możesz zobaczyć tutaj: DroneApi

Jak widzisz prompt ten zawiera każdą z wyżej wymienionych praktyk. Stosuję sekcje podobne do składni XML, żeby oddzielić poszczególne informacje. Nie jest to koniecznie, ale uważam, że jest to bardzo czytelne podejście.

Monitorowanie promptów

Niedeterministyczna natura dużych modeli językowych, sprawa że nie mamy pewności co do otrzymanego rezultatu. Możemy jednak zwiększać prawdopodobieństwo ich otrzymania na przykład poprzez wspomniane wcześniej dobre praktyki.

Dużą bolączką jest jeszcze fakt, że nie mamy żadnych narzędzi w stylu debuggera. Jedyne co nam zostaje to monitoring modelu poprzez prosty system logów lub bardziej zaawansowane narzędzie jak LangFuse.

LangFuse

Jest narzędziem służącym do monitoringu, analizy i optymalizacji interakcji w aplikacjach opartych o sztuczną inteligencję. Pozwala on na:

  • śledzenie pytań zadawanych przez użytkowników,
  • analizę odpowiedzi generowanych przez model,
  • kontrolę liczby przetwarzanych tokenów i związanych z nimi kosztów.

Polecam stworzenie darmowego LangFuse i przetestowanie dostępnych funkcjonalności. Na przykład mamy tam historię rozmowy danego użytkownika i modelu. Ilość przetworzonych tokenów oraz ich koszt.

Zastosowanie

Żeby podkreślić jak istotne jest monitorowanie promptów i ich odpowiedzi. Stworzyłem taki przykład:

Widać, że prompt poprawnie spełnia swoje zadanie. Natomiast jeżeli jako treść użytkownika zostanie podana wiadomość, która brzmi jak instrukcja dla modelu dostaniemy sprzeczny z założeniem rezultat.

Z tego możemy wywnioskować, że model podąża za instrukcjami użytkownika. Żeby rozwiązać ten problem, musimy doprecyzować prompt systemowy.

Podsumowanie

Przy pracy z dużymi modelami językowymi (LLM), kluczowym aspektem jest umiejętność tworzenia efektywnych promptów. Jest to szczególnie istotne, gdy modele te są integrowane z aplikacjami i systemami programistycznymi. W takich przypadkach prompty rzadko będą tworzone ręcznie od podstaw — znacznie częściej będą one generowane dynamicznie, na podstawie kontekstowych danych, reguł biznesowych i potrzeb użytkowników.

Scroll to Top