Откуда LLM берёт данные? Источники данных RAG в Python

Предыдущая статья, Что такое RAG? Самое простое объяснение того, как это работает, заложила ментальную модель: LLM пишет, RAG извлекает полезные знания, приложение владеет текущим состоянием, а инструменты выполняют действия. Эта статья делает следующий шаг: откуда на самом деле берутся данные и как выглядит извлечение в Python?
Важный сюрприз заключается в том, что «источник данных для LLM» обычно не представляет собой ничего экзотического. Это может быть текстовый файл, папка с Markdown-документами, база данных SQL, ответ API, каталог товаров, система поддержки или векторный индекс, построенный на основе этих источников. ИИ не знает эти системы магическим образом. Ваше приложение должно загрузить, запросить, найти или извлечь соответствующие данные и поместить результат в контекст модели.
Источник данных = где находится информация. Извлечение = как приложение находит полезную информацию. Контекст = выбранная информация, переданная модели. LLM = компонент, который интерпретирует этот контекст и генерирует ответ.— Четырёхчастная модель, используемая на протяжении всей этой статьи
Вопрос
Как LLM использует внешние данные, такие как файлы, базы данных или API, и как небольшая программа на Python может реализовать основные шаги RAG, не скрывая их за фреймворком?
Что это на самом деле означает
Когда разработчики говорят, что LLM «подключена к данным компании», за этой фразой может скрываться несколько различных операций. Одно приложение может выполнять SQL. Другое может вызывать API. Третье может выполнять полнотекстовый поиск. Четвёртое может вычислять сходство эмбеддингов по фрагментам документов. Все они могут предоставлять внешнюю информацию для LLM, но это не один и тот же метод извлечения, и их не следует рассматривать как взаимозаменяемые.
Это различие важно, потому что лучший метод извлечения зависит от формы вопроса. «Какова наша политика возврата?» — это задача извлечения документов. «Каков текущий статус заказа 4711?» — это обычно структурированный запрос к базе данных. «В каком абзаце обсуждается восстановление аккаунта?» — это может быть поиск по ключевым словам или семантический поиск. RAG наиболее полезен, когда система должна обнаружить релевантные знания до генерации.
Простейший пример
Начните с трёх строк в обычном Python. Здесь нет векторной базы данных, нет фреймворка и пока нет LLM. Мы лишь хотим сделать шаг извлечения видимым.
documents = [
"The AKM uses 7.62 mm ammunition.",
"A Med Kit restores health.",
"A 4x scope can be attached to several compatible weapons."
]
question = "Which ammunition does the AKM use?"
for document in documents:
if "AKM" in document:
print(document)
Программа выводит первое предложение, потому что оно содержит искомый термин. Это примитивное извлечение, но архитектура уже видна: вопрос → поиск → релевантный текст. RAG добавляет ещё один важный шаг: передать извлечённый текст языковой модели вместе с вопросом.
Немного более общая версия ранжирует документы по пересечению терминов запроса:
import re
documents = [
{"id": "weapon-akm", "text": "The AKM uses 7.62 mm ammunition."},
{"id": "healing-medkit", "text": "A Med Kit restores health."},
{"id": "scope-4x", "text": "A 4x scope can be attached to several compatible weapons."},
]
def words(text):
return set(re.findall(r"[a-zA-Z0-9.]+", text.lower()))
def retrieve(question, documents, top_k=2):
query_terms = words(question)
ranked = []
for document in documents:
score = len(query_terms & words(document["text"]))
if score > 0:
ranked.append((score, document))
ranked.sort(key=lambda item: item[0], reverse=True)
return [document for _, document in ranked[:top_k]]
question = "Which ammunition does the AKM use?"
hits = retrieve(question, documents)
for hit in hits:
print(hit["id"], "->", hit["text"])
Это не производственная поисковая система. Она игнорирует морфологию, синонимы, варианты написания, длину документа и многие сигналы ранжирования. Её ценность образовательная: RAG начинается не с векторной базы данных. Он начинается с извлечения.
Где пример перестаёт работать
Точное или лексическое сопоставление становится слабым, когда вопрос и источник используют разные слова. В документе может быть сказано «обслуживание транспортного средства», а пользователь спрашивает: «как мне отремонтировать машину?» Лексический поисковик может упустить эту связь, хотя человек видит её сразу. Семантическое извлечение решает эту проблему, представляя текст в виде векторов и сравнивая смысл, а не только точные токены.
Длинные файлы создают ещё одну проблему. Поиск по всему 80-страничному руководству как по единому целому слишком груб, но разбиение на каждое предложение может разрушить полезный контекст. Поэтому реальные системы RAG нуждаются в решениях относительно парсинга, разбиения на фрагменты, метаданных, ранжирования, актуальности, разрешений и происхождения данных.
В примере также ничего не говорится о структурированных актуальных фактах. Если пользователь спрашивает о текущем статусе заказа 4711, а в приложении уже есть ключ базы данных, семантический поиск обычно является неподходящим первым инструментом. Детерминированный запрос к базе данных лучше.
Прямой ответ
Источник данных для LLM — это любая внешняя система, из которой приложение может получить информацию для модели: файлы, базы данных, API, поисковые индексы, векторные хранилища или текущее состояние приложения. RAG — это паттерн извлечения релевантных знаний из таких источников перед генерацией.
В Python основной конвейер может быть очень небольшим: загрузить данные → создать извлекаемые единицы → найти релевантные доказательства → собрать контекст → вызвать LLM. Метод извлечения должен соответствовать источнику и вопросу. Используйте SQL для точных структурированных фактов, полнотекстовый поиск для лексического сопоставления, эмбеддинги для семантической близости и гибридное извлечение, когда ценны несколько сигналов.
Почему это так
Языковая модель не получает автоматически содержимое вашей файловой системы, базы данных PostgreSQL, CRM, частного API или недавно отредактированного документа. Приложение решает, какая внешняя информация доступна и что помещается в текущий контекст модели.
Оригинальная работа по Retrieval-Augmented Generation Льюиса и др. объединила генеративную модель с внешней непараметрической памятью, извлекаемой из плотного векторного индекса. Более широкая архитектурная идея сохраняется за пределами этой конкретной реализации: внешние доказательства можно извлекать во время вывода вместо того, чтобы ожидать, что все полезные знания закодированы в параметрах модели.
Это создает полезное разделение обязанностей: источник хранит информацию, средство извлечения выбирает доказательства, контекст переносит эти доказательства в запрос, а модель интерпретирует их. Сохранение этих границ видимыми значительно упрощает диагностику сбоев.
Контекст: основные типы источников данных
| Источник | Типичный метод извлечения | Подходит для |
|---|---|---|
| TXT / Markdown / HTML | Парсинг + лексический или семантический поиск | Документация, руководства, статьи, заметки |
| PDF / DOCX | Извлечение с учетом структуры + поиск | Политики, отчеты, договоры, руководства |
| База данных SQL | SQL-запрос или фильтрованное извлечение | Заказы, пользователи, продукты, структурированные записи |
| REST / GraphQL API | HTTP-запрос с параметрами | Удаленные системы и данные живых сервисов |
| Поисковый индекс | BM25 / полнотекстовый / гибридный поиск | Большие текстовые коллекции |
| Векторный индекс | Сходство эмбеддингов | Семантическое извлечение документов |
| Состояние приложения | Прямое чтение состояния или вызов инструмента | Что верно прямо сейчас |
Векторный индекс заслуживает особого внимания. Во многих архитектурах он не является каноническим источником истины. Это индекс извлечения, производный от документов или записей. Авторитетный документ может находиться в объектном хранилище, CMS, Git, PostgreSQL или другой системе, а эмбеддинги и метаданные хранятся отдельно для быстрого семантического поиска. Некоторые системы действительно используют векторное хранилище в качестве основного хранилища, но это архитектурный выбор, а не требование RAG.
Если граница между извлечением, постоянной памятью, текущим состоянием и контекстом модели все еще неясна, см. AI Agent Memory Is Not RAG. Эти слои могут использовать некоторые из одних и тех же технологий хранения, но при этом иметь разные правила корректности.
Допущения
- Приложению разрешен доступ к внешнему источнику.
- Соответствующий источник содержит достаточно информации для ответа на вопрос.
- Данные можно разобрать или запросить в форме, пригодной для использования слоем извлечения.
- Извлеченная информация достаточно свежа для запрашиваемого решения.
- Модель получает выбранные доказательства в своем контексте.
- Авторизация применяется до того, как защищенные доказательства попадут к модели.
- Генеративная модель все еще может ошибаться, даже если извлечение корректно.
Эти допущения важны, потому что извлечение не может компенсировать отсутствующие доказательства, устаревшие версии источников, сломанные парсеры или несанкционированный доступ. Конвейер RAG может быть настолько надежным, насколько надежен путь доказательств, который его питает.
Переменные
| Переменная | Почему она меняет дизайн |
|---|---|
| Структура источника | Таблица SQL, юридический PDF и репозиторий исходного кода требуют разных стратегий извлечения |
| Тип вопроса | Точный поиск, концептуальный поиск и многошаговое исследование — это разные задачи |
| Требование к свежести | Живое состояние может требовать прямых запросов вместо периодически перестраиваемых индексов |
| Размер корпуса | Поиск в памяти может работать для сотен фрагментов, но не для очень больших коллекций |
| Язык | Многоязычное извлечение требует моделей и токенизации, подходящих для фактических языков |
| Разрешения | Извлечение должно фильтроваться по правам доступа текущего пользователя |
| Задержка и стоимость | Больше этапов извлечения может улучшить качество, но добавить время выполнения и затраты на инфраструктуру |
| Потребность в происхождении | Системы с высоким доверием нуждаются в идентификаторах источников, версиях и отслеживаемых доказательствах |
Диагностический / решающий метод
Первое решение — не «Какую векторную базу данных мне установить?» Оно таково: Какого рода факт я пытаюсь извлечь?
| Тип вопроса | Предпочтительный первый подход | Причина |
|---|---|---|
| Точный ID или текущая запись | SQL / поиск по ключу / API | Детерминированный структурированный доступ |
| Точная формулировка, коды, названия | Полнотекстовый или ключевой поиск | Лексическая точность |
| Концептуальный вопрос по документам | Семантический векторный поиск | Смысл может отличаться от формулировки |
| Смешанные корпоративные знания | Гибридный поиск + фильтры по метаданным | Объединяет лексические и семантические сигналы |
| Текущее состояние приложения | Прямой доступ к состоянию/инструменту | Актуальность важнее сходства документов |
Полезная проверка: Я уже знаю, какая запись мне нужна, или система должна обнаружить, какой фрагмент релевантен? Если запись известна, запрашивайте её напрямую. Если релевантность нужно обнаружить, поиск становится важнее.
Когда ответ неверен, диагностируйте конвейер по порядку, а не сразу меняйте LLM:
- 1. Покрытие источников: Существует ли правильная информация в доступном наборе источников?
- 2. Актуальность: Достаточно ли свежа эта версия для вопроса?
- 3. Разбор: Был ли релевантный контент извлечён правильно?
- 4. Разбиение на фрагменты: Остались ли доказательства вместе с условиями, придающими им смысл?
- 5. Поиск: Появляется ли правильный фрагмент среди кандидатов?
- 6. Ранжирование: Ранжируются ли более сильные источники выше более слабых или противоречащих?
- 7. Сборка контекста: Действительно ли приложение отправило выбранные доказательства модели?
- 8. Генерация: Использовала ли LLM предоставленные доказательства достоверно?
- 9. Атрибуция: Можно ли проследить каждое важное утверждение до источника?
Для более глубокого метода отладки в продакшене см. RAG Failed — But Which Layer Actually Failed? A Diagnostic Method, где эта цепочка расширяется до независимо тестируемых слоёв сбоев.
Доказательства
Статья о RAG от Lewis et al. формализовала генерацию, обусловленную извлечённой внешней памятью, а не опирающуюся только на параметры модели. Это даёт концептуальную основу для отделения генератора от извлекаемого источника знаний.
Sentence Transformers описывает семантический поиск как встраивание корпуса и запроса в векторное пространство и извлечение элементов с высокой семантической близостью. Его текущий API также различает кодирование запроса и кодирование документа для задач поиска.
SQLite FTS5 демонстрирует другую сторону спектра: зрелый полнотекстовый поиск может ранжировать документы без эмбеддингов. Это важно, потому что лексический поиск остаётся ценным для идентификаторов, точной терминологии и многих гибридных схем поиска.
Документация OpenAI по эмбеддингам описывает эмбеддинги как числовые векторные представления, используемые для оценки связанности и поиска. Это один из путей реализации семантического поиска, а не определение самого RAG.
Реальный пример 1: Папка с текстовыми файлами
Предположим, каталог с именем knowledge/ содержит обычные текстовые файлы. Python может загрузить их вообще без библиотек ИИ.
from pathlib import Path
def load_text_files(folder="knowledge"):
documents = []
for path in Path(folder).glob("*.txt"):
documents.append({
"source": path.name,
"text": path.read_text(encoding="utf-8")
})
return documents
documents = load_text_files()
for document in documents:
print(document["source"], len(document["text"]))
Файловая система — это источник данных. Следующий вопрос: сколько текста должно стать одной извлекаемой единицей. Для длинных документов поиск по одному полному файлу часто слишком груб. Именно поэтому конвейеры RAG обычно создают фрагменты.
Очень простой разбиватель на фрагменты
def chunk_text(text, max_chars=800):
paragraphs = [p.strip() for p in text.split("\n\n") if p.strip()]
chunks = []
current = ""
for paragraph in paragraphs:
candidate = f"{current}\n\n{paragraph}".strip()
if current and len(candidate) > max_chars:
chunks.append(current)
current = paragraph
else:
current = candidate
if current:
chunks.append(current)
return chunks
Этот пример группирует абзацы, пока не достигнут примерный лимит символов. Он намеренно понятный, а не оптимальный. Продакшен-системы часто разбивают по токенам, заголовкам, разделам, границам предложений или структуре документа. Таблицы, исходный код, договоры и документация API могут требовать разных стратегий.
Сохранение происхождения при разбиении на фрагменты
def build_chunks(documents):
chunks = []
for document in documents:
for index, text in enumerate(chunk_text(document["text"])):
chunks.append({
"id": f'{document["source"]}:{index}',
"source": document["source"],
"chunk": index,
"text": text,
})
return chunks
Полезный фрагмент несёт больше, чем просто текст. Имя источника, идентификатор документа, URL, временная метка, версия или раздел могут впоследствии помочь при цитировании, отладке и проверке актуальности. Если происхождение теряется во время загрузки, становится гораздо труднее объяснить, почему был получен конкретный ответ.
Реальный пример 2: Структурированные данные — используйте SQL, когда SQL является подходящим инструментом
Не каждый внешний факт должен проходить через семантический поиск. Если вопрос требует точной текущей записи, прямой запрос к базе данных обычно понятнее и более детерминирован.
import sqlite3
def get_order_status(order_id):
connection = sqlite3.connect("shop.db")
cursor = connection.cursor()
cursor.execute(
"SELECT status, total, currency FROM orders WHERE id = ?",
(order_id,)
)
row = cursor.fetchone()
connection.close()
if row is None:
return None
return {
"order_id": order_id,
"status": row[0],
"total": row[1],
"currency": row[2],
}
print(get_order_status(4711))
Если приложение уже знает, что пользователь спрашивает о заказе 4711, встраивание всей таблицы заказов и просьба к семантическому поиску заново обнаружить эту строку обычно добавляет сложность без пользы. Сильное правило проектирования: извлекайте структурированные факты структурированными запросами; извлекайте неструктурированные знания с помощью поиска.
Возвращённую строку базы данных всё ещё можно поместить в контекст модели, чтобы LLM мог объяснить её на естественном языке. Но прямой доступ к состоянию или записи концептуально отличается от поиска по корпусу знаний.
Реальный пример 3: Полнотекстовый поиск перед эмбеддингами
Между наивным циклом на Python и векторным поиском лежит зрелый класс систем лексического поиска. SQLite включает FTS5 для полнотекстового поиска, в том числе ранжирование BM25.
import sqlite3
connection = sqlite3.connect("knowledge.db")
cursor = connection.cursor()
cursor.execute(
"CREATE VIRTUAL TABLE IF NOT EXISTS docs USING fts5(title, body)"
)
cursor.execute(
"INSERT INTO docs(title, body) VALUES (?, ?)",
("AKM", "The AKM uses 7.62 mm ammunition.")
)
connection.commit()
query = "AKM ammunition"
rows = cursor.execute(
"SELECT title, body, bm25(docs) AS score "
"FROM docs WHERE docs MATCH ? "
"ORDER BY score LIMIT 5",
(query,)
).fetchall()
for row in rows:
print(row)
connection.close()
Лексический поиск особенно полезен, когда важны точная терминология, коды продуктов, имена, идентификаторы или слова, специфичные для предметной области. Семантический поиск не обязательно лучше. Продакшн-системы часто комбинируют оба сигнала.
Реальный пример 4: Семантический поиск с эмбеддингами
Эмбеддинги превращают текст в числовые векторы, чтобы семантически связанные фрагменты можно было сравнивать, даже если они не используют одинаковые формулировки. Sentence Transformers предоставляет простую локальную реализацию.
# pip install sentence-transformers
from sentence_transformers import SentenceTransformer, util
documents = [
"The AKM uses 7.62 mm ammunition.",
"A Med Kit restores health.",
"Vehicle maintenance includes checking oil, brakes and tires.",
"Account recovery requires access to the registered email address."
]
model = SentenceTransformer(
"sentence-transformers/multi-qa-mpnet-base-cos-v1"
)
document_embeddings = model.encode_document(
documents,
convert_to_tensor=True
)
question = "How do I repair my car?"
query_embedding = model.encode_query(
question,
convert_to_tensor=True
)
hits = util.semantic_search(
query_embedding,
document_embeddings,
top_k=2
)[0]
for hit in hits:
print(round(float(hit["score"]), 3), documents[hit["corpus_id"]])
Запрос не содержит фразу «обслуживание транспортных средств», но семантическая модель всё равно может поставить этот фрагмент высоко, потому что понятия связаны. Это практическая причина, по которой эмбеддинги распространены в RAG-системах.
Для небольших коллекций эмбеддинги могут храниться в памяти. Более крупные системы обычно сохраняют их в индексе или базе данных с поддержкой векторов и выполняют там поиск ближайших соседей. Хранилище меняется, но логика остаётся: закодировать вопрос, найти релевантные представления документов, вернуть лучшие доказательства.
Реальный пример 5: Построение контекста для LLM
Система поиска должна возвращать доказательства. Затем LLM должна получить вопрос вместе с этими доказательствами. Разделение поиска и генерации упрощает их проверку и тестирование.
def build_prompt(question, retrieved_documents):
context = "\n\n".join(
f'[{doc["id"]}] {doc["text"]}'
for doc in retrieved_documents
)
return f"""
Answer the question using the supplied context.
Rules:
- Do not invent facts that are not supported by the context.
- If the context is insufficient, say so.
- Cite the source IDs you used.
Question:
{question}
Context:
{context}
""".strip()
Инструкция не делает модель безошибочной. Она лишь создаёт явную границу доказательств. Модель по-прежнему может неправильно понять хорошие доказательства, проигнорировать условие или сделать чрезмерное обобщение. Именно поэтому качество поиска и качество генерации должны оцениваться отдельно.
Реальный пример 6: Полный минимальный конвейер
def answer_question(question, all_documents, call_llm):
# 1. Retrieve evidence
retrieved = retrieve(question, all_documents, top_k=3)
# 2. Build model context
prompt = build_prompt(question, retrieved)
# 3. Generate the answer
answer = call_llm(prompt)
return {
"answer": answer,
"sources": [doc["id"] for doc in retrieved]
}
Функция намеренно принимает call_llm как зависимость. Поиску не должно быть важно, выполняется ли генерация облачной моделью, локальной моделью или другим провайдером. Путь данных принадлежит приложению.
Опциональный генератор: OpenAI Responses API
Одним из возможных генераторов является OpenAI Responses API. Хранение имени модели в переменной окружения позволяет избежать жёсткого кодирования конкретной модели в архитектуру RAG.
# pip install openai
import os
from openai import OpenAI
client = OpenAI()
def call_llm(prompt):
response = client.responses.create(
model=os.environ["OPENAI_MODEL"],
input=prompt,
)
return response.output_text
Тот же конвейер поиска можно подключить к локальному серверу вывода. Это важный архитектурный момент: RAG не принадлежит провайдеру LLM. Приложение владеет источником, поиском и сборкой контекста.
Вся архитектура в одном представлении
USER QUESTION
|
v
+-------------+
| Retriever |
+-------------+
| |
| +----> SQL / API / state query
|
+------------> keyword / full-text search
|
+------------> embedding / vector search
|
v
relevant evidence
|
v
+-----------------------------------+
| question + evidence + instructions |
+-----------------------------------+
|
v
LLM
|
v
answer
Эта модель потока данных более долговечна, чем запоминание одного фреймворка. Библиотеки, базы данных и поставщики моделей будут меняться; границы ответственности останутся.
Распространённые заблуждения и режимы отказа
«RAG означает векторную базу данных».
Нет. Векторный поиск — это лишь один метод поиска. RAG может использовать полнотекстовый поиск, SQL, API, графы знаний, векторный поиск или их комбинации. Определяющим шаблоном является поиск внешней информации для генерации.
«Если данные находятся в PostgreSQL, я должен векторизовать всю базу данных».
Нет. Структурированные записи обычно должны оставаться доступными для запросов как структурированные записи. Эмбеддинги полезны для семантической релевантности, а не как замена детерминированным запросам.
«Больше чанков — лучше ответ».
Не обязательно. Дополнительный контекст может вносить шум, конфликтующие версии и нерелевантный материал. Поиск должен оптимизироваться под полезные доказательства, а не под максимальный объём.
«Высокая оценка сходства доказывает ответ».
Нет. Сходство измеряет релевантность, а не истинность или применимость. Весьма похожий фрагмент может быть устаревшим, относиться к неверной версии продукта или быть действительным только при условиях, не соответствующих вопросу.
«Как только найден правильный чанк, проблема галлюцинаций решена».
Нет. Поиск улучшает обоснованность, но не гарантирует достоверных рассуждений. Генерация по-прежнему требует оценки, а рабочие процессы с высоким риском могут нуждаться в детерминированной валидации или проверке человеком.
«Модель не справилась — значит, надо сменить модель».
Не обязательно. Правильный источник мог отсутствовать, быть неверно разобран, плохо разбит, отфильтрован, оценён слишком низко или пропущен при сборке контекста. Замена модели не должна быть первым шагом диагностики.
Граничные случаи
- Конфликтующие документы: два источника могут противоречить друг другу из-за различий в версиях, юрисдикциях или продуктах.
- Факты, зависящие от времени: семантически релевантный источник может быть уже устаревшим.
- Права доступа: система поиска не должна возвращать документы, к которым у текущего пользователя нет авторизованного доступа.
- Многоязычные коллекции: модель эмбеддингов и стратегия поиска должны поддерживать фактически используемые языки.
- Таблицы и исходный код: разбиение на обычные абзацы может разрушить структуру, необходимую для ответа.
- Очень короткие идентификаторы: семантический поиск может быть слабее точного совпадения для артикулов, идентификаторов, кодов ошибок или аббревиатур.
- Длинные вопросы, требующие нескольких фактов: поиску может потребоваться декомпозиция, несколько запросов или переранжирование вместо одного запроса top-k.
- Иерархия источников: официальная действующая политика может должна иметь приоритет над более старым, но семантически более близким дискуссионным документом.
Ограничения
Примеры на Python намеренно оптимизированы для прозрачности, а не для масштаба. Поиск по ключевым словам наивен, разбиение использует длину в символах, примеры на SQLite не включают управление соединениями для продакшена, а семантический пример хранит все эмбеддинги в памяти.
Продакшен-система может требовать векторных индексов, переранжировщиков, гибридного поиска, парсеров документов, кэширования, инкрементальной индексации, версионирования источников, фильтров контроля доступа, наблюдаемости, наборов данных для оценки и обработки сбоев. Ни одно из этих дополнений не меняет базовую архитектуру; они делают каждую границу более надёжной.
RAG также не может создать доказательства, отсутствующие в наборе источников. Если источник неверен, неполон или устарел, лучшая модель эмбеддингов не сможет превратить его в авторитетное знание.
Что изменило бы этот ответ?
Архитектура меняется, когда задача требует большего, чем поиск знаний. Актуальный статус заказа требует текущего состояния. Финансовый расчёт может требовать детерминированного кода. Задача веб-исследования может требовать активного поиска. Рабочий процесс может требовать инструментов, способных записывать данные обратно в другую систему. Автономному агенту может потребоваться планирование, разрешения и контроль исполнения в дополнение к поиску.
Поэтому RAG лучше всего понимать как один слой получения доказательств внутри более крупной ИИ-системы. Он мощен именно потому, что у него узкая задача: находить полезную внешнюю информацию и помещать её в рабочий контекст модели.
Заключение
RAG становится гораздо проще понять, если убрать названия технологий. Файл — это источник. База данных — это источник. API — это источник. Функция поиска извлекает доказательства. Промпт передаёт эти доказательства модели. Затем LLM интерпретирует их и порождает текст.
Сложная часть production RAG — не вызов модели эмбеддингов. Это построение надёжного пути доказательств от исходного источника до финального утверждения: сохранение происхождения данных, выбор правильного метода извлечения, поддержание информации в актуальном состоянии, контроль доступа, оценка извлечения отдельно от генерации и понимание того, когда прямой вызов базы данных или инструмента лучше семантического поиска.
Это практическое продолжение базовой модели RAG: сначала понять роли, затем сделать путь данных явным.
Первоисточники
- Lewis et al. — Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks — статья 2020 года, вводящая формулировку RAG, которая сочетает генерацию с извлечённой непараметрической памятью.
- Sentence Transformers — Semantic Search — официальная документация по семантическому поиску, эмбеддингам запросов и эмбеддингам документов.
- OpenAI — Vector Embeddings — официальная документация, описывающая эмбеддинги как числовые представления, используемые для оценки связанности и поиска.
- SQLite — FTS5 Extension — официальная документация по полнотекстовому поиску и ранжированию BM25 в SQLite.
- OpenAI — SDKs and CLI — официальный пример Python SDK для Responses API, используемый в дополнительном примере генератора.
- What Is RAG? The Simplest Explanation of How It Works — концептуальная первая часть этой серии.
Related Articles

