Вход на сайт

Просмотр новости

Найдите то, что Вас интересует

RAG-бот для любого сайта на Python за 60 строк кода

Дата публикации: 26-08-2026 15:06:00

Соберите простого RAG-бота на Python, который читает любую веб-страницу и отвечает на вопросы только по её тексту. Гайд с кодом и объяснениями.— Читать дальше «RAG-бот для любого сайта на Python за 60 строк кода»

Основное содержимое страницы с новостью.

Если попросить языковую модель ответить по свежей документации или конкретному сайту, она с блеском выдумает то, чего там нет. Стандартное решение — Retrieval-Augmented Generation (RAG): сначала достать реальный текст, найти в нём нужные куски и только потом передать их модели в качестве контекста.

В этой статье соберём работающего RAG-бота, который отвечает на вопросы о любой веб-странице, примерно на 60 строках Python. Никаких парсеров HTML, headless-браузеров и сложных фреймворков — только requests, локальная Ollama и чистый Markdown.

RAG (retrieval-augmented generation) — это подход, при котором языковая модель не отвечает по своей памяти, а сначала ищет релевантные фрагменты во внешнем тексте, а потом генерирует ответ на их основе. Это резко снижает галлюцинации и позволяет работать с данными, которых не было в обучающей выборке.

Ключевые выводы

  • RAG-бот на Python укладывается в ~60 строк и работает без облачных LLM.
  • Самое неприятное в RAG-пайплайне — очистка HTML; готовый Markdown API убирает эту работу.
  • Текст разбивается на чанки (~1200 символов), каждый превращается в эмбеддинг и сравнивается с эмбеддингом вопроса.
  • Локальные модели nomic-embed-text и llama3 через Ollama не требуют иностранных карт и VPN.
  • Качество ответа зависит от качества исходного текста: сырой HTML зашумляет поиск, чистый Markdown улучшает ретривл.
Что мы соберём

Архитектура бота простая и универсальная:

  1. Отправляем URL в сервис извлечения текста и получаем чистый Markdown.
  2. Разбиваем Markdown на фрагменты (чанки) по границам абзацев.
  3. Превращаем каждый чанк в вектор — эмбеддинг.
  4. То же самое делаем с вопросом пользователя.
  5. Находим чанки, ближайшие к вопросу, по косинусной близости.
  6. Отдаём найденные фрагменты + вопрос языковой модели с инструкцией отвечать только по контексту.

Такая схема легко масштабируется: можно заменить локальную Ollama на OpenAI, Anthropic или российские модели, а векторы перенести в Qdrant или Chroma.

Что понадобится
  • Python 3.9+
  • Библиотека requests
  • Локально запущенная Ollama с моделями nomic-embed-text и llama3
  • Доступ к API извлечения текста (в примере — Web to Markdown/JSON API; бесплатный тариф даёт 50 запросов в сутки)
Код бота

Сохраните скрипт как rag_bot.py и подставьте свой ключ, если сервис извлечения текста требует авторизации:

			import requests

# URL сервиса, который превращает произвольную веб-страницу в Markdown
API_URL = "https://web2md-api-production-d822.up.railway.app/extract"
OLLAMA = "http://localhost:11434"  # REST API Ollama


def fetch_markdown(url: str) -> dict:
    """Получить очищенный Markdown по URL."""
    r = requests.post(
        API_URL,
        json={"url": url, "format": "markdown", "max_length": 50000},
        # headers={"X-RapidAPI-Key": "ВАШ_КЛЮЧ"},  # если требуется
    )
    r.raise_for_status()
    return r.json()


def chunk_markdown(md: str, max_chars: int = 1200) -> list[str]:
    """Разбить Markdown на чанки по границам абзацев."""
    paragraphs = [p.strip() for p in md.split("\n\n") if p.strip()]
    chunks, current = [], ""
    for p in paragraphs:
        if len(current) + len(p) > max_chars and current:
            chunks.append(current)
            current = p
        else:
            current = f"{current}\n\n{p}" if current else p
    if current:
        chunks.append(current)
    return chunks


