Fine tuning или RAG. Что выбрать?
- понедельник, 7 апреля 2025 г. в 00:00:03
Демо проект с RAG поиском можно посмотреть по ссылке
При разработке ИИ чатов существует два способа интеграции внешних данных: RAG хранилища и Fine tuning. Для не технаря отличия не очевидны, я столкнулся с мнением менеджера проекта, что первое это новая версия второго. Это не так. Поэтому, я сделал short summary, чтобы по существу изложить плюсы и минусы двух решений
Языковые модели умеют запускать python/javascript
функции через tool_calls. Делается такая функция, ей на вход падает аргумент search
import { addTool } from "agent-swarm-kit";
addTool({
type: "function",
call: async ({ params }) => {
console.log(params.search) // Строка, может содержать имя телефона, его модель,
// его характеристики. Человеческими словами
},
function: {
name: ToolName.SearchPhoneTool,
description: "Allows finding a phone using contextual search",
parameters: {
type: "object",
properties: {
search: {
type: "string",
description:
"A set of keywords for embedding search. Write the query in Russian",
},
},
required: ["search"],
},
},
});
Далее эта строка search
передается в базу данных. База данных делает следующее
const createEmbedding: async (text: string): number[] => {
//
// В проде лучше использовать OpenAI
// https://platform.openai.com/docs/guides/embeddings/embedding-models
//
const { embedding } = await ollama.embeddings({
model: "nomic-embed-text",
prompt: text,
});
return embedding;
};
const calculateSimilarity = async (a: number[], b: number[]): number => {
const cosineSimilarity = 0.42; // Схожесть двух embedding вычисляется сложной
// математической формулой легко генерируемой
// в Grok...
//
// Люди не нужны, особенно профессора вышмата
return cosineSimilarity;
};
...
const sortedItems = new SortedArray<IStorageItem>();
const searchVector = await createVector(filterData.search);
for (const item of data) {
//
// Если тупо склеить строки это исказит смысл и данные не найдутся.
// Соответственно, для ИИ поиска вычислять вектор нужно на каждую
// колонку базы, по которой будет поиск
//
const modelVector = await createEmbedding(item.model);
const descriptionVector = await createEmbedding(item.description);
const titleVector = await createEmbedding(item.title);
const [
modelSimilarify,
descriptionSimilarify,
titleSimilarify,
] = await Promise.all([
calculateSimilarity(searchVector, modelVector),
calculateSimilarity(searchVector, descriptionVector),
calculateSimilarity(searchVector, titleVector),
]);
const similarity = Math.max(
modelSimilarify,
descriptionSimilarify,
titleSimilarify
);
//
// Фокус: векторный поиск технически не может точно сказать
// то ли он нашел. Поэтому, в выборку поподает отсортированный
// ТОП элементов по убыванию `cosineSimilarity`
//
if (similarity > VECTOR_SEARCH_SIMILARITY) {
sortedItems.push(item, similarity);
}
}
return sortedItems.toArray();
Итого, если в базу запросить телефон (избежав англицизмы) под именем Гугол Пихель, будет успешно найден Google Pixel 8 Pro, так как при поиске используется modelVector
const createEmbedding = (text: string) => {
const words = text.toLowerCase().trim().split(/\s+/);
const vector = new Float32Array(4);
words.forEach((word, index) => {
let sum = 0;
for (let i = 0; i < word.length; i++) {
sum += word.charCodeAt(i) / 1000;
}
vector[index % 4] += sum / (word.length || 1);
});
const magnitude = Math.sqrt(vector.reduce((sum, val) => sum + val * val, 0));
return Array.from(
magnitude ? vector.map((v) => v / magnitude) : vector
);
};
Реализовать такой поиск можно без ИИ вообще, использовав как плоскость координат для вектора номер символа в таблице кодировки. Если вы понимаете этот код, можете претендовать на зарплату 6 тысяч долларов так как вы LLM Engineer
Fine tuning это когда мы пишем сегмент переписки с желательным и не желательным ответом и дообучаем на этом языковую модель. Детальная инструкция как дообучить модель вы можете посмотреть по ссылке
Заполняете переписку инструментом по ссылке выше, загружаете её на сайт OpenAI и готово... К слову (далее уделено отдельное внимание), можно генерировать синтетические данные переписок по базе, и обновлять знания чата фоновым скриптом:
Тезисы, исходя из которых я делаю вердикт
RAG подразумевает tool_call, помимо оплаты генерации embedding.
Это не ИИ вовсе, а обычная реляционная/nosql база данных
Это дороже в эксплуатации так как генерация вектора на каждый поисковой запрос пользователя в RAG базу платная (см генерация embeddings)
Это дороже в поддержке, так как чтобы сменить модель embeddings придется заного генерировать все векторные индексы. Они не универсальные, это вендор лок. 20 колонок поиска - 20 запросов в OpenAI на каждый create/update одной строки
Это дороже в программировании, так как это нужно программировать и администрировать в класическом понимании (DevOps, DBA)
Это медленней на порядок, так как tool_calling подразумевает запуск LLM модели второй раз после получения ответа
Это медленно на долгую перспективу, так как Embedding поиск подразумевает большой трафик памяти (2 миллиона записей будут обрабатываться 30 секунд)
Это плохо применимо к русскому языку (или платите деньги яндексу), так как nomic-embed-text релизнулся 2023-11-01 после одной всем известной ситуации
Fine tuning подразумевает, что думает сам ИИ, а не база данных
Малому и среднему бизнесу дешего взять студента текстовика, который подпишется работать дешего, а может и бесплатно. Дно курсов программирования тут работодателю на руку
Базу данных не нужно мониторить на предмет поломки в сравнении с RAG, так как её нет: нейронка ничего не пишет на жесткий диск вовсе, а вся работает в оперативе видеокарты как stateless.
Обновление дообучение модели можно автоматизировать скриптом
При использовании RAG, вы платите за embeddings пожизненно. При использовании fine tuning, вы платите фиксу
Если вы разрабатываете новый продукт, сфокусируйтесь на fine tuning. Начать можно бесплатно, если запрячь студентов. Как будут собраны структурированные данные в количестве, подразумевающем серьезность намерений, можно автоматизировать процесс актуализации знаний модели через автоматизацию fine tuning
Если вы банк с деньгами и со стеком Java Enterprise, вам ничего не остается, кроме как пытаться в RAG как адаптивную прослойку между ИИ и ванильным программированием
P.S. Если кому-то нужно дублирую реализацию вычисления вектора на основе word2vec без сторонних библиотек чистой функцией