← НАЗАД К КУРСУ Этап 5 · Урок 1 из 5

Урок 5.1 — RAG: поиск по своим данным

Claude знает много — но не знает содержимое твоих файлов, внутренних документов компании или вчерашнего отчёта. LLM обучена на публичных данных до определённой даты. Всё, что произошло после обучения, или всё, что никогда не было в интернете — для модели не существует. RAG решает эту проблему: он даёт модели доступ к твоим данным в момент запроса.


Проблема: модель не знает твои данные

LLM знает огромный объём информации — но у неё три ограничения:

1. Дата обучения (knowledge cutoff)
   Модель не знает, что произошло после обучения.
   "Какие продажи были в прошлом месяце?" → не знает

2. Приватные данные
   Модель не видела внутреннюю документацию, переписку, базу знаний.
   "Что написано в нашей политике возврата?" → не знает

3. Галлюцинации
   Если модель не знает ответ — она может придумать правдоподобный,
   но неверный ответ, вместо того чтобы сказать "не знаю".

Аналогия. Представь очень умного консультанта, который прочитал все книги в мире — но не видел ни одного документа из твоего офиса. Он может блестяще рассуждать, но на вопрос «Какой у нас график работы в праздники?» ответит неправильно или придумает.


Что такое RAG

RAG (Retrieval-Augmented Generation) — Генерация с дополненным поиском. Термин придумали исследователи из Meta (Facebook) в 2020 году.

Идея простая: перед тем как спросить модель — найди релевантную информацию в своих данных и вложи её в запрос.

Без RAG:
  Вопрос → LLM → Ответ (на основе обучения)
  "Когда платить аренду?" → "Обычно 1-го числа" (угадывает)

С RAG:
  Вопрос → Поиск по документам → Найденный фрагмент + Вопрос → LLM → Ответ
  "Когда платить аренду?" → [находит: "Аренда до 15-го числа"] →
  Claude получает: "Вот документ: {аренда до 15-го}. Вопрос: когда платить?" →
  "Согласно документу, аренда оплачивается до 15-го числа."

Аналогия. RAG — это как подсказка на экзамене, только легальная. Студент (модель) умный, но не может помнить всё. Вместо того чтобы зубрить каждый факт, он получает доступ к конспекту (твои документы) и находит нужную страницу перед ответом.


RAG vs Fine-tuning: две стратегии

Есть два способа дать модели новые знания. Они решают разные задачи:

┌──────────────────────────────────────────────────────────────────┐
│                    RAG vs FINE-TUNING                             │
│                                                                   │
│  RAG (поиск)                    Fine-tuning (дообучение)         │
│  ─────────────                  ──────────────────────           │
│  Данные: в отдельной базе       Данные: "вшиты" в модель         │
│  Обновление: мгновенное         Обновление: нужно переобучать    │
│  Стоимость: дешевле             Стоимость: дорого                │
│  Точность: высокая (есть        Точность: модель может           │
│    источник)                      "запомнить" неточно             │
│  Когда: факты, документы,       Когда: стиль, формат,           │
│    база знаний                    специфическая терминология      │
│                                                                   │
│  Пример: бот отвечает           Пример: модель пишет             │
│    по документации компании       в стиле юридических договоров   │
└──────────────────────────────────────────────────────────────────┘

Для большинства задач RAG — правильный выбор. Fine-tuning нужен редко и стоит дорого.

Источник: Lewis et al. — "Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks" (2020)
https://arxiv.org/abs/2005.11401

Как работает RAG: 5 шагов

         ПОДГОТОВКА (один раз)                    ЗАПРОС (каждый раз)
 ┌────────────────────────────────┐    ┌────────────────────────────────┐
 │                                │    │                                │
 │  1. Загрузить документы        │    │  4. Поиск: найти похожие       │
 │     ↓                          │    │     фрагменты по вопросу       │
 │  2. Разбить на фрагменты       │    │     ↓                          │
 │     (chunking)                 │    │  5. Генерация: отправить       │
 │     ↓                          │    │     фрагменты + вопрос         │
 │  3. Превратить в векторы       │    │     в Claude                   │
 │     (embeddings)               │    │                                │
 │     → сохранить в базу         │    │                                │
 │                                │    │                                │
 └────────────────────────────────┘    └────────────────────────────────┘