def embed(text: str) -> list[float]:
    """Получить эмбеддинг текста из Ollama."""
    r = requests.post(
        f"{OLLAMA}/api/embeddings",
        json={"model": "nomic-embed-text", "prompt": text},
    )
    r.raise_for_status()
    return r.json()["embedding"]


def cosine(a: list[float], b: list[float]) -> float:
    dot = sum(x * y for x, y in zip(a, b))
    na = sum(x * x for x in a) ** 0.5
    nb = sum(y * y for y in b) ** 0.5
    return dot / (na * nb) if na and nb else 0.0


def answer(chunks: list[str], question: str) -> str:
    """Найти релевантные чанки и ответить через LLM."""
    q_emb = embed(question)
    ranked = sorted(chunks, key=lambda c: cosine(embed(c), q_emb), reverse=True)
    context = "\n\n".join(ranked[:3])

    prompt = (
        "Ответь на вопрос, используя ТОЛЬКО приведённый ниже контекст. "
        "Если в контексте нет ответа, так и скажи.\n\n"
        f"Контекст:\n{context}\n\n"
        f"Вопрос: {question}\nОтвет:"
    )
    r = requests.post(
        f"{OLLAMA}/api/generate",
        json={"model": "llama3", "prompt": prompt, "stream": False},
    )
    r.raise_for_status()
    return r.json()["response"]


if __name__ == "__main__":
    data = fetch_markdown("https://en.wikipedia.org/wiki/Retrieval-augmented_generation")
    print(f"Извлечено: {data['title']} ({data['word_count']} слов)")

    chunks = chunk_markdown(data["content"])
    question = "Как RAG снижает галлюцинации языковых моделей?"
    print("Ответ:", answer(chunks, question))
		
На что обратить внимание:
Если вы используете RapidAPI-версию сервиса, запрос к API_URL обычно требует заголовка X-RapidAPI-Key. Без ключа бесплатный endpoint может вернуть 401.
Разбор по частям

fetch_markdown — единственный внешний вызов. Сервис сам забирает страницу, убирает навигацию, баннеры и футер и возвращает Markdown: заголовки, абзацы, списки. Это освобождает от зависимостей вроде BeautifulSoup или headless Chrome.

chunk_markdown режет текст на фрагменты примерно по 1200 символов, не разрывая абзацы. Мелкие чанки дают более точный ретривл, но увеличивают число эмбеддингов; для начала 1200 символов — хороший баланс.

embed и cosine превращают текст в векторы и считают их близость. Модель nomic-embed-text из Ollama бесплатна, быстрая и неплохо понимает русский и английский.

answer эмбеддит вопрос, выбирает три самых похожих чанка и строит промпт с жёстким ограничением: отвечать только по контексту. Это главная страховка от галлюцинаций.

Запуск

Установите зависимости и скачайте модели в Ollama:

			pip install requests
ollama pull nomic-embed-text
ollama pull llama3
python rag_bot.py
		

Если всё в порядке, в консоли появится примерно такой результат:

			Извлечено: Retrieval-augmented generation (1500 слов)
Ответ: RAG снижает галлюцинации, опирая ответы модели на извлечённые документы...
		
Почему важен чистый Markdown

Если скормить эмбеддинг-модели сырой HTML, в векторах окажутся теги <div>, меню навигации и копирайты из футера. В результате поиск похожести выдаст «Copyright © 2026» вместо полезного ответа. Чистый Markdown — заголовки, абзацы, списки — улучшает качество ретривла почти бесплатно.

Если не хочется зависеть от внешнего API, можно заменить fetch_markdown на один из альтернативных вариантов:

  • trafilatura — библиотека на Python для извлечения главного текста.
  • r.jina.ai/http://URL — бесплатный сервис без ключа.
  • Firecrawl — API с поддержкой сканирования сайтов целиком.
  • ScrapingBee — прокси + рендеринг для сложных страниц.

