Вот за что мне нравится Хабр — так это за возможность расширить свой кругозор за счёт мнений других коллег. Даже если мы не совпадаем во мнениях, другая точка зрения даёт возможность посмотреть на привычные вещи с непривычного ракурса. Коллега @mahairod в комментариях высказал мысль, что «ИИ катастрофически ненадёжен«, потому что основывается не на семантике текстов, а на статистических вероятностях зафиксированных в Модели при её обучении. Он привёл пример из своей практики, когда Модель делала неправильный перевод со словенского языка известной песни, используя популярный, но неправильный вариант, вместо того, чтобы делать перевод с использованием правил формирования падежных окончаний в словенском языке.
Я отношусь к LLM как к своего рода regex-процессору, использующему при формировании ответов вероятностные связи между словами. Обычный regex-процессор всегда даёт один и тот же результат для одного и того же входного шаблона. LLM же может варьировать результаты для одного запроса в силу своей вероятностной природы. И чем выше «температура» Модели, тем красочнее может быть результат.
Но я уверен, что в нормальных условиях, без завышенной температуры, есть такое подмножество входных запросов (промптов), которые дадут один и тот же результат на разных моделях. Я уже приводил подобный запрос в своей прошлой публикации «Инструмент непрямого управления«:
Замени во фразе «Мама мыла раму» слова «Мама» на «Маша», а «раму» на «Рому». Результат выведи одной строкой без кавычек.
Другими словами, есть очень большой объём текстов, которые будут выдавать один и тот же результат для разных Моделей вне зависимости от обучающей выборки и значений их весов. Разумеется, Модели должны быть одного класса — с сопоставимым количеством параметров нейросети.
Вот ещё пример запроса, который даст один и тот же результат на множестве различных моделей:
Сколько будет два плюс два? Одной цифрой.
Это очень простой запрос, но он демонстрирует саму идею — создать такой входной контекст, который детерминирует результат независимо от используемой модели. Можно создать аналогичный запрос для генерации программного кода, например:
Напиши функцию на JavaScript с именем bubbleSort. Функция должна принимать один параметр — массив целых чисел. Необходимо реализовать алгоритм пузырьковой сортировки. Функция должна возвращать новый отсортированный массив в порядке возрастания. Добавь пример вызова функции и вывод результата в консоль.
Этот промпт вернёт разные результаты при многократном применении даже на одной модели. Но если его переписать в стиле executable specification (спецификация, которая одновременно служит и документацией, и выполняемым артефактом: её можно прогонять как тест, компилировать или использовать для генерации кода), то результат станет более детерминированным.
Вот пример этого же промпта в виде исполняемой спецификации:
Напиши функцию на JavaScript с именем bubbleSort. Требования: 1. Функция принимает массив целых чисел в качестве единственного аргумента. 2. Используется алгоритм пузырьковой сортировки. 3. Функция возвращает новый массив, отсортированный по возрастанию. 4. В коде должны быть комментарии на английском языке, поясняющие каждый шаг алгоритма. 5. Переменные должны иметь осмысленные имена (arr, n, temp и т.п.). 6. Результат должен содержать **только код функции bubbleSort**, без примеров использования и вспомогательного кода. 7. Функция должна быть оформлена как **ES6-модуль**, экспортироваться через `export`. 8. Ответ не должен содержать ничего, кроме JS-кода функции.
И вот примеры выполнения этого запроса в разных моделях:
GPT 5
/** * Bubble sort implementation. * @param {number[]} arr - The input array of integers. * @returns {number[]} - A new sorted array in ascending order. */ export function bubbleSort(arr) { // Create a copy of the original array to avoid mutation const result = [...arr]; const n = result.length; // Outer loop to traverse the entire array for (let i = 0; i < n - 1; i++) { // Inner loop for comparing adjacent elements for (let j = 0; j < n - i - 1; j++) { // If the current element is greater than the next, swap them if (result[j] > result[j + 1]) { const temp = result[j]; result[j] = result[j + 1]; result[j + 1] = temp; } } } // Return the sorted array return result; }
DeepSeek
/** * Sorts an array of integers in ascending order using the bubble sort algorithm. * @param {number[]} arr - The array of integers to be sorted. * @returns {number[]} A new array sorted in ascending order. */ export function bubbleSort(arr) { // Create a copy of the original array to avoid mutating the input const sortedArr = [...arr]; const n = sortedArr.length; // Outer loop: passes through the array for (let i = 0; i < n - 1; i++) { // Inner loop: compares adjacent elements for (let j = 0; j < n - i - 1; j++) { // Swap if the current element is greater than the next if (sortedArr[j] > sortedArr[j + 1]) { const temp = sortedArr[j]; sortedArr[j] = sortedArr[j + 1]; sortedArr[j + 1] = temp; } } } return sortedArr; }
Gemini
export function bubbleSort(arr) { // Create a copy of the original array to avoid modifying it directly const newArr = [...arr]; const n = newArr.length; // A boolean flag to optimize the sorting process let swapped; // Outer loop for sorting passes for (let i = 0; i < n - 1; i++) { swapped = false; // Inner loop for comparing and swapping elements for (let j = 0; j < n - 1 - i; j++) { // Compare adjacent elements if (newArr[j] > newArr[j + 1]) { // Swap them if they are in the wrong order const temp = newArr[j]; newArr[j] = newArr[j + 1]; newArr[j + 1] = temp; // Set the flag to true because a swap occurred swapped = true; } } // If no swaps occurred in the inner loop, the array is already sorted if (!swapped) { break; } } // Return the sorted array return newArr; }
Grok
export function bubbleSort(arr) { // Create a copy of the input array to avoid modifying the original let sortedArr = [...arr]; // Get the length of the array let n = sortedArr.length; // Outer loop for passes for (let i = 0; i < n - 1; i++) { // Inner loop for comparisons and swaps for (let j = 0; j < n - i - 1; j++) { // Compare adjacent elements if (sortedArr[j] > sortedArr[j + 1]) { // Swap elements if they are in wrong order let temp = sortedArr[j]; sortedArr[j] = sortedArr[j + 1]; sortedArr[j + 1] = temp; } } } // Return the sorted array return sortedArr; }
Результат всё ещё различается, но в некоторых важных точках (имя экспортируемой функции, входные и выходные аргументы) он абсолютно детерминирован.
Я уверен, что с учётом размеров входного и выходного контекстов можно создавать такие промпты (спецификации), которые будут давать детерминированный с точки зрения важных для проекта критериев результат на целой линейке однотипных моделей. Все подобные промпты в совокупности задают пространство, где LLM работает как инженерный инструмент: с гарантией повторяемости и воспроизводимости.
Модели, вне зависимости от их происхождения, могут быть предсказуемыми в определённых случаях и могут быть использована в этих случаях в качестве надёжного инструмента для генерации кода.
ссылка на оригинал статьи https://habr.com/ru/articles/938538/
Добавить комментарий