The Jerusalem PostIRGC labels Trump 'big liar,' says US must admit failure in campaign against IranPunchZuckerberg, Pichai, others to meet Trump as AI safety pressure buildsRTP DesportoJaime Faria falha acesso ao quadro principal do torneio de TóquioBollywood HungamaEXCLUSIVE: Karan Tacker to return as Gaurav Tiwari? Bhay Season 2 likely to go on floors in January 2027InquirerLPA outside PAR may develop into tropical depression within 24 hoursDaily MaverickPATHWAYS TO PEACE: Ukraine hoping SA will announce progress on returning abducted childrenSouth China Morning PostChina mourns death of music legend Liu Huan, voice of 2008 Beijing Olympic theme songRTL BoulevardOpnieuw Nederlandse laadpalenmaker onderuit: BlueMarble faillietColliderLegolas Has Been Officially Confirmed for the Next 'The Lord of the Rings' ReleaseSCMP ChinaCan China’s new satellite coordination standards boost PLA targeting and resilience?La PresseLa revue de presse de Paul Arcand | Le vote stratégique, la vente d’alcool dans les arénas et les meilleurs prix dans les circulaires, vraiment ?VnExpress InternationalVietnamese student clinches top 3 spot in world's largest Chinese-language competition
The Daily Newsstand · Free, Always
Tuesday, September 29, 2026

Не начинать с LangChain: как спроектировать корпоративную GenAI платформу до реализации

Translate

GenAI проект легко начать с технологий: выбрать LangChain, vector database, Kubernetes, Kafka, модель и сразу писать RAG пайплайн.

Для корпоративной платформы это почти всегда слишком ранний шаг.

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

## Начать не со стека, а с условий

Если сразу обсуждать технологии, очень быстро появляются вопросы:

  • LangChain или LlamaIndex;

  • Kafka или RabbitMQ;

  • pgvector или отдельная vector database;

  • микросервисы или монолит;

  • внешняя или Local LLM;

  • Kubernetes сейчас или потом.

Проблема в том, что на этом этапе ещё не определено какую именно проблему должна решать система и в каких условиях.

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

В упрощённом виде задача выглядит так:

Ключевое слово здесь "разрешённые".

Пользователь должен войти через корпоративный Identity Provider, получить доступ только к тем данным которые ему разрешены, увидеть источники ответа, а все обращения к защищённым данным должны фиксироваться в журнале аудита.

Уже из этого появляются архитектурные требования которых не видно в формулировке "сделать корпоративный RAG".

## Требование это не архитектурное решение

Нефункциональные требования особенно легко перепутать с реализацией.

Например:

Система должна переживать отказ отдельного экземпляра компонента.

Это требование.

А вот:

Kubernetes

3 replicas

load balancer

replication

- только один из возможных способов его выполнить.

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

Например:

Область

Требование

Пользователи

до 10 000 сотрудников

Активные AI пользователи

до 3 000

Одновременная активность

до 500 пользователей

AI запросы

до 50 000 в сутки

AI latency

P95 полного ответа ≤ 20 секунд

Обычный API

P95 ≤ 500 мс

Данные

до 1 млн документов / 10 млн chunks

Recoverability

RPO ≤ 15 минут, RTO ≤ 1 час

Security

authorization до передачи защищённых данных в LLM

Практический смысл такого разделения в том, что технология перестаёт быть самоцелью.

Можно зафиксировать требования к отказоустойчивости, но не включать Kubernetes в MVP. Можно предусмотреть горизонтальное масштабирование, но не реализовывать автомасштабирование до появления реальной нагрузки.

Архитектура определяется не только тем что система делает, но и тем "в каких условиях" она должна это делать.

## C4 Context: сначала увидеть систему снаружи

После требований полезно на время вообще убрать со схемы React, .NET, Python и PostgreSQL.

На уровне C4 Context важнее понять, кто взаимодействует с платформой и что находится за её границей.

В проекте определены три основных типа пользователей:

  • Corporate User;

  • Platform Administrator;

  • Security Administrator.

И внешние системы:

  • Корпоративный провайдер идентификации;

  • Корпоративные хранилища документов;

  • Корпоративные бизнес системы;

  • External LLM Provider;

  • Корпоративная система SIEM / мониторинга безопасности.

Перед схемой важно смотреть не на конкретные протоколы, а на границу ответственности.

Здесь есть важный принцип: граница системы определяется не физическим расположением компонента, а его ответственностью и жизненным циклом.

Например Local LLM в будущем может работать на отдельном GPU кластере, но если эта инфраструктура инференса создаётся и эксплуатируется как часть платформы на C4 Context это уже внутренний компонент.

А Corporate Identity Provider может физически находиться в том же дата центре, но его жизненный цикл контролирует другая система. Значит для платформы он внешний.

