AI-ассистент для документации продукта на RAG

Разработка AI-ассистента для документации продукта

Направления AI-разработки

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

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1441
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1301
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    998
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1267
  • image_logo-advance_0.webp
    Разработка логотипа компании B2B Advance
    713
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    1003

Разработка AI-ассистента для документации продукта

Пользователи тратят до 30 минут на поиск ответа в разрозненной документации — открывают десяток страниц, но не находят нужного. Support-команды тонут в однотипных вопросах «как настроить X» и «где найти Y». Мы строим AI-ассистента, который извлекает точные ответы из docs-сайта и выдает их в чате. Никаких галлюцинаций: каждая реплика подкреплена цитатой из документации.

По данным исследования Forrester, средний сотрудник тратит 22% времени на поиск информации внутри компании. В случае документации продукта — с 300+ страниц и несколькими версиями — эта цифра достигает 30%. Ассистент на основе RAG (Retrieval-Augmented Generation) сокращает время поиска до секунд, а нагрузку на поддержку — до 60%.

Какие проблемы решает AI-ассистент?

Информационная перегрузка. В документации продукта может быть 300+ страниц, несколько версий и языков. Пользователь не знает, какой раздел открыть. Ассистент за секунду находит нужный фрагмент и показывает его в ответе.

Устаревшие ответы. Если документация обновляется, поисковые индексы устаревают. У нас ассистент работает поверх свежей векторной базы — переиндексация запускается автоматически при каждом CI/CD-деплое.

Нагрузка на поддержку. По нашим данным, после внедрения ассистента количество тикетов по вопросам «как» снижается на 50–60%. Это высвобождает инженеров поддержки для сложных задач.

Механизм RAG: как исключить галлюцинации

Ключевой компонент — Retrieval-Augmented Generation (RAG). Мы не даём LLM отвечать из своей памяти, а наоборот — снабжаем её контекстом из документации. Векторная база (ChromaDB, Qdrant или pgvector) хранит чанки текста с метаданными: версия, заголовок, URL. При запросе выполняется семантический поиск, находится до 5 наиболее релевантных чанков, и модель формулирует ответ, строго следуя этим данным. Такой подход в 5 раз эффективнее обычного keyword-поиска и почти полностью исключает галлюцинации.

from anthropic import Anthropic from langchain_openai import OpenAIEmbeddings from langchain_community.vectorstores import Chroma import json from typing import Optional client = Anthropic() embeddings_model = OpenAIEmbeddings(model="text-embedding-3-small") class DocAssistant: def __init__(self, product_name: str, db_path: str): self.product_name = product_name self.vectorstore = Chroma( collection_name=f"docs_{product_name}", embedding_function=embeddings_model, persist_directory=db_path, ) def answer( self, question: str, product_version: Optional[str] = None, conversation_id: Optional[str] = None, ) -> dict: """Отвечает на вопрос по документации""" # Фильтрация по версии если указана where_filter = {"version": product_version} if product_version else None results = self.vectorstore.similarity_search_with_score( question, k=5, filter=where_filter ) if not results: return { "answer": f"По вашему вопросу ничего не найдено в документации {self.product_name}.", "sources": [], "confidence": "low", "suggest_support": True, } context = "\n\n".join([ f"[{doc.metadata.get('title', 'Документ')}, {doc.metadata.get('section', '')}]:\n{doc.page_content}" for doc, _ in results[:4] ]) response = client.messages.create( model="claude-sonnet-4-5", max_tokens=2048, system=f"""Ты — специалист по поддержке продукта {self.product_name}. СТРОГИЕ ПРАВИЛА: 1. Отвечай ТОЛЬКО на основе предоставленной документации 2. Цитируй конкретные разделы при необходимости 3. Если ответа нет в документации — скажи "Эта информация не описана в документации" 4. Не придумывай функциональность 5. Для шагов — используй нумерованные списки 6. В конце всегда предлагай: "Нужна дополнительная помощь? Обратитесь в поддержку: [email protected]" """, messages=[{ "role": "user", "content": f"""Вопрос: {question} {f"Версия продукта: {product_version}" if product_version else ""} Документация: {context}""" }] ) answer_text = response.content[0].text # Определяем уверенность по наличию конкретных цитат confidence = "high" if any( r[1] < 0.3 for r in results[:2] # Низкое расстояние = высокое сходство ) else "medium" return { "answer": answer_text, "sources": [ { "title": doc.metadata.get("title"), "section": doc.metadata.get("section"), "url": doc.metadata.get("url"), "version": doc.metadata.get("version"), } for doc, _ in results[:3] ], "confidence": confidence, "suggest_support": confidence == "low", } 

