Objawy
Numer zamówienia w idealnym formacie, którego nie ma w bazie. Kwota, której w dokumencie nie ma. Nazwa pola API, które nigdy nie istniało. Cytat z regulaminu, brzmiący dokładnie jak reszta regulaminu i w nim nieobecny.
Cecha wspólna wszystkich tych przypadków: nic w odpowiedzi tego nie sygnalizuje. Zmyślona wartość nie jest zapisana ostrożniej ani opatrzona zastrzeżeniem. Powstała dokładnie tą samą drogą co prawdziwa.
Najpierw ustal, gdzie to się dzieje
Dwie klasy o zupełnie różnej wadze.
A — halucynacja w argumencie wywołania. Zmyślona wartość trafia do narzędzia i staje się wejściem operacji: zapytania do bazy, przelewu, maila. Groźniejsza, bo nie kończy się na zdaniu.
B — halucynacja w odpowiedzi dla użytkownika. Zostaje tekstem. Groźna inaczej: przy odpowiedziach opartych na dokumentach użytkownik nie ma jak sprawdzić.
Klasa A ma jedno skuteczne rozwiązanie — walidację przed wykonaniem. Klasa B wymaga innego zestawu środków.
Mechanizm w trzech zdaniach
Model zawsze ma rozkład prawdopodobieństwa kolejnego tokenu — także wtedy, gdy w danych nie było żadnej odpowiedzi. Nie istnieje osobny sygnał „nie wiem”, bo jedynym wyjściem jest kolejny token, a zdanie zmyślone i prawdziwe powstają tą samą drogą.
Pełne wyjaśnienie: Halucynacje nie są błędem. Tutaj interesuje nas, dlaczego zdarza się to akurat w tym miejscu twojego systemu.
Diagnostyka różnicowa
1. Danych po prostu nie ma w kontekście
Jak rozpoznać: przejrzyj kontekst tego obrotu tak, jak widzi go model. Czy zmyślona wartość mogła skądkolwiek pochodzić?
Dlaczego to zmyśla: model potrzebuje argumentu, w kontekście go nie ma, więc generuje coś prawdopodobnego. Najczęstsza przyczyna w całym syndromie.
2. Dane są, ale w formie nierozpoznawalnej
Jak rozpoznać: wartość jest w kontekście, ale zagnieżdżona głęboko, pod nieopisanym kluczem albo wśród setek podobnych.
Test: przeczytaj wynik narzędzia bez znajomości swojej bazy. Czy da się wskazać właściwe pole?
3. Pole wymagane bez legalnej drogi wyjścia
Jak rozpoznać: zmyślana wartość zawsze dotyczy tego samego pola, oznaczonego w schemacie jako wymagane.
Dlaczego to zmyśla: schemat mówi, że pole musi być wypełnione. Model nie ma jak powiedzieć „nie wiem”, bo taka odpowiedź jest formalnie niedopuszczalna. Wymusiłeś konfabulację konstrukcją schematu.
To przyczyna rzadko rozpoznawana i najłatwiejsza do naprawienia — o czym w postępowaniu.
4. Wynik narzędzia był pusty
Jak rozpoznać: poprzedni krok zwrócił pustkę, następny zawiera wymyślone dane.
Dlaczego to zmyśla: to ta sama przyczyna, która w pierwszym syndromie prowadziła do zapętlenia. Część modeli zamiast powtarzać próbę, uzupełnia lukę.
5. Model uzupełnia częściową odpowiedź wiedzą z treningu
Jak rozpoznać: odpowiedź jest w większości zgodna ze źródłem, a jeden–dwa szczegóły są nieobecne w dokumencie i przy tym prawdopodobne.
Dlaczego to zmyśla: RAG dostarczył fragment, w którym brakowało szczegółu. Model dopełnia całość, bo tak wygląda kompletna odpowiedź.
6. Sprzeczność w kontekście
Jak rozpoznać: dwa źródła podają różne wartości, a odpowiedź zawiera trzecią.
Dlaczego to zmyśla: model nie ma reguły rozstrzygania konfliktów, więc wypada coś pośredniego.
7. Prompt premiuje pewność
Jak rozpoznać: w instrukcjach są zdania w rodzaju „zawsze podaj numer”, „nie zadawaj pytań”, „odpowiadaj konkretnie”.
Dlaczego to zmyśla: instrukcja przesuwa rozkład w stronę odpowiedzi zdecydowanej, także wtedy, gdy podstaw nie ma. To ten sam mechanizm, który podczas treningu premiował pewność siebie.
8. Oryginał zniknął przy kompaktowaniu
Jak rozpoznać: halucynacja pojawia się dopiero w długich przebiegach, dotyczy szczegółów ustalonych wcześniej.
Dlaczego to zmyśla: podsumowanie historii pominęło szczegół, a model odtwarza go z tego, co zostało.
Postępowanie
Natychmiast, dla klasy A: walidacja istnienia przed wykonaniem. To najskuteczniejsze pojedyncze zabezpieczenie w całym stosie. Numer zaproponowany przez model sprawdzasz w źródle prawdy, zanim cokolwiek zrobisz — a odrzucenie zwracasz modelowi z powodem, bo ciche odrzucenie prowadzi do zapętlenia.
Daj legalną drogę wyjścia. To naprawa przyczyny trzeciej i najbardziej niedoceniana. Pole może przyjmować wartość nieznane. Schemat może dopuszczać odpowiedź „brak danych w kontekście”. Agent może mieć narzędzie do dopytania użytkownika. Model, który może powiedzieć, że nie wie, robi to znacznie częściej, niż się zakłada — problemem zwykle nie jest niechęć, tylko brak dopuszczalnej formy.
Dla klasy B: wymóg wskazania źródła. Odpowiedź ma podać fragment, na którym się opiera, a pętla sprawdza, czy ten fragment naprawdę zawiera to twierdzenie. Tanie i wychwytuje przyczyny piątą i szóstą.
Przejrzyj prompt pod kątem przyczyny siódmej. Usunięcie jednego zdania wymuszającego pewność bywa skuteczniejsze niż dopisanie trzech o ostrożności.
Nie licz na dopytanie modelu. „Jesteś pewny?” nie daje wiarygodnej odpowiedzi, bo deklaracja pewności powstaje tym samym mechanizmem co treść, którą ma ocenić.
Profilaktyka
Żaden identyfikator pochodzący od modelu nie jest zaufany. Numery, adresy, kwoty i klucze zawsze przechodzą przez sprawdzenie istnienia.
Wartości z zamkniętej listy trzymaj w schemacie jako wyliczenie, nie w opisie prozą — wtedy zmyślenie jest niemożliwe konstrukcyjnie.
Przy odpowiedziach opartych na dokumentach mierz wierność wobec kontekstu osobno od poprawności. Odpowiedź prawdziwa, ale nieobecna w źródle, to też awaria.
Jak zdiagnozować u siebie
Dwa narzędzia: walidator istnienia i detektor przez powtórzenia.
import re
from collections import Counter
from openai import OpenAI
client = OpenAI()
BAZA = {"ZAM-4471", "ZAM-1234", "ZAM-9001"}
def waliduj(argumenty):
numer = argumenty.get("numer_zamowienia", "")
if not re.fullmatch(r"ZAM-\d{4}", numer):
return False, f"Numer {numer!r} ma niepoprawny format (oczekiwano ZAM-0000)."
if numer not in BAZA:
return False, (f"Zamówienie {numer} nie istnieje w bazie. "
f"Nie zgaduj — poproś użytkownika o poprawny numer "
f"albo zwróć 'nieznane'.")
return True, None
def stabilnosc(pytanie, n=5):
"""Wielokrotne uruchomienie: rozbieżność = model zgaduje."""
odpowiedzi = []
for _ in range(n):
r = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": pytanie}],
temperature=1.0, max_tokens=60,
)
odpowiedzi.append(r.choices[0].message.content.strip())
licznik = Counter(odpowiedzi)
najczestsza, ile = licznik.most_common(1)[0]
print(f"zgodność {ile}/{n}")
if ile < n:
print(" ! ROZBIEŻNOŚĆ — model prawdopodobnie zgaduje")
for o in licznik:
print(f" - {o[:70]}")
return ile / n
for arg in [{"numer_zamowienia": "ZAM-4471"},
{"numer_zamowienia": "ZAM-7777"},
{"numer_zamowienia": "4471"}]:
ok, powod = waliduj(arg)
print(f"{'OK ' if ok else 'NIE'} {arg}")
if powod:
print(f" → {powod}")
Zwróć uwagę na treść komunikatu odrzucenia: mówi nie tylko, co jest źle, ale też co zrobić zamiast — poprosić użytkownika albo zwrócić wartość „nieznane”. To jest ta legalna droga wyjścia z przyczyny trzeciej, podana w momencie, w którym model jej potrzebuje.
Ćwiczenie: uruchom stabilnosc na pytaniu z pogranicza wiedzy modelu, na przykład o szczegół z twojej dokumentacji, którego nie ma w kontekście. Pięć różnych odpowiedzi oznacza zgadywanie. To najtańszy dostępny detektor i działa bez żadnej infrastruktury.
Drugie ćwiczenie: znajdź w swoim schemacie pole wymagane, którego wartości model nie może znać z kontekstu. Dopuść dla niego wartość nieznane i zmierz, jak często model po nią sięga. Zwykle częściej, niż się spodziewasz — bo wcześniej po prostu nie miał jak.
Powiązane
Mechanizm halucynacji i dlaczego nie da się jej wyłączyć: Anatomia LLM. Gdzie postawić walidację i dlaczego prompt jej nie zastąpi: Maszyneria agenta.
Następny syndrom: Agent gubi wątek w długim zadaniu.





















