Главная / Статьи

Четырехуровневая архитектура для агента выполнения кратких отчетов в Azure

Как агент для обработки информации с детерминированным подходом распределяет задачи между Fabric, процедурами хранения данных SQL, FastAPI в Azure Functions и Copilot Studio для создания руководящих документов.

Издатель: REACTAPP.TOP22 мин чтения5073 слов

Источники: **Chief of Staff Executive Briefing Agent: Enterprise-scale layered architecture for automated intelligence generation**

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

То, что делает эту архитектуру достойной изучения, — это минимум случайности в её работе. Вместо того чтобы просить модель составлять отчёт на основе указаний, здесь ручное объединение данных заменяется оркестрацией, регулируемой контрактами. Данные обрабатываются в рамках чётких правил, объединяются с помощью детерминированных SQL-запросов, передаются через безсостоянийные сервисы и доставляются в рамках контролируемого диалогового процесса. Архитектура устанавливает чёткие границы выполнения между четырьмя слоями: фундаментом, данными, сервисами и пользовательским интерфейсом, что позволяет воспроизводить результаты, проводить аудит и обеспечивать высокую скорость работы в рамках строгих требований к безопасности.

Этот дизайн был разработан в рамках внутренних усилий по развитию ИИ в экосистеме Microsoft, а приведенные ниже утверждения относительно производительности и результатов сделаны самими создателями и не проверялись независимо. Он наиболее полезен для архитекторов корпоративных систем, инженеров ИИ и руководителей платформ, которым нужны детерминистичные системы ИИ, объединяющие консолидацию данных, агрегацию с помощью SQL, оркестрацию без сохранения состояния и рабочие процессы на основе диалогов.