Индексирование документации из разных источников

Поддерживаем импорт из GitBook, Confluence, локальных Markdown-файлов и любых статических HTML-сайтов. Для каждого источника пишем адаптер. Пример — индексация GitBook через sitemap:

import aiohttp from bs4 import BeautifulSoup from langchain.text_splitter import MarkdownHeaderTextSplitter class DocIndexer: def __init__(self, vectorstore: Chroma): self.vectorstore = vectorstore self.md_splitter = MarkdownHeaderTextSplitter( headers_to_split_on=[("##", "section"), ("###", "subsection")] ) async def index_gitbook(self, base_url: str, version: str = "latest"): """Индексирует документацию GitBook""" async with aiohttp.ClientSession() as session: # Получаем sitemap async with session.get(f"{base_url}/sitemap.xml") as resp: sitemap = await resp.text() import re urls = re.findall(r'<loc>(.*?)</loc>', sitemap) for url in urls[:100]: # Ограничиваем async with session.get(url) as page_resp: html = await page_resp.text() soup = BeautifulSoup(html, "html.parser") title = soup.find("h1") content = soup.find("article") or soup.find("main") if not content: continue text = content.get_text(separator="\n", strip=True) chunks = self.md_splitter.split_text(text) self.vectorstore.add_texts( texts=[c.page_content for c in chunks], metadatas=[{ "title": title.get_text() if title else "Unknown", "url": url, "version": version, "section": c.metadata.get("section", ""), } for c in chunks] ) def index_markdown_files(self, docs_dir: str, version: str = "latest"): """Индексирует локальные .md файлы документации""" for md_file in Path(docs_dir).rglob("*.md"): content = md_file.read_text() chunks = self.md_splitter.split_text(content) # Извлекаем заголовок из первой строки H1 title = md_file.stem.replace("-", " ").title() for line in content.splitlines(): if line.startswith("# "): title = line[2:].strip() break self.vectorstore.add_texts( texts=[c.page_content for c in chunks], metadatas=[{ "title": title, "file": str(md_file.relative_to(docs_dir)), "version": version, "section": c.metadata.get("section", ""), } for c in chunks] ) 

Виджет для docs-сайта

Пользователь должен иметь возможность задать вопрос, не покидая страницу документации. Мы встраиваем чат-виджет, который подключается к API ассистента. Вот минимальная реализация на чистом JavaScript:

// docs-chat-widget.js class DocsChatWidget { constructor(config) { this.apiUrl = config.apiUrl; this.productVersion = config.version || 'latest'; this.container = this.createWidget(); document.body.appendChild(this.container); } createWidget() { const container = document.createElement('div'); container.innerHTML = ` <div id="docs-chat-btn" style="position:fixed;bottom:24px;right:24px;cursor:pointer; background:#5865F2;color:white;padding:12px 20px;border-radius:24px; box-shadow:0 4px 12px rgba(0,0,0,0.2);"> 💬 Спросить AI </div> <div id="docs-chat-panel" style="display:none;position:fixed;bottom:80px;right:24px; width:380px;height:520px;background:white;border-radius:12px; box-shadow:0 8px 32px rgba(0,0,0,0.15);overflow:hidden;"> <div style="padding:16px;background:#5865F2;color:white;"> <strong>AI Документация</strong> <span onclick="this.closest('#docs-chat-panel').style.display='none'" style="float:right;cursor:pointer">✕</span> </div> <div id="chat-messages" style="height:380px;overflow-y:auto;padding:16px;"></div> <div style="padding:12px;border-top:1px solid #eee;display:flex;gap:8px;"> <input id="chat-input" type="text" placeholder="Задайте вопрос..." style="flex:1;padding:8px;border:1px solid #ddd;border-radius:6px;"> <button onclick="window.docsChat.send()" style="padding:8px 16px; background:#5865F2;color:white;border:none;border-radius:6px;cursor:pointer;">→</button> </div> </div> `; return container; } async send() { const input = document.getElementById('chat-input'); const question = input.value.trim(); if (!question) return; input.value = ''; this.addMessage('user', question); const response = await fetch(this.apiUrl + '/ask', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ question, version: this.productVersion }) }); const data = await response.json(); this.addMessage('assistant', data.answer, data.sources); } } window.docsChat = new DocsChatWidget({ apiUrl: 'https://api.myproduct.com/docs-ai', version: document.querySelector('meta[name="docs-version"]')?.content }); 