Разберём каждый шаг.


Шаг 1: Загрузить документы

Данные для RAG — это любой текст: файлы .txt, .md, .pdf, .docx, страницы сайтов, записи из базы данных. Главное — превратить их в строки Python.

# Простейший вариант — текстовые файлы
def load_documents(folder_path):
    """Загружает все .txt и .md файлы из папки."""
    import os
    documents = []
    for filename in os.listdir(folder_path):
        if filename.endswith(('.txt', '.md')):
            filepath = os.path.join(folder_path, filename)
            with open(filepath, 'r', encoding='utf-8') as f:
                documents.append({
                    'text': f.read(),
                    'source': filename  # запоминаем откуда взяли
                })
    return documents

Шаг 2: Разбить на фрагменты (chunking)

Документ может быть огромным — 100 страниц. Нельзя отправить всё целиком в Claude: не влезет в контекстное окно, будет дорого, а модель будет искать иголку в стоге сена.

Решение — разбить документ на маленькие кусочки (chunks). Каждый кусочек — один факт, один параграф, одна мысль.

Аналогия. Представь учебник на 500 страниц. Если кто-то спросит «Что такое фотосинтез?» — не нужно отправлять все 500 страниц. Достаточно найти один параграф на стр. 47, где это объяснено. Chunking — это индексация учебника по параграфам.

Стратегии chunking

1. По фиксированному размеру (самый простой)
   Каждый чанк — 500 символов. Если мысль попала на границу — разрежет.
   Плюс: просто реализовать
   Минус: может разрезать предложение пополам

2. По предложениям / параграфам
   Чанк = один или несколько параграфов.
   Плюс: не рвёт мысль
   Минус: параграфы бывают разной длины

3. С перекрытием (overlap)
   Каждый чанк на 50-100 символов заходит на территорию соседнего.
   Плюс: если факт попал на границу — он будет в обоих чанках
   Минус: чуть больше данных

Рекомендуемый размер чанка: 200–1000 символов. Слишком маленькие — теряется контекст. Слишком большие — поиск становится неточным.

def split_into_chunks(text, chunk_size=500, overlap=50):
    """
    Разбивает текст на чанки с перекрытием.

    chunk_size: максимальный размер одного чанка (символы)
    overlap: сколько символов перекрывается между соседними чанками
    """
    chunks = []
    start = 0
    while start < len(text):
        end = start + chunk_size

        # Попробуем разрезать по точке или переносу строки
        if end < len(text):
            # Ищем ближайший конец предложения
            last_period = text.rfind('.', start, end)
            last_newline = text.rfind('\n', start, end)
            best_break = max(last_period, last_newline)

            if best_break > start:  # нашли хорошее место для разреза
                end = best_break + 1

        chunks.append(text[start:end].strip())
        start = end - overlap  # перекрытие

    return [c for c in chunks if c]  # убрать пустые

Шаг 3: Превратить в векторы (embeddings)

Это ключевой шаг. Чтобы искать «по смыслу», нужно превратить текст в числа — векторы. Этот процесс называется embedding (встраивание).

Что такое embedding

Embedding — это представление текста в виде списка чисел (вектора). Каждое число отражает какой-то аспект смысла текста.

Текст: "Кошка спит на диване"
Embedding: [0.12, -0.34, 0.56, 0.78, -0.23, ... ]  ← 384-1536 чисел

Эти числа — не случайные. Они расположены так, что похожие по смыслу тексты получают похожие векторы.

"Кот лежит на софе"        → [0.11, -0.33, 0.55, 0.77, -0.22, ...]
"Кошка спит на диване"     → [0.12, -0.34, 0.56, 0.78, -0.23, ...]
"Квантовая физика атома"   → [0.89, 0.45, -0.67, 0.12, 0.91, ...]

Первые два вектора БЛИЗКИ друг к другу (смысл похож).
Третий вектор ДАЛЁК от первых двух (смысл другой).

