Startseite / Artikel

Eine Vier-Schichten-Architektur für einen Executive Briefing Agent auf Azure

Wie ein deterministischer Berichtserstellungsagent Aufgaben auf Fabric, SQL-Speicherprozeduren, FastAPI in Azure Functions sowie Copilot Studio verteilt, um Geschäftsberichte zu erstellen.

Verlag: REACTAPP.TOP22 Min. Lesezeit5073 Wörter

Quellen: **Chief of Staff Executive Briefing Agent: Enterprise-scale layered architecture for automated intelligence generation**

Jeder, der Führungskräfte auf Kundentreffen vorbereitet, weiß, wie verstreut die Rohdaten sind. CRM-Daten befinden sich in einem System, Umsatzzahlen in einem anderen, Produktnutzungsinformationen in einem dritten – und die strategische Zusammenfassung muss von Hand aus all diesen Quellen zusammengestellt werden. Ein „Stabchef“-Brieferungsagent adressiert genau diese Aufgabe: Eine Person bittet in einfachen Worten um eine Zusammenfassung, und die Plattform liefert ein für Führungskräfte geeignetes Dokument, das aus fragmentierten operativen, finanziellen sowie KI-Einsatzdaten erstellt wurde.

Was das Design zum Studium lohnenswert macht, ist die geringe Abhängigkeit von Zufällen. Anstelle dafür, ein Modell zu bitten, die Zusammenfassung auf Basis einer Anweisung zu verfassen, ersetzt es die manuelle Aggregation durch durch Verträge festgelegte Orchestrierung. Die Daten werden unter Einhaltung von Richtlinien konsolidiert, mithilfe deterministischer SQL-Abfragen aggregiert, über stateless-Dienste geleitet und durch einen kontrollierten konversationalen Ablauf bereitgestellt. Die Architektur zieht klare Ausführungsgrenzen über vier Schichten – nämlich Foundation, Daten, Dienste und Benutzererfahrung –, sodass die Ergebnisse reproduziert, geprüft und mit Unternehmensgeschwindigkeit innerhalb strenger Sicherheitsvorgaben bereitgestellt werden können.

Das Design entstand aus einem internen KI-Entwicklungsprojekt innerhalb des Microsoft-Ökosystems, und die unten genannten Leistungs- und Ergebnisangaben stammen von den Entwicklern selbst, wurden jedoch nicht unabhängig gemessen. Es ist besonders nützlich für Enterprise-Architekten, KI-Ingenieure und Plattformleiter, die deterministische KI-Systeme benötigen, die Datenkonsolidierung, SQL-Aggregation, stateless Orchestrierung sowie konversationelle Workflows voneinander trennen.

Das vierlagige Design

