Как создать базу знаний RAG с любого веб-сайта 2026
TL;DR
Полезная база знаний RAG начинается с чистых, прослеживаемых исходных документов, а не с модели встраивания. Сохраняйте канонический URL, заголовок, время обхода, заголовки и хэш содержимого с каждым кусочком.
Конвейер — это обход → нормализация → удаление дубликатов → разбиение → встраивание → хранение → извлечение → ответ с ссылками. Оценивайте каждую границу независимо, чтобы ошибки извлечения не принимались за ошибки модели.
Markdown — это практический формат обмена для внедрения веб-сайтов. Он устраняет много навигационного шума, сохраняя структуру заголовков, которая может направлять семантическое разбиение.
Используйте Nstproxy Crawl, когда вам нужно отрендеренное содержимое веб-сайта без поддержки браузеров и прокси-оркестрации. Пример ниже использует его текущий маршрут сканирования, а затем демонстрирует базовый уровень локального извлечения без зависимостей.
Система генерации, дополняемой данными, столь же надежна, как и доказательства, которые она может извлечь. Если взаимодействие с веб-сайтом сохраняет баннеры cookie, повторную навигацию, устаревшие копии и фрагменты без метаданных источника, более мощная языковая модель не сможет восстановить отсутствующую подлинность.
Этот учебник создает небольшой, проверяемый пайплайн и показывает, где производственные системы нуждаются в более мощных компонентах. Он использует локальную базу хешированных векторов, чтобы логика извлечения могла работать с стандартной библиотекой Python. Замените эту базу на производственную модель встраивания и векторный индекс после того, как будут настроены контракты на данные.
Что нужно пайплайну Crawl-for-RAG?
Пайплайну crawl-for-RAG нужны шесть свойств: охват, чистый контент, стабильная идентичность, полезная сегментация, извлекаемые векторы и ответы, основанные на источниках. Скорость имеет значение, но полнота и прослеживаемость имеют большее значение.
Минимальная запись для каждой извлеченной страницы должна содержать:
Поле
Почему это важно
source_url
Позволяет ответу ссылаться на доказательства
canonical_url
Предотвращает дублирование параметров URL
title и заголовки
Улучшает отображение и семантические границы
crawled_at
Поддерживает актуальность политики
content_hash
Обнаруживает неизмененный или дублирующийся контент
markdown
Предоставляет нормализованный текст со структурой
http_status
Разделяет недоступные страницы от пустых извлечений
контекст локали/доступа
Объясняет региональные или языковые различия
Nstproxy Crawl может преобразовать URL в форматы, такие как Markdown и JSON, при обработке инфраструктуры рендеринга. Это не заменяет вашу политику базы знаний: ваше приложение все равно должно решать, какие пути разрешены, как часто они обновляются и что квалифицируется как принятый документ.
Перед индексацией проверьте правила сайта и вашу авторизацию. Протокол исключения роботов определяет, как краулеры обнаруживают инструкции robots.txt, но соблюдение стандартов роботов — лишь одна часть юридической и контрактной проверки. См. юридическое руководство Nstproxy по веб-скрапингу для более обширного контрольного списка.
Шаг 1: Определите объем и проиндексируйте веб-сайт
Начните с карты сайта, известного корневого документации или отобранного семени URL. Добавьте явные правила разрешения и запрета. Для сайта документации вы можете разрешить /docs/ и исключить страницу входа, поиска, пагинацию изменения и параметры запросов, а также загружаемые бинарные файлы.
Живой API Nstproxy в настоящее время принимает запросы на аутентифицированное скрапирование по указанному ниже маршруту. Маршрут был проверен для достижения аутентификации 3 сентября 2026 года; успешный ответ не удалось протестировать без ключа аккаунта. Подтвердите поля запроса в текущей документации по скрапингу перед использованием в производстве.
Храните необработанный ответ перед нормализацией. Сохранение необработанных данных делает обновления парсера воспроизводимыми и дает вам доказательства, когда правило извлечения изменяется. Никогда не фиксируйте ключи API, cookies или личные данные с аутентифицированных страниц.
Если вы выбираете между методами обнаружения, прочитайте скрапинг против индексации. Скрапинг одного известного URL подходит для целевых обновлений; индексация подходит, когда обнаружение ссылок является частью работы.
Шаг 2: Нормализуйте и устраните дубликаты перед встраиванием
Нормализация должна удалять повторяющуюся навигацию, текст внизу страницы, уведомления о cookies, невидимые элементы управления и пустые заголовки, не уплощая значимую структуру документа. Markdown помогает, потому что заголовки, списки, код и ссылки сохраняются в компактной форме. CommonMark предоставляет полезную базу для последовательного парсинга Markdown.
Идентичность контента: хешируйте нормализованный текст тела, чтобы обнаружить зеркальные или параметризованные дубликаты.
Не отклоняйте каждый близкий дубликат без разбора. Документация по продукту может повторять общую информацию, но содержать разные процедуры. Точные хеши безопасны для точного дублирования; нечёткое сходство должно дать предметы для проверки.
Свежесть должна быть в том же контракте. Храните crawled_at, подсказки модификаций источника, когда это возможно, и версию извлекателя. При обновлении повторно встраивайте только измененные фрагменты и удаляйте векторы для удаленных страниц.
Шаг 3: Разделение по смыслу, а не по произвольным количествам символов
Фрагмент должен быть достаточным, чтобы ответить на один вероятный вопрос, и достаточно малым, чтобы извлекать точно. Начните с сегментов, учитывающих заголовки, затем разбивайте длинные разделы на абзацы или предложения. Прикрепите заголовки навигации к каждому дочернему фрагменту.
Практическая начальная политика такова:
разбивайте на границах H2/H3;
ориентируйтесь на примерно 300–700 токенов на фрагмент;
сохраняйте фрагменты кода и таблицы целыми, когда это возможно;
добавляйте небольшой перекрытие только между действительно непрерывным текстом;
добавьте название страницы и путь заголовков к встроенному тексту;
храните неизмененный отображаемый текст отдельно.
Нет универсально лучшего размера фрагмента. Оценивайте по реальным вопросам. Если ответы требуют фактов, разбросанных по длинной процедуре, извлекайте соседние фрагменты или используйте извлечение родитель-дитя вместо создания каждого фрагмента огромным.
Шаг 4: Встраивайте, храните и извлекайте исполняемую локальную базу
Следующий скрипт реализует полную локальную механику только с помощью стандартной библиотеки Python. Он использует детерминированный хэшированный мешок слов — не семантическое встраивание. Это ограничение сделано намеренно: вы можете запускать поток данных локально, проверять записи SQLite и позже заменять только embed().
import hashlib
import json
import math
import re
import sqlite3
from datetime import datetime, timezone
DIMENSIONS =256defnormalize(text:str)->str: text = re.sub(r"\r\n?","\n", text) text = re.sub(r"[ \t]+"," ", text) text = re.sub(r"\n{3,}","\n\n", text)return text.strip()defchunk_markdown(markdown:str, max_words:int=90): chunks, heading,buffer=[],"",[]for line in normalize(markdown).splitlines():if line.startswith("#"):ifbuffer: chunks.append((heading,"\n".join(buffer)))buffer=[] heading = line.lstrip("# ")else:buffer.append(line)iflen(" ".join(buffer).split())>= max_words: chunks.append((heading,"\n".join(buffer)))buffer=[]ifbuffer: chunks.append((heading,"\n".join(buffer)))return[(h, t.strip())for h, t in chunks if t.strip()]defembed(text:str): vector =[0.0]* DIMENSIONS
for token in re.findall(r"[a-z0-9]+", text.lower()): slot =int(hashlib.sha256(token.encode()).hexdigest()[:8],16)% DIMENSIONS
vector[slot]+=1.0 length = math.sqrt(sum(x * x for x in vector))or1.0return[x / length for x in vector]defcosine(a, b):returnsum(x * y for x, y inzip(a, b))defingest(db, url, title, markdown): cleaned = normalize(markdown) page_hash = hashlib.sha256(cleaned.encode()).hexdigest() crawled_at = datetime.now(timezone.utc).isoformat() db.execute("DELETE FROM chunks WHERE source_url = ?",(url,))for index,(heading, text)inenumerate(chunk_markdown(cleaned)): embedding_text =f"{title}\n{heading}\n{text}" db.execute("INSERT INTO chunks VALUES (?, ?, ?, ?, ?, ?, ?)",(url, title, heading, index, text, json.dumps(embed(embedding_text)),f"{page_hash}:{crawled_at}"),) db.commit()defsearch(db, question, limit=3): query_vector = embed(question) rows = db.execute("SELECT source_url, title, heading, body, vector FROM chunks").fetchall() ranked =[(cosine(query_vector, json.loads(vector)), url, title, heading, body)for url, title, heading, body, vector in rows
]returnsorted(ranked, reverse=True)[:limit]db = sqlite3.connect(":memory:")db.execute("""CREATE TABLE chunks (
source_url TEXT, title TEXT, heading TEXT, chunk_index INTEGER,
body TEXT, vector TEXT, version TEXT
)""")sample ="""# Acme Docs
## Authentication
Отправьте API-ключ в заголовке Authorization. Никогда не раскрывайте ключ в клиентском коде.
## Retries
Повторно попытайтесь ограничить частоту с экспоненциальной задержкой и джиттером. Не пытайтесь повторить недействительные учетные данные.
"""ingest(db,"https://example.com/docs","Acme Docs", sample)for score, url, title, heading, body in search(db,"Как мне справиться с ограничениями частоты?"):print(f"{score:.3f}\t{heading}\t{url}\t{body}")
Скрипт был выполнен локально с использованием Python 3 с включенным иллюстративным документом. Он поставил раздел “Повторные попытки” на первое место для вопроса об ограничениях частоты. Это подтверждает, что хранилище и извлечение фрагментов подключены; это не подтверждает семантическое качество на реальном корпусе.
Для производства замените локальную векторную функцию на API встраивания и замените линейный поиск на векторный индекс. pgvector добавляет точный и приближенный векторный поиск в PostgreSQL; управляемые векторные базы данных — еще один вариант. Сохраняйте одни и те же метаданные независимо от движка хранения.
Шаг 5: Генерируйте Ответы ТОЛЬКО На Основе Извлеченных Доказательств
Передайте лучшие фрагменты модели ответов с URL-адресами источников и строгой инструкцией: отвечайте на основе предоставленного контекста, ссылайтесь на утверждения и указывайте, когда доказательства недостаточны. Не позволяйте модели тихо подменять общие знания недостающим контентом сайта.
Надежный этап ответов должен:
применять абсолютный порог релевантности, а не просто «топ три»;
разнообразить результаты, чтобы одна дублированная страница не занимала каждое место;
включать соседние фрагменты для процедур;
фильтровать по арендатору, местоположению, версии продукта и контролю доступа;
указывать канонический URL-адрес рядом с каждым поддерживаемым утверждением;
регистрировать ID извлеченных фрагментов для последующей оценки.
Перенумерация может повысить точность после первоначального векторного извлечения. Гибридный поиск — семантические векторы плюс баллы ключевых слов — особенно полезен для кодов ошибок, названий продуктов и точных параметров API.
Руководство Nstproxy по веб-поиску MCP-сервера предлагает связанный контекст для подключения живых веб-доказательств к AI-агентам. Фиксированная база знаний и живой поиск решают разные проблемы: первая контролируемая и быстрая, в то время как последняя может обнаруживать новые страницы.
Шаг 6: Оцените Конвейер От Начала До Конца
Составьте набор вопросов из реальных заявок поддержки, заголовков документации и известных случаев сбоя. Для каждого вопроса укажите ожидаемую страницу источника и содержит ли корпус ответ.
Измерьте по крайней мере:
покрытие обходом: ожидаемые страницы успешно приняты;
задержка новизны: время от изменения источника до обновления, доступного для поиска;
вызов извлечения: ожидаемые доказательства появляются в наборе кандидатов;
точность цитирования: указанные страницы действительно поддерживают ответ;
качество воздержания: система отказывается, когда данные отсутствуют.
Отладка в таком порядке. Если правильная страница никогда не была проинспектирована, настройка встраиваний — это напрасные усилия. Если правильный фрагмент был извлечен, но ответ его игнорирует, измените подсказку или этап модели.
Общие Ошибки При Вводе RAG
Наиболее распространенная ошибка — встраивание необработанного HTML. Это заполняет индекс меню, текстами скриптов и повторяющимся контентом шаблонов. Другие дорогостоящие ошибки включают разбивку на фрагменты до дедупликации, потерю путей заголовков, пропуск канонических URL, обновление всего корпуса вместо измененных страниц и разрешение на поиск удаленного контента.
Безопасность также важна. Не используйте обход частных страниц в общий индекс, если извлечение не обеспечивает модель авторизации источника. Обращайтесь с извлеченным текстом как с ненадежным вводом: он может содержать инъекции запроса, нацеленные на последующих агентов. Держите системные инструкции отдельно и ограничьте возможности инструментов во время ответа.
Перед запуском подтвердите, что каждый фрагмент имеет канонический источник, путь заголовка, временную метку обхода, версию и хеш содержимого. Проверьте распространение удаления, фильтры доступа, лимиты повторных попыток, наблюдаемость и задокументированную политику обновления. Храните небольшой золотой набор вопросов в CI, чтобы изменения парсера или модели не могли тихо снизить качество извлечения.
Обходчик — это первый компонент, но он задает потолок для всего, что идет вниз по цепочке. Чистый, версионированный Markdown плюс явные ворота качества обеспечивают встраивание и этапы ответов доказательствами, которые они действительно могут использовать.