Аналогия: GPS-координаты для текста

Представь, что каждому тексту присваиваются координаты на карте. Тексты про кошек оказываются в одном районе. Тексты про физику — в другом. Тексты про программирование — в третьем.

Когда приходит вопрос «Где купить корм для кота?» — он тоже получает координаты. И эти координаты оказываются рядом с районом «кошки». Поиск сводится к вопросу: какие точки на карте ближе всего к моему вопросу?

                    "Карта смыслов" (упрощённо)

     Физика                        Кулинария
       •                              •
   •       •                      •       •
       •                              •


        Программирование          Домашние животные
           •                         •  ← "кот лежит на софе"
       •       •                  •  ← "кошка спит на диване"
           •                      •
                                  ★  ← "где купить корм для кота?"
                                       (попадает в тот же район!)

Как получить embedding

Embedding создаёт специальная модель (не Claude — отдельная, маленькая модель). Самые популярные:

Модель Кто сделал Размер вектора Цена
text-embedding-3-small OpenAI 1536 $0.02 / 1M токенов
text-embedding-3-large OpenAI 3072 $0.13 / 1M токенов
Voyage AI Anthropic рекомендует 1024 есть бесплатный tier
Встроенная в ChromaDB ChromaDB (локальная) 384 Бесплатно

Для обучения и простых проектов встроенная модель ChromaDB — идеальный выбор: ничего не стоит, не нужен API-ключ, работает локально.

Источник: Anthropic — рекомендует Voyage AI для embeddings:
https://docs.anthropic.com/en/docs/build-with-claude/embeddings

Шаг 4: Поиск (retrieval)

Когда все чанки превращены в векторы и сохранены — можно искать.

Поиск работает так: 1. Получаем вопрос пользователя 2. Превращаем вопрос в вектор (тем же способом) 3. Ищем чанки, чьи векторы ближе всего к вектору вопроса 4. Возвращаем top-3 или top-5 самых близких

Как измерить «близость» векторов? Математически это косинусное сходство (cosine similarity) — угол между двумя векторами. Если угол маленький — тексты похожи. Если большой — разные.

Не нужно знать формулу — библиотеки делают это автоматически. Главное — понимать принцип: «ближе» в пространстве векторов = «похожее» по смыслу.


Шаг 5: Генерация с контекстом

Найденные фрагменты вставляются в промпт для Claude:

# Формируем промпт с контекстом
prompt = f"""Ответь на вопрос пользователя, используя ТОЛЬКО информацию
из предоставленных документов. Если в документах нет ответа — скажи об этом.

<documents>
{found_chunks}
</documents>

<question>
{user_question}
</question>"""

Ключевое: инструкция «используй ТОЛЬКО информацию из документов» — это то, что предотвращает галлюцинации. Модель не придумывает — она отвечает на основе конкретных фрагментов.


Практика: строим RAG-систему

Что нам нужно

pip install chromadb anthropic python-dotenv
Библиотека Зачем
chromadb Векторная база данных (хранит чанки и их embeddings)
anthropic Claude API для генерации ответов
python-dotenv Загрузка API-ключа из .env

ChromaDB — векторная база, которая работает прямо на компьютере, без серверов. Установил — пользуешься. Она сама превращает текст в векторы (встроенная модель) и умеет искать похожие. Идеально для обучения и небольших проектов.

Источник: ChromaDB — Getting Started
https://docs.trychroma.com/docs/overview/getting-started

Шаг 1: Подготовка данных

Создай папку my-docs/ с несколькими текстовыми файлами — это будет база знаний:

my-rag-project/
    my-docs/
        faq.txt          # Часто задаваемые вопросы
        rules.txt        # Правила компании
        products.txt     # Описание продуктов
    rag.py               # Основной код
    .env                 # API-ключ Claude

Пример файла my-docs/faq.txt:

Часто задаваемые вопросы

Как оформить возврат?
Возврат товара возможен в течение 14 дней с момента покупки.
Для оформления возврата обратитесь в службу поддержки по email: support@example.com
или позвоните по телефону 8-800-123-45-67. Необходимо предоставить чек и товар
в оригинальной упаковке.