Четырехуровневая архитектура

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

  • Основа: Microsoft Fabric Lakehouse, обеспечивающий консолидацию данных в рамках четких правил управления.
  • Данные: Fabric SQL (хранилище или точка входа SQL), содержащий процедуры хранения для операционных запросов и агрегации.
  • Сервис: движок оркестрации FastAPI, размещённый в Azure Functions.
  • Интерфейс: конверсационный рабочий процесс Copilot Studio, обеспечивающий взаимодействие с пользователем.
  • Вместе они формируют однонаправленную цепочку обработки данных. Данные сначала обрабатываются и управляются на базовом уровне, затем детерминированно агрегируются в SQL, собираются с помощью логики домена на уровне сервиса и в конечном итоге предоставляются через взаимодействие на естественном языке. Каждый слой имеет чёткий контракт с соседними слоями, поэтому элемент ИИ дополняет процесс принятия решений, а не мешает ему.

    Уровень основы: управляемая консолидация данных

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

    Пайплайн обновляется ежедневно, собирая и объединяя корпоративные данные из Dynamics 365, финансовых систем и внешних API. Заданное расписание обеспечивает предсказуемые окна обработки и гарантирует, что каждая исходная система завершит свою ежедневную работу до начала консолидации. Lakehouse хранит данные в их исходном формате вместе с информацией о происхождении и стандартами управления, а отфильтрованные наборы данных затем переходят в Fabric SQL — быстрый операционный слой запросов, структура которого оптимизирована для подготовки отчетов для руководства.

    Слой данных: операционный двигатель, созданный для доступа через API

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

    Архитектура. Fabric SQL Warehouse — это реляционный интерфейс, который оборачивает все операции с данными, связанными с отчетностью, в хранимые процедуры. Слой обслуживания никогда не выполняет запросы к таблицам напрямую. Сложные объединения таблиц, смысл каждой агрегации и бизнес-логика выполняются внутри базы данных, а не в коде приложения, что позволяет сохранять предсказуемость времени отклика при больших объемах данных. SQL-запросы настроены для операционных запросов, а не для аналитического анализа; дизайн направлен на обеспечение детерминистичных объединений, дающих единообразные результаты, повторно используемых планов запросов для стабильной производительности, параметризованного выполнения для безопасности и инкапсулированных агрегаций, которые легче обслуживать.

    Философия схемы: запрос в приоритете. Схема соответствует шаблонам запросов, а не правилам нормализации из учебников. Энтитет Account является основной структурой кластеризации, а вспомогательные таблицы организованы таким образом, чтобы объединения выполнялись эффективно по бизнес-идентификатору — TPID.

         --Accounts Table - Primary Business Entity
    
    CREATE TABLE [aieo].[Accounts] (
    
        [Id] INT IDENTITY(1,1) PRIMARY KEY,
    
        [TPID] BIGINT NOT NULL,
    
        [AccountName] NVARCHAR(255) NOT NULL,
    
        [AccountNumber] NVARCHAR(50),
    
        [SearchTokens] NVARCHAR(500),
    
        [Segment] NVARCHAR(100),
    
        [Industry] NVARCHAR(100),
    
        [ACR_FY25] DECIMAL(15,2),
    
        [RevenueRank] INT,
    
        [CreatedDate] DATETIME2 DEFAULT GETUTCDATE(),
    
        [LastSync] DATETIME2,
    
        [IsActive] BIT DEFAULT 1
    
    );
    
    
    
    CREATE CLUSTERED INDEX IX_Accounts_TPID ON [aieo].[Accounts]([TPID]);
    
    CREATE NONCLUSTERED INDEX IX_Accounts_Name ON [aieo].[Accounts](
    

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

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

    -- Revenue Table - Historical and Forecast Data
    
    CREATE TABLE [aieo].[Revenue] (
    
        [TPID] BIGINT,
    
        [FiscalYear] NVARCHAR(10),
    
        [RevenueType] NVARCHAR(20),
    
        [Amount] DECIMAL(15,2),
    
        [LastUpdated] DATETIME2
    
    );
    
    CREATE INDEX IX_Revenue_TPID_FY ON [aieo].[Revenue]([TPID], [FiscalYear]);
    

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

    -- AI Usage Table - Product Adoption Metrics
    
    CREATE TABLE [aieo].[AIUsage] (
    
        [TPID] BIGINT,
    
        [ProductCategory] NVARCHAR(50),
    
        [UsageLevel] NVARCHAR(20),
    
        [SeatCount] INT,
    
        [AdoptionRate] DECIMAL(5,2),
    
        [LastUpdated] DATETIME2
    
    );
    
    CREATE INDEX IX_AIUsage_TPID_Product ON [aieo].[AIUsage]([TPID], [ProductCategory]);
    

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

    Стратегия хранения процедур: бизнес-логика находится в базе данных. Три основные процедуры обеспечивают генерацию всех необходимых данных. SearchAccounts находит счета и ранжирует их по доходу, GetAccountDetails объединяет данные из различных источников в полный контекст для руководства, а GetBriefingTemplate контролирует авторизацию шаблонов в зависимости от ролей, чтобы доступ имели только уполномоченные пользователи. Слой сервисов вызывает только эти процедуры, и использование динамического SQL там не разрешено.

    --Account Search Procedure - Revenue-Prioritized Discovery
    
    CREATE OR ALTER PROCEDURE [aieo].[SearchAccounts]
    
        @searchTerm NVARCHAR(255),
    
        @top INT = 5
    
    AS
    
    BEGIN
    
        SET NOCOUNT ON;
    
    
    
        DECLARE @likeTerm NVARCHAR(257) = '%' + REPLACE(REPLACE(@searchTerm, '[', '[[]'), '%', '[%]') + '%'
    
    
    
        SELECT TOP (@top)
    
            a.TPID,
    
            a.AccountName,
    
            a.AccountNumber,
    
            ISNULL(acr.ACR_YTD, 0) as ACR_YTD
    
        FROM [aieo].[Accounts] a
    
        LEFT JOIN [aieo].[ACR] acr ON a.TPID = acr.TPID
    
        WHERE
    
            a.AccountName LIKE @likeTerm
    
            OR CAST(a.TPID AS NVARCHAR) = @searchTerm
    
            OR a.AccountNumber LIKE @likeTerm
    
        ORDER BY
    
            ISNULL(acr.ACR_YTD, 0) DESC,
    
            a.AccountName ASC
    
        FOR JSON PATH;
    
    END;
    
    --Account Details Retrieval Procedure - Comprehensive Intelligence Aggregation
    
    CREATE PROCEDURE [aieo].[GetAccountDetails]
    
    (@TPID int)
    
    AS
    
    BEGIN
    
        SET NOCOUNT ON;
    
        SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
    
    
    
        SELECT TOP 1
    
            JSON_QUERY(ap.[AccountProfile]) AS [Account],
    
            JSON_QUERY(ai.[AIUsage]) AS [AI],
    
            JSON_QUERY(acr.[Data]) AS [ACR],
    
            deal.[Deals.AgreementValue],
    
            deal.[Deals.DealType],
    
            deal.[Deals.Term],
    
            deal.[Deals.Remaining],
    
            deal.[Deals.EndDate],
    
            ecif.[ECIF.Committed],
    
            aco.[ACO.IncrementalRevenue],
    
            aco.[ACO.Discount],
    
            aco.[ACO.ACO],
    
            JSON_QUERY(bot.[Data]) AS [BoT],
    
            JSON_QUERY(inv.[Data]) AS [Investments],
    
            JSON_QUERY(rev.[Data]) AS [Revenue]
    
        FROM [dbo].[vw_Customer] P
    
        OUTER APPLY (
    
            SELECT TOP 1
    
                a.[TPID],
    
                a.[CRMAccountName] AS [AccountName],
    
                a.[Segment],
    
                a.[Industry],
    
                a.[EOU],
    
                a.[OU],
    
                LOWER(TRIM(c.[Value])) AS [ATU_Manager.Alias],
    
                aau.[Mail] AS [ATU_Manager.Email],
    
                [dbo].[RemoveJobTitle](aau.[DisplayName]) AS [ATU_Manager.DisplayName],
    
                NULLIF(TRIM(aau.[BusinessPhone]), '') AS [ATU_Manager.PhoneNumber],
    
                JSON_QUERY([am].[Data]) AS [AM],
    
                JSON_QUERY([atum].[Data]) AS [ATUM]
    
            FROM [dbo].[vw_Customer] A
    
            OUTER APPLY STRING_SPLIT(a.[AM], ',', 1) C
    
            LEFT JOIN [cm].[vw_AAD_User] AAU ON LOWER(TRIM(C.[Value])) = LOWER(AAU.[UserPrincipalName])
    
            WHERE A.TPID = P.TPID
    
        ) ap
    
        WHERE P.TPID = @TPID;
    
    END;
    
    --Template Management Procedure - Role-Based Access Control
    
    CREATE OR ALTER PROCEDURE [aieo].[GetBriefingTemplate]
    
    (
    
        @UserAlias NVARCHAR(200),
    
        @BriefingType NVARCHAR(200)
    
    )
    
    AS
    
    BEGIN
    
        SET @UserAlias = IIF(CHARINDEX('@', @UserAlias) > 0,
    
                            LEFT(@UserAlias, CHARINDEX('@', @UserAlias) - 1),
    
                            @UserAlias)
    
    
    
        SELECT DISTINCT
    
            [BriefingTemplateId],[TemplateDescription],[BriefingType],
    
            [UserAlias],FullName,[Filename],[FileType],[PreviewFilename]
    
        FROM [hr].[DimPerson] p
    
        INNER JOIN [aieo].[ExecutiveOfficeMember] eom ON eom.[PersonnelNumber] = p.[PersonnelNumber]
    
        INNER JOIN [aieo].[ExecutiveOffice] o ON o.[ExecutiveOfficeId] = eom.[ExecutiveOfficeId]
    
        INNER JOIN [aieo].[BriefingTemplate] bt ON bt.[ExecutiveOfficeId] = o.[ExecutiveOfficeId]
    
    
    
        UNION
    
    
    
        SELECT DISTINCT
    
            [BriefingTemplateId],[TemplateDescription],[BriefingType],
    
            p.EmailName As UserAlias,p.FullName,[Filename],[FileType],[PreviewFilename]
    
        FROM [aieo].[BriefingTemplate] bt
    
        CROSS JOIN [hr].[DimPerson] p
    
        WHERE bt.[UserAlias] = 'ALL' AND p.EmailName = @UserAlias
    
            AND bt.BriefingType = @BriefingType;
    
    END;
    

    Производительность и безопасность. Для повышения эффективности транзакции используют команду SET NOCOUNT ON, а для операций чтения — команду SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED, чтобы они не блокировали друг друга. Обработка JSON осуществляется с помощью встроенных функций SQL Server JSON_QUERY и FOR JSON PATH, которые обеспечивают эффективную обработку и прямую сериализацию данных из базы. Разрешена только параметризованная обработка запросов; сервисная идентичность приложения имеет право на выполнение хранимых процедур, но не имеет прямого доступа к таблицам.

    GRANT EXECUTE ON SCHEMA::[aieo] TO [service_identity];
     - No direct table access permitted
    

    Слой сервисов: оркестрация без состояния и границы выполнения

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

    Интерфейс API и валидация. Приложение FastAPI предоставляет явные REST-конечные точки с строго типизированными контрактами, определёнными как модели Pydantic:

    • POST /api/briefing/generate — основная конечная точка для генерации отчётов с полной валидацией входных данных.
    • GET /api/health — возвращает информацию о статусе системы.
    • GET /api/templates — показывает список шаблонов, доступных вызывающему пользователю.
    from pydantic import BaseModel
    from typing import Optional
    class BriefingRequest(BaseModel):
    account_name_or_tpid: str
    meeting_datetime: Optional[str] = None
    meeting_objective: Optional[str] = None
    ms_attendees: Optional[str] = None
    template_type: Optional[str] = None
    

    Модель обеспечивает строгую валидацию и безопасность типов, автоматически генерирует документацию OpenAPI и корректирует структуру каждого запроса. Никакой неструктурированный ввод не может пройти через этот контроль.

    Модель выполнения. Сервис выполняет детерминированную последовательность из пяти шагов:

    1. Валидация запроса. Модели Pydantic проверяют, соответствуют ли типы и данные установленным требованиям.
    2. Определение аккаунта. Формат входных данных определяет, следует ли напрямую искать TPID или вызывать функцию SearchAccounts для поиска по имени.
    3. Одновременный захват данных. Функции GetAccountDetails и GetBriefingTemplate выполняются одновременно с помощью asyncio.gather().
    4. Сбор контекста. Результаты процедур напрямую преобразуются в объекты, готовые к использованию в шаблонах, без какой-либо промежуточной обработки.
  • Отрисовка шаблонов. Jinja2 генерирует итоговый документ с детерминированным форматированием.
  • Асинхронная обработка и пулирование соединений через абстракцию DatabaseService обеспечивают то, что одинаковые входные данные дают одинаковые выходные результаты.

    Руководящие принципы. Слой обслуживания регулируется пятью правилами. В нем отсутствует бизнес-логика, поскольку обработка данных происходит исключительно внутри хранимых процедур, что освобождает слой обслуживания от правил, усложняющих тестирование и поддержку. Он занимается исключительно оркестрацией данных, координируя их получение и отображение без каких-либо преобразований или вычислений. Картирование контекста осуществляется напрямую, поэтому результаты процедур попадают в структуры шаблонов без лишних этапов, что снижает риск искажения значений при передаче данных между слоями. Обработка является детерминистичной, что гарантирует одинаковый результат для одних и тех же входных данных независимо от времени выполнения или состояния инфраструктуры. Кроме того, функции четко разделены: логика обработки данных находится в SQL-процедурах, оркестрация — в сервисах Python FastAPI, а отображение — в шаблонах Jinja2.

    Слой интеракции: Copilot Studio в качестве движка диалога

    В верхней части фреймворк AdaptiveDialog в Microsoft Copilot Studio преобразует запрос на естественном языке в детерминированный рабочий процесс. Он обрабатывает урегулирование вопросов, связанных с учетными записями, авторизацию шаблонов, интеграцию внешних данных, генерацию документов и их доставку через различные каналы. Процесс выполняется последовательно: от первого запроса до урегулирования вопросов с учетными записями, авторизации шаблонов, сбора внешних данных и их передачи в SharePoint, причем на каждом этапе диалога предусмотрены точки принятия решений и шаги проверки.

    Основной диалог. В рамках этого диалога автоматически собирается идентификатор учетной записи, определяются фразы-триггеры, запускающие процесс обработки запроса, а также устанавливается основная точка входа в диалог:

    kind: AdaptiveDialog
    
    inputs:
    
      - kind: AutomaticTaskInput
    
        propertyName: Account_Name_or_TPID
    
        name: Account Name or TPID
    
        description: The account/customer TPID (unique identifier) or name
    
        shouldPromptUser: true
    
    
    
    modelDescription: Create briefing document to prepare for meeting with customer
    
    beginDialog:
    
      kind: OnRecognizedIntent
    
      intent:
    
        displayName: Topic for creating briefing document to prepare for meeting with customer
    
        triggerQueries:
    
          - Generate a briefing document for account Accenture
    
          - I need a briefing for Amazon
    
          - Create briefing for Apple
    
          - I have a meeting with JPMorgan Chase at 4PM
    

    Решение проблем с учётными записями. Функция IsNumeric() определяет, является ли введённый текст прямым ID TPID или названием учётной записи, требующим поиска. При возможности отказ от поиска сокращает количество вызовов API и ускоряет получение ответа:

    - kind: SetVariable
    
      id: setVariable_IsNumeric
    
      variable: Topic.IsNumeric
    
      value: =IsNumeric(Topic.UserInput)
    
    
    
    - kind: ConditionGroup
    
      id: conditionGroup_InputType
    
      conditions:
    
        - id: condition_IsTPID
    
          condition: =Topic.IsNumeric
    
          actions:
    
            - kind: SetVariable
    
              variable: Topic.Account_TPID
    
              value: =Topic.UserInput
    

    Звонок для поиска учётной записи. Для имён сервис использует REST-интерфейс для обращения к точке входа поиска слоя сервисов. Он URL-кодирует специальные символы, аутентифицируется с помощью ключа подписки и указывает схему ответа, что позволяет автоматически проверять данные:

    - kind: HttpRequestAction
    
      id: httpRequest_SearchAccounts
    
      displayName: Search Accounts by Name
    
      url: =Global.ApiBaseUrl & "/api/mssales/search/" & EncodeUrl(Topic.UserInput)
    
      headers:
    
        Ocp-Apim-Subscription-Key: =Global.ApiKey
    
      response: Topic.SearchResults
    
      responseSchema:
    
        kind: Record
    
        properties:
    
          accounts:
    
            type:
    
              kind: Table
    
              properties:
    
                account_name: String
    
                tpid: String
    
          total_count: Number
    

    Карточка дисэмбигуации. Если поиск находит несколько учётных записей, адаптивная карточка отображает динамический набор вариантов, сгенерированный с помощью ForAll() из результатов, причём каждая запись показывает свой TPID. Таким образом, неоднозначный ввод не прерывает диалог:

    - kind: AdaptiveCardPrompt
    
      id: adaptiveCard_SelectAccount
    
      card: "=Concatenate('{
    
        \"$schema\":\"https://adaptivecards.io/schemas/adaptive-card.json\",
    
        \"type\":\"AdaptiveCard\",\"version\":\"1.5\",
    
        \"body\":[
    
          {\"type\":\"TextBlock\",\"text\":\"Multiple accounts found\",\"weight\":\"Bolder\"},
    
          {\"type\":\"Input.ChoiceSet\",\"id\":\"selectedAccount\",\"isRequired\":true,
    
           \"choices\":',
    
           JSON(ForAll(Topic.SearchResults.accounts,
    
             {title: Concatenate(account_name, \" (TPID: \", tpid, \")\"), value: tpid})),
    
           '}],
    
        \"actions\":[{\"type\":\"Action.Submit\",\"title\":\"Continue\"}]
    
      }')"
    

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

    - kind: HttpRequestAction
    
      id: httpRequest_GetUserTemplates
    
      url: =Global.ApiBaseUrl & "/api/briefings/templates?user_alias=" &
    
           EncodeUrl(System.User.PrincipalName) & "&briefing_type=Customer"
    
      headers:
    
        Ocp-Apim-Subscription-Key: =Global.ApiKey
    
      response: Topic.UserTemplates
    

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

    - kind: AdaptiveCardPrompt
    
      id: adaptiveCard_MeetingDetails
    
      card: "=Concatenate('{
    
        \"$schema\":\"https://adaptivecards.io/schemas/adaptive-card.json\",
    
        \"type\":\"AdaptiveCard\",\"version\":\"1.5\",
    
        \"body\":[
    
          {\"type\":\"TextBlock\",\"text\":\"Create Executive Briefing Document\",
    
           \"weight\":\"Bolder\",\"size\":\"Large\",\"color\":\"Accent\"},
    
          {\"type\":\"Input.Date\",\"id\":\"meetingDate\",\"isRequired\":true,
    
           \"label\":\"Meeting Date\"},
    
          {\"type\":\"Input.Time\",\"id\":\"meetingTime\",\"value\":\"09:00\"},
    
          {\"type\":\"Input.Text\",\"id\":\"msAttendees\",\"isVisible\":false,
    
           \"label\":\"Microsoft Attendees\"}
    
        ],
    
        \"actions\":[
    
          {\"type\":\"Action.ToggleVisibility\",\"title\":\"Additional Options ▼\",
    
           \"targetElements\":[\"msAttendees\"]},
    
          {\"type\":\"Action.Submit\",\"title\":\"Generate Briefing\"}
    
        ]
    
      }')"
    

    Одновременный сбор данных и генерация документов. Слой обработки опыта одновременно вызывает API с данными о счете и Azure AI Foundry, установив для каждого таймаут в 60 секунд. После получения ответов от обоих источников формируется один структурированный JSON-пакет на основе всех данных, который затем передается в API для генерации документов; процессы проверки и сборки выполняются автономно, что обеспечивает детерминированное создание отчета.

    Azure AI Foundry: организационный интеллект

    Интеграция с Foundry расширяет возможности агента за пределы внешних рыночных данных, позволяя использовать контекст изнутри организации благодаря компоненту «M365 Researcher». Для поиска писем в Outlook и сообщений в Teams используется делегированный доступ к Microsoft Graph; при этом все операции происходят в рамках корпоративных мер безопасности и принципов нулевого доверия.

    Доступ к Microsoft Graph через делегированную аутентификацию без хранения секретов. Исследователь использует делегированную аутентификацию, которая полностью исключает хранение секретов клиента. Для этого применяются коннекторы, управляемые Azure Logic Apps — приложения от Microsoft с заранее согласованными диапазонами полномочий делегированной аутентификации. Это избавляет от необходимости управления регистрацией приложений, поскольку Azure отвечает за жизненный цикл токенов и их автоматическое обновление.

    Кроме того, временные инстансы Logic Apps обеспечивают доступ к данным пользователя с использованием HTTP-триггеров, защищенных SAS. При каждом поиске запускается новая инстанция Logic App, которая параллельно загружает данные из Microsoft Graph и сразу же удаляется, поэтому SAS-адрес невозможно использовать повторно, и никакие постоянные токены не остаются доступными.

    // Ephemeral Logic App Security Pattern
    const createSearchLogicApp = async (userAlias, searchQuery) => {
    const logicAppName = `Researcher-${userAlias}`;
    // Create Logic App with SAS trigger
    const logicApp = await armClient.logicApps.createOrUpdate({
    resourceGroupName: 'Azure_OpenAI',
    workflowName: logicAppName,
    definition: buildResearchWorkflow(userAlias)
    });
    // Execute search via SAS URL
    const searchResults = await triggerLogicApp(logicApp.triggerUrl, searchQuery);
    // Immediate cleanup for security
    await armClient.logicApps.delete(logicAppName);
    return searchResults;
    };
    

    Параллельный поиск и настройка Graph. Данные из электронной почты и Teams собираются одновременно, при этом соблюдаются ограничения на одновременную работу, чтобы сессии множества пользователей не вызывали замедления работы системы. Для почты модуль подключения Office 365 выполняет массовый захват последних 250 сообщений от каждого пользователя, причем фильтрация происходит на клиенте для обхода ограничений Graph при поиске в теле сообщений. В случае с Teams используется двухэтапный подход: сначала через пагинированные запросы находятся чаты, а затем сообщения из отдельных чатов загружаются с настраиваемым лимитом одновременной работы.

    # Logic App Parallel Execute Pattern
    
    HTTP_Trigger_SAS_Secured:
    
      Email_Branch:
    
        - Get_Emails: Office365_Connector.Mail (top=250)
    
    
    
      Teams_Branch_Parallel:
    
        - Get_Teams_Chats_Page1: Teams_Connector.Chats (top=50)
    
        - Get_Teams_Chats_Page2: Teams_Connector.Chats (skip=50, top=50)
    
        - For_Each_Chat:
    
            concurrency: 10
    
            actions:
    
              - Get_Chat_Messages: Teams_Connector.Messages (top=50)
    
              - Append_Chat_Data: Variable_Accumulation
    
    
    
      Response_Assembly:
    
        - Combine: Email_Results + Teams_Results + Metadata
    
        - Return: JSON_Structured_Response
    

    Типичный поиск выполняет примерно 101 вызов Graph API: один для почты, два для перечисления чатов в Teams и в среднем 98 вызовов для получения сообщений чатов. Это позволяет получить большой объем данных, при этом соблюдаются лимиты одновременных операций Graph API, а согласно проектированию время отклика остается ниже 60 секунд.

    Подключения и токены на уровне пользователя. Каждому пользователю требуются два управляемых подключения для хранения делегированных токенов OAuth в течение всех сессий поиска: office365-{alias} для работы с почтой с диапазоном полномочий Mail.ReadWrite и teams-{alias} для чата с диапазоном полномочий Chat.Read. Инфраструктура управляемых соединителей Azure автоматически обновляет токены и обеспечивает соблюдение требований безопасности. Процесс настройки осуществляется на основе согласия пользователя: он входит в систему один раз через встроенный механизм OAuth от Microsoft, а делегированные полномочия действуют до момента их отзыва. Функциональное приложение управляет жизненным циклом подключений с помощью API Azure Resource Manager под управлением идентификатора управляемой учетной записи, поэтому клиентские учетные данные не хранятся на уровне приложения.

    // Per-User Connection Provisioning
    
    const provisionUserConnections = async (userAlias) => {
    
        const connections = [
    
            {
    
                name: `office365-${userAlias}`,
    
                api: '/providers/Microsoft.PowerApps/apis/shared_office365',
    
                scopes: ['Mail.ReadWrite']
    
            },
    
            {
    
                name: `teams-${userAlias}`,
    
                api: '/providers/Microsoft.PowerApps/apis/shared_teams',
    
                scopes: ['Chat.Read']
    
            }
    
        ];
    
    
    
        for (const conn of connections) {
    
            await armClient.connections.createOrUpdate({
    
                resourceGroupName: 'Azure_OpenAI',
    
                connectionName: conn.name,
    
                properties: {
    
                    displayName: conn.name,
    
                    api: { id: conn.api },
    
                    parameterValues: {}
    
                }
    
            });
    
        }
    
    
    
        return generateConsentUrls(connections);
    
    };
    

    Синтез с помощью модели GPT. Чистые сообщения преобразуются в готовую к использованию организационную информацию с помощью модели из сервиса Azure OpenAI Service (указанной как GPT-4.1, хотя в примерном коде говорится о предварительной версии GPT-4). Система преобразует отфильтрованную почту и контент Teams в структурированные выводы, охватывающие анализ заинтересованных сторон, модели коммуникации и действия, связанные с собранием. Запросы ориентированы на потребности руководства, такие как картирование отношений, статус проектов и стратегические темы, при этом модель возвращает структурированный JSON-формат, который можно вставить в существующие шаблоны Jinja2 с единым форматированием во всех документах.

    # Organizational Intelligence Synthesis
    
    async def synthesize_organizational_context(filtered_data, account_context):
    
        synthesis_prompt = """
    
        Analyze the following organizational communications for executive briefing preparation:
    
    
    
        Account Context: {account_name}
    
        Email Communications: {email_count} relevant messages
    
        Teams Discussions: {chat_count} relevant conversations
    
        Generate executive intelligence focusing on:
        Financial performance, earnings trends, and capital allocation signals.
        Corporate strategy, market positioning, and competitive landscape.
        AI strategy, digital transformation initiatives, and cloud ecosystem alignment.
        Recent material developments (≤ 90 days) with actionable insights for executive engagement.
    
        Format as structured JSON with executive_summary, stakeholder_analysis, recent_activities, and recommended_actions.
    
        """
    
    
    
        response = await azure_openai_client.chat.completions.create(
    
            model="gpt-4-1106-preview",
    
            messages=[{
    
                "role": "system",
    
                "content": "You are an executive intelligence analyst."
    
            }, {
    
                "role": "user",
    
                "content": synthesis_prompt.format(**filtered_data, **account_context)
    
            }],
    
            temperature=0.1,
    
            max_tokens=2000
    
        )
    
    
    
        return parse_structured_intelligence(response.choices[0].message.content)
    

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

    # Enhanced Copilot Studio Parallel Execution
    
    - kind: ParallelExecution
    
      id: parallelExecution_ComprehensiveIntelligence
    
      branches:
    
        - account_data:
    
            kind: HttpRequestAction
    
            url: =Global.ApiBaseUrl & "/api/accounts/" & Topic.Account_TPID
    
        - organizational_intelligence:
    
            kind: HttpRequestAction
    
            url: =Global.ApiBaseUrl & "/api/search?q=" & EncodeUrl(Topic.Account_Name) & "&alias=" & System.User.PrincipalName
    
            requestTimeoutInMilliseconds: 60000
    
            continueOnError: true
    
        - market_intelligence:
    
            kind: HttpRequestAction
    
            url: =Global.FoundryBaseUrl & "/bingnews/api/AgentFunction"
    
    
    
    - kind: SetVariable
    
      id: setVariable_CombinedIntelligence
    
      variable: Topic.BriefingContext
    
      value: ={
    
        account_details: Topic.AccountData,
    
        organizational_context: Topic.OrganizationalIntelligence,
    
        market_insights: Topic.MarketIntelligence
    
      }
    

    Управление и соблюдение правил. Благодаря делегированным полномочиям пользователи могут искать только свою собственную почту и сообщения в Teams, что предотвращает доступ других пользователей и обеспечивает строгий контроль над данными. Каждый вызов Graph API фиксируется с указанием контекста пользователя, параметров поиска и метаданных результатов. Срок хранения данных можно настроить, а соединения, которые не используются в течение установленного периода, обычно 80 дней, автоматически удаляются. Обработка данных происходит внутри тенанта Azure, а механизмы контроля местоположения данных способствуют соблюдению политик управления организации.

    // Enterprise Governance and Cleanup
    
    const implementGovernanceControls = async () => {
    
        // Automated stale connection cleanup
    
        const staleThreshold = 80; // days
    
        const allConnections = await listManagedConnections();
    
    
    
        const staleConnections = allConnections.filter(connection => {
    
            const lastUsed = parseISO(connection.properties.lastConnection);
    
            const daysSinceUse = differenceInDays(new Date(), lastUsed);
    
            return daysSinceUse > staleThreshold;
    
        });
    
    
    
        // Compliance audit logging
    
        for (const connection of staleConnections) {
    
            await auditLogger.log({
    
                action: 'CONNECTION_CLEANUP',
    
                userAlias: connection.userAlias,
    
                reason: 'AUTOMATED_GOVERNANCE',
    
                retentionPolicy: `${staleThreshold}_DAYS_INACTIVE`,
    
                timestamp: new Date().toISOString()
    
            });
    
    
    
            await deleteUserResources(connection.userAlias);
    
        }
    
    };
    

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

    // Fault-Tolerant Execution Pattern
    
    const executeOrganizationalIntelligence = async (searchQuery, userAlias) => {
    
        const executionTimeout = 60000; // 60 second maximum
    
        const fallbackResponse = { summary: "Organizational context unavailable", status: "fallback" };
    
    
    
        try {
    
            // Health check before expensive operations
    
            const connectionsHealthy = await verifyConnectionHealth(userAlias);
    
            if (!connectionsHealthy) {
    
                return fallbackResponse;
    
            }
    
    
    
            // Execute with timeout boundary
    
            const intelligencePromise = gatherOrganizationalIntelligence(searchQuery, userAlias);
    
            const timeoutPromise = new Promise((_, reject) =>
    
                setTimeout(() => reject(new Error('TIMEOUT')), executionTimeout)
    
            );
    
    
    
            return await Promise.race([intelligencePromise, timeoutPromise]);
    
    
    
        } catch (error) {
    
            // Graceful degradation logging
    
            await logger.warn(`M365 Researcher fallback: ${error.message}`, {
    
                userAlias,
    
                searchQuery,
    
                fallbackMode: true
    
            });
    
    
    
            return fallbackResponse;
    
        }
    
    };
    

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

    Вызов для генерации документа. На этом этапе создается окончательный отчет путем объединения всей собранной информации из разговора в один пакет данных для слоя обслуживания. В этот пакет входят контекст пользователя, детали встречи и необязательные данные от внешних ИИ-систем; срок выполнения всей процедуры генерации документа составляет 60 секунд:

    - kind: HttpRequestAction
    
      id: p4tceX
    
      method: Post
    
      url: =Global.ApiBaseUrl & "/api/briefings/" & Topic.templateId & "/accounts/" & Topic.Account_TPID
    
      body:
    
        kind: JsonRequestContent
    
        content: "={
    
          user_alias: Topic.SenderEmail,
    
          MeetingDateTime: Topic.MeetingDateTime,
    
          msAttendees: Topic.msAttendees,
    
          FoundryResponse: Topic.FoundryResponse
    
        }"
    
      requestTimeoutInMilliseconds: 60000
    
      response: Topic.BriefingDocument
    

    Размещение в SharePoint. Все сгенерированные документы попадают в центральный хранилище через коннектор SharePoint Power Platform с управляемой аутентификацией, поэтому каждый документ сохраняется и остается доступным независимо от способа вторичной доставки, что соответствует требованиям к управлению данными. Целевой сайт и папка в приведённом ниже примере являются местоположениями-заменителями.

    - kind: InvokeConnectorAction
    
      id: invokeConnectorAction_YKkMK4
    
      input:
    
        binding:
    
          dataset: https://microsoft.sharepoint.com/teams/MCAPSAIIncubationHub
    
          folderPath: /Shared Documents/General/AI Prototypes & Solutions/AI Executive Office Use Cases/Published Cust Template/
    
          name: =Topic.CustomFilename
    
          file: =Global.File
    

    Имена файлов формируются таким образом, чтобы они были читаемыми, объединяя имя учетной записи, идентификатор руководителя и дату встречи. Функция Substitute() обеспечивает их безопасность в файловой системе и сохраняет единообразие названий во всех рабочих процессах руководителей:

    - kind: SetVariable
    
      id: setVariable_CustomFilename
    
      variable: Topic.CustomFilename
    
      value: =Concatenate(
    
        Substitute(Topic.Account_Name, " ", "_"), "_",
    
        Topic.ExecutiveName, "_Brief_",
    
        Text(Topic.meetingDate, "yyyy-MM-dd"), ".docx"
    
      )
    

    Обработка ошибок и состояние. При неудачном доступе к шаблону предоставляется контекстуальная инструкция в виде карточки адаптивного типа с предупреждением, а не общая ошибка. Система анализирует конкретные коды ошибок из API-сервиса, сообщает пользователю, какие разрешения отсутствуют, и скрывает конфиденциальные детали системы:

    - kind: ConditionGroup
    
      id: conditionGroup_CheckBriefingError
    
      conditions:
    
        - condition: =!IsBlank(Topic.BriefingDocument.error) && Topic.BriefingDocument.error.error_code = "TEMPLATE_ACCESS_DENIED"
    
          actions:
    
            - kind: AdaptiveCardPrompt
    
              card: ={
    
                "$schema":"https://adaptivecards.io/schemas/adaptive-card.json",
    
                "type":"AdaptiveCard","version":"1.5",
    
                "body":[{
    
                  "type":"Container","style":"warning",
    
                  "items":[{
    
                    "type":"TextBlock","text":"Template Access Required",
    
                    "weight":"Bolder","color":"Attention"
    
                  },{
    
                    "type":"TextBlock","wrap":true,
    
                    "text": Topic.BriefingDocument.error.user_message
    
                  }]
    
                }]
    
              }
    

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

    - kind: ConditionGroup
    
      id: conditionGroup_ValidateInputs
    
      conditions:
    
        - condition: =Topic.meetingDate < Today()
    
          actions:
    
            - kind: SendActivity
    
              activity: The meeting date cannot be in the past. Please start over and enter a future date.
    
            - kind: EndConversation
    

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

    - kind: SetVariable
    
      id: setVariable_ClearUserInput
    
      variable: Topic.UserInput
    
      value: =Blank()
    
    
    
    - kind: SetVariable
    
      id: setVariable_ClearAccountDetails
    
      variable: Topic.AccountDetails
    
      value: =Blank()
    
    
    
    - kind: SetVariable
    
      id: setVariable_ClearFoundryResponse
    
      variable: Topic.FoundryResponse
    
      value: =Blank()
    
    
    
    - kind: SetVariable
    
      id: setVariable_ClearBriefingDocument
    
      variable: Topic.BriefingDocument
    
      value: =Blank()
    

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

    Безопасность и детали реализации

    Федеративная идентичность и аутентификация

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

    # Environment-aware authentication pattern
    
    def get_credential():
    
        if is_azure_environment():
    
            return ManagedIdentityCredential(client_id=os.getenv('AZURE_CLIENT_ID'))
    
        else:
    
            return AzureCliCredential()
    

    В Azure используется управляемая идентичность, при которой учетные данные автоматически предоставляются и обновляются, а для локальной разработки применяются учетные данные Azure CLI. Токены хранятся в кэше безопасным способом, обеспечивающим синхронизацию между потоками, а вопросы истечения срока действия решаются автоматически.

    Структура сервиса и управление зависимостями

    Слой сервиса опирается на внедрение зависимостей, что позволяет одному и тому же коду работать как с имитациями в тестах, так и с полностью настроенными экземплярами в производстве. Вопросы, касающиеся нескольких компонентов, такие как обработка ошибок и управление конфигурацией, используются всеми компонентами сервиса; каждый из них (SharePoint, база данных, Power BI) принимает необязательные зависимости через свой конструктор, при этом оставаясь слабо связанным с внешними API и ресурсами Azure. Это обеспечивает возможность тщательного тестирования с использованием имитаций, а также надежную работу в производстве благодаря правильной абстракции.

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

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

    Для работы с базой данных используется пул подключений через механизм управления движком SQLAlchemy, причем применяется паттерн синглтон для эффективного использования ресурсов. Запросы объединяются в хранимые процедуры, в которых находится бизнес-логика, что сокращает объем сетевого трафика и упрощает код приложения. Большие наборы результатов обрабатываются путем интеллектуальной реконструкции JSON, что позволяет обходить ограничения библиотеки pyodbc при работе с большими объемами данных, обеспечивая надежную обработку независимо от размера результата и сохраняя разумное использование памяти.

    Интеграция внешних сервисов

    Интеграция с SharePoint и Microsoft Graph откладывает кэширование свойств до момента необходимости, чтобы сократить количество запросов к API при сохранении актуальности данных. ID сайтов и папок кэшируются с умным механизмом аннулирования данных и динамическим выбором библиотек, что обеспечивает надежность загрузок. Интеграция с Dynamics 365 парсит ответы Search v2.0 и преобразует сырые результаты в структуры, имеющие практическую ценность для бизнеса, с логикой повторных попыток при ограничениях по частоте запросов и тщательной обработкой ошибок.

    Генерация документов

    Пайплайн генерации сочетает обработку шаблонов Jinja2 с формированием контекста, преобразующим необработанные данные в полезную информацию, готовую к использованию руководством. Контекст шаблона включает необработанные данные, рассчитанные показатели, инструменты форматирования и аналитические данные, полученные в результате межсистемного анализа. Система управления шаблонами проверяет синтаксис и обрабатывает ошибки, что обеспечивает надежность генерации даже при редактировании шаблонов; кроме того, благодаря настройкам типов MIME поддерживается несколько форматов вывода для гибкой доставки информации.

    Ошибки и исключения

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

    Structured exception hierarchy
    
    class AIExecutiveOfficeError(Exception):
    
        def __init__(self, message: str, error_code: str = None, details: dict = None):
    
            self.message = message
    
            self.error_code = error_code or self.__class__.__name__
    
            self.details = details or {}
    
            self.timestamp = datetime.utcnow()
    

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

    Оценка и проверка качества

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

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

    Качественная оценка учитывает один аспект — уровень осведомленности компании, то есть насколько хорошо в материалах отражается реальное понимание целевой организации и насколько адекватно о ней говорится. Судья, использующий ИИ-модель, оценивает каждый материал по пяти стандартным критериям: релевантность (подходит ли содержание для принятия решений руководством), связность (логическая структура и последовательность), точность (соответствие фактам и исходным данным), ясность (язык и формат представления, подходящие для руководства) и полнота (охват стратегических аспектов). Такой подход обеспечивает последовательную и масштабируемую оценку с объективным подсчётом баллов для различных типов клиентов и отраслей, однако, как и в случае с любой оценкой на основе ИИ-моделей, он унаследовывает собственные предубеждения модели судьи.

    Следующие шаги: переход на Microsoft Agent Framework

    Команда считает четырехуровневую архитектуру хорошей основой для миграции на Microsoft Agent Framework (MAF), что позволит усилить оркестрацию ИИ, сохраняя при этом принципы детерминизма. MAF в основном будет внедряться на уровне сервисов, заменяя логику оркестрации FastAPI агентами MAF, которые будут использовать те же самые шаблоны чистой оркестрации данных. Уровень пользовательского интерфейса полностью изменится: Copilot Studio уступит место нативной интеграции с Microsoft 365, которая разместит рабочие процессы руководства внутри Outlook, Teams и SharePoint, используя возможности понимания языка от MAF для более точного распознавания намерений и ведения многократных диалогов, при этом для анализа бизнес-информации будут продолжать использоваться те же хранимые процедуры.

    Встроенные инструменты для наблюдаемости, управления сообщениями и контроля жизненного цикла агентов MAF позволят отказаться от собственной инфраструктуры и получить мониторинг и процессы развертывания корпоративного уровня. Путь миграции сохраняет существующие инвестиции в процедуры хранения данных, шаблоны Jinja2 и интеграцию с SharePoint, добавляя при этом возможности для более сложных сценариев, таких как подготовка отчетов, охватывающих несколько учетных записей, синтез анализа конкурентов, а также генерация шаблонов динамически на основе контекста встречи и участников. Благодаря интеграции с Microsoft 365 генерация отчетов станет частью существующих рабочих процессов продуктивности, а не отдельным чат-интерфейсом, причем слои данных и сервисов останутся детерминистичными.

    Что показывает дизайн

    Этот агент превращает подготовку кратких отчетов из процесса ручной координации в автоматическую генерацию информации с использованием четырех уровней, отвечающих за консолидацию данных, агрегацию операций, организацию бизнес-процессов и взаимодействие с помощью естественного языка. Говорится, что этот детерминистический подход в рамках интегрированной экосистемы Microsoft обеспечивает быструю генерацию отчетов (утверждается, что это происходит «за доли секунды», хотя собственные временные ограничения процесса составляют 60 секунд, поэтому это, скорее всего, касается шагов обработки в базе данных и сервисах), а также безопасность, управление и возможности аудита, которые системам, основанным исключительно на вводе команд, трудно гарантировать.

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