Изучаем новый шаблон ИИ-чата .NET AI Chat Web App
|
В .NET появилось интересное обновление - новый шаблон ИИ-чата под названием .NET AI Chat Web App. Когда я впервые наткнулся на анонс этого шаблона, то сразу понял, что Microsoft наконец-то среагировала на взрывной рост популярности чат-интерфейсов после успеха ChatGPT. Суть шаблона проста - он предоставляет готовый каркас для создания веб-приложения с чат-интерфейсом, работающим на основе больших языковых моделей (LLM). Как разработчик, который не раз сталкивался с необходимостью интеграции ИИ в свои проекты, могу сказать, что появление подобного шаблона - отличная новость. Раньше приходилось собирать подобные решения буквально по кирпичикам, а теперь у нас есть структурированный подход. Почему Microsoft вообще решила создать такой шаблон? Думаю, причин несколько. Во-первых, нельзя отрицать, что ChatGPT и подобные ему системы произвели настоящую революцию в представлении людей о том, каким должно быть взаимодействие с компьютером. Чат-интерфейсы стали не просто модной фишкой, а реальным инструментом решения задач. Во-вторых, Microsoft активно инвестирует в OpenAI и другие ИИ-технологии, так что им выгодно облегчать разработчикам доступ к этим инструментам. Шаблон позволяет быстро выбрать провайдера языковой модели (GitHub Models, OpenAI, Azure OpenAI или Ollama для локального запуска) и хранилище векторных вложений (локальное на основе JSON, Azure AI Search или Qdrant в Docker-контейнере). Это дает гибкость при выборе инфраструктуры - можно начать с бесплатных или локальных решений, а потом легко перейти на более мощные облачные сервисы. Любопытно, что шаблон использует технику RAG (Retrieval-Augmented Generation) - это когда ИИ не просто генерирует ответы из своей "внутренней памяти", а опирается на конкретные документы, которые мы ему предоставляем. Такой подход позволяет создавать более надежные и контролируемые чат-системы, которые не будут выдумывать факты. Первое впечатление: устанавливаем и запускаем приложениеИтак, давайте установим этот новый шаблон. Процесс оказался проще, чем я ожидал - достаточно выполнить одну команду в терминале:
aichatweb. Помимо этого, в выводе указывается, что шаблон поддерживает C# и использует теги Common/AI/Web/Blazor/.NET Aspire. Теперь самое интересное - выбор конфигурации шаблона. Здесь нам нужно определиться с тремя ключевыми аспектами:1. Использовать ли Aspire? Я выбрал "да", потому что Aspire - это новый подход Microsoft к разработке облачных приложений, и он значительно упрощает конфигурацию и запуск. 2. Какого провайдера LLM использовать? На выбор предлагаются: - GitHub Models (бесплатный вариант для разработчиков), - OpenAI (требует платного аккаунта), - Azure OpenAI (требует подписку Azure), - Ollama (локальный запуск на вашей машине). Я остановился на GitHub Models - это самый быстрый способ начать работу без дополнительных затрат. 3. Какое векторное хранилище использовать для данных: - Local (простой JSON-файл на диске), - Azure AI Search (автоматизированное управление данными в облаке), - Qdrant (векторная база данных в Docker-контейнере). Для начала я выбрал локальное хранилище - оно идеально подходит для прототипирования. Создаем проект с помощью команды:
В корне решения также находится файл README.md с инструкциями по дальнейшей настройке. Для нашей конфигурации нужно только настроить GitHub Models. Чтобы получить токен GitHub Models, я перешел на страницу github.com/marketplace/models, выбрал модель из выпадающего списка, нажал на "Get developer key", создал новый токен без дополнительных разрешений. Обратите внимание, что с мая 2025 года для токенов GitHub Models требуется разрешение model:read, так что будьте внимательны при создании токена.Полученный токен нужно добавить как строку подключения в проект Aspire AppHost. Я использовал команду:
После этого запускаем приложение, выполнив запуск проекта Aspire AppHost. Первый запуск может занять некоторое время, так как приложение выполняет "заглатывание" (ingestion) PDF-файлов, которые по умолчанию находятся в каталоге контента. И вот, перед нами появляется стандартный интерфейс чата, очень похожий на ChatGPT или GitHub Copilot Chat. Можно задавать вопросы о содержимом загруженных PDF-файлов, и ассистент отвечает на них, ссылаясь на конкретные места в документах. Конвертирование web app(jquery mobile) в mobile app(Android/IOS) Ошибка import App from './app.vue' - net::ERR_ABORTED 404 Изучаем ASP.NET VS 2008, C#: 1 Error. Constructor on type 'App.App.Forms.FormBase' not found. в FormDerived [Design] Разбираем структуру проекта и базовые компонентыТеперь, когда у нас есть рабочее приложение, давайте заглянем под капот и разберем его архитектуру. После создания шаблона у нас получилось решение с тремя основными проектами. Открыв его в IDE, я увидел следующую структуру:
В проекте AppHost определяется общая конфигурация приложения. Это центральное место, где регистрируются все сервисы и их зависимости. Заглянув в Program.cs этого проекта, можно увидеть всю архитектуру на ладони:
1. Строка подключения к OpenAI (GitHub Models). 2. База данных SQLite, которая используется как кэш для обработаных документов. 3. Веб-приложение, которое зависит от предыдущих двух компонентов. Метод WaitFor() гарантирует, что приложение не стартанет, пока база данных не будет инициализирована. Это простое решение распространенной проблемы с порядком запуска компонентов.ServiceDefaults - это проект, который содержит общие настройки для всех сервисов в приложении. Обычно тут находятся конфигурации логирования, трассировки, метрик и прочих кросс-функциональных аспектов. Теперь перейдем к самому интересному - проекту Web. Это Blazor Server приложение, в котором реализована вся логика чат-бота. Ключевые компоненты: 1. Components/Pages/Chat.razor - основной интерфейс чата. 2. Components/Pages/Index.razor - стартовая страница. 3. Data/ - папка с моделями данных и сервисами доступа к данным. 4. wwwroot/Data/ - папка с PDF-файлами для обработки. 5. Services/ - сервисы для работы с ИИ и векторными хранилищами. Изюминка приложения - это способ, которым оно обрабатывает PDF-документы. Для этого используется класс DataIngestor, который извлекает текст из документов, создает эмбеддинги (векторные представления текста) с помощью языковой модели и сохраняет их в векторном хранилище.
PDFDirectorySource - это класс, который умеет читать PDF-файлы из указаной директории и преобразовывать их в текст. Стоит отметить, что приложение не просто хранит текст целиком, а разбивает его на параграфы и создает эмбеддинги для каждого параграфа. Это позволяет потом эффективно искать релевантные фрагменты текста для ответов на вопросы пользователя.Весь этот механизм основан на концепции RAG (Retrieval-Augmented Generation), которая стала стандартом для систем, работающих с документами. Суть в том, что мы не полагаемся только на "знания", заложеные в модель, а обогащаем их конкретными данными из наших документов. Конфигурация приложения через appsettings.json и секреты разработчикаЛюбое серьезное приложение требует гибкой конфигурации, и наш ИИ-чат не исключение. Разбирая файлы проекта, я обнаружил стандартный для .NET Core подход - использование appsettings.json для хранения настроек. В appsettings.json веб-проекта находятся базовые настройки логирования, но самое интересное - отсутствие каких-либо ключей API или конфиденциальных данных. И это правильно! Никогда не стоит хранить секретные ключи в открытом виде в репозитории - это классическая ошибка безопасности, которую я сам не раз наблюдал в проектах начинающих разработчиков. Вместо этого шаблон активно использует механизм секретов разработчика (User Secrets). Если вы помните, при настройке GitHub Models мы добавляли ключ API через команду:
%APPDATA%\Microsoft\UserSecrets\<user_secrets_id>\secrets.json, а для Linux и macOS - ~/.microsoft/usersecrets/<user_secrets_id>/secrets.json. Идентификатор секретов (user_secrets_id) указывается в файле проекта .csproj в элементе <UserSecretsId>. В нашем шаблоне уже настроена эта интеграция, что избавляет нас от лишних телодвижений.Интересно, что в Aspire-приложении секреты, добавленые в проект AppHost, автоматически передаются в зависимые сервисы. Это можно увидеть в коде AppHost, где строка подключения openai добавляется к веб-приложению:
IConfiguration, что и настройки из appsettings.json, и код приложения работает одинаково независимо от источника данных.Помимо ключа API для ИИ-сервиса, в конфигурации приложения есть несколько интересных параметров, которые можно настроить через appsettings.json или переменные среды:
Если вы захотите изменить модель, используемую для генерации эмбеддингов или для чата, это можно сделать в файле Program.cs веб-проекта:
Архитектура решения: как устроен чат изнутриЗаглянув глубже в архитектуру нашего чат-приложения, я обнаружил ряд интересных решений, которые стоит разобрать. В основе шаблона лежит несколько ключевых компонентов, образующих гибкую и расширяемую систему. Веб-приложение, созданное по шаблону, представляет собой Blazor Server, но с особым акцентом на интеграцию с искуственным интеллектом. Если разбить его на функциональные части, получится примерно такая картина: 1. Клиент чата для ИИ-моделей - обертка над API провайдера, которая абстрагирует работу с конкретной моделью и предоставляет унифицированный интерфейс для общения с ней. В нашем случае это GitHub Models, но архитектура позволяет легко заменить его на другого провайдера. 2. Генератор эмбеддингов - компонент, преобразующий текст в числовые векторы, которые отражают семантическое значение текста. Это критически важная часть системы, так как именно эмбеддинги позволяют искать релевантные фрагменты текста при ответе на вопросы. 3. Векторное хранилище - отвечает за хранение и поиск по эмбеддингам. В случае локального хранилища это просто JSON-файл, но интерфейс IVectorStore позволяет подключить любую другую реализацию.4. Кэш обработки данных - реализованный через EF Core `DbContext`, который отслеживает, какие документы были обработаны и превращены в эмбеддинги. Это позволяет избежать повторной обработки и ускоряет перезапуск приложения. 5. Инжестор данных - компонент, который извлекает текст из документов, создает эмбеддинги и сохраняет их в векторном хранилище. Его особенность в том, что он работает с абстракцией IIngestionSource, которая может быть реализована для разных типов документов.6. Компонент семантического поиска - связующее звено между пользовательским запросом и хранилищем эмбеддингов. Он преобразует вопрос пользователя в эмбеддинг и ищет наиболее релевантные фрагменты в векторном хранилище. 7. Пользовательский интерфейс чата - Blazor-компонент, который отображает сообщения и обрабатывает ввод пользователя. Ключевая особенность архитектуры - это то, как организовано взаимодействие с языковой моделью. Вместо того чтобы позволить модели самостоятельно генерировать ответы, шаблон реализует подход RAG, где модель получает доступ к локальной базе знаний через специальную функцию поиска. Анализ основных классов и их взаимодействияПогружаясь в исходный код шаблона, я выделил несколько ключевых классов, которые формируют его ядро. Понимание их взаимодействия даст нам полную картину того, как работает приложение. Начнем с класса DataIngestor - он стоит в сердце процесса подготовки данных. Его конструктор принимает четыре зависимости:
Основной метод класса - IngestDataAsync, который принимает источник данных (IIngestionSource) и выполняет всю работу по обработке документов. Здесь прослеживается четкое разделение ответственности: DataIngestor не знает, откуда берутся документы - он просто знает, как их обработать. Сам источник данных представлен интерфейсом IIngestionSource, который определяет методы для получения списка документов и создания записей для них. В шаблоне есть реализация PDFDirectorySource, которая умеет читать PDF-файлы, но вы можете создать свою реализацию для любого другого типа данных.Особый интерес представляет класс SemanticSearch, который используется для поиска релевантных фрагментов текста:
IVectorStore абстрагирует работу с хранилищем векторов и определяет операции для получения "коллекций" векторов, их создания, удаления и поиска. В шаблоне есть реализация JsonVectorStore, которая хранит векторы в JSON-файле, но в реальных проектах вы, скорее всего, захотите использовать специализированую векторную базу данных.Отдельно стоит отметить класс IngestionCacheDbContext - это стандартный EF Core `DbContext`, который хранит метаданные об обработаных документах. Его структура проста:
Chat.razor, который взаимодействует с IChatClient для отправки сообщений и получения ответов. Интересно, что этот компонент настраивает языковую модель на использование специальной функции поиска:
Паттерны проектирования в действииИзучая исходный код шаблона .NET AI Chat Web App, я обнаружил ряд классических паттернов проектирования, которые делают архитектуру гибкой и расширяемой. Microsoft явно уделила внимание не только функциональности, но и качеству кода, что в долгосрочной перспективе критически важно для любого проекта. Первый и самый очевидный паттерн - Внедрение зависимостей (Dependency Injection). Он пронизывает весь шаблон и является краеугольным камнем архитектуры. Взгляните на конструктор DataIngestor:
Следующий паттерн, который сразу бросается в глаза - Стратегия (Strategy). Он реализован через интерфейсы IIngestionSource, IVectorStore и IEmbeddingGenerator. Каждый из этих интерфейсов может иметь несколько реализаций, и клиентский код не зависит от конкретной реализации. Например, для извлечения данных из документов шаблон использует PDFDirectorySource, но вы легко можете создать свою реализацию для работы с веб-страницами, базами данных или любыми другими источниками. Аналогично, JsonVectorStore можно заменить на QdrantVectorStore или AzureAISearchVectorStore без изменения остального кода.Мне также понравилось использование паттерна Репозиторий (Repository) для работы с векторным хранилищем. Интерфейс IVectorStore абстрагирует операции CRUD и поиска, скрывая детали реализации:
AIFunctionFactory.Create() для создания функций, которые может вызывать ИИ:
В шаблоне также прослеживается паттерн Медиатор (Mediator), где Chat.razor выступает в роли центрального компонента, координирующего взаимодействие между пользовательским интерфейсом и различными сервисами.С точки зрения архитектурных паттернов, шаблон явно следует принципу Разделения ответственности (Separation of Concerns). Каждый компонент имеет четко определеную роль: DataIngestor отвечает за обработку документов, SemanticSearch занимается поиском релевантных фрагментов, IngestionCacheDbContext отслеживает состояние обработки, Chat.razor управляет пользовательским интерфейсом, Такое разделение делает код понятным и упрощает его поддержку. Интересно, что в шаблоне также прослеживается подход, похожий на CQRS (Command Query Responsibility Segregation) - разделение операций чтения и записи. Запись (обработка документов) происходит асинхронно при старте приложения, а чтение (поиск релевантных фрагментов) - во время обработки запросов пользователя. Отдельно хочу отметить использование Unit of Work в связке с Entity Framework Core для отслеживания обработаных документов. Это позволяет эффективно управлять транзакциями и сохранять согласованность данных. Все эти паттерны вместе создают гибкую и расширяемую архитектуру, которая может адаптироваться к различным сценариям использования. Радует, что Microsoft не пошла по пути простейшего решения, а создала действительно продуманный шаблон, который может служить основой для серьезных проектов. Интеграция с AI-сервисами: настройка и конфигурацияНастройка интеграции с AI-сервисами оказалась одним из самых интересных аспектов работы с шаблоном. Микрософт тут действительно постаралась создать унифицированную абстракцию для взаимодействия с различными провайдерами ИИ. В файле Program.cs веб-проекта можно найти основную конфигурацию для работы с провайдером искуственного интеллекта. Для GitHub Models (который мы выбрали в нашем примере) настройка выглядит следующим образом:
AddAzureOpenAIClient. Это связано с тем, что GitHub Models внутри работает через Azure OpenAI Service, просто предоставляет к нему бесплатный доступ для разработчиков.Интересная особенность - настройка модели разделена на две части: клиент чата ( AddChatClient) и генератор эмбеддингов (AddEmbeddingGenerator). Это дает возможность использовать разные модели для разных задач, что может быть критично с точки зрения оптимизации затрат и производительности. Метод UseFunctionInvocation() особенно заинтересовал меня. Он активирует возможность вызова функций из языковой модели - то есть модель может не просто генерировать текст, а выполнять определенные действия в вашем приложении. В нашем случае это функция поиска по обработаным документам.Если вы захотите использовать другого провайдера, настройка будет немного отличаться. Например, для "классического" OpenAI:
Важно понимать, что при использовании разных провайдеров меняются не только строки подключения, но и доступные модели. Например, если вы используете Ollama, вам доступны только те модели, которые вы скачали локально. А при использовании Azure OpenAI, вам нужно сначала развернуть модели в вашем ресурсе Azure. Внутри шаблона все эти различия скрыты за единым интерфейсом IChatClient, который обеспечивает унифицированный способ взаимодействия с разными моделями. Это прекрасный пример паттерна Стратегия в действии.Работа с OpenAI API и альтернативными провайдерамиГлубже погрузившись в механизмы работы с различными провайдерами ИИ, я обнаружил, что шаблон предоставляет действительно гибкую абстракцию. Давайте разберем, как именно происходит взаимодействие с OpenAI API и другими провайдерами на уровне кода. В основе всего лежит пакет Microsoft.Extensions.AI.OpenAI, который предоставляет обертку над официальным SDK от OpenAI. Если заглянуть в файл .csproj веб-проекта, можно увидеть зависимости от нескольких пакетов:
Microsoft.Extensions.AI.Abstractions. Это позволяет менять провайдеров без изменения основного кода. Основной интерфейс для взаимодействия с языковыми моделями - IChatClient. Он определяет метод GetChatCompletionsAsync, который принимает сообщения и возвращает ответ модели. Есть также асинхронная версия с потоковой передачей ответа - GetStreamingChatCompletionsAsync. При работе с OpenAI вызовы API происходят примерно так:
С Ollama дела обстоят немного иначе. Этот провайдер запускает модели локально, что дает преимущества в приватности и отсутствии интернет-зависимости, но ограничивает выбор доступных моделей. Для его использования требуется запущеный Docker-контейнер:
Что касается выбора конкретного провайдера, тут стоит руководствоваться несколькими критериями:
В целом, шаблон предоставляет исключительно гибкий механизм для работы с различными провайдерами ИИ, позволяя сосредоточиться на бизнес-логике, а не на деталях интеграции. Абстракция провайдеров и создание единого интерфейса для разных AI-сервисовОдна из самых сильных сторон шаблона .NET AI Chat Web App - это продуманная система абстракций для различных AI-провайдеров. В процессе изучения кода я был приятно удивлен, насколько элегантно Microsoft решила проблему переключения между разными сервисами искуственного интеллекта. Вся эта магия происходит благодаря пакету Microsoft.Extensions.AI.Abstractions, который определяет ключевые интерфейсы для взаимодействия с языковыми моделями. Основные абстракции, которые я обнаружил в коде:
Для реализации этих интерфейсов в шаблоне используются различные провайдеры. Например, для OpenAI это OpenAIChatClient и OpenAIEmbeddingGenerator, для Ollama - аналогичные классы из пакета Ollama. Но благодаря DI-контейнеру клиентский код никогда не взаимодействует с этими конкретными реализациями напрямую. Регистрация этих сервисов происходит через методы расширения, которые добавляют удобный флюент-интерфейс:
Любопытная деталь: реализации интерфейсов для разных провайдеров могут иметь свои особенности и ограничения. Например, не все провайдеры поддерживают вызов функций или работу с определеными типами эмбеддингов. Шаблон решает эту проблему через механизм "возможностей" (capabilities), который позволяет клиентскому коду проверять, доступна ли та или иная функциональность. Если вы хотите добавить поддержку нового провайдера, вам нужно реализовать эти базовые интерфейсы для вашего сервиса и зарегистрировать их в DI-контейнере. Это делает шаблон невероятно расширяемым - вы можете добавить поддержку любого ИИ-сервиса, даже того, который еще не существовал на момент создания шаблона! Эта система абстракций - пример того, как грамотное применение паттерна "Стратегия" и принципа инверсии зависимостей из SOLID может сделать код не только более гибким, но и готовым к будущим изменениям в ландшафте ИИ-технологий. Управление контекстом диалога и мониторинг расходов APIОдин из ключевых вопросов, который меня всегда беспокоит при работе с ИИ-системами - как эффективно управлять контекстом диалога и не разориться на API-запросах. В шаблоне .NET AI Chat Web App эти аспекты продуманы достаточно хорошо. Начнем с контекста диалога. Если заглянуть в компонент Chat.razor, можно увидеть, что история сообщений хранится в простом списке:
Однако тут есть подводный камень - чем длиннее становится диалог, тем больше токенов отправляется при каждом запросе. А больше токенов - значит больше денег! В реальных проектах я обычно реализую "скользящее окно" для истории сообщений, оставляя только N последних сообщений или ограничивая общее количество токенов. В текущей версии шаблона такой механизм не реализован явно, но его легко добавить. Примерно так:
В рабочих проектах я часто добавляю прокси-слой между приложением и API, который ведет точный учет использованых токенов и стоимости каждого запроса. Это можно реализовать, создав декоратор для IChatClient:
Фронтенд и пользовательский интерфейсПерейдем к анализу пользовательского интерфейса шаблона. Как я уже упоминал, фронтенд построен на Blazor Server - технологии, которая позволяет создавать интерактивные веб-приложения с использованием C# вместо JavaScript. Такой подход дает несколько интересных преимуществ для чат-приложения. Центральный компонент интерфейса - Chat.razor, расположенный в директории Components/Pages. Его структура достаточно проста и интуитивно понятна:
displayMessages. Каждое сообщение получает свой CSS-класс в зависимости от роли (пользователь или ассистент), что позволяет визуально различать их в интерфейсе.Во-вторых, обратите внимание на (MarkupString)FormatMessage(msg.Content) - этот код преобразует обычный текст в HTML-разметку. Это позволяет языковой модели возвращать форматированный текст, например, с выделением, списками или даже цитатами из найденых документов. Для обработки потоковых ответов от ИИ используется интересный механизм. Вместо того чтобы ждать полного ответа, шаблон показывает ответ постепенно, по мере его получения:
Стоит отметить и индикатор загрузки ( isLoading), который блокирует отправку новых сообщений во время ожидания ответа. Это простое, но важное решение для UX, которое предотвращает отправку нескольких сообщений подряд.В шаблоне также есть адаптивный дизайн, который хорошо работает как на десктопе, так и на мобильных устройствах. Стили определены в файле wwwroot/css/chat.css и используют современные подходы к верстке с применением flexbox.Blazor-компоненты для чата и обработка потоковых ответовУглубившись в изучение фронтенд-части шаблона, я обнаружил несколько интересных Blazor-компонентов, которые заслуживают отдельного разбора. Кроме основного компонента Chat.razor, там есть еще несколько вспомогательных, которые вместе создают удобный пользовательский опыт.Одним из таких компонентов является MessageRenderer.razor, который отвечает за правильное отображение разных типов сообщений:
Обработка потоковых ответов реализована особенно интересно. В шаблоне используется метод GetStreamingChatCompletionsAsync, который возвращает не просто строку, а IAsyncEnumerable<ChatStreamingResponse>. Это позволяет обрабатывать ответ модели по частям, по мере его поступления:
InvokeAsync(StateHasChanged) после обновления ответа - это критически важно в Blazor для перерендеринга компонента. Без этого интерфейс не будет обновляться, пока не завершится весь метод. Интересно, что шаблон также включает механизм отмены запросов через CancellationTokenSource:
Реактивность интерфейса и индикаторы состоянияРаботая с чат-приложениями, я всегда обращаю особое внимание на реактивность интерфейса — насколько быстро и плавно он реагирует на действия пользователя. В шаблоне .NET AI Chat Web App реактивность реализована на удивление хорошо, учитывая, что Blazor Server иногда критикуют за задержки из-за SignalR-соединения. Ключевым элементом реактивности в Blazor является метод StateHasChanged(), который сигнализирует фреймворку о необходимости перерендерить компонент. В шаблоне этот метод используется в нескольких критических местах:
InvokeAsync — это важный паттерн для Blazor, который гарантирует, что обновление UI произойдет в правильном контексте синхронизации. Я часто наблюдал, как разработчики забывают об этом, из-за чего возникают странные ошибки "изменение состояния было обнаружено во время рендеринга".Индикаторы состояния играют огромную роль в UX чат-приложений. В шаблоне реализовано несколько типов таких индикаторов: 1. Индикатор загрузки — появляется, когда система ожидает ответа от LLM:
Что мне особенно понравилось — использование CSS-анимаций для создания плавных переходов между состояниями. Например, для индикатора загрузки:
Безопасность и производительностьРазрабатывая чат-приложения на основе ИИ, я всегда особое внимание уделяю вопросам безопасности и производительности. Шаблон .NET AI Chat Web App предлагает несколько интересных решений в этих областях, хотя для рабочего окружения их придется еще доработать. В плане безопасности первое, что бросается в глаза — хорошо организованная защита API-ключей. Шаблон использует механизм секретов разработчика для хранения чувствительных данных, что значительно снижает риск их случайной утечки через репозиторий. Этот подход реализован через стандартные возможности .NET:
С точки зрения защиты данных стоит отметить, что обмен сообщениями между браузером и сервером в Blazor Server происходит через SignalR, и эти данные по умолчанию не шифруются. В продакшене необходимо обязательно настроить HTTPS. Переходя к производительности, отмечу несколько важных аспектов. Blazor Server хорошо работает при небольшом количестве одновременных пользователей, но может столкнуться с проблемами масштабирования при высоких нагрузках. Это связано с тем, что для каждого пользователя на сервере хранится состояние сессии. Один из способов оптимизации — кэширование результатов запросов к языковым моделям. В шаблоне эта функциональность не реализована, но ее можно добавить, создав простой сервис-декоратор для IChatClient:
Защита API-ключей и данных пользователейКогда дело касается чат-приложений на базе ИИ, безопасность стоит на первом месте. Особенно критичен вопрос защиты API-ключей - эти цифровые пропуска в мир языковых моделей часто стоят реальных денег, и их утечка может обернуться серьезными финансовыми потерями. В шаблоне .NET AI Chat Web App реализован базовый уровень защиты через механизм секретов разработчика, но для боевого применения этого недостаточно. Я на своём опыте убедился, что простое использование User Secrets - это только начало пути к надежной защите. Первое, что я обычно делаю в продакшен-приложениях - настраиваю механизм ротации ключей. Даже если ключ утечет, злоумышленники смогут использовать его лишь ограниченное время. Реализовать ротацию можно через Azure Key Vault и настроить автоматическое обновление ключей:
DataProtectionProvider:
Практические доработки: расширяем функционалШаблон .NET AI Chat Web App предоставляет отличную базу, но в реальных проектах его функциональности может быть недостаточно. Имея опыт внедрения подобных решений, я хочу поделиться несколькими практическими доработками, которые значительно расширяют возможности шаблона. Первое, что напрашивается - добавление поддержки дополнительных типов документов. По умолчанию шаблон работает только с PDF-файлами, но можно легко реализовать поддержку Word, Excel или даже HTML-страниц. Для этого достаточно создать новую реализацию интерфейса IIngestionSource:
Контейнеризация приложения с помощью DockerРазработав чат-приложение на базе .NET AI Chat Web App, логичным следующим шагом становится его контейнеризация. Docker предоставляет идеальную среду для упаковки и развертывания нашего ИИ-чата, обеспечивая стабильность работы независимо от инфраструктуры. Давайте создадим базовый Dockerfile для нашего приложения. Я предпочитаю использовать многоэтапную сборку, которая помогает существенно уменьшить размер финального образа:
Поскольку наше приложение использует SQLite для кэша обработаных документов, необходимо позаботиться о персистентности данных. Для этого лучше использовать Docker volumes:
Для оптимизации размера образа я обычно использую несколько приемов: 1. Строго контролирую, какие файлы копируются в образ через .dockerignore. 2. Использую alpine-версии базовых образов, где это возможно. 3. Объединяю несколько RUN-команд, чтобы уменьшить количество слоев. Когда приложение упаковано в контейнер, его гораздо проще масштабировать и развертывать в различных средах — от локальной разработки до полноценных облачных кластеров. Отличия App и Application. Отличия App.Current.Shutdown() и Application.Current.Shutdown() Можно ли как-то переместить файлы app.xmal в папку и app.config? App.UseRouting() и App.UseEndpoints() Написать простой анонимный chat с использованием: ASP.NET MVC 2 библиотеки ExtJS VS2019, в чем разница, приложение WPF (.Net Framework) и App WPF (.NET Core) Разница между ASP.NET Core 2, ASP.NET Core MVC, ASP.NET MVC 5 и ASP.NET WEBAPI 2 Изучаем C# с пользой Изучаем C# Обучение программированию по книге "Изучаем С#" Ошибки в Save the Humans (книга "Изучаем С#") Не работают примеры из книги "Эндрю Стиллмен, Грин - Изучаем c#" Книга "Изучаем с#". Проблема с проектом "Guys" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||