Какие способы оплаты доступны?
Мы принимаем банковские карты (Visa, Mastercard, МИР), электронные кошельки
(ЮMoney, QIWI) и наличные при доставке курьером.

Сколько стоит доставка?
Доставка бесплатная при заказе от 3000 рублей. При заказе менее 3000 рублей
стоимость доставки — 300 рублей. Доставка по Москве — 1-2 дня,
по России — 3-7 дней.

Шаг 2: Код RAG-системы

# rag.py — RAG-система: поиск по своим документам + ответ от Claude

import os
from dotenv import load_dotenv
import chromadb
from anthropic import Anthropic

load_dotenv()

# === ШАГ 1: ЗАГРУЗКА ДОКУМЕНТОВ ===

def load_documents(folder_path):
    """Загружает все .txt и .md файлы из папки."""
    documents = []
    for filename in os.listdir(folder_path):
        if filename.endswith(('.txt', '.md')):
            filepath = os.path.join(folder_path, filename)
            with open(filepath, 'r', encoding='utf-8') as f:
                text = f.read()
                documents.append({
                    'text': text,
                    'source': filename
                })
                print(f"  Загружен: {filename} ({len(text)} символов)")
    return documents


# === ШАГ 2: РАЗБИВКА НА ЧАНКИ ===

def split_into_chunks(text, source, chunk_size=500, overlap=50):
    """
    Разбивает текст на фрагменты.
    Каждый фрагмент запоминает, из какого файла он взят.
    """
    chunks = []
    start = 0
    chunk_number = 0

    while start < len(text):
        end = start + chunk_size

        # Ищем хорошее место для разреза (точка или перенос строки)
        if end < len(text):
            last_period = text.rfind('.', start, end)
            last_newline = text.rfind('\n\n', start, end)
            best_break = max(last_period, last_newline)
            if best_break > start:
                end = best_break + 1

        chunk_text = text[start:end].strip()
        if chunk_text:
            chunks.append({
                'text': chunk_text,
                'source': source,
                'chunk_id': f"{source}_chunk_{chunk_number}"
            })
            chunk_number += 1

        start = end - overlap

    return chunks


# === ШАГ 3: СОЗДАНИЕ ВЕКТОРНОЙ БАЗЫ ===

def create_vector_store(chunks):
    """
    Сохраняет чанки в ChromaDB.
    ChromaDB сама превращает текст в векторы (embeddings).
    """
    # Создаём клиент ChromaDB (локальный, в памяти)
    client = chromadb.Client()

    # Создаём коллекцию (аналог таблицы в обычной БД)
    collection = client.create_collection(
        name="my_documents",
        metadata={"hnsw:space": "cosine"}  # искать по косинусному сходству
    )

    # Добавляем все чанки в коллекцию
    collection.add(
        ids=[c['chunk_id'] for c in chunks],           # уникальный ID каждого чанка
        documents=[c['text'] for c in chunks],          # текст (ChromaDB сама сделает embedding)
        metadatas=[{'source': c['source']} for c in chunks]  # откуда взят
    )

    print(f"  Сохранено {len(chunks)} чанков в базу")
    return collection


# === ШАГ 4: ПОИСК ===

def search(collection, query, n_results=3):
    """
    Ищет чанки, похожие на запрос.
    n_results: сколько фрагментов вернуть.
    """
    results = collection.query(
        query_texts=[query],  # ChromaDB сама превратит запрос в вектор
        n_results=n_results
    )

    found = []
    for i in range(len(results['documents'][0])):
        found.append({
            'text': results['documents'][0][i],
            'source': results['metadatas'][0][i]['source'],
            'distance': results['distances'][0][i]  # чем меньше — тем ближе
        })

    return found


# === ШАГ 5: ГЕНЕРАЦИЯ ОТВЕТА ===