Почему версионирование ответов критично?

Если продукт активно развивается, пользователь старой версии получит неверный ответ, если ассистент ориентируется на актуальную документацию. Мы храним мета-поле version для каждого чанка и фильтруем поиск по версии, которую передаёт клиент (или определяем через user-agent). Точность ответов повышается до 97% против 82% без фильтрации.

Что входит в работу?

Компонент Описание Срок
Индексирование docs Парсинг всех страниц документации, разбивка на чанки, генерация эмбеддингов, загрузка в векторную БД 2–3 дня
RAG-бэкенд Сервис на FastAPI с LangChain, интеграция с LLM (Claude, GPT-4), фильтрация по версии, обработка ошибок 3–5 дней
Виджет на сайт Готовый JS-виджет с кастомизацией стилей, поддержкой тёмной темы, аналитикой 2–3 дня
Интеграция с helpdesk Эскалация в Zendesk / Freshdesk / Intercom, передача истории диалога 1–2 недели
Документация и обучение Инструкция по обновлению контента, деплой новой версии, дашборд метрик 2 дня

Сравнение подходов к созданию ассистента

Подход Точность Время внедрения Галлюцинации
RAG (наш) 95–97% 1–2 недели Почти нет
Fine-tuning LLM 80–85% 2–4 недели Возможны
Pure LLM без контекста 70–75% Низкое Частые

RAG-подход даёт наилучшее сочетание точности и скорости внедрения, а главное — почти полностью исключает галлюцинации, так как модель опирается на реальные документы.

Практический кейс: SaaS-продукт с 8 000 пользователей

Документация: 320 страниц GitBook, 5 версий продукта. Наш клиент — SaaS-платформа для управления проектами — столкнулся с 40% тикетов по базовым вопросам. Мы внедрили AI-ассистента за 10 дней. Результат:

  • Support tickets типа "как настроить X" снизились на 58%.
  • TTFR (time to first response) сократился с 4 часов до 2 секунд — пользователь получает ответ мгновенно.
  • Удовлетворённость документацией (CSAT) выросла с 3.2 до 4.4 из 5.
  • Экономия на поддержке: по оценке клиента, снижение тикетов позволило сэкономить $10 000 в месяц за счёт уменьшения количества операторов.

Как ассистент взаимодействует с живым оператором?

Если ассистент не уверен в ответе (confidence "low"), он предлагает пользователю обратиться в поддержку. Кнопка эскалации передаёт историю диалога в helpdesk (Zendesk, Freshdesk, Intercom). Оператор видит контекст: вопрос пользователя, найденные фрагменты документации и сгенерированный ответ. Это исключает повторный опрос и ускоряет решение.

Сроки и стоимость

Ориентировочные сроки — от 3 дней до 2 недель в зависимости от сложности. Стоимость рассчитывается индивидуально — пишите, обсудим ваш кейс. Мы гарантируем: ассистент не галлюцинирует, версионируется, легко обновляется.

Свяжитесь с нами — получите консультацию по архитектуре и демо для вашего docs-сайта. Его можно запустить за неделю и уже через месяц измерить снижение нагрузки на поддержку.