Программирование с ИИ
ENRU
4.8

Галлюцинации

выдуманные библиотеки, методы и параметры

Что это

Галлюцинация — когда ИИ уверенно описывает то, чего не существует: библиотеку, метод, параметр, поле в ответе API. Выглядит это как обычный код, читается как обычный код и падает при запуске.

Явление не случайное, а предсказуемое: оно возникает там, где примеров было мало, — редкие библиотеки, свежие версии, узкие API (статья 1.3).

Как выглядит в коде

async with aiohttp.ClientSession() as session:
    data = await session.fetch_json(url)      # такого метода нет

Правдоподобно: у requests есть .json(), у многих клиентов есть fetch. Сочетание выглядит естественно — и не существует.

Три вида, по убыванию заметности:

ВидКак проявляется
Выдуманный пакетImportError при запуске — если повезёт; если имя уже кто-то занял, ошибки не будет вовсе
Выдуманный методAttributeError при вызове — заметно при запуске этой ветки
Выдуманный параметрв Python обычно TypeError; молчит там, где параметры не проверяются

Первый и третий опаснее, чем выглядят.

Пакет. Имена, которые ИИ выдумывает, повторяются от ответа к ответу, и их заранее регистрируют в PyPI и npm — с чужим кодом внутри. Тогда pip install проходит, импорт работает, а пакет делает то, что в него положили. «Пакет существует» ещё не значит «это тот пакет».

Параметр. Сама функция Python на незнакомый аргумент ругается сразу:

await session.get(url, timeout_ms=5000)
измерено
TypeError: ClientSession._request() got an unexpected keyword argument 'timeout_ms'. Did you mean 'timeout'?

Молча он проходит там, где параметры никто не проверяет: в объекте настроек JavaScript ({ timeoutMs: 5000 }), в **kwargs, которые передаются дальше без разбора, в YAML и JSON конфигах. Ошибки нет, действует значение по умолчанию, поведение не то, что задумано.

Как проверять

Пакет:

pip index versions aiohttp

Если пакета нет, команда так и скажет. Заодно покажет доступные версии.

Это только половина проверки. Вторая — тот ли это пакет: открой его страницу на pypi.org или npmjs.com и посмотри, сколько ему лет, сколько у него загрузок и есть ли ссылка на исходники. Пакет, созданный на прошлой неделе, с именем, которое предложил ИИ, — повод остановиться.

Метод или поле:

python3 -c "import aiohttp; print([m for m in dir(aiohttp.ClientSession) if 'fetch' in m])"
измерено
[]

Пустой список — метода нет.

Параметр функции:

python3 -c "import inspect, aiohttp; print(inspect.signature(aiohttp.ClientSession.get))"
измерено
(self, url: Union[str, yarl.URL], *, allow_redirects: bool = True, **kwargs: Any) -> '_RequestContextManager'

Сигнатура показывает, какие аргументы принимаются. Но если в ней есть **kwargs, как здесь, она ничего не докажет: аргументы уходят дальше, и ответ даст только документация или вызов с этим параметром.

Все три проверки — одна строка в терминале, и они надёжнее любых рассуждений.

Как сказать ИИ

Предупредить дешевле, чем исправлять:

Запрос
Используй только методы, в существовании которых уверен.
Если не уверен — пометь строку комментарием # проверить
и скажи, что именно проверить в документации.

Такая формулировка работает: прямо разрешив сомневаться, получаешь честные пометки вместо уверенной выдумки.

После получения кода:

Запрос
Перечисли все внешние методы и параметры, которые ты
использовал в этом коде, с указанием библиотеки и версии.
Списком, без кода.

Короткий список удобно проверить за минуту — быстрее, чем перечитывать код.

Когда уже упало:

Запрос
AttributeError: 'ClientSession' object has no attribute
'fetch_json'. У меня aiohttp 3.9.5. Какой метод там есть
для этой задачи на самом деле?

На что смотреть

Слишком удобный метод. Если библиотека предлагает ровно ту функцию, которая нужна тебе, одним вызовом, — проверь. Реальные библиотеки редко настолько точно совпадают с задачей.

Нестандартное имя. fetch_json, get_all, auto_retry — имена, которые звучат как то, что должно быть. Это и есть признак: ИИ собрал имя из частей, встречавшихся у похожих библиотек.

Параметры, которых нет в документации. Самый незаметный вид. Если параметр важен — проверь сигнатурой.

Код не запускался. Запуск ловит выдуманные методы и почти все выдуманные параметры. Пакет, имя которого кто-то успел занять, запуск не поймает. Запуск — минимальная защита, но он обязателен.

Новый пакет в зависимостях. ИИ добавил библиотеку, о которой ты не просил, — проверь её до установки, а не после.

Выдумка в ответе API, а не в коде. ИИ может предположить, какие поля придёт в JSON, и ошибиться. Печатай реальный ответ, а не доверяй описанию (статья 4.5).

Шпаргалка

  • Галлюцинации живут там, где примеров мало: редкое, свежее, узкое.

  • Три вида: пакет · метод · параметр. Пакет и параметр опаснее, чем кажутся.

  • Проверка пакета: pip index versions — и страница пакета: возраст, загрузки, исходники.

  • Проверка метода: dir(). Проверка параметра: inspect.signature().

  • Не спрашивай ИИ, существует ли то, что он написал, — проверяй сам.

  • Слишком удобный метод с «говорящим» именем — первый кандидат на проверку.