Google I/O 2026: Агентные продукты в Поиске, Workspace и Покупках
Google I/O 2026 показала, что агентный ИИ выходит за рамки демонстраций моделей и инструментов для разработчиков и переходит в повседневные интерфейсы продуктов. В этой статье подробно разбирается, как Search, Workspace, Gemini Spark и Universal Cart указывают на новую продуктовую модель, в которой агенты Google помогают пользователям искать информацию, работать, делать покупки и совершать действия в связанных сервисах.

Мульти-базовая архитектура с Prisma 7: Глубокое погружение для экспертов
Управление сложными ландшафтами данных требует современных архитектур. Prisma 7 предлагает расширенные функции для интеграции с несколькими базами данных и решает проблемы полиглотной персистентности.

Резервное переключение Dual-SIM на ZBT Z8102AX: что работает, чего не хватает и что требует лучшей прошивки
ZBT Z8102AX — это 5G-роутер OpenWrt с поддержкой двух SIM-карт, но одно лишь аппаратное обеспечение с поддержкой двух SIM-карт — это не то же самое, что интеллектуальное резервирование. Роутер распознает SIM-карту и успешно подключается, но автоматическое переключение, восстановление модема, решения на основе сигнала и четкая логика резервирования все еще требуют более глубокого тестирования.