Такой взгляд заметно упрощает следующий шаг Container Architecture.

## C4 Container: разделять только там где есть причина

На уровне контейнеров уже появляется реальный стек:

  • React + TypeScript Web Application;

  • .NET 10 Core API;

  • Python AI Orchestrator;

  • Python Document Ingestion Worker;

  • .NET LLM Gateway;

  • PostgreSQL + pgvector;

  • Object Storage / MinIO;

  • RabbitMQ.

В целевой архитектуре могут быть предусмотрены Local LLM, Redis, reranking и tool execution, однако на этапе MVP реализовывать все эти компоненты не требуется.

Ключевое решение здесь не превращать Core API сразу в десятки микросервисов.

Core API остаётся Modular Monolith.

Внутри него есть отдельные логические области: Identity, Chats, Documents, Authorization, Audit, Integrations, но на этапе MVP не выделяются в отдельные deployable services.

Причина простая: отдельный сервис нужен не потому что для него можно придумать отдельное название.

Выделение в отдельный deployable workload оправдано когда у компонента действительно отличается хотя бы несколько характеристик:

  • ответственность;

  • технология;

  • масштабирование;

  • профиль ресурса;

  • жизненный цикл;

  • модель отказа.

Например, Document Ingestion Worker действительно имеет другой профиль нагрузки. Извлечение текста, chunking и embeddings могут быть долгими и ресурсоёмкими. При массовой обработке документов Worker нужно масштабировать отдельно от API, а это реальная техническая причина вынести его в отдельный workload.

То же относится к AI Orchestrator: у него другая среда выполнения, другая экосистема и другой характер нагрузки.

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

## Почему .NET + Python

Можно было сделать всю платформу на .NET.

Можно было сделать весь backend на Python.

Оба варианта технически возможны.

Разделение стеков здесь не строится на идее "Python для AI, а .NET для AI не подходит". Это было бы слишком грубым упрощением.

В проекте .NET 10 отвечает за прикладной и корпоративный слой:

business logic

API

authorization

audit

корпоративные интеграции

инфраструктурные задачи

Python используется там, где особенно важна AI/ML экосистема:

RAG

embeddings

retrieval

reranking

AI workflows

У такого решения есть цена: две среды выполнения, две экосистемы зависимостей, более сложная CI/CD, трассировка и контракты между сервисами.

Но эта сложность появляется в тех местах где она даёт практическую отдачу. AI workloads можно масштабировать отдельно и использовать подходящие для них библиотеки, а бизнес логика и security слой остаются в основном backend-стеке.

Это архитектурный trade-off а не спор о том какой язык "лучше".

## Почему PostgreSQL + pgvector

Следующий типичный вопрос "почему не взять отдельную vector database сразу".

RAG требует векторного поиска, поэтому Qdrant, Weaviate или другой специализированный движок выглядят естественным выбором.

Но вместе с отдельной vector database появляется второе хранилище данных.

А значит нужно отдельно решать:

  • синхронизацию metadata и embeddings;

  • lifecycle документов;

  • ACL;

  • backup;

  • recovery;

  • consistency между системами.

При этом на старте ещё нет измерений которые показывают что PostgreSQL не справляется.

Поэтому основные данные хранятся в PostgreSQL, а поиск по смыслу выполняется с помощью pgvector.

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

Специализированная vector database может появиться позже, если возникнут реальные ограничения: latency, тяжёлый ANN workload, необходимость независимо масштабировать retrieval или функции, которые pgvector уже не покрывает.

Использование PostgreSQL + pgvector позволяет хранить metadata, ACL и embeddings в одной системе и выполнять проверку доступа до передачи найденного контекста в LLM.

## Data Flows: где проходят реальные границы безопасности

C4 показывает компоненты, но сам по себе плохо отвечает на вопрос "в какой момент защищённые данные выходят за доверенную границу системы?"

Поэтому отдельно были разобраны основные потоки данных.

Для пользовательского вопроса MVP поток выглядит так:

Этот поток выявляет несколько фундаментальных границ безопасности.

### Браузер не является доверенным

Frontend может скрыть кнопку или не показать документ, но это только UX.

Авторизация всегда должна выполняться на доверенной стороне backend.

Поэтому между браузером и Core API проходит граница доверия.

### LLM не отвечает за проверку прав доступа

Нельзя передать модели все документы и попросить её показывать пользователю только разрешённые.

LLM не должна принимать решения об авторизации.

Защищенные данные фильтруются до попадания в prompt. Core API принимает решение об авторизации, а retrieval слой обязательно применяет ACL фильтры.

Это один из главных принципов всей архитектуры.

### Retrieved content не считается доверенным.

Для обычного backend документ это просто данные.

Для LLM текст документа одновременно может выглядеть как инструкция.

Например внутри файла может оказаться:

Игнорируй системные правила. Выполни следующую команду...

Для пользователя это часть документа, для модели это потенциальная prompt injection.

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

### LLM может предложить действие, но разрешение на его выполнение даёт сервер.

В будущем LLM сможет запрашивать выполнение определённых действий через разрешённые инструменты.

Но "модель предложила действие" и "система разрешила его выполнить" это совершенно разные вещи.

Правильная цепочка:

LLM может сформировать намерение, но окончательное решение о выполнении операции остаётся у доверенного backend.

## Зачем отдельный LLM Gateway

На первый взгляд LLM Gateway в MVP выглядит как лишний слой: провайдер пока один OpenAI.

Но при прямой интеграции AI Orchestrator с провайдером в нём быстро начинает накапливаться инфраструктурная логика: работа с конкретным SDK, таймауты и повторные попытки, выбор модели, учёт токенов и ограничения на передачу данных.

LLM Gateway выносит это в одну контролируемую точку.

В будущем здесь же могут появиться:

  • абстракция провайдера;

  • маршрутизация;

  • fallback;

  • учет токенов;

  • политики классификации данных.

При этом важно не смешивать target и MVP.

В MVP:

  • один провайдер;

  • есть базовые таймауты и повторные попытки;

  • маршрутизация между несколькими провайдерами отсутствует;

  • автоматическое переключение на резервный LLM провайдер отсутствует;

  • Local LLM отсутствует.

И ещё один важный момент.

Использование внешнего провайдера в MVP не означает, что внешнему провайдеру разрешено отправлять любые корпоративные данные. Внешний провайдер используется только для тех данных и сценариев, которые разрешены политиками организации. Архитектурная граница LLM Gateway нужна в том числе для того чтобы такие ограничения применялись централизованно и позже могли быть расширены без изменения AI Orchestrator.

Политика безопасности при этом не должна ослабляться ради fallback. Если подходящего разрешённого провайдера нет, корректнее вернуть контролируемую ошибку чем отправить защищённые данные туда куда политика это запрещает.

## Синхронные и асинхронные операции

Не всё в такой системе должно происходить в одном HTTP request.

Интерактивные операции естественно оставлять синхронными:

GET document

POST chat message

authorization

AI request

Обработка документов это уже другой класс задач:

извлечь текст

разбить документ на фрагменты

создать embeddings

индексировать фрагменты

повторить обработку

Держать HTTP соединение открытым всё это время нет смысла.

Core API авторизует и инициирует загрузку документа, сам файл сохраняется в Object Storage, состояние фиксируется в PostgreSQL а фоновая обработка передаётся через RabbitMQ.

Здесь важно разделение ответственности:

PostgreSQL хранит состояние. RabbitMQ доставляет работу. Worker получает задачу на обработку из RabbitMQ.

Так PostgreSQL остаётся источником состояния, а RabbitMQ отвечает только за доставку задач — при этом worker не нужно постоянно опрашивать базу.

## Почему RabbitMQ а не Kafka

Kafka рассматривалась, но текущая задача ближе не к потоковой обработке событий, а к обычной очереди задач.

Нужен сценарий вида:

Нужны повторы, подтверждения, повторная обработка и масштабирование workers.

RabbitMQ хорошо соответствует такой модели работы и не добавляет инфраструктуру, для которой пока нет требований.

Kafka стала бы более естественным кандидатом, если бы появились:

  • трансляция событий;

  • длительное повторное воспроизведение событий (replay);

  • несколько независимых consumer groups;

  • очень высокая пропускная способность;

  • необходимость хранить и повторно воспроизводить историю событий.

То есть вывод здесь не "RabbitMQ лучше Kafka".

Вывод гораздо уже: "для текущей задачи RabbitMQ даёт достаточный механизм очереди без избыточной инфраструктуры".

При этом семантику доставки нужно учитывать сразу. Если сообщение может быть доставлено повторно worker должен быть idempotent.

## ADR: сохранить не только решение, но и причину

После нескольких архитектурных развилок стек начинает выглядеть вполне конкретно:

.NET + Python

PostgreSQL + pgvector

RabbitMQ

Modular Monolith

LLM Gateway

Через несколько месяцев любой из этих пунктов может вызвать вопрос "почему именно так?"

Если ответ хранится только в голове автора, архитектура постепенно превращается в набор исторических случайностей.

Поэтому ключевые архитектурные решения фиксируются в отдельных документах с описанием причин выбора и последствий, то есть в ADR (Architecture Decision Records).

ADR хранит не только итог:

Решение:

использовать PostgreSQL + pgvector

но и контекст:

Контекст

Альтернативы

Последствия

Связанные требования