def ask(collection, question):
    """
    Полный цикл RAG:
    1. Найти релевантные фрагменты
    2. Отправить их + вопрос в Claude
    3. Вернуть ответ
    """
    # Поиск
    results = search(collection, question)

    # Собираем контекст из найденных фрагментов
    context_parts = []
    for r in results:
        context_parts.append(
            f"[Источник: {r['source']}]\n{r['text']}"
        )
    context = "\n\n---\n\n".join(context_parts)

    # Генерация
    claude = Anthropic()

    response = claude.messages.create(
        model="claude-haiku-4-5-20251001",
        max_tokens=1024,
        system=(
            "Ты — ассистент, который отвечает на вопросы СТРОГО на основе "
            "предоставленных документов. Если в документах нет ответа — "
            "честно скажи: 'В предоставленных документах нет информации об этом.' "
            "Указывай источник (имя файла), откуда взята информация."
        ),
        messages=[{
            "role": "user",
            "content": f"""Вот фрагменты из документов:

<documents>
{context}
</documents>

Вопрос: {question}"""
        }]
    )

    return response.content[0].text


# === ЗАПУСК ===

if __name__ == "__main__":
    print("=== RAG-система ===\n")

    # 1. Загружаем документы
    print("Загрузка документов...")
    docs = load_documents("my-docs")

    # 2. Разбиваем на чанки
    print("\nРазбивка на фрагменты...")
    all_chunks = []
    for doc in docs:
        chunks = split_into_chunks(doc['text'], doc['source'])
        all_chunks.extend(chunks)
    print(f"  Всего фрагментов: {len(all_chunks)}")

    # 3. Создаём векторную базу
    print("\nСоздание векторной базы...")
    collection = create_vector_store(all_chunks)

    # 4. Задаём вопросы
    print("\n" + "="*50)
    print("Готово! Задавай вопросы (введи 'выход' для завершения)")
    print("="*50 + "\n")

    while True:
        question = input("Вопрос: ").strip()
        if question.lower() in ('выход', 'exit', 'quit'):
            break
        if not question:
            continue

        print("\nПоиск и генерация ответа...\n")
        answer = ask(collection, question)
        print(f"Ответ: {answer}\n")

Как запустить

# 1. Убедись, что .env содержит ANTHROPIC_API_KEY
# 2. Создай папку my-docs/ с текстовыми файлами
# 3. Запусти:
python rag.py

Пример работы:

=== RAG-система ===

Загрузка документов...
  Загружен: faq.txt (612 символов)
  Загружен: rules.txt (445 символов)

Разбивка на фрагменты...
  Всего фрагментов: 5

Создание векторной базы...
  Сохранено 5 чанков в базу

==================================================
Готово! Задавай вопросы (введи 'выход' для завершения)
==================================================

Вопрос: Как вернуть товар?

Поиск и генерация ответа...

Ответ: Согласно документу faq.txt, возврат товара возможен в течение
14 дней с момента покупки. Для оформления возврата нужно обратиться
в поддержку по email support@example.com или по телефону 8-800-123-45-67.
Необходимо предоставить чек и товар в оригинальной упаковке.

Разбор кода: что делает каждая часть

ChromaDB — векторная база

client = chromadb.Client()  # создаёт локальную базу (в оперативной памяти)

Client() без параметров — база живёт в памяти и исчезает при завершении. Для постоянного хранения:

# Постоянная база (сохраняется на диск)
client = chromadb.PersistentClient(path="./chroma_db")
collection = client.create_collection(name="my_documents")

Коллекция — как таблица в обычной базе данных (урок 4.2). Но вместо SQL-запросов — поиск по похожести.

collection.add(
    ids=["doc1", "doc2"],           # уникальные ID
    documents=["текст 1", "текст 2"],  # тексты (ChromaDB сама сделает embedding)
    metadatas=[{"source": "file.txt"}, {"source": "file2.txt"}]  # метаданные
)

add() — добавить документы. ChromaDB автоматически: 1. Превращает каждый текст в вектор (embedding) 2. Сохраняет вектор + текст + метаданные

results = collection.query(
    query_texts=["мой вопрос"],  # что ищем
    n_results=3                  # сколько результатов
)

query() — поиск. ChromaDB: 1. Превращает вопрос в вектор 2. Находит 3 ближайших вектора в базе 3. Возвращает их тексты, метаданные и расстояния