Новый Qwen 3.5-Plus: Open-source ИИ — теперь всё серьезно
Откройте для себя революционные функции и преимущества Qwen 3.5-Plus от Alibaba — меняющего правила игры ИИ с открытым исходным кодом для разработчиков.

Следующий 5G-роутер OpenWrt: почему важны Wi-Fi 7, более мощный процессор и улучшенная прошивка
ZBT Z8102AX — полезный первый образец, но следующий шаг должен быть сильнее: Wi-Fi 7, более мощная четырёхъядерная платформа, лучшая ясность прошивки, улучшенная упаковка и более стабильная ценовая политика. Цель — не просто ещё один 5G-маршрутизатор, а лучше настроенное устройство на базе OpenWrt для продвинутых пользователей.

Промпт — часть предвзятости: как фрейминг ИИ формирует рассуждения
Формулировка промпта не нейтральна. Узнайте, как фрейминг, допущения, следование инструкциям и сикофантия могут формировать рассуждения ИИ — и почему для получения надежных выводов требуется тестирование за рамками исходного промпта.

Каноническая архитектура, Дизайн URL, Логика резолвера, Спецификация API и масштабируемости
Геоориентированная архитектура обнаружения для мультитенантных порталов. Определяет канонические URL-адреса, логику разрешения, стратегию кэширования и гео-модель чтения без привязки к CMS или рефакторинга базы данных. Разработано для стабильности SEO, масштабируемости и будущих расширений, таких как бронирование и карты.

