Tworzenie promptów LLM gotowych do użycia w produkcji: siedmiowarstwowa struktura
Naucz się ustrukturyzowanej, inspirowanej API ramy składającej się z siedmiu warstw promptów – instrukcji, kontekstu, ograniczeń i innych elementów – służącej do tworzenia niezawodnych systemów LLM o jakości produkcyjnej.
21 dni zaawansowanej inżynierii promptów
Praktyczny kurs, który prowadzi cię od podstaw tworzenia promptów do projektowania pełnych systemów AI.
Większość ludzi uważa, że prompt to nic więcej niż pytanie skierowane do modelu językowego.
Np.:
Classify this customer support ticket.
I to działa.
Aż nagle przestaje.
Kilka prób może dać dokładnie to, czego oczekujesz. Potem pojawia się nieco inny zapytanie, i nagle model:
- wybiera złą kategorię,
- wymyśla szczegóły, których nie było we wprowadzeniu,
- zwraca format, o którym nie prosiłeś,
- pisze akapit wyjaśnień zamiast ustrukturyzowanych danych,
- lub zachowuje się niespójnie tylko dlatego, że zmieniła się sformułowanie.
To właśnie tutaj zaczyna mieć znaczenie różnica pomiędzy promptem przetestowanym przypadkowo a promptem stworzonym do użycia w produkcji.
W systemie produkcyjnym prompt to nie jest zwykłe pytanie.
Funkcjonuje on jako część umowy pomiędzy twoją aplikacją a modelem.
Rozwijający już wiedzą, jak projektować API z dobrze określonymi granicami:
Request → Validation → Business Logic → Response
Systemy oparte na promptach wymagają tej samej dyscypliny:
Instructions
↓
Context
↓
Constraints
↓
Task
↓
Examples
↓
Output Contract
↓
Validation
Pozostała część tego tekstu omawia każdą z tych warstw osobno, a następnie łączy je w jeden działający przykład.
1. Problem z „Po prostu zapytaj modela”
Wyobraź sobie funkcję opartą na sztucznej inteligencji dla platformy obsługi klienta. Każda przychodząca zgłoszenie musi zostać skierowana do jednej z czterech kategorii:
billing
technical
account
general
Minimalny prompt może wyglądać w ten sposób:
Classify this customer support ticket:
"I was charged twice for my subscription."
A model może odpowiedzieć:
Billing
Na pierwszy rzut oka wygląda to dobrze.
Ale twoja warstwa backendowa zazwyczaj wymaga czegoś więcej niż pojedynczej etykiety. Prawdopodobnie oczekuje czegoś ustrukturyzowanego, na przykład:
{
"category": "billing",
"priority": "high"
}
W tym miejscu sprawy stają się trudniejsze.
Jak właściwie decyduje się o priorytecie?
Rozważmy zgłoszenie, które zawiera tylko:
"Nie mogę się zalogować."
Czy to należy do kategorii account, czy to rzeczywiście problem technical?
Co się stanie, jeśli klient poruszy zarówno kwestię fakturowania, jak i problem z logowaniem w tym samym wiadomości?
A co, jeśli kategoria jest rzeczywiście niejednoznaczna?
Jakie powinno być zachowanie awaryjne w takim przypadku?
Żadna z tych pytań nie może zostać wiarygodnie odpowiedziana przez model, jeśli w pytaniu nie określono od początku zasad.
Dokładnie dlatego tworzenie promptów do użycia w produkcji zaczyna się od określenia specyfikacji, a nie dopracowywania sformułowań.
2. Anatomia promptu klasy produkcyjnej
Solidny prompt przeznaczony do użycia w produkcji można podzielić na siedem odrębnych komponentów.
Te sekcje nie muszą dosłownie pojawiać się jako oznaczone nagłówki w samym tekście promptu.
Ważne jest, aby zrozumieć, jaką funkcję pełni każda warstwa.
Rozpatrzmy je po kolei.
3. Instrukcje systemowe — określenie roli i zachowania
Pierwsza warstwa określa zakres obowiązków modelu.
W przykładzie klasyfikatora ticketów:
You are a customer support classification assistant.
Your job is to classify incoming support tickets
according to the provided category definitions.Return only information supported by the ticket.
Do not invent customer information.
To jest o wiele bardziej przydatne niż coś ogólnego typu:
You are an intelligent AI assistant.
Dlaczego ta różnica ma znaczenie?
Ponieważ określenie modelu jako „inteligentnego asystenta AI” nie precyzuje żadnego konkretnego zachowania.
Bardziej szczegółowa wersja określa:
- jaki zadanie wykonuje model
- w jakiej dziedzinie działa
- jakie informacje może wykorzystywać
- kterze zachowania są zabronione
Instrukcje systemowe można traktować jako umowę behawioralną dla interakcji.
4. Kontekst — Daj modelowi to, czego potrzebuje
Następny poziom dostarcza wszelkich informacji niezbędnych do faktycznego wykonania zadania.
Naprzимер:
Available categories:
billing:
Questions about charges, invoices, refunds, or payments.technical:
Problems with product functionality, errors, or system behavior.account:
Login, password, profile, access, or account-management issues.general:
Questions that don't clearly belong to the above categories.
Następnie następuje rzeczywista treść zgłoszenia:
Customer ticket:
"I was charged twice for my subscription this month."
Różnica ta zasługuje na wyraźne podkreślenie:
Instructions = What to do
Context = Information needed to do it
Jeśli zamienisz kontekst, pozostawiając instrukcje bez zmian, model powinien nadal móc prawidłowo przetworzyć nowy wpis.
Rozdzielenie tych elementów ułatwia również utrzymanie szablonów promptów z biegiem czasu.
5. Ograniczenia — Poinformuj model, gdzie ma się zatrzymać
Ograniczenia to warstwa, w której eliminuje się niejednoznaczność.
Kontynuując przykład:
Rules:
1. Select exactly one category.
2. Use only the four categories provided.
3. Do not create new categories.
4. Do not infer facts that are not present.
5. If the issue is unclear, use "general".
6. Priority must be one of: low, medium, high.
7. Return only the requested JSON.
Te zasady znacznie zmniejszają zakres możliwych odpowiedzi.
Bez nich prompt taki jak:
Classify the ticket.
mógłby wygenerować coś w rodzaju:
This appears to be a billing-related issue because
the customer mentions being charged twice.
To jest zupełnie rozsądna odpowiedź dla ludzkiego czytelnika.
Jednak twoja API prawdopodobnie oczekuje czystego JSON, a nie prozy.
Dodaj ograniczenie wprost:
Return only the requested JSON.
i oczekiwane zachowanie staje się jednoznaczne.
6. Zadanie — Określ dokładną operację
Gdy już ustalono instrukcje i ograniczenia, należy dokładnie opisać operację, której oczekuje się wykonania.
Task:
1. Identify the most appropriate category.
2. Determine the priority based on the rules.
3. Provide a short reason.
4. Return the result using the specified JSON structure.
Porównaj to z przekazaniem niejasnej instrukcji w stylu:
Understand this customer issue.
Gdy zadanie jest sformułowane tak precyzyjnie, można później sprawdzić, czy model rzeczywiście wykonał to, o co proszono.
Zobacz proces przypominający ten schemat:
Input
↓
Classify
↓
Determine priority
↓
Generate reason
↓
Return JSON
Wtedy zadanie przestaje być domysłem i staje się czymś mierzalnym i testowalnym.
7. Przykłady — Pokaż zachowanie, którego oczekujesz
Instrukcje mówią modelowi słowami, co ma zrobić.
Przykłady pokazują to bezpośrednio.
Weź ten przykład:
Example 1
Example 1Input:
"I was charged twice for the same subscription."Output:
{
"category": "billing",
"priority": "medium",
"reason": "The customer reports a duplicate subscription charge."
}
Drugi przykład może ilustrować zupełnie inny scenariusz, na przykład raport o błędzie technicznym:
Example 2Input:
"The application crashes every time I upload an image."Output:
{
"category": "technical",
"priority": "high",
"reason": "The customer reports a repeatable application failure."
}
Przykłady są najskuteczniejsze wtedy, gdy zachowanie, którego szukamy, trudno jest określić wyłącznie na podstawie reguł, ponieważ umożliwiają modelowi przywiązanie się do konkretnego wzorca.
Mimo to istnieje pewna wada, o której należy pamiętać.
Kumulowanie przykładu po przykładzie ma rzeczywiste konsekwencje negatywne. Powoduje to wzrost:
- rozmiaru promptu
- zużycia tokenów
- opóźnienia
- potencjalnych sprzeczności
Mądrzejszą strategią jest ręczne wybranie niewielkiej, dobrze przemyślanej grupy przykładów.
Należy priorytetowo wybierać przykłady reprezentujące znacząco różne sytuacje, szczególnie te niejednoznaczne i typu edge case.
Np. taka trójka:
Clear billing issue
Clear technical issue
Ambiguous issue
zazwyczaj przewyższy dziesięć niemal identycznych przykładów fakturowania ułożonych jedno na drugim.
8. Format wyjściowy — traktuj go jak umowę API
Niewiele rzeczy jest tak ważnych w promptach o poziomie produkcyjnym jak właśnie ta warstwa.
Jeśli jakiś inny system ma analizować to, co zwraca model, nie można pozostawić struktury tej odpowiedzi przypadkowi w postaci swobodnego tekstu.
Lepiej jasno określić schemat.
Naprzимер:
{
"category": "billing | technical | account | general",
"priority": "low | medium | high",
"reason": "string"
}
Gdy to zostanie wdrożone, model ma określony cel do osiągnięcia, a kod poniżej może polegać na takim przepływie jak:
LLM
↓
JSON
↓
Parser
↓
Schema validation
↓
Business logic
Zamiast czegoś znacznie bardziej chaotycznego, na przykład:
LLM
↓
Some paragraph
↓
Regex
↓
Hope it works
Ta druga konfiguracja to koszmar pod względem utrzymania jej przez dłuższy czas.
Dobrze sprecyzowany, strukturyzowany wynik tworzy wyraźną granicę pomiędzy tym, co wytwarza LLM, a tym, czego faktycznie potrzebuje aplikacja.
9. Walidacja — Model nie jest twoim walidatorem
Oto błąd, który ciągle pojawia się w systemach opartych na sztucznej inteligencji.
Załóżmy, że model zwraca:
{
"category": "billing",
"priority": "urgent",
"reason": "The customer has a billing issue."
}
Syntaktycznie ten JSON jest w porządku.
Problem kryje się tutaj:
"urgent"
"urgent" nigdy nie było jedną z dozwolonych wartości.
Zadaniem twojej aplikacji jest wykrycie takiej niezgodności, a nie modelu.
Oto jak to wygląda przy użyciu Pydantic:
from pydantic import BaseModel
from typing import Literal
class TicketClassification(BaseModel):
category: Literal[
"billing",
"technical",
"account",
"general"
]
priority: Literal[
"low",
"medium",
"high"
]
reason: str
Następnie wywołasz:
result = TicketClassification.model_validate(llm_response)
A jeśli model zwróci coś w rodzaju:
{
"category": "billing",
"priority": "urgent",
"reason": "Duplicate charge."
}
krok walidacji powinien go bezwzględnie odrzucić.
To właśnie ma na celu takie odrzucenie.
Nigdy nie pozwól, by wynik modelu przeszedł bez sprawdzenia.
To prowadzi do zasady, którą warto przyjąć przy projektowaniu systemów opartych na LLM:
LLM generuje. Twoja aplikacja waliduje.
Model może pomóc w podejmowaniu decyzji, ale wszelkie wymagania, które są naprawdę niekwestionowalne, powinny znajdować się w kodzie aplikacji deterministycznej, która je bezpośrednio egzekwuje.
10. Kompletny prompt nastawiony na produkcję
Gdy połączymy wszystkie warstwy, otrzymamy coś w tym rodzaju:
SYSTEM
You are a customer support classification assistant.
Your job is to classify incoming support tickets
according to the provided category definitions.
Return only information supported by the ticket.
Do not invent customer information.
CONTEXT
Available categories:
billing:
Charges, invoices, refunds, or payment-related issues.
technical:
Product functionality, errors, crashes, or system behavior.
account:
Login, password, profile, access, or account-management issues.
general:
Issues that do not clearly belong to another category.
Customer ticket:
{{ticket_text}}
CONSTRAINTS
1. Select exactly one category.
2. Use only the categories provided above.
3. Do not create new categories.
4. Do not infer unsupported facts.
5. If the issue is unclear, use "general".
6. Priority must be "low", "medium", or "high".
7. Return only the requested JSON.
TASK
1. Classify the ticket.
2. Determine the priority.
3. Provide a short reason.
4. Return the result in the required JSON format.
EXAMPLE
Input:
"I was charged twice for the same subscription."
Output:
{
"category": "billing",
"priority": "medium",
"reason": "The customer reports a duplicate subscription charge."
}
OUTPUT FORMAT
{
"category": "billing | technical | account | general",
"priority": "low | medium | high",
"reason": "string"
}
Następnie umieść to obok miejsca, gdzie rozpoczęło się całe to ćwiczenie:
Classify this customer support ticket.
Różnica pomiędzy tymi dwoma promptami nie dotyczy tak naprawdę liczby słów.
To, co się zmieniło, to stopień wyraźności wszystkich elementów.
Każdy blok dłuższej wersji pełni określoną funkcję:
- Część dotycząca systemu określa, jak model powinien działać
- Część dotycząca kontekstu dostarcza informacje, z którymi ma do czynienia
- Część dotycząca ograniczeń precyzyjnie określa zasady, których nie może złamać
- Część dotycząca zadania określa dokładnie to, co musi zrealizować
11. Projektowanie promptów jest podobne do projektowania API
Dla inżynierów oprogramowania to porównanie sprawia, że tworzenie promptów w środowisku produkcyjnym staje się niemal natychmiastowe.
Pomyśl o typowym punkcie końcowym REST.
Moglibyśmy opisać coś takiego:
POST /tickets/classify
Ciało żądania:
{
"ticket": "I was charged twice."
}
A ciało odpowiedzi:
{
"category": "billing",
"priority": "medium",
"reason": "Duplicate charge reported."
}
Teraz przenieś to samo podejście na prompt do LLM.
Prompt jest w istocie logiką implementacyjną znajdującą się za tym punktem końcowym.
API
↓
Input
↓
Prompt Template
↓
LLM
↓
Structured Output
↓
Validation
↓
API Response
Dlatego też inżynieria promptów coraz bardziej przypomina dyscyplinę inżynierii oprogramowania, a nie ćwiczenie z umiejętności pisania tekstów.
Nie szukasz idealnego sformułowania.
Budujesz niezawodną interfejs na bazie systemu, który zachowuje się probabilistycznie.
12. Powszechne błędy w promptach produkcyjnych
1. Niejasność
Analyze the ticket carefully.
Czym jest tutaj „staranność”?
Określ dokładnie pożądane zachowanie zamiast pozostawiać to interpretacji.
2. Prośba o rzeczy, których nie potrzebujesz
Napisz, że twoja aplikacja konsumuje tylko:
{
"category": "billing"
}
Nie prosz więc o:
category
reason
summary
sentiment
customer mood
recommended response
next action
chyba że twoja aplikacja rzeczywiście wykorzystuje te pola dalej w procesie.
Każde dodatkowe pole, o które prosisz, to kolejne miejsce, gdzie wynik może ulec zmianie lub stać się niespójny.
3. Umieszczanie logiki biznesowej wyłącznie w promptzie
Przykład tego błędu:
If the customer has been waiting more than 48 hours,
has contacted support three times, and is a premium customer,
set priority to high...
Takie zasady powinny zazwyczaj znajdować się w deterministycznym kodzie aplikacji, a nie w promptach.
Czystszy podział wygląda tak:
LLM → classify issue
Application → calculate priority
Rozdzielanie elementów w ten sposób sprawia, że cały system staje się znacznie łatwiejszy do testowania.
4. Modyfikacja promptów bez oceny
Załóżmy, że wersja 1 działa dobrze w środowisku produkcyjnym.
Następnie ktoś dokonuje modyfikacji:
Classify the ticket.
na:
Analyze and intelligently classify the ticket.
Wygląda to jak błahe przepisanie słów.
Jednak zachowanie w środowisku produkcyjnym może ulec znacznym zmianom.
Dlatego właśnie prompty wymagają kontroli wersji i oceny, tej samej dyscypliny, którą stosuje się w kodzie aplikacji.
5. Zakładanie, że model zawsze będzie postępował zgodnie z instrukcjami
Pamiętaj, że modele językowe są z natury probabilistyczne.
Nawet starannie sformułowany prompt może nadal zwrócić coś, o czym nie prosiłeś.
Dlatego prawdziwy system produkcyjny wymaga czegoś więcej niż dobrego promptu — potrzebuje:
Prompt
+
Structured output
+
Validation
+
Monitoring
+
Fallback handling
Opieranie się wyłącznie na sformułowaniu promptu nie jest bezpieczną strategią.
13. Tworzenie promptów w środowisku produkcyjnym wymaga oceny
Główna różnica pomiędzy przypadkowymi eksperymentami z modelami językowymi a wdrożeniem rzeczywistej funkcji AI sprowadza się do oceny.
Załóżmy, że masz 1000 historycznych zgłoszeń obsługi klienta.
Moglibyś stworzyć na ich podstawie zbiór testowy, ustrukturyzowany w ten sposób:
200 billing
200 technical
200 account
200 general
100 ambiguous
100 edge cases
Następnie przetestuj różne wersje promptów na tym samym zbiorze i porównaj wyniki.
Naprzимер:
Prompt V1 Prompt V2
----------------------------------------
Category accuracy 88% 93%
Schema failures 4% 1%
Invalid values 3% 0.5%
Average latency 1.8s 2.1s
Token usage 650 820
W tym momencie praca nad promptami przestaje być subiektywna.
Nie zadajesz już pytania:
">Czy ten prompt wydaje się lepszy?"
Zamiast tego pytasz:
">Czy ta wersja osiąga lepsze wyniki w przypadkach, które są naprawdę ważne dla naszej aplikacji?"
To o wiele bardziej praktyczne pytanie do postawienia.
14. Kompromis: Więcej instrukcji vs większa złożoność
Nie istnieje żadne stałe prawo mówiące:
">Dłuższy prompt zawsze daje lepsze wyniki."
Prompty mogą zdecydowanie stać się nadmiernie skomplikowane.
Cos takiego jak:
30 rules
+
20 examples
+
multiple exceptions
+
long explanations
+
repeated instructions
może przerodzić się w obciążenie zamiast być pomocą.
Korzystnym nawykiem jest ciągłe zadawanie sobie pytania:
Czy ta instrukcja rzeczywiście dotyczy prawdziwego problemu, który zaobserwowałem?
Jeśli odpowiedź brzmi nie, ta instrukcja prawdopodobnie nie powinna tam być.
Najlepszy prompt do użycia w produkcji to nie ten z największą ilością treści.
To właśnie on dostarcza właściwego kontekstu, odpowiednich ograniczeń oraz oczekiwanego zachowania, przy jednoczesnym unikaniu jak najmniejszego zbędnego obciążenia.
15. Praktyczny model mentalny
Gdy zaczynasz tworzyć prompt, pomocne jest rozważenie siedmiu kluczowych pytań.
1. Kto jest modelem w tym procesie?
Instrukcje systemowe
2. Co model musi wiedzieć?
Kontekst
3. Czego absolutnie nie może robić?
Ograniczenia
4. Co dokładnie musi osiągnąć?
Zadanie
5. Czy mogę pokazać oczekiwane zachowanie?
Przykłady
6. Jak powinna wyglądać odpowiedź?
Format wyjścia
7. Skąd moja aplikacja będzie wiedziała, że odpowiedź jest przyjęta?
W połączeniu te siedem pytań tworzy spójną strukturę.
To model mentalny jest o wiele cenniejszy niż zapamiętywanie jakiegokolwiek pojedynczego szablonu promptu.
16. Inżynieria promptów zmierza w kierunku projektowania systemów
To może być najważniejsza idea z całej tej dyskusji.
Na początku praca z LLM zwykle sprowadza się do pytania typu:
How can I phrase this question better?
Gdy systemy stają się bardziej złożone, to pytanie zmienia się w coś zupełnie innego:
What does the model need to know?
What should it be allowed to do?
What should it return?
How do I validate it?
What happens when it fails?
How do I evaluate changes?
To już nie są pytania dotyczące sformułowania – to pytania z zakresu inżynierii oprogramowania.
I właśnie dlatego inżynieria promptów na poziomie produkcyjnym ma mniej wspólnego z odkrywaniem „magicznych” zdań, a znacznie więcej z projektowaniem niezawodnej interakcji pomiędzy twoją aplikacją a modelem, który zachowuje się probabilistycznie.
Główne wnioski
Kilka podstawowych idei warto zapamiętać po całej tej dyskusji:
1. Gotowy do użycia prompt to coś więcej niż pojedyncze pytanie.
Określa on zachowanie modelu, dostarcza kontekstu, ustala granice, formułuje zadanie, podaje przykłady i określa, jak powinien wyglądać wynik.
2. Trzymaj instrukcje oddzielnie od danych.
Model powinien móc od razu zrozumieć, co ma zrobić, a jakie informacje ma wykorzystać do pracy.
3. Jasne ograniczenia zmniejszają konieczność domysłów.
Nie pozostawiaj modelowi decyzji o tym, co robić w przypadku braku danych, ich niejednoznaczności lub błędnej struktury.
4. Przykłady służą do ilustracji zachowania modelu.
Wykorzystuj je celowo, szczególnie w trudnych przypadkach granicznych.
5. Strukturyzowany wynik powinien być traktowany jak umowa API.
Za każdym razem, gdy usługa poniżej w łańcuchu przetwarzania odczytuje odpowiedź modelu, dokładnie opisz, jaka forma ta odpowiedź musi mieć.
6. Nie pozwól, by prompt pełnił jednocześnie rolę jedynego mechanizmu weryfikacji bezpieczeństwa.
Prawdziwa weryfikacja powinna odbywać się w twojej aplikacji, poprzez sprawdzanie schematów i deterministyczne reguły biznesowe.
7. Traktuj prompts jako kod, który wymaga oceny.
Versjonuj je, testuj w reprezentatywnych przypadkach i śledź ich wydajność.
8. Dłuższy prompt nie jest automatycznie lepszy.
Każdy dodany wiersz powinien uzasadniać swoje istnienie.
Wniosek
Budowa promptów o poziomie produkcyjnym nie polega na zmuszaniu modeli językowych do brzmienia bardziej inteligentnie.
Chodzi o to, by wymiana informacji była bardziej przewidywalna, bardziej przejrzysta i łatwiejsza do integracji z rzeczywistym systemem.
Zmiana ta zazwyczaj wygląda w ten sposób:
Simple question
↓
Structured instructions
↓
Clear context
↓
Explicit constraints
↓
Defined task
↓
Useful examples
↓
Structured output
↓
Application validation
↓
Evaluation + monitoring
Gdy ta koncepcja stanie się jasna, projektowanie promptów przestaje być procesem prób i błędów w tworzeniu tekstu i zaczyna przypominać projektowanie umowy API dla komponentu, który zachowuje się probabilistycznie.
Ta zmiana ma ogromne znaczenie, gdy przechodzimy od demonstracji do budowy systemów przeznaczonych do działania w środowisku produkcyjnym.
Literatura pokrewna
- Budowanie agenta AI od zera: wzorce, ReAct i LangGraph — Poznaj podstawowe koncepcje agentów AI – planowanie, używanie narzędzi, refleksja oraz wzorzec ReAct – oraz to, jak LangChain i LangGraph wpisują się w ręczne budowanie takiego agenta.