{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "8f10ec99",
      "metadata": {
        "id": "8f10ec99"
      },
      "source": [
        "# Лабораторная работа 4\n",
        "# Retrieval-Augmented Generation (RAG) для больших языковых моделей\n",
        "\n",
        "\n",
        "Большие документы (законы, инструкции, статьи, техническая документация)\n",
        "не могут быть полностью переданы языковой модели.\n",
        "\n",
        "RAG позволяет дополнить модель внешними знаниями:\n",
        "сначала найти релевантные фрагменты документа, а затем передать их LLM.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a65e3841",
      "metadata": {
        "id": "a65e3841"
      },
      "source": [
        "# 1. Подготовка модели\n",
        "\n",
        "Используйте инструкционную LLM:\n",
        "\n",
        "Возможные варианты:\n",
        "\n",
        "- Qwen2.5-Instruct;\n",
        "- Saiga;\n",
        "- Gemma;\n",
        "- Mistral-Instruct.\n",
        "\n",
        "Загрузите модель и токенизатор.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "bb7fb55b",
      "metadata": {
        "id": "bb7fb55b"
      },
      "outputs": [],
      "source": [
        "# Импорт необходимых библиотек\n",
        "\n",
        "import torch\n",
        "from transformers import AutoTokenizer, AutoModelForCausalLM\n",
        "\n",
        "# Укажите модель\n",
        "model_name = \"Qwen/Qwen2.5-1.5B-Instruct\"\n",
        "\n",
        "tokenizer = AutoTokenizer.from_pretrained(model_name)\n",
        "\n",
        "model = AutoModelForCausalLM.from_pretrained(\n",
        "    model_name,\n",
        "    device_map=\"auto\",\n",
        "    torch_dtype=torch.float16\n",
        ")\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7ec37bd6",
      "metadata": {
        "id": "7ec37bd6"
      },
      "source": [
        "# 2. Подготовка базы знаний\n",
        "\n",
        "В качестве базы знаний можно использовать:\n",
        "\n",
        "- Гражданский кодекс РФ;\n",
        "- техническую документацию;\n",
        "- набор научных статей;\n",
        "- внутренние инструкции.\n",
        "\n",
        "## Задание 1\n",
        "\n",
        "Загрузите Гражданский кодекс РФ и определите:\n",
        "\n",
        "- размер текста в символах;\n",
        "- количество токенов;\n",
        "- может ли модель обработать документ целиком.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "d5408da6",
      "metadata": {
        "id": "d5408da6"
      },
      "outputs": [],
      "source": [
        "with open('Гражданский кодекс.txt') as f:\n",
        "    codex = f.read()"
      ]
    },
    {
      "cell_type": "code",
      "source": [],
      "metadata": {
        "id": "GnYxEoOvNCaq"
      },
      "id": "GnYxEoOvNCaq",
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "id": "51ebbd87",
      "metadata": {
        "id": "51ebbd87"
      },
      "source": [
        "# 3. Разбиение документа на chunks\n",
        "\n",
        "Для поиска информации необходимо разделить документ на небольшие части.\n",
        "\n",
        "Используйте:\n",
        "\n",
        "`RecursiveCharacterTextSplitter`\n",
        "\n",
        "## Задание 2\n",
        "\n",
        "Исследуйте параметры:\n",
        "\n",
        "- chunk_size;\n",
        "- chunk_overlap.\n",
        "\n",
        "Ответьте:\n",
        "\n",
        "- как слишком маленькие chunks влияют на качество?\n",
        "- почему overlap может улучшить поиск?\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "5eed2bbf",
      "metadata": {
        "id": "5eed2bbf"
      },
      "outputs": [],
      "source": [
        "!pip install langchain-text-splitters\n",
        "from langchain_text_splitters import RecursiveCharacterTextSplitter\n",
        "\n",
        "splitter = RecursiveCharacterTextSplitter(\n",
        "    chunk_size=700,\n",
        "    chunk_overlap=100\n",
        ")\n",
        "\n",
        "documents = splitter.create_documents([codex])\n",
        "\n",
        "print(\"Количество chunks:\", len(documents))\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6a96fca3",
      "metadata": {
        "id": "6a96fca3"
      },
      "source": [
        "# 4. Создание embedding-представлений\n",
        "\n",
        "Каждый фрагмент документа преобразуется в вектор.\n",
        "\n",
        "Используйте embedding-модель:\n",
        "\n",
        "- multilingual-e5;\n",
        "- bge-m3;\n",
        "- другую мультиязычную модель.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "59ca648c",
      "metadata": {
        "id": "59ca648c"
      },
      "outputs": [],
      "source": [
        "!pip install langchain-huggingface sentence-transformers\n",
        "from langchain_huggingface import HuggingFaceEmbeddings\n",
        "\n",
        "embeddings = HuggingFaceEmbeddings(\n",
        "    model_name=\"intfloat/multilingual-e5-large\"\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "source": [],
      "metadata": {
        "id": "UZdqWQQwQwn3"
      },
      "id": "UZdqWQQwQwn3",
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "id": "830fae12",
      "metadata": {
        "id": "830fae12"
      },
      "source": [
        "# 5. Создание векторной базы данных\n",
        "\n",
        "Используйте FAISS.\n",
        "\n",
        "## Задание 3\n",
        "\n",
        "Создайте индекс документов и выполните поиск похожих фрагментов.\n",
        "\n",
        "Проверьте несколько вопросов:\n",
        "\n",
        "- найден ли правильный раздел документа?\n",
        "- сколько chunks достаточно для ответа?\n"
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "!pip install langchain-community faiss-cpu"
      ],
      "metadata": {
        "id": "M6trc_IkSMOu"
      },
      "id": "M6trc_IkSMOu",
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "5e2dbd4c",
      "metadata": {
        "id": "5e2dbd4c"
      },
      "outputs": [],
      "source": [
        "from langchain_community.vectorstores import FAISS\n",
        "\n",
        "db = FAISS.from_documents(\n",
        "    documents,\n",
        "    embeddings\n",
        ")\n",
        "\n",
        "print(\"Векторная база создана\")\n"
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "question = \"Какие права имеет собственник имущества?\""
      ],
      "metadata": {
        "id": "EzOdo1ciU4FL"
      },
      "id": "EzOdo1ciU4FL",
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [],
      "metadata": {
        "id": "Cnob4vLdU8m7"
      },
      "id": "Cnob4vLdU8m7",
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [],
      "metadata": {
        "id": "pmtpy6OEU8x6"
      },
      "id": "pmtpy6OEU8x6",
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "id": "89ffe4e9",
      "metadata": {
        "id": "89ffe4e9"
      },
      "source": [
        "# 6. Реализация RAG-пайплайна\n",
        "\n",
        "Создайте функцию:\n",
        "\n",
        "```python\n",
        "generate_rag_answer(\n",
        "    model,\n",
        "    tokenizer,\n",
        "    database,\n",
        "    question\n",
        ")\n",
        "```\n",
        "\n",
        "Функция должна:\n",
        "\n",
        "1. найти релевантные документы;\n",
        "2. сформировать контекст;\n",
        "3. создать prompt для LLM;\n",
        "4. получить ответ.\n",
        "\n",
        "Шаблон:\n",
        "\n",
        "```\n",
        "Используй только приведенный контекст.\n",
        "\n",
        "Контекст:\n",
        "{documents}\n",
        "\n",
        "Вопрос:\n",
        "{question}\n",
        "\n",
        "Ответ:\n",
        "```\n"
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "Проверьте работу функции на некотором примере"
      ],
      "metadata": {
        "id": "zc3grIsZWEsV"
      },
      "id": "zc3grIsZWEsV"
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "7d53c976",
      "metadata": {
        "id": "7d53c976"
      },
      "outputs": [],
      "source": [
        "def generate_rag_answer(model, tokenizer, database, question):\n",
        "\n",
        "    docs = database.similarity_search(question, k=5)\n",
        "\n",
        "    context = \"\\n\".join(\n",
        "        [d.page_content for d in docs]\n",
        "    )\n",
        "\n",
        "    prompt = f'''\n",
        "    Используй только следующий контекст:\n",
        "\n",
        "    {context}\n",
        "\n",
        "    Вопрос:\n",
        "    {question}\n",
        "\n",
        "    Ответ:\n",
        "    '''\n",
        "\n",
        "    # генерация ответа модели\n",
        "\n",
        "    return prompt\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1ff6b615",
      "metadata": {
        "id": "1ff6b615"
      },
      "source": [
        "# 7. Оценка качества RAG\n",
        "\n",
        "## Задание 4\n",
        "\n",
        "Сравните два варианта:\n",
        "\n",
        "### Вариант 1\n",
        "Обычный запрос к LLM.\n",
        "\n",
        "### Вариант 2\n",
        "Запрос через RAG.\n",
        "\n",
        "Оцените:\n",
        "\n",
        "- правильность ответа;\n",
        "- наличие галлюцинаций;\n",
        "- наличие ссылок на источник;\n",
        "- качество найденного контекста.\n"
      ]
    },
    {
      "cell_type": "code",
      "source": [],
      "metadata": {
        "id": "anZwkiOxNaJ_"
      },
      "id": "anZwkiOxNaJ_",
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "id": "8e50d24a",
      "metadata": {
        "id": "8e50d24a"
      },
      "source": [
        "# 8. Анализ ошибок\n",
        "\n",
        "Для 3 вопросов определите:\n",
        "\n",
        "- ошибка поиска (не найден нужный chunk);\n",
        "- ошибка генерации;\n",
        "- недостаточный контекст;\n",
        "- неправильная интерпретация вопроса.\n",
        "\n",
        "Сделайте вывод:\n",
        "какая часть RAG-системы требует улучшения.\n"
      ]
    },
    {
      "cell_type": "code",
      "source": [],
      "metadata": {
        "id": "kiZbpCMTNdqG"
      },
      "id": "kiZbpCMTNdqG",
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "id": "9cb4af94",
      "metadata": {
        "id": "9cb4af94"
      },
      "source": [
        "# 9. Научный помощник\n",
        "\n",
        "Создайте систему ответов по набору статей.\n"
      ]
    },
    {
      "cell_type": "code",
      "source": [],
      "metadata": {
        "id": "AUfMTocINjUj"
      },
      "id": "AUfMTocINjUj",
      "execution_count": null,
      "outputs": []
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "colab": {
      "provenance": []
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}