Промпт для Claude

system = ("Ты — ассистент, который отвечает СТРОГО на основе "
          "предоставленных документов...")

Ключевое слово — «СТРОГО на основе документов». Без этого Claude может добавить информацию из своих знаний, что нежелательно в RAG.

content = f"""<documents>{context}</documents>
Вопрос: {question}"""

XML-теги <documents> отделяют контекст от вопроса — рекомендация Anthropic из урока 4.5.


Карта векторных баз данных

ChromaDB — не единственная векторная база. Вот обзор популярных:

Что тебе нужно?
│
├── Учёба, эксперименты, простые проекты
│   → ChromaDB (pip install, работает локально, бесплатно)
│
├── Продакшн, много данных (миллионы документов)
│   → Pinecone (облачный сервис, масштабируемый)
│   → Weaviate (self-hosted или облако)
│
├── Максимальная скорость, исследования
│   → FAISS (от Meta, только поиск, без хранения)
│
├── Уже используешь PostgreSQL
│   → pgvector (расширение для PostgreSQL)
│
└── Всё в одном (база + API + интерфейс)
    → Qdrant (Rust, быстрый, open-source)

Для этого курса ChromaDB — правильный выбор. Она покрывает задачи до десятков тысяч документов.


Когда RAG не работает (и что делать)

Проблема 1: Плохое качество поиска

Симптом: Модель отвечает "В документах нет информации", хотя она там есть.
Причина: Чанки слишком большие или слишком маленькие.
Решение: Попробовать размер 300-500 символов с overlap 50.

Проблема 2: Ответ неточный

Симптом: Модель находит фрагмент, но отвечает некорректно.
Причина: Фрагмент обрезан на середине мысли (chunking разрезал).
Решение: Увеличить overlap или использовать разбивку по параграфам.

Проблема 3: Слишком дорого

Симптом: Каждый вопрос стоит дорого.
Причина: Отправляешь слишком много фрагментов в промпт.
Решение: Использовать n_results=3 (не 10), модель haiku, max_tokens=1024.

Проблема 4: Данные устарели

Симптом: Ответы основаны на старых данных.
Причина: Документы обновились, но в базе — старые чанки.
Решение: Пересоздавать базу при обновлении документов
         (удалить коллекцию → загрузить заново).

RAG в реальном мире

┌──────────────────────────────────────────────────────────┐
│              ГДЕ ИСПОЛЬЗУЕТСЯ RAG                         │
│                                                           │
│  Поддержка клиентов                                      │
│    Бот отвечает по документации продукта.                 │
│    Не нужно обучать людей — бот знает всё.               │
│                                                           │
│  Внутренняя база знаний компании                         │
│    Сотрудник спрашивает: "Как оформить отпуск?"          │
│    Бот находит ответ в HR-документах.                    │
│                                                           │
│  Юридический поиск                                       │
│    Юрист загружает 100 договоров → спрашивает:           │
│    "В каких договорах есть штраф за просрочку?"          │
│                                                           │
│  Медицина                                                │
│    Врач загружает справочники → спрашивает               │
│    о взаимодействии препаратов.                          │
│                                                           │
│  Образование                                             │
│    Студент загружает учебник → задаёт вопросы            │
│    по конкретным главам.                                 │
└──────────────────────────────────────────────────────────┘

Практика

Задание 1: Базовый RAG

Создай папку my-docs/ с 2-3 текстовыми файлами на любую тему (правила компании, рецепты, описание продуктов). Запусти rag.py и задай несколько вопросов. Убедись, что ответы основаны на документах, а не на знаниях Claude.

Задание 2: Проверка на галлюцинации

Задай вопрос, ответа на который НЕТ в документах. Например, если в документах — правила магазина, спроси про погоду. Модель должна ответить «В документах нет информации». Если она придумывает ответ — усиль системный промпт.

Задание 3: Постоянная база

Замени chromadb.Client() на chromadb.PersistentClient(path="./chroma_db"). Запусти программу дважды — убедись, что при втором запуске данные уже в базе (не нужно загружать заново). Подсказка: при втором запуске используй get_or_create_collection() вместо create_collection().


