javascript

Fine tuning или RAG. Что выбрать?

  • понедельник, 7 апреля 2025 г. в 00:00:03
https://habr.com/ru/articles/898026/

Демо проект с RAG поиском можно посмотреть по ссылке

При разработке ИИ чатов существует два способа интеграции внешних данных: RAG хранилища и Fine tuning. Для не технаря отличия не очевидны, я столкнулся с мнением менеджера проекта, что первое это новая версия второго. Это не так. Поэтому, я сделал short summary, чтобы по существу изложить плюсы и минусы двух решений

Что такое RAG?

Языковые модели умеют запускать 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?

Fine tuning это когда мы пишем сегмент переписки с желательным и не желательным ответом и дообучаем на этом языковую модель. Детальная инструкция как дообучить модель вы можете посмотреть по ссылке

https://agent-tune.github.io/

Заполняете переписку инструментом по ссылке выше, загружаете её на сайт 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 без сторонних библиотек чистой функцией