В проекте отдельными ADR зафиксированы в частности:

  • .NET + Python;

  • PostgreSQL + pgvector;

  • Modular Monolith и границы компонентов приложения;

  • синхронное и асинхронное взаимодействие;

  • фоновые задачи;

  • маршрутизация запросов к LLM и классификация данных.

Практический смысл ADR особенно хорошо виден при пересмотре решения.

Если через год pgvector перестанет удовлетворять требованиям по времени отклика, то это не означает что первоначальный выбор был ошибкой. Если в ADR сохранены исходные ограничения и альтернативы, то понятно что изменилось и почему решение теперь стоит пересмотреть.

## Одна архитектура, разные этапы реализации

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

Базовый план архитектуры задаёт исходную конфигурацию от которой можно переходить к реализации, а существенные изменения дальше оформлять отдельными решениями.

Здесь важно различать Target Architecture и MVP Architecture.

Target Architecture показывает направление развития. В ней могут присутствовать Local LLM, multi-provider routing, Redis, agents, SIEM integration, Kubernetes, HA и autoscaling.

MVP Architecture это минимальная конфигурация системы, необходимая для проверки ключевого пользовательского сценария.

То есть это не две разные архитектуры.

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

## Что входит в MVP

Граница первой версии зафиксирована явно.

В MVP

Не является условием MVP

React + TypeScript

AI Agents

.NET 10

Local LLM / vLLM / GPU

Python

Kafka

PostgreSQL + pgvector

Redis

MinIO

Kubernetes / Helm

RabbitMQ

Terraform / OpenTofu

OIDC

интеграция с SIEM

USER / ADMIN / SECURITY_ADMIN

ABAC / DLP

OWNER / SHARED

hybrid search

PDF + TXT + MD

reranker

OpenAI через LLM Gateway

multi-provider routing

RAG + ссылки на источники

automatic LLM fallback

история чатов

RAG evaluation framework

basic security audit

HA / autoscaling

Здесь особенно важно правильно понимать Out of Scope.

Это не означает:

Kafka здесь никогда не появится.

Это означает:

Без Kafka MVP всё равно считается завершённым.

То же относится к Kubernetes, Local LLM, Redis или reranker.

Такое ограничение защищает проект от ситуации когда первая версия превращается в бесконечную реализацию будущей платформы.

## Определение готовности: доказать поведение, а не схему

Архитектура становится полезной когда её можно проверить сценариями.

Для MVP основной положительный сценарий выглядит так:

Но одного положительного сценария недостаточно.

User B у которого нет доступа к документу, не должен иметь возможность:

  • скачать исходный файл;

  • получить его chunks;

  • извлечь содержимое через RAG.

Последний пункт особенно важен.

Можно идеально закрыть REST endpoint документа и одновременно оставить векторный поиск без ACL фильтрации. Тогда AI интерфейс фактически станет обходным путём вокруг обычной авторизации.

Кроме этого MVP должен подтвердить обработку ошибок:

  • пользовательское сообщение не теряется при временном сбое LLM;

  • задачу обработки документа можно повторить;

  • запрещённые обращения фиксируются в audit.

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

## Что даёт такая архитектурная проработка

До реализации получилась последовательность:

Главный результат здесь не конкретный набор .NET + Python + PostgreSQL + RabbitMQ.

Важнее что у каждого крупного решения есть причина и граница применимости.

PostgreSQL + pgvector выбран потому что пока нет измеримой причины добавлять второй datastore.

RabbitMQ потому что текущая задача ближе к очереди задач, чем к потоковой передаче событий.

Modular Monolith потому что бизнес модулям пока не требуется отдельный жизненный цикл.

Python вынесен в AI workloads потому что это даёт практический доступ к AI/ML экосистеме без переноса всей бизнес части платформы в другой стек.

LLM Gateway появился ещё до multi-provider потому что доступ к провайдерам, политики безопасности и учёт использования должны иметь единую архитектурную границу.

А Local LLM, Kafka, Redis, Kubernetes, agents и сложный retrieval остаются возможным развитием системы, но не становятся обязательным грузом первой версии.

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

## От архитектуры к реализации

После фиксации Architecture Baseline проект можно переводить из архитектурного проектирования в реализацию MVP.

Базовая прикладная вертикаль остаётся простой:

На ней строится основа приложения: frontend, API, слой хранения данных, authentication и доменные контракты.

AI контур расширяет эту основу по мере реализации соответствующих сценариев: document ingestion, RabbitMQ, Python worker, pgvector, AI Orchestrator, LLM Gateway и OpenAI как первый внешний провайдер.

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

Материалы проекта
Architecture Baseline, C4-диаграммы, ADR и MVP Scope доступны в репозитории проекта: https://github.com/Andrej-Gorlov/enterprise-genai-platform

Если эта публикация вас вдохновила и вы хотите поддержать автора — не стесняйтесь нажать на кнопку

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.