Генерация с дополнением из поиска
Вы когда-нибудь сталкивались с такой ситуацией:
У вас есть руководство по продукту на сотни страниц, и пользователь задаёт очень конкретный вопрос. Вы долго ищете, но не можете найти, где находится ответ.
-
В вашей компании накопились внутренние документы, протоколы совещаний и технические спецификации за несколько лет. Новые сотрудники, которые хотят понять конкретное бизнес-правило, понятия не имеют, с чего вообще начать поиск.
-
У вас есть груда электронных книг, исследовательских отчётов и статей, и вы хотите, чтобы ИИ отвечал на вопросы на основе этого содержимого, но если вы вставите всю книгу прямо в ИИ, контекстное окно не вместит её.
Именно эту проблему и призван решить RAG.
RAG (Retrieval-Augmented Generation) — это технология, которая позволяет большим языковым моделям отвечать на вопросы на основе конкретных баз знаний.。
Основная идея RAG проста: сначала извлечь наиболее релевантный контент из вашей базы знаний, затем отправить этот контент вместе с вопросом пользователя в LLM и позволить LLM ответить на основе этого контекста.
Без RAG LLM знает только то, что есть в обучающих данных; с RAG LLM может использовать ваши приватные, актуальные данные.
Зачем нужен RAG?
RAG — не единственное решение этих проблем, но на данный момент это один из самых практичных и недорогих вариантов.
Проблема отсечения знаний LLM.
-
Все LLM имеют дату отсечения знаний — обучающие данные доходят только до определённого момента времени, и они не знают о событиях после него.
-
Например, дата отсечения знаний GPT-4 — октябрь 2023. Если спросить его о новостях 2024 года, он может только сказать «Не знаю».
-
Что ещё важнее, ваши приватные данные (внутренние документы, руководства по продуктам, политики компании) никогда не появлялись в обучающих данных LLM — как она могла бы о них узнать?
Приватные данные нельзя напрямую вводить в LLM.
Вы можете подумать: разве нельзя просто вставить документы напрямую в LLM?
Ответ таков: короткие документы работают, а длинные — нет.
-
Во-первых, контекстное окно LLM ограничено. Например, у GPT-3.5 всего 16K tokens, примерно 10,000 символов. Руководство на несколько сотен страниц просто не поместится.
-
Во-вторых, даже если контекстное окно достаточно велико, запихивание всего документа целиком работает плохо. LLM склонны теряться в длинном тексте и не могут найти действительно относящуюся к делу информацию.
-
И наконец, есть стоимость. GPT-4 с контекстом 128K стоит $10 за миллион входных токенов. Если вы каждый раз впихиваете целую книгу, ваш кошелёк заплачет.
RAG против дообучения: как выбрать
Ещё один способ дать LLM новые данные — дообучение, то есть продолжение обучения модели на новых данных.
Но дообучение и RAG принципиально различны и имеют совершенно разные сценарии использования:
| Пункт сравнения | RAG | Дообучение |
|---|---|---|
| Актуальность данных | Можно обновлять в любое время, сразу готово к использованию | Требует повторного обучения, длительный цикл |
| Подходящий объём данных | Очень большой (миллионы документов) | Средний (от тысяч до десятков тысяч примеров) |
| Источник цитирования | Может показать, из какого документа взят ответ | Невозможно отследить источник |
| Проблема галлюцинаций | Снижает галлюцинации за счёт предоставления контекста | Всё ещё может галлюцинировать |
| Изменение знаний | Просто удалить или обновить документы | Требует переобучения, сложно «забыть» |
| Технический барьер | Относительно низкий, можно использовать существующие фреймворки | Относительно высокий, требуются GPU и опыт обучения |
| Стоимость | В основном векторная база данных и Embedding | Высокая стоимость обучения, а также высокая стоимость инференса |
Простое практическое правило: если вы хотите, чтобы LLM «знала» определённые фактические знания (например, описания продуктов, политики компании), используйте RAG; если вы хотите, чтобы LLM «освоила» определённый стиль или возможность (например, стиль письма, соглашения о написании кода), используйте fine-tuning.
Обзор архитектуры RAG
RAG делится на две фазы: фаза офлайн-индексации и фаза онлайн-поиска.
Сначала давайте посмотрим на полную схему архитектуры:
Этап офлайн-индексации (подготовка данных)
Эта фаза выполняется в фоновом режиме, и пользователи не видят её напрямую.
Её задача — обработать ваши документы в формат, который можно быстро извлечь.
Шаги следующие:
-
1. Загрузка документов: чтение документов в различных форматах, таких как PDF, TXT, DOCX, и веб-страниц.
-
2. Разбиение документов: разбить длинные документы на более мелкие текстовые фрагменты, обычно от нескольких сотен до тысячи слов.
-
3. Векторизация: используйте модель Embedding, чтобы преобразовать каждый текстовый фрагмент в вектор (последовательность чисел).
-
4. Хранение: сохраните векторы и исходный текст вместе в векторной базе данных.
Этот этап нужно выполнить только один раз или запустить повторно при обновлении документов.
Этап онлайн-поиска (запрос пользователя)
Этот этап происходит в реальном времени, когда пользователь задаёт вопрос.
Шаги следующие:
1. Векторизация вопроса: Используйте ту же модель эмбеддингов, чтобы также преобразовать вопрос пользователя в вектор.
-
2. Поиск по сходству: Найдите текстовые фрагменты, наиболее близкие к вектору вопроса, в векторной базе данных.
-
3. Создание промпта: Используйте извлечённые текстовые фрагменты как контекст и соберите их вместе с вопросом пользователя в промпт.
-
4. Генерация LLM: Отправьте промпт в LLM и дайте ей ответить на основе контекста.
-
5. Возврат ответа: Верните ответ LLM пользователю, обычно вместе с источниками документов, на которые были ссылки.
Введение в векторные базы данных
Векторная база данных — один из ключевых компонентов RAG. Чтобы понять её, сначала нужно понять, что такое вектор.
Что такое вектор (эмбеддинг)?
Вектор (эмбеддинг) — это строка чисел, преобразованная из текста.
Например, слово "кошка" может быть преобразовано в вектор с несколькими сотнями измерений, например [0.23, -0.45, 0.12, 0.89, ...].
Ключевой момент:Тексты со схожей семантикой будут иметь векторы, расположенные близко друг к другу в пространстве.。
Например:
- Векторное расстояние между "кошкой" и "котёнком" очень мало.
- Векторное расстояние между "кошкой" и "собакой" меньше, чем между "кошкой" и "машиной".
- Векторное расстояние между "Я люблю кошек" и "Я обожаю кошек" очень мало.
Это основа для "семантического поиска" — сопоставление по смыслу, а не по ключевым словам.
Вычислительный принцип семантического сходства.
Сходство двух векторов обычно вычисляется с помощью "косинусного сходства".
Диапазон значений косинусного сходства — от -1 до 1:
- 1 означает полное совпадение
- 0 означает отсутствие связи
- -1 означает полную противоположность
На практике мы обычно обращаем внимание только на положительное сходство; чем ближе к 1, тем более релевантно.
Когда вы задаёте вопрос, векторная база данных быстро вычисляет сходство между вектором вопроса и всеми векторами документов, возвращая несколько наиболее релевантных.
Основные векторные базы данных
На рынке представлено множество векторных баз данных, каждая со своими особенностями:
| Базы данных | Type | Особенности | Сценарии использования |
|---|---|---|---|
| Chroma | Локальные/с открытым исходным кодом | Лёгкие, простые в использовании, удобные для Python | Прототипирование, небольшие приложения |
| Pinecone | Облачный сервис/SaaS | Управляемый сервис, не требует эксплуатации, эластичное масштабирование | Продакшен-среды, крупномасштабные приложения |
| Weaviate | С открытым исходным кодом/управляемые | Богатый функционал, поддерживает GraphQL | Сценарии, требующие расширенных возможностей |
| Qdrant | С открытым исходным кодом/управляемые | Высокая производительность, написан на Rust | Сценарии с высокими требованиями к производительности |
| Milvus | С открытым исходным кодом/управляемые | Полный набор функций, корпоративного уровня | Крупномасштабные корпоративные приложения |
| FAISS | Локальная библиотека | От Facebook, чрезвычайно быстрый | Сценарии, где не требуется постоянное хранение |
Для начинающих мы рекомендуем начать с Chroma — её легко установить, она не требует дополнительной настройки и отлично подходит для обучения и прототипирования.
Рабочий процесс обработки документов
Обработка документов — это шаг в RAG, который легко упустить из виду, но на самом деле он очень важен.
То, насколько хорошо работает ваш поиск, во многом зависит от того, насколько хорошо обработаны документы.
Поддерживаемые форматы документов.
LangChain поддерживает множество форматов документов:
- Обычный текст: .txt, .md
- PDF:.pdf
- Office:.docx, .pptx, .xlsx
- Веб-страницы: HTML, URL
- Код: .py, .js, .java и т. д.
- JSON:.json, .jsonl
- CSV:.csv
Для каждого формата есть соответствующий загрузчик, что делает использование очень удобным.
Стратегия сегментации документов
Разбиение документа на фрагменты — это процесс разделения длинных документов на более мелкие части.
Это кажется простым, но есть много нюансов:
- Слишком маленький: можно потерять контекст, целостный смысл обрывается
- Слишком большой: может содержать нерелевантную информацию, впустую расходуя контекстное окно
Распространённые стратегии разбиения:
| Стратегия | Принцип | Применимые сценарии |
|---|---|---|
| По количеству символов | Простое разбиение по количеству символов, например, по 500 символов на фрагмент | Простые сценарии с низкими требованиями к контексту |
| По абзацам | Разбивать по символам новой строки, сохраняя абзацы как можно более целыми | Хорошо отформатированные документы |
| Рекурсивное разбиение | Сначала предпочитайте абзацы, затем предложения, если они слишком длинные, и наконец слова | Первый выбор для большинства сценариев |
| Семантический чанкинг | Разделяйте на основе семантической близости, чтобы обеспечить семантическую полноту | Сценарии с высокими требованиями к семантике |
В большинстве случаев достаточно использовать RecursiveCharacterTextSplitter из LangChain.
Советы по выбору размера разбиения
Chunk Size — это параметр, который нужно настраивать в зависимости от сценария.
Несколько справочных рекомендаций:
- Сценарии QA: 500-1000 символов, достаточно для полной пары вопрос-ответ
- Сценарии суммирования: 1000-2000 символов, требуется больше контекста
- Сценарии с кодом: можно разбивать по функциям или классам, сохраняя блоки кода целыми
Есть также важный параметр: Overlap — количество символов, перекрывающихся между соседними текстовыми фрагментами.
Перекрытие может предотвратить разделение важной информации между двумя чанками, обычно устанавливается на 10%-20% от размера чанка.
Не гонитесь слепо за «оптимальными» параметрами разбиения на чанки. Начните с 500 символов и перекрытия 50, проверьте реальные результаты, а затем корректируйте.
Модель эмбеддингов
Модель эмбеддингов — это модель, которая преобразует текст в векторы.
Её качество напрямую влияет на эффективность поиска — хорошая модель эмбеддингов может точно понимать семантику и ставить релевантные документы выше в ранжировании.
Что такое модель эмбеддингов?
Модель эмбеддингов — это предварительно обученная нейронная сеть, которая принимает текст на вход и выдаёт векторы.
Её цель обучения: для текстов с похожей семантикой выходные векторы также должны быть похожими.
Например:
- «Как выучить Python» и «Методы изучения Python» → векторы близки
- «Кошки милые» и «Щенки милые» → векторы несколько отдалены, но всё ещё относительно близки
- «Как выучить Python» и «Кошки милые» → векторное расстояние очень велико
Серия OpenAI text-embedding-3
OpenAI предоставляет наиболее популярные на данный момент модели эмбеддингов:
| Модель | Размерность | Цена (за миллион токенов) | Особенности |
|---|---|---|---|
| text-embedding-3-small | 1536 | $0.02 | Высокая экономическая эффективность, достаточно для большинства сценариев |
| text-embedding-3-large | 3072 | $0.13 | Лучшая производительность, подходит для задач, требующих высокой точности |
text-embedding-3-small в настоящее время является лучшим выбором — она работает лучше, чем предыдущее поколение text-embedding-ada-002, и дешевле.
Модель эмбеддингов с открытым исходным кодом
Если вы не хотите использовать OpenAI или у вас есть требования к конфиденциальности данных, также есть много вариантов с открытым исходным кодом:
| Модель | Размерность | Особенности |
|---|---|---|
| sentence-transformers/all-MiniLM-L6-v2 | 384 | Лёгкая, быстрая, достойная производительность |
| sentence-transformers/all-mpnet-base-v2 | 768 | Более высокая производительность, но медленнее и крупнее |
| BAAI/bge-large-zh-v1.5 | 1024 | Оптимизирована специально для китайского языка |
| Alibaba-NLP/gte-large-zh | 1024 | Создана Alibaba, хорошая производительность на китайском языке |
Для китайских сценариев мы рекомендуем серии BAAI/bge или Alibaba-NLP/gte — они специально оптимизированы для китайского языка и работают лучше универсальных моделей.
Стратегия извлечения
Поиск не так прост, как «найти самые релевантные документы» — разные стратегии подходят для разных сценариев.
Поиск по векторному сходству
Это самый распространённый метод поиска: вычислить сходство между вектором вопроса и всеми векторами документов и вернуть первые K наиболее релевантных.
Преимущества: понимает семантику, поэтому могут сопоставляться синонимы и близкие по значению слова.
Недостатки: может быть менее точным, чем поиск по ключевым словам, для точных терминов и имён собственных.
Например, если пользователь спрашивает «руководство по Python от example», векторный поиск может понять, что «руководство» и «курс» похожи, но если пользователь спрашивает «документация Python3.10 от example», поиск по ключевым словам может быть точнее.
Поиск по ключевым словам (BM25)
Это метод, используемый традиционными поисковыми системами: сопоставление ключевых слов и оценка на основе частоты термина, обратной частоты документа и т. д.
-
Преимущества: эффективен для точного сопоставления терминов, названий продуктов, номеров моделей и т. д.
-
Недостатки: не понимает синонимы и семантические связи.
Например, если пользователь спрашивает, как научиться программировать, поиск по ключевым словам может найти только документы, содержащие «программирование», и не может найти документы, в которых сказано «написание кода», но имеется в виду то же самое.
Гибридный поиск
Поскольку у обоих методов есть свои плюсы и минусы, почему бы не использовать их вместе?
Гибридный поиск выполняет одновременно векторный поиск и поиск по ключевым словам, затем объединяет и повторно ранжирует результаты.
Таким образом, он может использовать семантическое понимание, обеспечивая при этом точное совпадение.
Многие векторные базы данных поддерживают гибридный поиск, например Weaviate, Pinecone, Qdrant и т. д.
Если вы не уверены, какой из них использовать, выберите гибридный поиск — в большинстве случаев он работает лучше всего.
Оптимизация этапа генерации
Извлечение релевантных документов — это только первый шаг. Существует также множество техник, позволяющих добиться того, чтобы LLM генерировала хорошие ответы на основе этих документов.
Проектирование шаблона промпта
Шаблон промпта — ключевой фактор, влияющий на качество вывода в RAG.
Хороший промпт для RAG обычно включает:
- Задание роли: скажите LLM, какую роль она играет
- Контекст: содержимое извлечённого документа
- Описание задачи: что должна сделать LLM
- Ограничения: например, "отвечай только на основе контекста" и "если не знаешь, скажи, что не знаешь"
- Формат вывода: как вы хотите, чтобы LLM отвечала
Классический шаблон:
Пример
RAG_PROMPT_TEMPLATE = """Вы — профессиональный {role}.
Пожалуйста, ответьте на вопрос пользователя на основе следующего контекста. Если контекст не содержит релевантной информации, скажите: "Извините, я не смог найти релевантную информацию."
Контекст:
{context}
Вопрос пользователя: {question}
Пожалуйста, отвечайте кратко и точно: """
Как уменьшить галлюцинации?
Галлюцинация — это явление, когда LLM выдумывает факты: это может звучать очень убедительно, но всё это вымысел.
RAG может уменьшить галлюцинации, но не может полностью их устранить.
Некоторые приёмы для уменьшения галлюцинаций:
- Сделайте акцент в промпте на "отвечай только на основе контекста"
- Попросите LLM приводить цитаты из исходного текста в своих ответах
- Если результаты поиска нерелевантны, попросите LLM сказать "Я не знаю"
- Используйте несколько LLM для перекрёстной проверки ответов
- Сначала попросите LLM найти релевантный контент в контексте, а затем ответить
Аннотация с указанием источника
Важно сообщать пользователям, откуда берётся ответ, — это не только повышает достоверность, но и упрощает пользователям проверку.
Распространённые практики:
- Отмечайте источник в ответе, например: "согласно Документу A, страница 2"
- Перечислите названия и ссылки справочных документов в конце ответа
- Позвольте пользователям нажать и перейти к месту в исходном тексте
Некоторые продвинутые фреймворки в LangChain (такие как LlamaIndex) могут сделать это за вас автоматически.
Практика: создание системы вопросов и ответов по документам на основе LangChain
Хватит разговоров — перейдём к практике и построим полноценную RAG-систему.
Мы будем использовать LangChain + Chroma + OpenAI для создания системы вопросов и ответов по документам.
Настройка окружения
Сначала установите необходимые библиотеки:
pip install langchain langchain-openai langchain-chroma python-dotenv
Затем создайте файл .env в каталоге проекта и укажите ваш ключ OpenAI API:
OPENAI_API_KEY=你的-api-key-在这里
Полная реализация кода
Это полноценная RAG-система, включающая создание индекса и функцию запросов:
Пример
# Полная реализация системы вопросов и ответов по документам RAG
# ============================================
import os
from dotenv import load_dotenv
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
from langchain_chroma import Chroma
from langchain_openai import ChatOpenAI
from langchain.chains import RetrievalQA
from langchain.prompts import PromptTemplate
from langchain.schema import Document
def load_documents_from_directory(directory: str) -> list[Document]:
"""Загрузить документы из каталога
Для демонстрационных целей мы вручную создаём несколько документов
В реальных проектах вы можете использовать DirectoryLoader для загрузки реальных файлов
"""
документы = [
Документация(
page_content="""Веб-сайт учебника EXAMPLE был основан в 2013 году, создан командой Rookie Tutorial.
Сайт стремится предоставлять простые для понимания руководства по программированию для начинающих программистов.
Мы предоставляем руководства по множеству языков программирования, включая HTML, CSS, JavaScript, Python, Java, C++ и другие.""",
metadata={"source": "example_intro.txt", "page": 1}
),
Документация(
page_content="""Учебник Python от EXAMPLE охватывает все важные знания по Python.
Включая: базовый синтаксис Python, типы данных, управляющие операторы, функции, модули, файловые операции и т. д.
Учебник содержит большое количество примеров кода, каждый из которых тщательно разработан и протестирован.
Мы также предоставляем онлайн-редактор Python, позволяющий запускать код прямо в браузере.""",
metadata={"source": "python_tutorial.txt", "page": 1}
),
Документация(
page_content="""Учебники EXAMPLE отличаются кратким содержанием, богатыми примерами и акцентом на практику.
Мы считаем, что "лучший способ научиться программировать — писать код."
Поэтому к каждой теме прилагаются исполняемые примеры кода, так что вы можете учиться и практиковаться одновременно.
Наши руководства полностью бесплатны, и любой может получить к ним доступ и учиться.""",
metadata={"source": "features.txt", "page": 1}
),
Документация(
page_content="""В дополнение к текстовым руководствам, EXAMPLE также предоставляет видеоуроки.
Видеоуроки более наглядны и подходят для визуалов.
Наши видеоуроки охватывают популярные темы, такие как Python, веб-разработка, анализ данных и многое другое.
Вы можете найти наши видео на Bilibili и YouTube.""",
metadata={"source": "video_course.txt", "page": 1}
),
]
print(f"Загружено {len(documents)} документов")
return documents
def split_documents(documents: list[Document], chunk_size: int = 500, chunk_overlap: int = 50) -> list[Документация]:
"""Разделить документы"""
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=chunk_size,
chunk_overlap=chunk_overlap,
length_function=len,
separators=["\n\n", "\n", "。", "!", "?", ",", " ", ""],
)
splits = text_splitter.split_documents(documents)
print(f"Разделено {len(documents)} документов на {len(splits)} текстовых фрагментов")
return splits
def create_vector_store(splits: list[Document], persist_directory: str = "./chroma_db") -> Chroma:
"""Создать векторную базу данных"""
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vector_store = Chroma.from_documents(
documents=splits,
embedding=embeddings,
persist_directory=persist_directory,
)
print(f"Векторная база данных создана, всего записей: {vector_store._collection.count()}")
return vector_store
def load_vector_store(persist_directory: str = "./chroma_db") -> Chroma:
"""Загрузить существующую векторную базу данных"""
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vector_store = Chroma(
persist_directory=persist_directory,
embedding_function=embeddings,
)
print(fВекторная база данных загружена, всего записей: {vector_store._collection.count()})
return vector_store
def create_rag_chain(vector_store: Chroma):
"""Создание RAG-цепочки вопросов и ответов"""
# Пользовательский шаблон промпта
template = """Вы — профессиональный ассистент по обслуживанию клиентов EXAMPLE.
Пожалуйста, ответьте на вопрос пользователя на основе следующего контекста. Если контекст не содержит соответствующей информации, скажите: "Извините, я не нашёл соответствующей информации."
Сделайте ответ кратким и ясным, используя китайский язык.
Контекст:
{context}
Вопрос пользователя: {question}
Ответ: """
prompt = PromptTemplate(
template=template,
input_variables=["context", "question"],
)
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
# Создать цепочку извлечения
rag_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=vector_store.as_retriever(search_kwargs={"k": 3}),
chain_type_kwargs={"prompt": prompt},
return_source_documents=True,
)
return rag_chain
def main():
"""Основная функция"""
# Загрузить переменные окружения
load_dotenv()
# Проверить, существует ли уже база данных
db_exists = os.path.exists("./chroma_db") and os.path.isdir("./chroma_db")
if db_exists:
print("Найдена существующая база данных, загрузка...")
vector_store = load_vector_store()
else:
print("Создание новой базы данных...")
# 1. Загрузить документы
docs = load_documents_from_directory("./data")
# 2. Разделить документы
splits = split_documents(docs)
# 3. Создайте векторную базу данных
vector_store = create_vector_store(splits)
# 4. Создайте RAG-цепочку
rag_chain = create_rag_chain(vector_store)
# 5. Проверьте запросы
test_questions = [
"Когда был основан EXAMPLE?",
"Каковы особенности учебника Python от EXAMPLE?",
"Есть ли у EXAMPLE видеоуроки?",
"Как изучать C++ на EXAMPLE?",
"Требуют ли учебники EXAMPLE оплаты?",
]
for question in test_questions:
print(f"\n{'='*60}")
print(f"Вопрос: {question}")
print(f"{'='*60}")
result = rag_chain.invoke({"query": question})
answer = result["result"]
sources = result["source_documents"]
print(f"Ответ: {answer}")
print("\nИсточники:")
for i, doc in enumerate(sources, 1):
print(f" [{i}] {doc.metadata['source']} (страница {doc.metadata['page']})")
print(f" Фрагмент: {doc.page_content[:50]}...")
if __name__ == "__main__":
main()
Запустив эту программу, вы увидите примерно такой вывод:
创建新的数据库...
已加载 4 个文档
已将 4 个文档切分为 4 个文本块
向量数据库已创建,共 4 条记录
============================================================
问题:EXAMPLE 是什么时候创立的?
============================================================
回答:EXAMPLE 教程网站创立于 2013 年。
参考来源:
[1] example_intro.txt (第 1 页)
片段:EXAMPLE 教程网站创立于 2013 年,由Example团队创建。...
[2] features.txt (第 1 页)
片段:除了文字教程,EXAMPLE 还提供了视频教程。...
============================================================
问题:EXAMPLE 的 Python 教程有什么特点?
============================================================
回答:EXAMPLE 的 Python 教程涵盖了 Python 的所有重要知识点,包括基础语法、数据类型、控制语句、函数、模块、文件操作等,并且提供了大量经过精心设计和测试的代码示例,还提供了在线 Python 编辑器,可以直接在浏览器中运行代码。
参考来源:
[1] python_tutorial.txt (第 1 页)
片段:EXAMPLE 的 Python 教程涵盖了 Python 的所有重要知识点。...
[2] features.txt (第 1 页)
片段:EXAMPLE 教程的特点是内容简洁、示例丰富、注重实践。...
Поздравляем! Вы успешно создали полноценную RAG-систему вопросов и ответов по документам.
Продвинутая оптимизация: реранжирование, HyDE
Базовый RAG работает, но если вы хотите лучших результатов, можете попробовать эти продвинутые методы оптимизации.
Повторное ранжирование
Результаты, возвращаемые векторным поиском, сортируются по сходству, но высокое сходство не обязательно означает, что это наиболее подходящий ответ на вопрос.
Повторное ранжирование означает: сначала с помощью векторного поиска возвращаются top K результатов (например, 20), затем используется более точная модель, чтобы повторно ранжировать эти результаты, и выбираются лучшие несколько для отправки в LLM.
Распространённые модели повторного ранжирования:
- cross-encoder/ms-marco-MiniLM-L-6-v2
- BAAI/bge-reranker-large
Хотя это добавляет дополнительный шаг, улучшение результатов очевидно, и это стоит делать.
HyDE(Hypothetical Document Embedding)
HyDE — это остроумная идея: сначала с помощью LLM сгенерировать «гипотетический ответ» на вопрос пользователя, затем использовать этот гипотетический ответ для поиска.
Почему это эффективно? Потому что вопросы обычно короткие и имеют низкую информационную плотность; а гипотетические ответы длиннее, больше похожи по стилю на документы и имеют более высокое сходство с реальными документами.
Например:
- Вопрос пользователя: «Когда был основан EXAMPLE?»
- Гипотетический ответ: «Сайт обучающих руководств EXAMPLE был основан в 2013 году, создан командой Rookie Tutorial, стремясь предоставлять качественные руководства для начинающих программистов.»
Использование гипотетического ответа для поиска часто позволяет найти более релевантные документы.
Другие расширения