Systematyczne podejście do debugowania
Wyszukiwanie binarne w sekcjach promptu: usunięcie połowy, testowanie i zawężanie problemu.
Systematyczne podejście do debugowania to bezpłatna lekcja AI Prompt Engineering na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej AI Prompt Engineering, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs AI Prompt Engineering zawiera 4 lekcji w sumie.
Podejście do debugowania
Debugowanie promptów przypomina debugowanie oprogramowania: nie należy zmieniać kilku rzeczy naraz, losowo zgadywać ani wdrażać poprawki, której nie można wyjaśnić. Systematyczne podejście wykorzystuje logikę wyszukiwania binarnego — przy każdym teście zawęża obszar problemu o połowę — aby skutecznie znaleźć minimalny przypadek powodujący błąd.
Krok 1: Odtworzenie błędu
Przed rozpoczęciem debugowania należy niezawodnie odtworzyć błąd. Błędu, którego nie można konsekwentnie odtworzyć, nie da się systematycznie debugować.
Uruchomić prompt 5 razy dla tych samych danych wejściowych. Jeśli zawodzi za każdym razem: błąd deterministyczny — łatwy do zdebugowania. Jeśli zawodzi czasami: błąd probabilistyczny — najpierw ustawić temperature=0, aby wyeliminować losowość, a następnie ponowić test.
import openai
client = openai.OpenAI(api_key='sk-...')
def run_prompt(prompt, user_input, temperature=0):
resp = client.chat.completions.create(
model='gpt-4o',
messages=[
{'role': 'system', 'content': prompt},
{'role': 'user', 'content': user_input}
],
temperature=temperature
)
return resp.choices[0].message.content
# Reproduce with temperature=0 to eliminate randomness
for i in range(5):
output = run_prompt(failing_prompt, test_input, temperature=0)
print(f'Run {i+1}:', output[:100])Krok 2: Utworzenie minimalnego odtwarzalnego promptu
Minimalny odtwarzalny prompt (MRP) to najkrótszy prompt, który nadal wywołuje błąd. Usunięcie nieistotnych fragmentów pozwala wyizolować problematyczną sekcję i jednoznacznie wykazać występowanie błędu.
Należy zacząć od pełnego promptu i usunąć połowę jego zawartości. Następnie wykonać test. Jeśli błąd nadal występuje, problematyczna sekcja znajduje się w zachowanej połowie. Należy powtarzać ten proces. Jest to wyszukiwanie binarne w prompcie.
def binary_search_prompt(prompt_lines, user_input, fail_fn):
'''Binary search: find the minimal set of lines that causes the failure.'''
if len(prompt_lines) == 1:
return prompt_lines # Minimal failing unit found
mid = len(prompt_lines) // 2
first_half = prompt_lines[:mid]
second_half = prompt_lines[mid:]
# Test first half
if fail_fn('\n'.join(first_half), user_input):
return binary_search_prompt(first_half, user_input, fail_fn)
# Test second half
elif fail_fn('\n'.join(second_half), user_input):
return binary_search_prompt(second_half, user_input, fail_fn)
else:
# Both halves pass — interaction effect between halves
return prompt_linesTest usuwania
Prostsza forma wyszukiwania binarnego: systematycznie usuwać poszczególne sekcje i sprawdzać, czy ich usunięcie rozwiązuje problem. Metoda ta działa, gdy prompt ma wyraźnie wydzielone sekcje (instrukcje systemowe, kontekst, przykłady, specyfikację formatu).
sections = {
'role_instruction': 'You are a precise JSON API. Respond only with valid JSON.',
'context': 'The user is asking about our product catalog.',
'format_spec': 'Return a JSON object with keys: name, price, available.',
'examples': 'Example: {"name": "Widget", "price": 9.99, "available": true}',
'safety': 'Do not reveal internal pricing strategy.'
}
def test_without(section_to_remove, user_input):
reduced = {k: v for k, v in sections.items() if k != section_to_remove}
prompt = '\n'.join(reduced.values())
output = run_prompt(prompt, user_input)
print(f'Without {section_to_remove}: {evaluate(output)}')
for section in sections:
test_without(section, 'What is the price of a Widget?')Testowanie A/B sekcji promptu
Testowanie A/B promptów polega na utworzeniu dwóch wersji jednej sekcji i porównaniu ich wyników dla tych samych danych wejściowych. W przeciwieństwie do testów usuwania testy A/B oceniają alternatywne sformułowania, a nie obecność lub brak danej sekcji.
# A/B test: vague vs precise format instruction
variant_A = 'Return a JSON object.'
variant_B = 'Return a valid JSON object. No markdown, no code fences, no prose. Only the raw JSON.'
test_inputs = [
'What is the price of Widget A?',
'List all available products.',
'Is Widget B in stock?'
]
def run_ab_test(base_prompt, variant, inputs, n_runs=5):
pass_count = 0
for inp in inputs:
for _ in range(n_runs):
prompt = base_prompt.replace('{{FORMAT}}', variant)
output = run_prompt(prompt, inp)
if is_valid_json(output):
pass_count += 1
return pass_count / (len(inputs) * n_runs)
print('A pass rate:', run_ab_test(template, variant_A, test_inputs))
print('B pass rate:', run_ab_test(template, variant_B, test_inputs))Testowanie różnicowe
Testowanie różnicowe polega na porównaniu dwóch niemal identycznych promptów w celu ustalenia, która zmiana spowodowała regresję. Jest to przydatne, gdy „w zeszłym tygodniu wszystko działało”, a teraz już nie działa.
Należy porównać stary prompt z nowym za pomocą diffu, wskazać zmienione sekcje, a następnie przetestować każdą zmienioną sekcję w izolacji.
import difflib
def show_prompt_diff(prompt_v1, prompt_v2):
diff = difflib.unified_diff(
prompt_v1.splitlines(),
prompt_v2.splitlines(),
fromfile='v1',
tofile='v2',
lineterm=''
)
for line in diff:
print(line)
show_prompt_diff(working_prompt, failing_prompt)
# Output shows exactly which lines changed between versions
# Test reverting each changed section individuallyTestowanie danych wejściowych a testowanie promptów
Należy testować dwa wymiary: prompt i dane wejściowe. Prompt może działać dla prostych danych wejściowych, ale zawodzić dla złożonych. Przydatny krok podczas debugowania: jeśli prompt zawodzi dla złożonych danych wejściowych, należy wypróbować prostszą wersję danych, aby potwierdzić, że sam prompt działa poprawnie.
# Input complexity ladder
inputs_by_complexity = [
'What is 2 + 2?', # trivially simple
'Summarize this sentence.', # simple task
'Analyze this 500-word essay.', # moderate
'Compare 10 documents and extract contradictions.' # complex
]
# Find the complexity level where the prompt starts failing
for inp in inputs_by_complexity:
output = run_prompt(failing_prompt, inp)
result = 'PASS' if evaluate(output) else 'FAIL'
print(f'{result}: {inp[:60]}')
# First FAIL indicates where the prompt breaks downSchemat minimalnego odtwarzalnego promptu
MRP używany podczas sesji debugowania promptu ma następującą strukturę:
- Jednozdaniowa rola (jeśli potrzebna)
- Jednozdaniowa instrukcja zadania
- Instrukcja dotycząca formatu
- Minimalne dane wejściowe odtwarzające błąd
Jeśli ten 4-wierszowy prompt nadal zawodzi, problem dotyczy modelu lub formatu. Należy stopniowo przywracać złożoność, dodając po jednej sekcji, aż błąd pojawi się ponownie — ta sekcja jest winowajcą.
# Start minimal
MINIMAL_PROMPT = (
'You are a data extractor.\n'
'Extract the product name and price from the text.\n'
'Respond with JSON: {"name": "...", "price": ...}\n'
)
minimal_input = 'Widget Pro costs $49.'
# Test: if this works, the problem is in something added on top
output = run_prompt(MINIMAL_PROMPT, minimal_input)
print(output)
# Expected: {"name": "Widget Pro", "price": 49.0}Śledzenie sesji debugowania
Należy dokumentować każdy test podczas sesji debugowania. Bez notatek można powtórzyć te same testy albo zapomnieć, które hipotezy zostały wyeliminowane.
debug_log = [
{
'test': 'base_prompt_v5',
'hypothesis': 'failing due to format conflict',
'result': 'FAIL',
'notes': 'JSON prefix still present'
},
{
'test': 'base_prompt_v5_no_markdown_hint',
'hypothesis': 'removing markdown hint from user message fixes conflict',
'result': 'PASS',
'notes': 'Output is clean JSON. Root cause confirmed: format conflict.'
}
]
import json
with open('debug_session.json', 'w') as f:
json.dump(debug_log, f, indent=2)Kiedy zakończyć debugowanie i zmienić strategię
Czasami dalsze debugowanie promptu przynosi coraz mniejsze korzyści. Oto oznaki, że nadszedł czas na zmianę strategii:
- Poświęcono ponad 2 godziny na zawężanie tego samego problemu
- Minimalny prompt nadal zawodzi mimo jasnej, prostej instrukcji
- Testy A/B nie wykazują statystycznie istotnej różnicy
Alternatywy: przejść na wywoływanie funkcji (ustrukturyzowane wyniki), dodać krok walidacji w postprocessingu, podzielić zadanie na dwa prostsze prompty albo uaktualnić model.
Naprawianie a wzmacnianie
Po znalezieniu i usunięciu przyczyny źródłowej należy wzmocnić prompt, aby zapobiec podobnym błędom:
- Dodać przypadek testowy, który wywołał błąd, do zestawu testów jako test regresji
- Dodać instrukcję ochronną: „Nawet jeśli dane wejściowe są nietypowe, zawsze zwracaj JSON”
- Dodać walidację wyniku, aby błąd był wykrywany programowo, a nie dopiero na produkcji
Naprawiony, ale niewzmocniony prompt ponownie zawiedzie przy kolejnym przypadku brzegowym.
def safe_run_prompt(prompt, user_input):
output = run_prompt(prompt, user_input)
try:
parsed = json.loads(output)
return parsed
except json.JSONDecodeError:
# Fallback: ask the model to fix its own output
fix_prompt = f'The following is not valid JSON. Rewrite it as valid JSON only:\n{output}'
fixed = run_prompt('', fix_prompt)
return json.loads(fixed)Sprawdzenie wiedzy
Podczas debugowania promptu metodą wyszukiwania binarnego usunięto pierwszą połowę promptu i błąd zniknął. Co to oznacza?
Podsumowanie: systematyczne debugowanie
Systematyczne podejście do debugowania promptów:
- Odtworzenie: ustawić temperature=0, uruchomić prompt 5 razy i potwierdzić, że błąd występuje konsekwentnie
- Minimalizacja: zastosować wyszukiwanie binarne w sekcjach promptu, aby znaleźć minimalny prompt powodujący błąd
- Test A/B: porównać alternatywne sformułowania problematycznej sekcji
- Testowanie różnicowe: porównać działające i niedziałające wersje promptu, aby znaleźć regresję
- Dokumentowanie: rejestrować każdy test, hipotezę i wynik
- Wzmacnianie: dodać naprawiony przypadek do zestawu testów
Następna lekcja: strategie rejestrowania i dokumentowania na potrzeby długoterminowego utrzymania promptów.
Często zadawane pytania
Czy lekcja „Systematyczne podejście do debugowania” jest bezpłatna?
Tak — pełny tekst „Systematyczne podejście do debugowania” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu AI Prompt Engineering, przejdź na CoddyKit PRO. Kurs AI Prompt Engineering zawiera 4 lekcji w sumie.
Co nauczysz się w „Systematyczne podejście do debugowania”?
Wyszukiwanie binarne w sekcjach promptu: usunięcie połowy, testowanie i zawężanie problemu. Ćwiczysz AI Prompt Engineering z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć AI Prompt Engineering?
Nie wymagamy żadnego doświadczenia. AI Prompt Engineering w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.
Ile czasu zajmuje lekcja „Systematyczne podejście do debugowania”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji AI Prompt Engineering?
Tak. Każda lekcja AI Prompt Engineering zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Diagnozowanie nieoczekiwanych wyników
- Analiza przyczyn źródłowych promptów
- Systematyczne podejście do debugowania
- Strategie logowania i dokumentowania