Для российских разработчиков локальная Ollama особенно удобна: модели качаются бесплатно, не нужны иностранные карты, а инференс идёт на своём железе.

Куда развивать
  • Направьте бота на документацию, чейнджлог или блог конкурента и задавайте вопросы по ним.
  • Замените Ollama на OpenAI, Anthropic, Gemini или российские модели — функция answer меняется в двух строках.
  • Сохраняйте эмбеддинги в векторную БД: Chroma, Qdrant или FAISS, чтобы индексировать сразу много страниц.
  • Используйте формат json вместо Markdown, если нужна структура: параграфы, заголовки, ссылки — отдельно.

Часто задаваемые вопросы

1

Что такое RAG простыми словами?

RAG — это подход, при котором языковая модель перед ответом ищет релевантные фрагменты во внешнем документе. Это помогает ей отвечать по свежим или специфическим данным, а не по обучающей выборке.

2

Можно ли обойтись без внешнего API для извлечения текста?

Да. Вместо Web to Markdown/JSON API можно использовать библиотеку trafilatura, сервис r.jina.ai или написать собственный парсер на BeautifulSoup. Главное — получить чистый текст без навигации и рекламы.

3

Почему для эмбеддингов и ответов используется Ollama?

Ollama запускает модели локально, бесплатно и без облачных API-ключей. Для учебных и pet-проектов этого достаточно, а при необходимости легко перейти на коммерческий провайдер.

4

Как повысить качество ответов?

Три очевидных рычага: улучшить очистку текста, подобрать размер чанков и увеличить число релевантных фрагментов в промпте. Также помогает явная инструкция модели отвечать только по контексту.

5

Какие сайты подходят для такого бота?

Подходят любые текстовые страницы: статьи, документация, справочники, блоги. Сложности возникают со страницами, где весь контент загружается JavaScript, или с капчами — там нужен рендеринг и прокси.

Выводы

RAG — не магия, а последовательность простых шагов: получить чистый текст, разрезать его на фрагменты, найти ближайшие к вопросу и отдать их модели. Весь минимальный пайплайн укладывается в короткий Python-скрипт, который можно запустить на своём ноутбуке.

RAG работает ровно так хорошо, каков текст, который вы ему скармливаете. Уберите самую утомительную часть — очистку HTML, — и останется интересное: поиск и генерация.

bao001 xiaoавтор туториала на DEV Community

Исходник идеи — статья «Chat With Any Website: Build a RAG Bot in ~60 Lines of Python». Попробуйте собрать бота на своей странице и посмотрите, где он справляется, а где начинает фантазировать.

Схожие новости

#Наименование новостиТональностьИнформативностьДата публикации
1Ваши open source-контрибьюторы теперь ИИ-first. Как не утонуть в потоке агентских пулреквестов011.919-08-2026
2Как написать отчёт по практике с помощью ИИ и готовых промптов?5702-07-2026
3ИИ для автоматизации РКО. Как финансовые организации сокращают расходы и убирают ручной ввод документов5701-07-2026
4Fine-tuning LLM в 2026: гид по LoRA, QLoRA и полному дообучению0725-06-2026
5Распознавание документов в браузере с оценкой качества изображения: пошаговая интеграция05.526-08-2026
6Как мы детектили фрод, а получили Джонни и Джулию: история одной браузерной разминки04.7517-08-2026
7Как мы создаём аналог Vercel, Render, Railway, Netlify и PythonAnywhere04.1627-08-2026
8Собери программиста в отпуск: игра-квест от Тproger09.8421-08-2026
97 стратегий модернизации легаси: что рефакторить, переносить, заменять или переписывать04.425-08-2026
10Пошаговые диалоги в Python без боли: описываем визарды в JSON, а не в if-ах010.6521-04-2026

Классификация: Мнения. Схожих патентов: 0. Схожих новостей: 10. Тональность: 0. Информативность: 14.5. Источник: tproger.ru.