Задачки на закрепление

Задача 1: Что делает RAG?

Ответ RAG (Retrieval-Augmented Generation) — это подход, при котором перед запросом к языковой модели происходит поиск релевантных фрагментов в собственных данных. Найденные фрагменты добавляются в промпт, и модель отвечает на основе этих конкретных данных, а не своих общих знаний. Это решает проблему «модель не знает мои данные» и снижает галлюцинации.

Задача 2: Зачем разбивать документ на чанки?

Ответ Документ может быть очень длинным (100+ страниц). Отправлять весь документ в каждый запрос — дорого (много токенов) и неэффективно (модель ищет иголку в стоге сена). Чанки позволяют найти только релевантный фрагмент и отправить именно его. Это и дешевле, и точнее.

Задача 3: Что такое embedding?

Ответ Embedding — представление текста в виде списка чисел (вектора). Специальная модель превращает текст в вектор так, что тексты с похожим смыслом получают близкие векторы. Это позволяет искать «по смыслу», а не по точному совпадению слов: вопрос «как вернуть покупку» найдёт фрагмент, где написано «оформление возврата товара», хотя слова разные.

Задача 4: В чём разница между RAG и fine-tuning?

Ответ RAG — поиск информации в базе данных в момент запроса. Данные хранятся отдельно и обновляются мгновенно. Fine-tuning — дообучение модели на новых данных, которые «вшиваются» в модель. Обновление требует переобучения (дорого и долго). RAG подходит для фактов и документов, fine-tuning — для обучения стилю или формату. Для большинства задач RAG — правильный выбор.

Глоссарий

Термин Что значит
RAG Retrieval-Augmented Generation — генерация ответа с предварительным поиском по своим данным
Embedding Представление текста в виде вектора (списка чисел), где похожие тексты → близкие векторы
Вектор Список чисел, представляющий смысл текста в «пространстве значений»
Chunk (чанк) Фрагмент документа, на которые разбивается текст для индексации
Chunking Процесс разбивки документа на чанки
Overlap (перекрытие) Часть текста, общая между соседними чанками — защита от разрезания мысли
Векторная база данных База, которая хранит векторы и умеет искать по похожести (ChromaDB, Pinecone, FAISS)
ChromaDB Простая векторная база на Python — работает локально, бесплатная
Cosine similarity Метрика похожести двух векторов — чем ближе к 1, тем более похожи тексты
Collection Коллекция в ChromaDB — аналог таблицы в обычной базе данных
Fine-tuning Дообучение модели на своих данных — данные «вшиваются» в модель
Knowledge cutoff Дата, после которой модель не имеет данных (всё, что позже — не знает)
Галлюцинации Когда модель уверенно генерирует неверную информацию
Retrieval Этап поиска релевантных документов перед генерацией ответа

Главное

Проблема:
  LLM не знает твои данные (документы, базы, записи)
  LLM может придумывать ответы (галлюцинации)

Решение — RAG:
  1. Загрузить документы
  2. Разбить на чанки (фрагменты по 300-500 символов)
  3. Превратить в векторы (embeddings) → сохранить в ChromaDB
  4. При вопросе: найти похожие чанки → отправить их + вопрос в Claude
  5. Claude отвечает на основе найденных фрагментов

Ключевые принципы:
  • Embedding = GPS-координаты для текста (похожие тексты → рядом)
  • ChromaDB = простейшая векторная база (pip install, бесплатно)
  • Системный промпт: "отвечай СТРОГО на основе документов"
  • Чанки: 300-500 символов с overlap 50

RAG vs Fine-tuning:
  RAG = подсказка на экзамене (данные в базе, обновляются мгновенно)
  Fine-tuning = зубрёжка (данные в модели, обновляются дорого)

Что дальше?

RAG работает с одним агентом — он ищет и отвечает. Но что если задача требует нескольких агентов? Один ищет, другой анализирует, третий пишет отчёт. В следующем уроке — мульти-агентные системы: как несколько AI-агентов работают вместе над сложными задачами.

← ПРЕДЫДУЩИЙ СЛЕДУЮЩИЙ →