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

Проектируем и внедряем системы искусственного интеллекта: от прототипа до production-ready решения. Наша команда объединяет экспертизу в машинном обучении, дата-инжиниринге и MLOps, чтобы AI работал не в лаборатории, а в реальном бизнесе.
Показано 1 из 1 услугВсе 1566 услуг
Разработка AI-ассистента для документации продукта
Средняя
~1-2 недели
Часто задаваемые вопросы
Направления AI-разработки
Этапы разработки AI-решения
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1218
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    853
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1047
  • image_logo-advance_0.png
    Разработка логотипа компании B2B Advance
    561
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    825

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

AI-ассистент для продуктовой документации позволяет пользователям получать ответы на вопросы о продукте вместо поиска в разрозненных docs-сайтах. Ключевые требования: точные цитаты из документации (не галлюцинации), версионирование (ответ должен соответствовать версии продукта пользователя), возможность эскалации к поддержке.

Специфика документационного ассистента

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",
        }

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

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-сайта

// 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
});

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

Документация: 320 страниц GitBook, 5 версий продукта.

Результат:

  • Support tickets типа "как настроить X": -58%
  • TTFR (time to first response): мгновенно vs 4 часа
  • Удовлетворённость документацией (CSAT): 3.2 → 4.4

Сроки

  • Базовый RAG + индексирование docs: 3–5 дней
  • Виджет для docs-сайта: 2–3 дня
  • Версионирование + мультиязычность: 1 неделя
  • Интеграция с helpdesk: 1 неделя