О насБлогКонтакты
ИИ и машинное обучение18 октября 2023 г. 5 мин 110Обновлено: 22 июня 2026 г.

RAG-архитектура: как мы заставили GPT-4 отвечать строго по базе знаний компании

AunimedaAunimeda
📋 Содержание

Клиент - юридическая компания - хотел внутреннего ассистента, который отвечает на вопросы по их процедурам, формам и нормативным инструкциям. Проблема с прямыми запросами к GPT-4: модель отвечает уверенно из обучающих данных, которые не включают проприетарные документы компании. И иногда выдумывает правдоподобно звучащие, но неверные юридические процедуры.

Retrieval-Augmented Generation (RAG) решает обе проблемы: модель отвечает только из найденных документов, и можно указать - из каких именно.


Проблема галлюцинаций и почему RAG помогает

Знания языковой модели заморожены на момент обучения. Документы, написанные в прошлом месяце, ей недоступны. При вопросах о неизвестном - модель часто генерирует убедительный, но неверный текст.

RAG разделяет поиск и генерацию:

Запрос пользователя
  → Найти: 3-5 наиболее релевантных документов из базы знаний
  → Дополнить: добавить найденные документы в промпт как контекст
  → Сгенерировать: LLM отвечает на основе предоставленного контекста, не обучающих данных

Если ответа в найденных документах нет - хорошо настроенная модель скажет «в предоставленных документах нет информации по этому вопросу» вместо того, чтобы выдумывать.


Архитектура системы

Документы (PDF, Word, HTML)
  → Извлечение текста
  → Разбивка на чанки (500 токенов с перекрытием)
  → Эмбеддинг (OpenAI text-embedding-ada-002)
  → Векторная база Pinecone

Конвейер запроса:
  Вопрос пользователя
    → Эмбеддинг вопроса (та же модель)
    → Поиск по сходству в Pinecone (топ-5 чанков)
    → Промпт: система + чанки контекста + вопрос
    → GPT-4 генерирует ответ
    → Ответ + ссылки на источники

Шаг 1: Загрузка документов

// ingestion/ingest.ts
import { OpenAI } from 'openai';
import { Pinecone } from '@pinecone-database/pinecone';
import { RecursiveCharacterTextSplitter } from 'langchain/text_splitter';
import { PDFLoader } from 'langchain/document_loaders/fs/pdf';

const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const pinecone = new Pinecone({ apiKey: process.env.PINECONE_API_KEY });

// Размер чанка важен: слишком маленький - теряем контекст,
// слишком большой - шум при поиске
const splitter = new RecursiveCharacterTextSplitter({
    chunkSize: 500,
    chunkOverlap: 100,  // Перекрытие не даёт разрезать середину предложения
    separators: ['\n\n', '\n', '. ', ' ', ''],
});

async function ingestDocument(filePath: string) {
    const fileName = path.basename(filePath);

    // Загружаем и извлекаем текст
    const loader = new PDFLoader(filePath);
    const docs = await loader.load();
    const text = docs.map(d => d.pageContent).join('\n\n');

    // Разбиваем на чанки
    const chunks = await splitter.splitText(text);
    console.log(`${fileName}: ${chunks.length} чанков`);

    const index = pinecone.index('company-knowledge-base');

    // Эмбеддим и загружаем батчами по 100
    for (let i = 0; i < chunks.length; i += 100) {
        const batch = chunks.slice(i, i + 100);

        const embeddingResponse = await openai.embeddings.create({
            model: 'text-embedding-ada-002',
            input: batch,
        });

        const vectors = batch.map((chunk, j) => ({
            id: `${fileName}-chunk-${i + j}`,
            values: embeddingResponse.data[j].embedding,
            metadata: {
                text: chunk,
                source: fileName,
                chunkIndex: i + j,
            },
        }));

        await index.upsert(vectors);
    }
}

Шаг 2: Конвейер запроса

