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.
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.
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/generateist der Haupt-Endpunkt für die Erstellung von Berichten, bei dem eine vollständige Eingabeverifikation erfolgt.GET /api/healthgibt den Systemzustand an.GET /api/templateslistet 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:
- Anfragenvalidierung. Pydantic-Modelle stellen sicher, dass Typen und Eingaben zulässig sind.
- Kontoinformationen abrufen. Das Eingabeformat bestimmt, ob direkt ein TPID abgerufen wird oder ob für die Namenssuche
SearchAccountsaufgerufen wird. - Gleichzeitige Abfrage.
GetAccountDetailsundGetBriefingTemplatewerden überasyncio.gather()gleichzeitig ausgeführt. - Kontext zusammenstellen. Die Ergebnisse der Verfahren werden direkt in für Vorlagen bereitstehende Objekte umgewandelt, ohne Zwischenvorverarbeitung.
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.