Почему больше контекста может ухудшить ответы ИИ
Большее контекстное окно не гарантирует более качественного ответа. В этой статье объясняется, как размывание сигнала, противоречивые данные, устаревшее состояние, чувствительность к позиции и сжатие с потерями могут снизить надежность ИИ — и предлагается практический стресс-тест контекста.

Удаление двойных источников пакетов APT: экспертное руководство для Ubuntu и Debian
Представлена подробная инструкция по идентификации и удалению избыточных или дублирующихся источников пакетов APT в системах Debian и Ubuntu для обеспечения стабильности и производительности.

ComfyUI на Fedora 43: две виртуальные среды + запуск в один клик (март 2026)
Цель: сохранить два виртуальных окружения Python (например, 3.12 + 3.14) для совместимости, но запускать ComfyUI автоматически с чистой и легковесной конфигурацией.

Переход графического стека Ubuntu: Сбои загрузки гибридных ГПУ, Риски Wayland и Практики стабильного развертывания
Обновления рабочего стола Ubuntu могут вызывать зависания при загрузке, отсутствующие сеансы входа и нестабильный рендеринг — особенно на гибридных системах Intel + NVIDIA. В этой статье объясняется переход базового графического стека, почему возникают регрессии, и как безопасно развернуть Ubuntu, используя базовые версии LTS и проверенные стратегии драйверов.

Ollama — это не продукт: создание готовых к продакшену приложений на базе открытых LLM
Запустить локальную модель с Ollama просто. Создать готовое к продакшену Open-LLM-приложение сложнее: для этого требуются RAG, контроль доступа, абстракция провайдеров, оценка, логирование, дисциплина развертывания и контролируемый уровень приложения вокруг модели.