Der Agent folgt einem vierlagigen Orchestrierungsmodell, wobei jede Schicht eine spezifische Aufgabe hat und mehrere Azure-Dienste sowie Sicherheitsgrenzen umfasst:

  • Grundlage: Ein Microsoft Fabric Lakehouse, das Daten unter Governance konsolidiert.
  • Daten: Fabric SQL (ein Warehouse oder SQL-Endpunkt), der gespeicherte Prozeduren für operative Abfragen und Aggregationen enthält.
  • Dienst: Ein FastAPI-Orchestrierungsmechanismus, der in Azure Functions gehostet wird.
  • Benutzererfahrung: Ein Copilot Studio-Dialogworkflow, der die Absichten der Benutzer vermittelt.
  • Zusammen bilden sie einen einrichtungsorientierten Intelligenzpfad. Die Daten werden an der Basis kuratiert und verwaltet, deterministisch in SQL aggregiert, im Dienstebereich durch Domänenlogik zusammengestellt und schließlich über natursprachliche Interaktionen bereitgestellt. Jede Schicht hat einen expliziten Vertrag mit ihren Nachbarn, sodass das KI-Element zur Entscheidungsfindung beiträgt, diese aber nicht verunreinigt.

    Basislayer: verwaltete Datenkonsolidierung

    Microsoft Fabric dient als einheitliche Analyseplattform sowie als einzige Quelle der Wahrheit für Kontodetails, Finanzdaten, Nutzungsmetriken und historische Trends. Die Leitregel ist einfach: Speichern Sie die Daten einmal und wenden Sie sie mehrfach erneut an, damit nichts zwischen den Systemen doppelt aufgenommen wird.

    Ein Pipeline aktualisiert sich täglich, indem es Unternehmensdaten aus Dynamics 365, Finanzsystemen sowie externen APIs abruft und zusammenführt. Der Zeitplan sorgt für vorhersehbare Verarbeitungsfenster und stellt sicher, dass jedes Quellsystem seine täglichen Aufgaben abgeschlossen hat, bevor mit der Konsolidierung begonnen wird. Das Lakehouse bewahrt die Daten in ihrem ursprünglichen Format zusammen mit Verfolgungsmechanismen und Governance-Standards auf, wobei die verfeinerten Datensätze anschließend in Fabric SQL überführt werden – die schnelle operative Abfrageschicht, deren Strukturen auf die Erstellung von Managementberichten abgestimmt sind.

    Datenschicht: Ein für API-Zugriff konzipierter Betriebsmotor

    Diese Schicht wandelt sorgfältig ausgewählte Grunddaten in deterministische, niedriglatenzige Abfragesysteme zur Erstellung von Zusammenfassungen um. Sie legt strenge Aggregierungsgrenzen fest sowie die Leistungsversprechen, die Führungskräfte von einem reaktionsfähigen Tool erwarten.

    Architektur. Fabric SQL Warehouse ist eine relationale Schnittstelle, die jede datenbezogene Operation im Zusammenhang mit Berichten in gespeicherten Prozeduren abwickelt. Die Serviceebene fragt niemals direkt Tabellen ab. Komplexe Verknüpfungen zwischen Tabellen, die Bedeutung jeder Aggregation sowie die Geschäftslogik laufen alle innerhalb der Datenbank und nicht im Anwendungscode – dadurch bleiben die Reaktionszeiten bei großen Datenvolumina vorhersehbar. Der SQL ist für operative Abfragen optimiert, nicht für analytische Untersuchungen, und das Design zielt auf deterministische Verknüpfungen ab, die konsistente Ergebnisse liefern, auf wiederverwendbare Abfrageschemata für stabile Leistung, auf parametrisierte Ausführung zur Sicherheit sowie auf eingebettete Aggregationen, die einfacher zu warten sind.

    Philosophie des Schemas: Abfragen zuerst. Das Schema folgt den Abfragemustern und nicht der in Lehrbüchern beschriebenen Normalisierung. Die Entität „Account“ bildet die Hauptklustruktur, und die unterstützenden Tabellen sind so angeordnet, dass Join-Operationen anhand des Geschäftsidentifikators TPID effizient ablaufen.

         --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](
    

    Die Tabelle „Accounts“ ist die zentrale Entität, wobei TPID als Clustering-Schlüssel dient. Dies ermöglicht eine annähernd logarithmische Abfragezeit für die häufigsten suchbaren Informationen zu den Konten und erlaubt sowohl direkte TPID-Abfragen als auch Suchvorgänge nach Name.

    Hilfstabellen. Einige der Hilfstabellen zeigen, wie finanzielle Kennzahlen, Erkenntnisse zur AI-Nutzung sowie die Verfeinerung von Daten über verschiedene Systeme abgebildet werden.

    -- 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]);
    

    Die Einnahmen-Tabelle speichert finanzielle Daten mehrerer Jahre und verwendet zusammengesetzte Indizes, die sich für Zeitreihen- und Trendberechnungen eignen.

    -- 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]);
    

    Die Tabelle zur AI-Nutzung dokumentiert die Verbreitung der Produkte nach Kategorien, was eine Analyse der Nutzungsverhaltensmuster sowie der Technologieadoption ermöglicht – Faktoren, die für die Kontenplanung von Bedeutung sind.

    Strategie der gespeicherten Prozeduren: Die Geschäftslogik befindet sich in der Datenbank. Drei zentrale Prozeduren übernehmen die gesamte Informationsgenerierung. SearchAccounts findet Konten und ordnet sie nach Umsatz ein, GetAccountDetails aggregiert Daten aus verschiedenen Quellen zu einem vollständigen Überblick für Führungskräfte, und GetBriefingTemplate steuert die autorisierte Verwendung von Vorlagen je nach Rolle, sodass nur die entsprechenden Personen Zugang erhalten. Die Service-Schicht ruft ausschließlich diese Prozeduren auf; die Erstellung dynamischen SQLs ist dort nicht zulässig.

    --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;
    

    Leistung und Sicherheit. Transaktionen verwenden SET NOCOUNT ON zur Effizienzsteigerung sowie SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED für Lesevorgänge, damit diese nicht blockiert werden. Die Verarbeitung von JSON stützt sich auf SQL Servers native Funktionen JSON_QUERY und FOR JSON PATH, die den Prozess effizient abwickeln und direkt aus der Datenbank serialisieren. Nur parametrisierte Ausführungen sind zulässig, und die Serviceidentität der Anwendung erhält lediglich Ausführungsberechtigungen für die gespeicherten Prozeduren, ohne direkten Zugriff auf Tabellen.

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

    Dienstschicht: stateless Orchestrierung und Ausführungsgrenze

    Die Dienstschicht übernimmt rein die Datenorchestrierung. Sie holt Daten ab, rendernt Vorlagen und wendet keine eigenen Geschäftsregeln an. Jeder Dienst hat eine einzige Verantwortung und ist lose voneinander gekoppelt, wodurch die Daten- und Präsentationsschicht klar getrennt bleiben.

    API-Oberfläche und Validierung. Eine FastAPI-Anwendung stellt explizite REST-Endpunkte mit stark typisierten Verträgen bereit, die als Pydantic-Modelle definiert sind:

    • POST /api/briefing/generate ist der Haupt-Endpunkt für die Erstellung von Berichten, bei dem eine vollständige Eingabeverifikation erfolgt.
    • GET /api/health gibt den Systemzustand an.
    • GET /api/templates listet die dem aufrufenden Benutzer zur Verfügung stehenden Vorlagen auf.
    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
    

    Das Modell gewährleistet strenge Validierung und Typsicherheit, erzeugt automatisch OpenAPI-Dokumentation und stellt die Struktur jeder Anfrage sicher. Keine unstrukturierte Eingabe kommt an dieser Grenze vorbei.

    Ausführungsmodell. Der Service führt eine deterministische Fünf-Schritte-Sequenz aus:

    1. Anfragenvalidierung. Pydantic-Modelle stellen sicher, dass Typen und Eingaben zulässig sind.
    2. Kontoinformationen abrufen. Das Eingabeformat bestimmt, ob direkt ein TPID abgerufen wird oder ob für die Namenssuche SearchAccounts aufgerufen wird.
    3. Gleichzeitige Abfrage. GetAccountDetails und GetBriefingTemplate werden über asyncio.gather() gleichzeitig ausgeführt.
    4. Kontext zusammenstellen. Die Ergebnisse der Verfahren werden direkt in für Vorlagen bereitstehende Objekte umgewandelt, ohne Zwischenvorverarbeitung.
  • Vorlagenausgabe. Jinja2 erzeugt das Ausführungsdokument mit deterministischer Formatierung.
  • Durch asynchrone Ausführung und Verbindungspooling über eine DatabaseService-Abstraktion ergeben sich aus identischen Eingaben immer identische Ausgaben.

    Richtlinien. Fünf Regeln gelten für die Service-Schicht. Es gibt keine Geschäftslogik darin, da die Verarbeitung ausschließlich innerhalb von gespeicherten Prozeduren stattfindet, was den Service vor Regeln schützt, die das Testen und Warten erschweren würden. Sie übernimmt ausschließlich die reine Datenorchestrierung, koordiniert das Abrufen und Darstellen ohne jegliche Transformation oder Berechnung. Das Kontextkarten-Verfahren ist direkt, sodass die Ergebnisse der Prozeduren ohne Umwege in Template-Strukturen gelangen und so das Risiko verringert, dass die Bedeutung zwischen Daten und Präsentation verloren geht. Die Verarbeitung ist deterministisch, wodurch für denselben Eingang immer derselbe Ausgang erzeugt wird, unabhängig von Zeitpunkt oder Infrastrukturzustand. Zudem bleiben die Aufgaben klar getrennt: Die Datenlogik befindet sich in SQL-Prozeduren, die Orchestrierung in Python-FastAPI-Diensten und die Präsentation in Jinja2-Templaten.

    Erfahrungs-Schicht: Copilot Studio als Konversationsmotor

    Oben wandelt das AdaptiveDialog-Framework in Microsoft Copilot Studio eine Anfrage in natürlicher Sprache in einen deterministischen Arbeitsablauf um. Es kümmert sich um die Klärung der Kontoinformationen, die Autorisierung von Vorlagen, die Integration externer Daten, die Erstellung von Dokumenten sowie deren Übermittlung über mehrere Kanäle. Der Ablauf verläuft sequenziell von der ersten Anfrage über die Klärung der Kontoinformationen, die Autorisierung der Vorlagen, die Erfassung externer Daten bis hin zur Übermittlung an SharePoint, wobei an jedem Gesprächspfad Entscheidungspunkte und Validierungs Schritte vorhanden sind.

    Kerndialog. Der Dialog sammelt automatisch den Kontoinhaber-Identifikator ein, definiert die Auslösephrasen, die eine Einweisung starten, und legt den Haupteingangspunkt des Gesprächs fest:

    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
    

    Kontenlösung. Eine IsNumeric()-Prüfung klassifiziert die Eingabe entweder als direkten TPID oder als Kontonamen, der eine Suche erforderlich ist. Das Vermeiden von Suchvorgängen, wo immer möglich, reduziert die API-Aufrufe und beschleunigt die Antwort:

    - 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
    

    Aufruf zur Suche nach Konten. Für Namen ruft der Prozess über REST den Such-Endpunkt der Service-Schicht auf. Dabei werden Sonderzeichen URL-kodiert, mit einer Abonnementschlüssel authentifiziert und ein Antwortschema deklariert, damit die Daten automatisch validiert werden können:

    - 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
    

    Ausklarungskarte. Wenn eine Suche mehrere Konten ergeben hat, zeigt eine Anpassungskarte eine dynamische Auswahlmenge an, die mithilfe von ForAll() aus den Ergebnissen erstellt wird, wobei jede Eintragung ihren TPID anzeigt. Eine unpräzise Eingabe verhindert somit nicht den Fortgang des Gesprächs:

    - 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\"}]
    
      }')"
    

    Genehmigung von Vorlagen. Über GetBriefingTemplate prüft der Ablauf, ob der Benutzer aufgrund seiner organisatorischen Rolle sowie seines Zugehörigkeitsstatus zum Vorstand Executive-Vorlagen verwenden darf. Der Benutzername dient zur Identitätsüberprüfung, die Art der Besprechung filtert die Ergebnisse, und die Verwaltung der Vorlagen ist standardmäßig sicher:

    - 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
    

    Karte mit Details zur Besprechung. Die nächste Karte nutzt eine schrittweise Darstellung, indem die erforderlichen Felder zuerst angezeigt werden und die optionalen hinter einem Schalter versteckt sind. Dadurch verringert sich die kognitive Belastung, während der für eine Einweisung benötigte Kontext weiterhin erfasst wird:

    - 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\"}
    
        ]
    
      }')"
    

    Gleichzeitige Datenerfassung und Dokumentgenerierung. Die Experience-Schicht ruft gleichzeitig die Account Details API sowie Azure AI Foundry auf, wobei für jede Anfrage eine Frist von 60 Sekunden gilt. Nachdem beide Dienste geantwortet haben, erstellt sie einen strukturierten JSON-Inhalt aus allen Quellen und übermittelt diesen an die Dokumentgenerierungs-API. Dabei bleiben Validierung und Zusammenstellung eigenständig, sodass die Zusammenfassung deterministisch erstellt wird.

    Azure AI Foundry: Unternehmensintelligenz

    Durch die Integration von Foundry erweitert sich der Erfassungsbereich des Agents über externe Marktdaten hinaus um Kontexte aus dem Unternehmen selbst, wobei ein „M365 Researcher“-Komponente genutzt wird. Es werden delegierte Microsoft Graph-Zugriffsrechte verwendet, um E-Mails aus Outlook sowie Konversationen in Teams zu durchsuchen – dabei bleiben die Prozesse innerhalb der Unternehmenssicherheitsgrenzen sowie unter Berücksichtigung der Zero-Trust-Prinzipien.

    Delegierter Graph-Zugriff ohne gespeicherte Geheimnisse. Der Forscher verlässt sich auf delegierte Authentifizierung, die gespeicherte Client-Geheimnisse vollständig beseitigt. Dabei werden von Azure Logic Apps verwaltete Connector verwendet, die Microsoft-Anwendungen erster Klasse mit im Voraus genehmigten delegierten Berechtigungsbereichen sind. Dadurch entfällt die Last des Verwaltens von Anmeldungen, da Azure den Token-Lebenszyklus sowie das automatische Erneuern übernimmt.

    Zusätzlich wird der Zugriff auf die Daten eines Benutzers durch kurzlebige Logic Apps hinter HTTP-Trigger geschützt, die mit SAS gesichert sind. Jede Suche startet eine neue Logic-App-Instanz, holt parallel Daten aus Microsoft Graph und löscht die Instanz unmittelbar danach wieder, sodass eine SAS-URL nicht erneut verwendet werden kann und kein dauerhafter Token offen bleibt.

    // 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;
    };
    

    Paralleler Abruf und Anpassung des Graph-Datenbankmodells. E-Mail- sowie Teams-Daten werden gleichzeitig gesammelt, wobei Konkurrenzbeschränkungen eingehalten werden, damit die Sitzungen vieler Benutzer keine Drosselung auslösen. Bei E-Mails zieht der Office 365-Connector pro Benutzer die neuesten 250 Nachrichten heran, wobei das Filtern auf der Client-Seite erfolgt, um die Beschränkungen des Graph-Modells bei der Suche in den Nachrichtentexten zu umgehen. Bei Teams wird zunächst mithilfe paginierter Aufrufe nach Chats gesucht, anschließend werden die Nachrichten aus den einzelnen Chat-Threads mit einer einstellbaren Konkurrenzgrenze abgerufen.

    # 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
    

    Eine typische Suche führt etwa 101 Graph API-Aufrufe durch: einen für E-Mails, zwei zur Auflistung der Teams-Chats und im Durchschnitt 98 zum Abrufen der Chatnachrichten. Damit werden viele Daten abgerufen, bleiben gleichzeitig innerhalb der Konkurrenzlimits von Graph und halten laut Design die Antwortzeiten unter 60 Sekunden.

    Benutzerbezogene Verbindungen und Token. Jeder Benutzer benötigt zwei verwaltete Verbindungen, die delegierte OAuth-Token über Suchsitzungen aufrechterhalten: office365-{alias} für E-Mails mit dem Scope Mail.ReadWrite sowie teams-{alias} für Chats mit Chat.Read. Azures verwaltete Connector-Infrastruktur aktualisiert die Token automatisch und unterstützt die Einhaltung von Vorschriften. Die Bereitstellung erfolgt nach einem auf Zustimmung basierenden Ablauf, bei dem der Benutzer einmal über Microsofts eigenes OAuth-Interface einloggt; die delegierten Berechtigungen gelten bis zu ihrer Widerrufung. Die Function App verwaltet den Lebenszyklus der Verbindungen über Azure Resource Manager-APIs unter Verwendung einer verwalteten Identität, sodass keine Client-Zertifikate in der Anwendungslogik gespeichert werden.

    // 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);
    
    };
    

    Synthese mit einem GPT-Modell. Rohdaten aus Kommunikationen werden durch ein Modell aus dem Azure OpenAI Service – beschrieben als GPT-4.1, obwohl der Beispielcode eine Vorschauversion von GPT-4 angibt – in für Berichte geeignete organisatorische Erkenntnisse umgewandelt. Der Prozess wandelt gefilterte E-Mails sowie Inhalte aus Teams in strukturierte Erkenntnisse um, die eine Analyse der Beteiligten, Kommunikationsmuster sowie für das Meeting relevante Maßnahmen umfassen. Die Anfragen richten sich an Führungskräfte und beinhalten Anforderungen wie die Darstellung von Beziehungsnetzwerken, den Projektstatus sowie strategische Themen; das Modell liefert dabei strukturierte JSON-Daten, die in vorhandene Jinja2-Vorlagen eingefügt werden können und eine einheitliche Formatierung in allen Dokumenten gewährleisten.

    # 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)
    

    Integration in den Dialog. Der Forscher schließt sich dem Copilot Studio-Arbeitsablauf parallel zum herkömmlichen Abrufen von Kontodaten sowie externen Marktinformationen an, sodass der zusätzliche organisatorische Kontext voraussichtlich die Gesamtgenerierung der Zusammenfassungen nicht verlangsamt.

    # 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
    
      }
    

    Verwaltung und Konformität. Durch delegierte Berechtigungen können Benutzer nur ihre eigenen E-Mails sowie Teams-Nachrichten durchsuchen, wodurch ein Zugriff zwischen Benutzern verhindert wird und die Datengrenzen streng gehalten werden. Jeder Aufruf der Graph API wird mit Benutzerkontext, Suchparametern sowie Metadaten zu den Ergebnissen protokolliert. Die Aufbewahrungsfrist ist konfigurierbar, und Verbindungen, die über einen definierten Zeitraum – in der Regel 80 Tage – nicht genutzt werden, werden automatisch gelöscht. Die Verarbeitung findet innerhalb des Azure-Tenants statt, und die Kontrollen zur Datenspeicherung unterstützen die Verwaltungsrichtlinien der Organisation.

    // 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);
    
        }
    
    };
    

    Leistung und Fehlertoleranz. Das System speichert den Verbindungsstatus der Benutzer und überprüft den Verbindungsstatus, bevor teure Graph-Operationen ausgeführt werden. Falls Graph eingeschränkt oder kurzzeitig nicht verfügbar ist, funktioniert das System weiterhin zuverlässig, wobei für vorübergehende Fehler ein exponentielles Warteverfahren genutzt wird und strenge Zeitlimits verhindern, dass die Erstellung von Berichten verzögert wird. Wenn die organisatorische Suche fehlschlägt oder einen Zeitlimit erreicht, werden die Berichte dennoch zusammen mit Kontodaten und externer Marktinformationen versandt, sodass Führungskräfte unabhängig davon, ob Microsoft 365 verfügbar ist, eine konstante Erfahrung erhalten.

    // 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;
    
        }
    
    };
    

    Sobald der Forscher eingesetzt ist, wechselt der Agent von externen Marktinformationen zu einem umfassenden Bild, das auch Einblicke der internen Interessengruppen enthält, um bessere strategische Entscheidungen zu unterstützen, ohne die Sicherheits-, Governance- oder Leistungsstandards zu schwächen.

    Dokumentgenerierungsaufruf. In diesem Schritt wird die endgültige Zusammenfassung erstellt, indem alles, was im Gespräch gesammelt wurde, in einen einzigen Datensatz für die Service-Schicht zusammengefasst wird. Dieser enthält den Benutzerkontext, Details zur Besprechung sowie optionalen Erkenntnisse externer KI-Systeme, wobei für den gesamten Dokumentenprozess eine Frist von 60 Sekunden gilt:

    - 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
    

    Zustellung an SharePoint. Alle erzeugten Dokumente werden über den SharePoint-Connector der Power Platform mit verwalteter Authentifizierung in ein zentrales Repository übertragen, sodass jedes Dokument unabhängig von weiteren Zustellungsverfahren gespeichert und zugänglich bleibt, was den Anforderungen an die Governance entspricht. Die Zielseite und das Zielverzeichnis im untenstehenden Beispiel sind Platzhalter.

    - 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
    

    Die Dateinamen werden so erstellt, dass sie lesbar sind, indem sie den Kontonamen, den Identifikator des Entscheiders sowie das Treffenster kombinieren. Substitute() sorgt dafür, dass sie für das Dateisystem sicher sind, und bewahrt eine konsistente Benennung in allen Arbeitsabläufen der Entscheider:

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

    Fehlerbehandlung und Zustand. Fehlschläge beim Zugriff auf ein Template liefern kontextbezogene Anleitungen in einer warnenden Adaptive Card anstelle eines allgemeinen Fehlers. Der Ablauf prüft spezifische Fehlercodes aus der Service-API, teilt dem Benutzer mit, welche Autorisierung fehlt, und hält sensible Systemdetails aus Sichtweite:

    - 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
    
                  }]
    
                }]
    
              }
    

    Die Geschäftsvalidierung findet auf der Client-Seite statt, sodass ungültige Eingaben niemals die Backend-Dienste erreichen. Dadurch wird die Benutzererfahrung verbessert und unnötige API-Aufrufe vermieden. Ein Termin in der Vergangenheit wird beispielsweise umgehend abgelehnt und es werden Anleitungen gegeben, was zu tun ist:

    - 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
    

    Eine sicherheitsrelevante Bereinigungsphase löscht alle Variablen, die Kontodaten, API-Antworten sowie Benutzereingaben enthalten, sobald das Gespräch beendet ist. Dadurch werden Datenschutzanforderungen erfüllt und ein Anstieg des Speicherverbrauchs in langlaufenden Gesprächsdiensten, die vertrauliche Geschäftsinformationen verarbeiten, vermieden:

    - 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()
    

    Insgesamt bietet die Experience-Schicht eine konversationelle Orchestrierung mit deterministischen Workflows, umfassender Fehlerbehandlung, fehlertoleranten Aufrufen externer Dienste, rollenbasierten Autorisierungen sowie mehrkanaliger Übermittlung über das AdaptiveDialog-Framework.

    Sicherheit und Implementierungsdetails

    Föderierte Identität und Authentifizierung

    Das System verwendet Azure-föderierte Identitätsanmeldeinformationen, sodass keine Geheimnisse gespeichert werden und die Anmeldung in allen Umgebungen einheitlich funktioniert. Ein Anmeldeinformationen-Selektor erkennt, in welchem Umfeld der Code ausgeführt wird, und wählt das entsprechende Verfahren aus:

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

    In Azure wird eine verwaltete Identität verwendet, wobei die Anmeldeinformationen automatisch bereitgestellt und erneuert werden, während die lokale Entwicklung auf die Anmeldeinformationen von Azure CLI zurückgreift. Tokens werden auf threadsichere Weise im Cache gespeichert, und ihr Ablauf wird automatisch geregelt.

    Dienststruktur und Abhängigkeitsverwaltung

    Die Dienstschicht stützt sich auf die Abhängigkeitsinjektion, wodurch derselbe Code sowohl in Tests mit Simulaten als auch in voll konfigurierten Instanzen in der Produktion ausgeführt werden kann. Querschnittsaufgaben wie Fehlerbehandlung und Konfigurationsverwaltung werden von allen Dienstkomponenten gemeinsam genutzt, wobei jede Komponente (SharePoint, Datenbank, Power BI) über ihren Konstruktor optionale Abhängigkeiten entgegennimmt, ohne dabei eng mit externen APIs und Azure-Ressourcen verknüpft zu sein. Dies ermöglicht gründliche Tests mit Simulationsimplementierungen sowie zuverlässiges Verhalten in der Produktion durch angemessene Abstraktion.

    Die Orchestrierung erfolgt asynchron, um das Maximum aus der parallelen Datenerfassung zu ziehen. Wenn eine Zusammenfassung erstellt wird, werden mehrere Quellen mithilfe von async/await sowie sorgfältiger Fehlerbehandlung abgerufen, sodass das System bei Ausfall einer Quelle reibungslos weiterarbeiten kann.

    Datenbankverbindungen und Leistung

    Siebenebene Datenbankanbindung nutzt durch SQLAlchemy’s Engine-Management eine Verbindungs-Pooling-Strategie sowie einen Singleton, um Ressourcen effizient zu nutzen. Abfragen werden in gespeicherten Prozeduren gebündelt, die die Geschäftslogik direkt in der Datenbank enthalten; dadurch wird der Netzwerkverkehr reduziert und der Anwendungscode vereinfacht. Große Ergebnismengen werden durch intelligente Wiederaufbauweise von JSON bewältigt, wodurch die Einschränkungen von pyodbc bei großen Antwortmengen umgangen werden, sodass die Verarbeitung unabhängig von der Größe der Ergebnisse zuverlässig bleibt und der Speicherverbrauch im Rahmen bleibt.

    Integration externer Dienste

    Die Integration von SharePoint und Microsoft Graph speichert Eigenschaften verzögert, um API-Aufrufe zu reduzieren und gleichzeitig die Aktualität der Daten zu gewährleisten. Die IDs von Seiten und Speicherorten werden mit sinnvoller Gültigkeitsprüfung sowie dynamischer Auswahl von Bibliotheken gekachtet, wodurch Uploads zuverlässig ablaufen. Die Integration mit Dynamics 365 analysiert die Search v2.0-Antworten und wandelt die Rohdaten in für das Geschäft relevanten Strukturen um, wobei eine Wiederholungslogik für das Rate-Limiting sowie sorgfältige Fehlerbehandlung vorhanden sind.

    Dokumentenerstellung

    Der Generierungsprozess kombiniert die Verarbeitung von Jinja2-Vorlagen mit dem Aufbau eines Kontexts, der Rohdaten in für Führungskräfte nutzbare Erkenntnisse umwandelt. Der Vorlagenkontext enthält Rohdaten, berechnete Metriken, Formatierungshilfen sowie aus der Analyse mehrerer Systeme gewonnene Informationen. Die Vorlagenverwaltung überprüft die Syntax und handhabt Fehler, sodass die Generierung auch bei Änderungen der Vorlagen zuverlässig bleibt. Zudem werden durch MIME-Typ-Konfigurationen mehrere Ausgabeformate unterstützt, um eine flexible Bereitstellung zu ermöglichen.

    Fehler und Ausnahmen

    Die Anwendung verfügt über eine strukturierte Hierarchie von Ausnahmen, die detaillierte Fehlerinformationen liefert, ohne Sicherheitsgrenzen zu überschreiten. Benutzerdefinierte Ausnahmeklassen enthalten Kontextinformationen, die bei der Fehlersuche helfen, ohne interne Systemdetails preiszugeben:

    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()
    

    Ein globaler Ausnahmehandler wandelt technische Fehler in strukturierte API-Antworten um, die dem Aufrufer helfen, ohne zu viele Details preiszugeben.

    Bewertung und Qualitätsprüfung

    Das System wird mit einem strukturierten Testframework bewertet, das die technische Leistung sowie die Qualität der Berichte in mehreren Unternehmenskonten überprüft. Quantitative und qualitative Methoden werden in einem mehrstufigen Bewertungsprozess kombiniert, bei dem jede architektonische Komponente in Batches getestet wird.

    Auf der quantitativen Ebene liegt der Fokus auf der Genauigkeit der Daten. Die Metriken in den fertigen, mit Daten gefüllten Berichtsvorlagen werden mit den Quelldaten aus der Grundschicht verglichen, wobei der Prozessablauf Genauigkeitswerte sowie den durchschnittlichen absoluten Prozentsatzfehler (MAPE) berechnet. Diese Werte zeigen, inwieweit die Service-Schicht die Daten im gesamten Prozessablauf – von den Ergebnissen der gespeicherten Prozeduren bis zum endgültigen Dokument – zuverlässig weiterleitet. Batch-Ausführungen umfassen viele Konten und liefern ein konsolidiertes Leistungsprotokoll, das statistische Belege dafür liefert, dass ein rein orchestrierendes Design die Datengenauigkeit bewahrt, ohne Rechenfehler oder semantische Abweichungen zwischen Grund- und Benutzeroberflächen-Schicht zu verursachen.

    Die qualitative Bewertung misst ein einzelnes Kriterium – die Kompetenz des Unternehmens –, d.h. inwieweit eine Präsentation ein tatsächliches Verständnis der Zielorganisation zeigt und angemessen darüber spricht. Ein LLM-Bewerter bewertet jede Präsentation anhand von fünf Standardkriterien: Relevanz (ist der Inhalt geeignet für Entscheidungen von Führungskräften?), Kohärenz (logischer Ablauf und Aufbau), Genauigkeit (faktische Richtigkeit und Übereinstimmung mit den Quelldaten), Klarheit (Sprache und Präsentation, die sich an Führungskräfte richten) sowie Vollständigkeit (Abdeckung der strategischen Bereiche). Dieser Ansatz ermöglicht eine konsistente, skalierbare Bewertung mit objektiven Noten für verschiedene Kundenarten und Branchen – doch wie bei jeder auf LLMs basierenden Bewertung übernimmt er auch die Vorurteile des jeweiligen Bewertermodells.

    Nächste Schritte: Umstieg auf das Microsoft Agent Framework

    Das Team betrachtet die vierschichtige Architektur als gute Grundlage für den Umstieg auf das Microsoft Agent Framework (MAF), welches die KI-Orchestrierung stärken würde, ohne dabei die deterministischen Prinzipien zu verletzen. MAF würde hauptsächlich in der Service-Schicht eingesetzt, wobei die FastAPI-Orchestrierungslogik durch MAF-Agenten ersetzt würde, die denselben reinen Daten-Orchestrierungsmustern folgen. Die Erfahrungs-Schicht würde völlig verändert: Copilot Studio würde durch eine native Integration in Microsoft 365 ersetzt, wodurch Geschäftsprozesse innerhalb von Outlook, Teams und SharePoint ablaufen. Dabei wird die Sprachverständnisfunktion von MAF genutzt, um eine genauere Intentionserkennung sowie mehrteilige Gespräche zu ermöglichen, während weiterhin dieselben gespeicherten Prozeduren für die Business-Intelligenz aufgerufen werden.

    Die integrierte Überwachungsfunktion, das Tool für die Verwaltung von Nachrichten sowie die Werkzeuge zum Lebenszyklusmanagement von Agenten bei MAF würden eine eigene Infrastruktur überflüssig machen und unternehmensweite Überwachung sowie Bereitstellungsmöglichkeiten bieten. Der Migrationsweg bewahrt die bestehenden Investitionen in gespeicherte Prozeduren, Jinja2-Vorlagen sowie die Integration mit SharePoint, während gleichzeitig Funktionen für schwierigere Szenarien hinzugefügt werden – wie Besprechungen, die mehrere Konten umfassen, die Zusammenfassung von Wettbewerbsanalysen sowie Vorlagen, die dynamisch aus dem Kontext der Besprechung und den Teilnehmern erzeugt werden. Durch die Integration mit Microsoft 365 würde die Erstellung von Besprechungsunterlagen zu einer Funktion, die in bestehende Produktivitätsworkflows integriert ist und nicht über eine separate Chat-Schnittstelle erfolgt, wobei die Datenebene und die Serviceebene weiterhin deterministisch bleiben.

    Was das Design zeigt

    Der Agent verwandelt die Vorbereitung von Zusammenfassungen aus manueller Koordination in automatische Erstellung von Informationen durch vier Ebenen, die die Datenkonsolidierung, die operationelle Aggregation, die Geschäftsorchestrierung sowie die Interaktion in natürlicher Sprache voneinander trennen. Der deterministische Ansatz innerhalb von Microsofts integriertem Ökosystem soll eine schnelle Erstellung von Zusammenfassungen ermöglichen – der angegebene Zeitraum beträgt „unter einer Sekunde“, obwohl die Timeout-Werte des eigenen Pipelines bis zu 60 Sekunden betragen; damit ist vermutlich eher auf die Schritte in der Datenbank und bei den Diensten Bezug genommen – zusammen mit Sicherheits-, Verwaltungs- und Prüfungsmerkmalen, die rein promptbasierte Systeme nur schwer gewährleisten können.

    Die wichtigere Lektion ist, dass erfolgreiche Unternehmens-KI-Anwendungen die Lösung des Geschäftsproblems über technische Komplexität stellen und ihren Wert eher durch eine solide Datenintegration sowie Prozessautomatisierung als durch fortschrittliches Maschinellen Lernen schaffen. Eine schichtweise Trennung der Aufgaben, Dependency Injection sowie deterministische Ausführungsgrenzen machen dieses Design zu einem wiederverwendbaren Muster für die Automatisierung des Kundenservice, Workflows zur finanziellen Analyse sowie operative Intelligenz in anderen Organisationen.