Если рассматривать GenAI решения с точки зрения детерминизма результатов (а именно стабильности результатов нам и хочется в большинстве случаев), то
1) В общем случае детерминизм в LLM/LVM не достижим.
2) Всегда стоит рассматривать промпт и языковую модель как одно целое.
Про недетерминизм:
100% точности и воспроизводимости результатов инференса не будет даже при нулевой температуре, фиксированном seed параметре и других рандомных параметрах ввиду особенностей работы GPU вычислений (операции с плавающей точкой и квантизации). Тем не менее, обеспечить точность в три девятки можно. А это уже что-то.
Про систему "промпт + модель":
Prompt Engineering — это алхимия. А LLM — "черный ящик". С этим важно свыкнуться, особенно если вы любите one-shot prompting для принятия сложных логических решений внутри одного запроса. Одно небольшое изменение в промпте или изменение модели (даже простой переход с неквантизованной на квантизованную версию) приводит к тому, что отлаженная функциональность перестаёт работать и нужно начинать всё сначала. А уж если использовать облачные версии типа ChatGPT и Claude, то там вообще под капотом целые подсистемы роутеров и всяких "улучшайзеров ваших промптов", после которых даже сами разработчики этих решений, скорее всего, не угадают, какой будет результат. И они постоянно что-то в этих подсистемах подкручивают.
Какие выводы я сделал к текущему моменту для себя:
🔹 Выбор языковой модели для прода — это как выбор жены. Тестить как можно на большем кол-ве моделей до релиза, а в релиз выбирать и фиксироваться на какой-то конкретной, лучшей. На ней и "жениться" ;) Потом поменять уже сложнее.
🔹 Облачным моделям доверять нельзя, они имеют неприятное свойство меняться, ухудшаться. Кажется, что каждый новый релиз ChatGPT должен быть только лучше, но для конкретных задач может оказаться совсем наоборот. Например, в одном моём решении
gpt-4 (которая уже почти на пенсии) работает в плане генерации кода по инструкции значительно лучше gpt-4o-2024-11-20. Значит ли это, что модели становятся в целом хуже? Нет. Но мне не нужно "в целом", мне нужно решать конкретные задачи. 🔹 Принимать решения или делать обработку нужно как можно больше в коде, и как можно меньше в LLM. Если есть возможность что-то сделать без LLM, нужно делать без LLM, так достигается детерминизм. Если вытаскиваются ключевые сущности: максимально очистите данные до LLM, и всякие операции сортировки, ранжирования, нормализации делайте уже в python, а модели оставьте только работу с неструктурированными данными. У меня есть решение по отслеживанию трендов, там вытаскивают определенные классы тегов, имен компаний и продуктов из текста. Эти сущности извлекаются как получится, а нормализуются по словарю уже в коде, потому что модель это делает плохо.
🔹 Большой и сложный промпт — скорее зло. Простой промпт позволяет мигрировать между моделями без особой деградации качества. А сложный промпт приколочен гвоздями к конкретной модели, для которой писался и тестился. Эффективнее делать мелкие, несложные запросы.
🔹 У меня лучше работает серия простых промптов + объединение результатов в коде, чем один огромный промпт со всеми агрегациями и принятиями финальных решений внутри LLM. Такой большой и сложный промпт невозможно дебажить. Внутри что-то "решилось", а вы гадаете, почему. Папример, как один абзац инструкций повлиял на другой абзац. Меняете что-то вверху, а оно аффектит то, что внизу. Получается этакая игра Wack-A-Mole (из рандомных дырок вылазит крот, а вы ему по голове стучите молотком).
🔹 Structured Output — не панацея. Иногда он делает хуже вывод или дороже решение. Например, я никогда не использую его в задачах генерации кода или там, где нужны "плоские" одноуровневые тексты, или где нужно обрабатывать большой массив данных. В последнем случае это просто экономически не выгодно. При большом числе запросов оцените, насколько увеличивается число токенов в OpenAI либе при structured output и сделайте вывод (можно включить logger.DEBUG и увидеть это в консоли). А ещё json универсальнее Pydantic.
Конец.