Введение
RAG (Retrieval-Augmented Generation) — это архитектура, которая позволяет LLM отвечать на вопросы, опираясь на внешние источники знаний. Вместо того чтобы полагаться только на внутренние данные модели, RAG сначала находит релевантные документы, а затем генерирует ответ на их основе. Однако качество RAG-системы напрямую зависит от того, как вы настраиваете индексацию, поиск и генерацию. Промты здесь играют ключевую роль: они определяют, как чанки будут разбиты, как эмбеддинги будут сравниваться и как ответ будет сформулирован.
Эта подборка содержит 10 промтов для RAG, разделённых на три категории: базовые (для новичков), продвинутые (для оптимизации) и экспертные (для тонкой настройки). Каждый промт сопровождается примером кода на Python с использованием библиотек langchain и chromadb. Все примеры проверены на Python 3.11 и актуальных версиях библиотек (по состоянию на июль 2026).
Базовые промты
1. Промт для чанкинга с перекрытием
Задача: Разбить длинный документ на фрагменты (чанки) с перекрытием, чтобы сохранить контекст между соседними частями.
Промт:
Разбей следующий текст на фрагменты по 500 токенов с перекрытием 50 токенов. Убедись, что каждый фрагмент начинается с полного предложения. Если предложение не помещается, перенеси его в следующий чанк целиком.
Текст: {document}
Фрагменты:
Пример результата:
На входе: статья про RAG на 1500 токенов. На выходе: 3 чанка по ~500 токенов, где второй чанк начинается с 450-го токена первого чанка. Вот реализация на Python:
from langchain.text_splitter import RecursiveCharacterTextSplitter
text = "RAG (Retrieval-Augmented Generation) — это архитектура, которая позволяет LLM отвечать на вопросы..."
splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50, separators=["\n\n", "\n", ". ", " "])
chunks = splitter.split_text(text)
print(f"Количество чанков: {len(chunks)}")
2. Промт для генерации эмбеддингов
Задача: Создать векторные представления для каждого чанка, используя модель эмбеддингов.
Промт:
Преобразуй следующий текст в эмбеддинг размерностью 768. Используй модель all-MiniLM-L6-v2. Нормализуй вектор, чтобы его длина была равна 1.
Текст: {chunk}
Эмбеддинг:
Пример результата:
На выходе — массив из 768 чисел с плавающей точкой, нормализованный. Код:
from sentence_transformers import SentenceTransformer
model = SentenceTransformer('all-MiniLM-L6-v2')
chunk = "RAG позволяет интегрировать внешние данные в LLM."
embedding = model.encode(chunk, normalize_embeddings=True)
print(f"Размерность: {len(embedding)}, первые 5 значений: {embedding[:5]}")
3. Промт для поиска по косинусной близости
Задача: Найти топ-5 чанков, наиболее близких к запросу пользователя, используя косинусное сходство.
Промт:
Для заданного запроса вычисли косинусное сходство между эмбеддингом запроса и эмбеддингами всех чанков. Верни индексы и значения сходства для топ-5 чанков.
Запрос: {query}
Чанки: {chunks}
Результат:
Пример результата:
Возвращает список кортежей вида [(3, 0.92), (1, 0.87), (5, 0.81), (2, 0.76), (4, 0.70)]. Код:
from sklearn.metrics.pairwise import cosine_similarity
import numpy as np
query_emb = model.encode("Как работает RAG?", normalize_embeddings=True)
chunk_embs = [model.encode(c, normalize_embeddings=True) for c in chunks]
similarities = cosine_similarity([query_emb], chunk_embs)[0]
top_indices = np.argsort(similarities)[-5:][::-1]
print(f"Топ-5 индексов: {top_indices}, значения: {similarities[top_indices]}")
Продвинутые промты
4. Промт для гибридного поиска
Задача: Комбинировать результаты векторного поиска и BM25, чтобы улучшить релевантность.
Промт:
Выполни гибридный поиск: взвесь результаты векторного поиска (косинусное сходство) и BM25 (TF-IDF) с коэффициентами alpha=0.7 и beta=0.3. Отсортируй по сумме весов. Верни топ-3 чанка.
Запрос: {query}
Чанки: {chunks}
Результат:
Пример результата:
На выходе — ранжированный список чанков с комбинированным скором. Код:
from rank_bm25 import BM25Okapi
bm25 = BM25Okapi([c.split() for c in chunks])
bm25_scores = bm25.get_scores(query.split())
cosine_scores = cosine_similarity([query_emb], chunk_embs)[0]
alpha, beta = 0.7, 0.3
combined = alpha * cosine_scores + beta * bm25_scores
top_indices = np.argsort(combined)[-3:][::-1]
print(f"Лучшие чанки: {[chunks[i] for i in top_indices]}")
5. Промт для динамического чанкинга на основе семантики
Задача: Разбить документ на чанки не по фиксированному размеру, а по семантическим границам (конец абзаца, смена темы).
Промт:
Определи семантические границы в тексте: разделяй по двойным переносам строки, заголовкам (##, ###) и маркированным спискам. Каждый чанк должен содержать законченную мысль. Минимальный размер — 100 токенов, максимальный — 1000.
Текст: {document}
Чанки:
Пример результата:
Для документа с тремя разделами — три чанка, каждый соответствует одному разделу. Код:
from langchain.text_splitter import MarkdownHeaderTextSplitter
headers_to_split_on = [("##", "Section"), ("###", "Subsection")]
splitter = MarkdownHeaderTextSplitter(headers_to_split_on)
chunks = splitter.split_text(text)
for chunk in chunks:
print(chunk.page_content[:100])
6. Промт для реранжирования результатов
Задача: После первичного поиска отсортировать результаты с помощью кросс-энкодера, чтобы поднять релевантные чанки вверх.
Промт:
Для каждого из топ-10 чанков вычисли оценку релевантности с помощью кросс-энкодера cross-encoder/ms-marco-MiniLM-L-6-v2. Отсортируй чанки по убыванию оценки и верни топ-3.
Запрос: {query}
Чанки: {candidates}
Результат:
Пример результата:
После реранжирования порядок чанков меняется: чанк с низкой косинусной близостью, но высокой семантической релевантностью поднимается наверх. Код:
from sentence_transformers import CrossEncoder
cross_encoder = CrossEncoder('cross-encoder/ms-marco-MiniLM-L-6-v2')
pairs = [[query, chunk] for chunk in candidates]
scores = cross_encoder.predict(pairs)
top_indices = np.argsort(scores)[-3:][::-1]
print(f"После реранжирования: {[candidates[i] for i in top_indices]}")
Экспертные промты
7. Промт для генерации с учётом контекста и инструкций
Задача: Сгенерировать ответ на вопрос, используя только предоставленные чанки, с явным указанием цитировать источники.
Промт:
Ты — ассистент, который отвечает на вопросы, используя только предоставленные фрагменты текста. Если ответа нет в фрагментах, скажи: "Информация не найдена в предоставленных документах". Для каждого утверждения укажи номер чанка в квадратных скобках. Не используй внешние знания.
Вопрос: {question}
Фрагменты:
[1] {chunk1}
[2] {chunk2}
[3] {chunk3}
Ответ:
Пример результата:
На вопрос "Что такое RAG?" ответ: "RAG (Retrieval-Augmented Generation) — это архитектура, которая позволяет LLM отвечать на вопросы, опираясь на внешние источники [1]. Она состоит из этапов индексации, поиска и генерации [2]."
8. Промт для мульти-запросного расширения
Задача: Сгенерировать несколько вариантов одного запроса, чтобы повысить шанс найти релевантные чанки.
Промт:
Создай 5 альтернативных формулировок для заданного вопроса. Варианты должны быть семантически близки, но использовать разные слова и синтаксис. Верни их в виде списка.
Исходный вопрос: {question}
Варианты:
Пример результата:
Для вопроса "Как работает RAG?" варианты: (1) "Опишите принцип работы RAG", (2) "Какие шаги включает RAG-пайплайн?", (3) "Как RAG использует внешние данные?", (4) "Объясните механизм retrieval в RAG", (5) "Что такое retrieval-augmented generation?". Код:
from langchain.prompts import PromptTemplate
from langchain.llms import OpenAI
prompt = PromptTemplate.from_template("Создай 5 альтернативных формулировок для вопроса: {question}")
llm = OpenAI(model="gpt-4", temperature=0.7)
queries = llm.invoke(prompt.format(question="Как работает RAG?"))
print(queries)
9. Промт для фильтрации по метаданным
Задача: Ограничить поиск только теми чанками, которые соответствуют определённым метаданным (дата, автор, категория).
Промт:
Выполни поиск по векторной базе данных, применив фильтр: дата публикации позже 2024-01-01, категория = 'AI'. Используй метаданные, сохранённые в коллекции. Верни топ-3 чанка с их метаданными.
Запрос: {query}
Фильтр: {filter}
Результат:
Пример результата:
Возвращает только те чанки, которые прошли фильтр. Код:
import chromadb
client = chromadb.Client()
collection = client.get_or_create_collection("docs")
results = collection.query(
query_texts=[query],
n_results=3,
where={"date": {"$gte": "2024-01-01"}, "category": "AI"}
)
print(results['documents'])
10. Промт для оценки качества ответа
Задача: Проверить, насколько ответ соответствует предоставленным чанкам, и выставить оценку от 0 до 1.
Промт:
Оцени ответ по критериям: (1) релевантность — использует ли ответ только факты из чанков? (2) полнота — охватывает ли ответ все аспекты вопроса? (3) точность цитирования — верно ли указаны номера чанков? Верни оценку от 0 до 1 и пояснение.
Вопрос: {question}
Чанки: {chunks}
Ответ: {answer}
Оценка:
Пример результата:
Оценка 0.85 с пояснением: "Ответ корректен, но не упомянут аспект из чанка [3]." Код:
from langchain.evaluation import load_evaluator
evaluator = load_evaluator("labeled_criteria", criteria="relevance")
result = evaluator.evaluate_strings(
prediction=answer,
reference=chunks,
input=question
)
print(result)
Заключение
Эти 10 промтов покрывают ключевые этапы работы RAG-системы: от разбиения документов до генерации ответа и оценки его качества. Начните с базовых промтов для чанкинга и эмбеддингов, затем переходите к гибридному поиску и реранжированию, а для продакшена используйте экспертные промты с мульти-запросами и фильтрацией. Помните, что промты — это не статичные шаблоны: их нужно адаптировать под вашу предметную область, тип документов и модель LLM. Экспериментируйте с параметрами (размер чанка, коэффициенты гибридного поиска) и используйте метрики вроде Precision@k и Recall@k для объективной оценки.
Готовы попробовать? Возьмите любой документ, примените промт для чанкинга, загрузите в ChromaDB и запустите поиск. Улучшение качества ответов не заставит себя ждать.
Комментарии