# RAG на .NET: архитектура, которая переживает продакшн

Разбираем, почему наивный RAG ломается на реальных данных, и строим пайплайн на .NET: чанкинг, гибридный поиск, evaluation и cost-control.

> For the index of this section of the site, see [llms.txt](https://anetlab.com/llms.txt)

28 сентября 2026 г.3 мин чтения

# RAG на .NET: архитектура, которая переживает продакшн

Разбираем, почему наивный RAG ломается на реальных данных, и строим пайплайн на .NET: чанкинг, гибридный поиск, evaluation и cost-control.

[Виктор Бузин](https://anetlab.com/about.md) · Founder & Principal Engineer, AnetLab

16+ лет в enterprise-разработке: .NET, AI/LLM-системы, RAG, MCP. Автор материала и практик в студии.

Десятки команд пытаются внедрить RAG. У половины получается демо, которое работает на десяти документах и разваливается на тысяче. Разберём, где именно ломается и как это чинить инженерно.

## Наивный RAG и почему он не работает

Классическая схема: разбить документы на чанки → эмбеддинги → векторный поиск → склеить в промпт → отдать LLM. На презентации это выглядит отлично. В проде вы получаете три класса проблем.

**Проблема первый: чанкинг.** Разрезали PDF на фиксированные 512 токенов — и половина ответов потеряла контекст. Вопрос «а какой у него SLA?» не находит ничего, потому что SLA упомянут в начале документа, а чанк с ответом — в середине.

**Проблема вторая: семантика.** Векторный поиск хорошо ловит синонимы и плохо — точные идентификаторы, артикулы, номера договоров. Вопрос «что по контракту 44-А/2024?» не найдётся, потому что эмбеддинг числа «44-А» почти не несёт смысла.

**Проблема третья: качество неизмеримо.** Команда не может ответить на вопрос «стало ли лучше после нового чанкера». Есть ощущение, что да, но это ощущение.

## Что мы делаем по-другому

### Чанкинг по структуре, а не по длине

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

В .NET это удобно делать на этапе извлечения текста: мы знаем, где заголовок, где таблица, где подпись, и режем по этим границам, а не по с512 токенов.

### Гибридный поиск

Векторный поиск **плюс** полнотекстовый. Вектор ловит смысл, FTS — точные совпадения. Объединяем через Reciprocal Rank Fusion:

```
public static IReadOnlyList<Chunk> Fuse(
    IReadOnlyList<Chunk> vectorHits,
    IReadOnlyList<Chunk> keywordHits,
    int limit)
{
    var scores = new Dictionary<string, double>();

    const double K = 60.0; // стандартный коэффициент RRF
    foreach (var (chunk, rank) in vectorHits.Select((c, i) => (c, i)))
        scores[chunk.Id] = scores.GetValueOrDefault(chunk.Id) + 1.0 / (K + rank + 1);

    foreach (var (chunk, rank) in keywordHits.Select((c, i) => (c, i)))
        scores[chunk.Id] = scores.GetValueOrDefault(chunk.Id) + 1.0 / (K + rank + 1);

    return scores
        .OrderByDescending(kv => kv.Value)
        .Take(limit)
        .Select(kv => kv.Value == null ? null : Lookup(kv.Key))
        .Where(c => c is not null)
        .Cast<Chunk>()
        .ToList();
}
```

Запрос «контракт 44-А/2024» теперь находит и по вектору, и по FTS — и RRF объединяет выдачу.

### Evaluation как обязательный шаг

Без набора вопросов с известными ответами любая оптимизация — гадание. Минимальный жизнеспособный вариант — 50–100 вопросов из реальной поддержки, покрывающих типовые сценарии.

Мы считаем четыре метрики:

| Метрика | Что показывает |
| --- | --- |
| **Recall@5** | Нашёл ли нужный документ в выдаче |
| **MRR** | Насколько высок ранжирован правильный ответ |
| **Answer faithfulness** | Не выдумала ли LLM то, чего нет в контексте |
| **Answer relevancy** | Отвечает ли на вопрос, а не на смежную тему |

Faithfulness — метрика, которую чаще всего пропускают, и именно она определяет, пойдёт ли система в прод. Модель, уверенно выдумывающая несуществующий пункт договора, хуже, чем честно сказавшая «не нашла».

### Стоимость

Два рычага: **кеш на уровне эмбеддингов** (документы меняются редко — переэмбеддинг только дельты) и **маршрутизация по сложности** (простые вопросы — дешёвая модель, сложные с рассуждением — дорогая).

На типовом проекте это даёт снижение счёта в 3–4 раза без потери качества.

## Стек

*   **.NET 10** — извлечение, чанкинг, пайплайн
*   **Semantic Kernel** — оркестрация, подключение моделей
*   **Qdrant** или **pgvector** — хранилища векторов
*   **OpenTelemetry** — трейсинг каждого шага

## Чеклист перед продом

*   [ ]  Набор из 50+ eval-вопросов из реальных обращений
*   [ ]  Recall@5 выше 0.85 на этом наборе
*   [ ]  Чанкинг по структуре, а не по фиксированному окну
*   [ ]  Гибридный поиск, а не только векторный
*   [ ]  Faithfulness замеряется, а не предполагается
*   [ ]  Кеширование эмбеддингов настроено
*   [ ]  Трейсинг каждого шага доступен в проде

Самое частое, что мы видим на аудите: пункт 7 отсутствует, и когда в проде что-то ломается, диагностировать нечем.

Если хотите обсудить свой пайплайн — напишите, разберём на конкретике.

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

20 октября 2026 г.AI/LLM

### [Оценка качества RAG на .NET: Recall@5, MRR и гейт релиза](https://anetlab.com/blog/rag-evaluation-dotnet.md)

Как измерять качество RAG на .NET: Golden Set из 50–100 вопросов, расчёт Recall@5 и MRR, измерение faithfulness и eval-как-гейт-релиза в CI.

[Читать разбор](https://anetlab.com/blog/rag-evaluation-dotnet.md)

[.NET](https://anetlab.com/blog?tag=.NET)[RAG](https://anetlab.com/blog?tag=RAG.md)[Оценка качества](https://anetlab.com/blog?tag=%D0%9E%D1%86%D0%B5%D0%BD%D0%BA%D0%B0%20%D0%BA%D0%B0%D1%87%D0%B5%D1%81%D1%82%D0%B2%D0%B0.md)

13 октября 2026 г..NET

### [.NET и Azure для AI-систем: референсная архитектура](https://anetlab.com/blog/dotnet-azure-ai-architecture.md)

Как собрать production-ready AI-систему на .NET и Azure: async-пайплайн, RAG, Polly, observability и контроль стоимости — с рабочим кодом.

[Читать разбор](https://anetlab.com/blog/dotnet-azure-ai-architecture.md)

[AI/LLM](https://anetlab.com/blog?tag=AI%2FLLM.md)[Архитектура](https://anetlab.com/blog?tag=%D0%90%D1%80%D1%85%D0%B8%D1%82%D0%B5%D0%BA%D1%82%D1%83%D1%80%D0%B0.md)[RAG](https://anetlab.com/blog?tag=RAG.md)