// rag/query.ts
async function queryKnowledgeBase(question: string) {
    // 1. Эмбеддим вопрос
    const embedding = await openai.embeddings.create({
        model: 'text-embedding-ada-002',
        input: question,
    });

    // 2. Ищем похожие чанки в Pinecone
    const index = pinecone.index('company-knowledge-base');
    const results = await index.query({
        vector: embedding.data[0].embedding,
        topK: 5,
        includeMetadata: true,
    });

    // Фильтруем нерелевантные результаты (порог косинусного сходства)
    const relevant = results.matches.filter(m => (m.score ?? 0) > 0.75);

    if (relevant.length === 0) {
        return {
            answer: 'В базе знаний не найдено релевантной информации по данному вопросу.',
            sources: [],
        };
    }

    // 3. Формируем контекст из найденных чанков
    const context = relevant
        .map((chunk, i) => `[Источник ${i + 1}: ${chunk.metadata?.source}]\n${chunk.metadata?.text}`)
        .join('\n\n---\n\n');

    // 4. Генерируем ответ с GPT-4
    const completion = await openai.chat.completions.create({
        model: 'gpt-4',
        messages: [
            {
                role: 'system',
                content: `Вы ассистент юридической компании. Отвечайте на вопросы ТОЛЬКО на основе предоставленных документов.

Если в контексте недостаточно информации для ответа - скажите об этом явно. Не используйте знания из других источников.

Всегда указывайте, из какого документа взята информация.

Контекст:
${context}`,
            },
            {
                role: 'user',
                content: question,
            },
        ],
        temperature: 0.1,  // Низкая температура = детерминированность
        max_tokens: 1000,
    });

    return {
        answer: completion.choices[0].message.content ?? '',
        sources: relevant.map(chunk => ({
            source: chunk.metadata?.source as string,
            text: chunk.metadata?.text as string,
            relevance: chunk.score ?? 0,
        })),
    };
}

Что сделало систему надёжной в продакшене

Стратегия чанкинга важнее, чем кажется

Для структурированных юридических документов лучше резать по разделам:

const splitter = new RecursiveCharacterTextSplitter({
    chunkSize: 800,
    chunkOverlap: 150,
    separators: [
        '\n## ',    // Разделы H2
        '\n### ',   // Подразделы H3
        '\n\n',     // Абзацы
        '\n',
        '. ',
    ],
});

Начальный процент попаданий (нужный чанк в топ-5 результатов) был 71%. После настройки стратегии чанкинга - 89%.

Ре-ранкинг найденных чанков

Векторное сходство не идеально коррелирует с «лучший ответ на вопрос». Cohere re-ranker переупорядочивает результаты перед формированием контекста:

import { CohereClient } from 'cohere-ai';

const cohere = new CohereClient({ token: process.env.COHERE_API_KEY });

// Находим топ-10, потом ре-ранкером выбираем лучшие 5
const reranked = await cohere.rerank({
    query: question,
    documents: top10.map(c => c.metadata?.text as string),
    topN: 5,
});

Добавляет ~200ms к запросу, но заметно улучшает качество ответов.


Стоимость при реальной нагрузке

Для этого клиента (200 пользователей, ~150 запросов/день):

Компонент Стоимость/мес
OpenAI embeddings (ada-002) ~$2
GPT-4 генерация ~$45
Pinecone Starter $70
Итого ~$117

Для небольших объёмов можно заменить Pinecone на pgvector (расширение PostgreSQL) - дополнительная инфраструктура не нужна, если PostgreSQL уже используется.


Ограничения RAG

Устаревшие эмбеддинги. При обновлении документа старые векторы остаются в индексе. Нужен пайплайн: при изменении документа - удалить старые векторы, загрузить новые.

Противоречия между документами. Если два документа противоречат друг другу - модель выберет один или будет уклоняться. Решение: добавлять дату документа в метаданные и предпочитать более свежие.

Вопросы, требующие синтеза из многих источников. «Сравни все изменения в процедуре X за 3 года» - плохо работает с базовым RAG. Для этого - иерархическое суммирование или декомпозиция запроса на подзапросы.

RAG - это золотой стандарт для Q&A по корпоративной базе знаний. Быстрее, чем файнтюнинг, легче обновлять и проще аудировать - знаем точно, из каких документов сформирован ответ.

Читайте также

DeepSeek и открытые ИИ-модели: что изменилось для бизнеса в Кыргызстане в 2026aunimeda
ИИ и машинное обучение

DeepSeek и открытые ИИ-модели: что изменилось для бизнеса в Кыргызстане в 2026

В январе 2025 DeepSeek R1 вышел с качеством GPT-4 и открытым кодом. К 2026 году открытые модели изменили стоимость AI-решений для малого бизнеса. Что это значит конкретно для бизнеса в Бишкеке?

AI чатбот для сайта и бизнеса в Бишкеке: GPT, обученные боты и что реально работает в 2026aunimeda
ИИ и машинное обучение

AI чатбот для сайта и бизнеса в Бишкеке: GPT, обученные боты и что реально работает в 2026

Разбираем AI чатботы для бизнеса в Бишкеке: GPT-4 vs Gemini vs обученные боты, реальные кейсы, цены в сомах, подводные камни и когда AI чатбот окупается.

Как внедрить AI в существующий бизнес - пошаговый планaunimeda
ИИ и машинное обучение

Как внедрить AI в существующий бизнес - пошаговый план

Практический план внедрения искусственного интеллекта в бизнес без замены всего стека. С чего начать, что автоматизировать первым и как измерить эффект.

Нужна IT-разработка для вашего бизнеса?

Разрабатываем сайты, мобильные приложения и AI-решения для бизнеса в Кыргызстане. Бесплатная консультация.

Получить консультацию Все статьи