Die Data2Day ist eine von wenigen deutschen Konferenzen, deren Thema nicht primär auf AI oder Machine Learning liegt, sondern sich dem Datenmanagement widmet. Sie wird vom Heise Verlag ausgerichtet und fand bereits zum achten Mal statt. Wir waren mit dabei und haben uns bemüht, mit unserem Vortrag eine Brücke zwischen beiden Themen zu schlagen: ‚SiloX-GPT: Daten-Silos verbinden mittels Multi-Agenten-System‘.
Unser Vortrag zu Multi-Agenten-Systemen
Unser Kollege Nico Kreiling beim präsentieren.
Gemeinsam mit Bertelsmann konnten wir die Ergebnisse unseres Content-Search Projektes vorstellen. In diesem Projekt lösen wir das Problem, dass es aufgrund der großen und verzweigten Firmenstruktur der sogenannten Berthelsphere keinen Ort gibt, wo sämtliche Daten der unterschiedlichen Bereiche entdeckt werden können. Wir lösen das Problem der sehr heterogenen Datenlandschaft dabei mit Hilfe von LLM-Agenten, welche mit Hilfe von Tools APIs abfragen, Knowledge-Graphs durchsuchen oder klassisches RAG durchführen können. Orchestriert wird all dies mit Hilfe von LangGraph, welches erlaubt Langchain-basierte Agenten und andere Verarbeitungsknoten in einem Kommunikationsgraphen frei zu modellieren. Neben der Vorstellung des Systems standen auch zahlreiche Learnings im Zentrum des Talks, denn in der ersten Zusammenarbeit zwischen Bertelsmann und Scieneers stand zunächst eine Evaluation der neuen technischen Möglichkeiten von LLMs im Zusammenspiel mit einem Knowledge-Graph im Vordergrund. Erst über mehrere Iterationen mit verschiedenen Stakeholdern hinweg entwickelte sich daraus die eigentliche Produktidee. Einige der wichtigen Learnings waren:
Technologie-Exploration und Produktentwicklung haben sehr unterschiedliche Anforderungen an Team, Organisationsform und Zielstellung
Tracing und Monitoring ist bei LLM-Applikationen mindestens so wichtig wie bei klassischer Softwareentwicklung, um ein resilientes und stabiles System zu entwickeln
Ein Multi-Agenten-Setup ähnelt einem Micro-Service-Design und bringt ähnliche Vorteile: Modulare Komponenten sorgen für bessere Wartbarkeit und Stabilität
LLM-Agenten sind mächtige Werkzeuge. Entscheidend ist dabei eine klare Ausrichtung des Prompts und der verwendeten Tools getreu dem UNIX-Motto: Do just one thing and do it well!
Die weiteren wichtigen Themen der Konferenz
Gefühlte Wahrnehmung von Data Science Teams Anfang 2023 (von Dr. Sarah Henni)
In der Eröffnungskeynote zeigte Dr. Sarah Henni von EnBW auf unterhaltsame Art den ChatGPT-Moment, als AI im Alltag vieler Menschen ankam und Postfächer von Data Science Abteilungen geflutet wurden. Seitdem wurden zahlreiche „Hook“-Projekte realisiert, die wichtig sind, um die neue Technologie zu erproben und ins Gespräch darüber zu kommen, wo nun die wirklichen Transformations-Potentiale liegen. Diese Einschätzung können wir nur bestätigen, denn nach vielen PoCs im Jahr 2023 liegt der Fokus dieses Jahr auch in unseren Projekten nun mehr auf Produktivierung, Stabilität und Resilienz. Außerdem haben immer mehr Projekte neben strategischen Zielen auch klare finanzielle KPIs.
Schematische Darstellung des MVC-Pattern für LLMs nach Robert Bauer
Ein weiterer spannender Vortrag kam von Robert Bauer von der HMS Analytical Software. Er nutzte das aus der Applikationsentwicklung bekannte MVC-Pattern, um LLM-Applikationen zu strukturieren. Soll etwa ein Blog-Eintrag von einem LLM verfasst werden, so werden die einzelnen notwendigen Felder (wie Überschrift, Volltext, Excerpt, Tags, SEO-Text etc.) mit Hilfe von Pydantic als Modell repräsentiert. Die View hat dann ausschließlich die Aufgabe, dieses rein-textuelle Modell mit Hilfe von HTML-Templates in einen ansprechend formatierten Eintrag zu überführen. Der Controller übernimmt schließlich mit Hilfe unterschiedlicher, möglichst atomarer und damit besser promptbarer LLM-Calls das Befüllen des Modells.
Der Ansatz überzeugt vor allem, weil er bei der Strukturierung des Codes hilft und ermöglicht eine große LLM-Anfrage in mehrere kleinere, für das LLM besser verarbeitbare Abfragen zu zerlegen. Darüber hinaus lassen sich mit Hilfe des Modells abhängige Felder identifizieren (der SEO-Text hängt beispielsweise von Überschrift und Text ab), die automatisch als invalide markiert werden können, wenn sich im Abhängigkeitsbaum zuvor etwas geändert hat.
Natürlich haben auch bekannte Data Management Themen wie etwa Data Mesh, Knowledge Graphs oder Data Contracts das Programm der Data2Day bestimmt. Aber auch diese wurden entsprechend um AI erweitert: So zeigten die Macher von datacontract.com ihren GPT-Bot zur automatischen Erzeugung von Verträgen.
Zu guter Letzt war auch der AI-Act ein wichtiges Thema der Konferenz. Gut gefallen hat uns hier vor allem die Sichtweise von Larysa Visengeriyeva, die ihn im Wesentlichen als rechtliche Verpflichtung von Software-Best-Practices (wie etwa Transparenz, Erklärbarkeit, Data Governance, Fehlertoleranz/Resilienz, Dokumentation) für AI darstellte.
Bei der Gelegenheit wollen wir uns abschließend beim Heise Verlag für die Durchführung der gelungenen Konferenz und das Vernetzen der vielen engagierten Sprecher und Teilnehmer bedanken.
https://www.scieneers.de/wp-content/uploads/2024/09/DPK_9954-scaled.jpg17092560Nico Kreilinghttps://www.scieneers.de/wp-content/uploads/2020/04/scieneers-gradient.pngNico Kreiling2024-09-24 16:24:462025-01-31 13:32:52Multi-Agenten LLM auf der Data2Day
API-Connections sind ein essenzieller Bestandteil von Azure Logic Apps, einer cloudbasierten Plattform zur Erstellung und Verwaltung automatisierter Workflows. Sie können als Brücke zwischen Logic Apps und externen Diensten oder APIs gesehen werden. Sie ermöglichen es, auf externe Datenquellen und Ressourcen wie Datenbanken, Web-APIs, SaaS-Anwendungen (z. B. Salesforce, Office 365) und andere Dienste zuzugreifen und diese in automatisierte Prozesse einzubinden.
API-Connections sind eigenständige Azure-Ressourcen, die innerhalb derselben Ressourcengruppe der Logic App erstellt werden. Dadurch können auch andere Logic Apps dieser Ressourcengruppe auf dieselbe API-Connection zugreifen und sie gleichermaßen nutzen.
Wie erstellt man eine API-Connection?
Um eine API-Connection manuell zu erstellen, wählt man innerhalb eines Workflows eine Aktion aus. Falls noch keine API-Connection angelegt ist, öffnet sich ein Dialogfenster, durch das man unter Angabe der korrekten Verbindungsdaten eine API- Connection anlegen kann:
Nach dem Anlegen der API-Connection erscheint diese mit dem vorher definierten Namen in der Aktion und kann künftig auch für weitere Aktionen Logic App-übergreifend in der gleichen Ressourcegruppe verwendet werden:
Obwohl API-Connections eigenständige Azure Ressourcen darstellen, können sie nicht manuell über das Azure Portal angelegt werden, sondern nur innerhalb einer Logic App.
Potenzielle Probleme
Wie bereits beschrieben, sind API-Connections eigenständige Azure Ressourcen und werden somit auch als solche angelegt. Bei der Erstellung der API-Connection wird ein Name definiert. Man könnte annehmen, dass er auch der Ressourcenname der API-Connection ist, welches leider nicht der Fall ist:
Die erstellte API-Connection bekommt einen generischen Ressourcennamen basierend auf der Verbindungsart. Dadurch hat sie zwei Namen: 1) einen internen Namen, der nur innerhalb der Logic App sichtbar ist, und 2) einen Ressourcennamen, der sowohl innerhalb als auch außerhalb der Logic App sichtbar ist. Unschön, aber bisher kein Problem. Falls man nun eine zweite Datenquelle des gleichen Typs anbinden möchte, so wird eine neue API-Connection erstellt und von Azure entsprechend benannt:
Diese Art der Benennung kann beispielsweise bei einer zunehmenden Anzahl von API-Connections die Übersichtlichkeit beinträchtigen und die Ressourcengruppe mit API-Connections überschwemmen, die möglicherweise gar nicht verwendet werden oder versehentlich angelegt wurden.
Zudem kann die Benennung bei der Integration in einen CI/CD-Prozess, je nach Setup, Probleme verursachen. Es könnte dadurch z.B. unklar werden, welche API-Connection für eine DEV/UAT/PROD Ressource steht, welche veraltet ist, etc.
Leider gibt es aktuell keine Möglichkeit mehr, eine API-Connection über die grafische Oberfläche im Azure Portal umzubenennen.
API-Connections können aber über ihr ARM-Template unter geändertem Namen neu deployed werden, was somit verschiedene Möglichkeiten eröffnet. Diese Möglichkeiten wollen wir uns in dem folgenden Abschnitt anschauen.
Deployment über das Azure Portal & Probleme
Eine Möglichkeit ist, das Deployment direkt über die Benutzeroberfläche des Azure Portal vorzunehmen.
Hierzu wird die gewünschte API-Connection und ihr ARM-Template über den Menü-Punkt „Export Template“ geöffnet. Da das ARM-Template in dieser Ansicht schreibgeschützt ist, wählt man „Deploy“ und dann „Edit Template“ aus, um zu einer editierbaren Ansicht des ARM-Templates zu kommen.
Hier öffnet sich ein neues Dialogfenster, in dem man einige Änderungen für ein valides ARM-Template vornehmen muss. Im Parameter-Objekt muss der Value für „defaultValue“ (blau umrandet) zum gewünschten API Connection Namen geändert werden.
Da „defaultValue“ im api-Objekt referenziert wird (rot umrandet), muss die Referenz durch die Art der Connection, hier sql, ersetzt werden.
Das Referenzieren des „defaultValues“ findet man logischerweise nur im api-Objekt, wenn die API-Connection wie die Art der Connection (z.B. sql) heißt. Wenn die umzubenennende API-Connection z.B. „sql-1“ heißt, werden die vorherigen Parameterreferenzen hartkodiert:
Nach dem Deployment der neuen API-Verbindung wird schnell klar, dass diese noch keine Verbindung zur gewünschten Quelle herstellen kann, da keine Zugangsdaten oder sonstige Authentifizierungsinformationen im ARM-Template enthalten bzw. übergeben worden sind. Diese Informationen müssen manuell über die Benutzeroberfläche des Azure Portals hinzugefügt werden:
Mögliche Probleme
Ein Problem bei dieser Art der Bereitstellung von API-Connections ist, dass bestimmte Konfigurationen, wie der „Authentication Type“, fest vom vorherigen Template übernommen werden. Im Vergleich zu den manuell erstellten API-Connections, die angepasst werden können, sind sie nicht mehr flexibel. Dies kann insbesondere dann problematisch werden, wenn die Sicherheitsanforderungen sich ändern und der Authentifizierungstyp entsprechend angepasst werden muss.
Automatisch erstellte API-Connection vs. Custom ARM-Template Deployment
Um die oben genannten Einschränkungen zu überwinden, kann das ParameterValueSet-Objekt im properties-Objekt des ARM-Templates hinzugefügt werden. Dieses Objekt ermöglicht eine flexible Konfiguration der API-Verbindung.
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"connections_cooleAPI_name": {
"defaultValue": "cooleAPI",
"type": "String"
}
},
"variables": {},
"resources": [
{
"type": "Microsoft.Web/connections",
"apiVersion": "2016-06-01",
"name": "[parameters('connections_cooleAPI_name')]",
"location": "westeurope",
"kind": "V1",
"properties": {
"displayName": "DWH-Connection",
"statuses": [
{
"status": "Connected"
}
],
"parameterValueSet": {
"name": "placeholder",
"values": {}
},
"customParameterValues": {},
"createdTime": "2024-08-27T06:40:25.2075565Z",
"changedTime": "2024-08-27T07:44:30.0313207Z",
"api": {
"name": "sql",
"displayName": "SQL Server",
"description": "Microsoft SQL Server is a relational database management system developed by Microsoft. Connect to SQL Server to manage data. You can perform various actions such as create, update, get, and delete on rows in a table.",
"iconUri": "https://connectoricons-prod.azureedge.net/releases/v1.0.1710/1.0.1710.3861/sql/icon.png",
"brandColor": "#ba141a",
"id": "/subscriptions/829bb898-ffa4-49b7-b8ef-ecf88d32b68e/providers/Microsoft.Web/locations/westeurope/managedApis/sql",
"type": "Microsoft.Web/locations/managedApis"
},
"testLinks": [
{
"requestUri": "[concat('https://management.azure.com:443/subscriptions/829bb898-ffa4-49b7-b8ef-ecf88d32b68e/resourceGroups/apiDeployments/providers/Microsoft.Web/connections/', parameters('connections_cooleAPI_name'), '/extensions/proxy/testconnection?api-version=2016-06-01')]",
"method": "get"
}
]
}
}
]
}
Das parameterValueSet-Objekt wird in ARM-Templates eigentlich verwendet, um Parameterwerte einer API-Connection zu definieren und zu konfigurieren. Es besteht hauptsächlich aus zwei Komponenten:
name: Der Name der Connection-Art, z.B. „keyBasedAuth “, „managedIdentityAuth“, etc. In der Regel entspricht der Name also einer vordefinierten Gruppe von Werten, die von der API erwartet werden.
values: Das Kernstück des parameterValueSet-Objekts, da es die tatsächlichen Verbindungsdaten enthält, die für die API-Connection benötigt werden.
Da wir in unserem Beispiel keine Credentials im Code übergeben wollen, sondern diese wie bisher über die Benutzeroberfläche im Azure Portal setzen wollen, lassen wir das Values-Objekt leer und übergeben dem name-Key einen zufälligen Wert.
Nach dem Deployment kann man nun die Verbindungsdaten hinzufügen, wie in den vorherigen Schritten schon beschrieben.
Deployment mit einem PowerShell Skript
Um die Fehleranfälligkeit zu reduzieren und repetitive Arbeit zu vermeiden, können einige der bisher händisch ausgeführten Schritte mithilfe eines PowerShell Skriptes automatisiert werden. Das nachfolgende Skript führt unter der Angabe von Daten (Subscription Id, Name der Ressourcengruppe, Connection Name, etc.) folgende Aufgaben aus und erzielt das gleiche Ergebnis wie das händisch bearbeitete ARM-Template:
Herunterladen des ARM-Templates einer angegebenen API-Connection
Ändern des defaultValues in den gewünschten API-Connection Namen
Ersetzen von Parameterreferenzen im API-Objekt
Hinzufügen des ParameterValueSet-Objekts
Deployment der API-Connection in der angegebenen Ressourcengruppe unter dem angegeben Ressourcennamen
Nachdem das Skript erfolgreich durchgelaufen ist, erscheint die API-Connection in der gewünschten Ressourcengruppe. Jetzt müssen die Verbindungsdaten noch manuell über das Azure Portal gesetzt werden, bevor die API-Connection einsatzbereit ist.
$subscriptionId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" # Your SubscriptionId
$rg = "apiDeployments"
$apiConnectionName = "sql"
$newApiConnectionName = "sql_dev"
$connectionType = "sql" # z.B. sql, azureblob, ftp
#SetContext
Set-AzContext -Subscription $subscriptionId
#Export template
$APIConnectionID=$(az resource show --resource-group $rg --name $apiConnectionName --resource-type Microsoft.Web/connections --query id --output tsv)
az group export --resource-group $rg --resource-ids $APIConnectionID > template.json
# Load JSON content into a variable
$jsonFile = "template.json"
$jsonContent = Get-Content -Path $jsonFile -Raw | ConvertFrom-Json
#Build ParameterName
$parameterConnectionName = $apiConnectionName.Replace('-','_')
$ParameterName = "connections_${parameterConnectionName}_name"
# Check if the 'defaultValue' property exists and add it if necessary
if (-not $jsonContent.parameters.$ParameterName.PSObject.Properties['defaultValue']) {
# Add the 'defaultValue' property with the desired value
$jsonContent.parameters.$ParameterName | Add-Member -MemberType NoteProperty -Name defaultValue -Value $NewApiConnectionName
} else {
# If exists, just update the value
$jsonContent.parameters.$ParameterName.defaultValue = $newApiConnection
}
# Access the specific resource and add the parameterValueSet if it doesn't exist
$jsonResource = $jsonContent.resources[0] # Assuming there's only one resource in the array
# Check if 'parameterValueSet' exists & add the 'parameterValueSet' property
if (-not $jsonResource.properties.PSObject.Properties['parameterValueSet']) {
$parameterValueSet = @{
name = "hasToBeSetInThePortal"
values = @{}
}
$jsonResource.properties | Add-Member -MemberType NoteProperty -Name parameterValueSet -Value $parameterValueSet
}
# Update the api properties (only if API Connectionname = ConnectionType)
if ($apiConnectionName -eq $connectionType) {
$jsonResource.properties.api.name = $ConnectionType
$jsonResource.properties.api.iconUri = $jsonResource.properties.api.iconUri -replace [regex]::Escape("parameters('$($ParameterName)')"), "'$($ConnectionType)'"
$jsonResource.properties.api.id = $jsonResource.properties.api.id -replace [regex]::Escape("parameters('$($ParameterName)')"), "'$($ConnectionType)'"
}
# Convert the modified JSON back to a string
$updatedJsonContent = $jsonContent | ConvertTo-Json -Depth 10
# Save the updated JSON back to the file
Set-Content -Path $jsonFile -Value $updatedJsonContent
# Deploy the new Api Connection
New-AzResourceGroupDeployment -Mode Incremental -Name "${NewApiConnectionName}-Deployment" -ResourceGroupName $rg -TemplateFile $jsonFile
Write-Host 'Deployment done'
Fazit:
API-Connections sind ein unverzichtbarer Bestandteil von Azure Logic Apps, da sie die Integration und den Zugriff auf externe Dienste und Datenquellen ermöglichen. Wenn jedoch zahlreiche verschiedene Datenquellen genutzt werden, kann die Verwaltung der API-Connections schnell unübersichtlich und komplex werden. Die in diesem Blog-Post beschriebenen Methoden bieten Strategien, um Struktur in die Verwaltung zu bringen und die Übersichtlichkeit zu verbessern, indem sie es erlauben entsprechende Ressourcennamen für API-Connections zu setzen
Darüber hinaus eröffnen diese Ansätze die Möglichkeit, Skripte und Methoden weiterzuentwickeln, um beispielsweise API-Connections nahtlos in CI/CD-Prozesse zu integrieren und automatisch mit den benötigten Verbindungsdaten zu deployen.
https://www.scieneers.de/wp-content/uploads/2024/09/Unbenannt.png10801920Maximilian Leisthttps://www.scieneers.de/wp-content/uploads/2020/04/scieneers-gradient.pngMaximilian Leist2024-09-20 16:23:142025-01-31 13:33:43Logic App API Connections – Herausforderungen und Lösungswege in der Verwaltung
Einblicke in die European Society of Human Genetics (ESHG) 2024 – eine beeindruckende, hybriden Veranstaltung, die Tausende von Besuchern aus aller Welt anlockte.
https://www.scieneers.de/wp-content/uploads/2024/06/53782461515_2a32608750_k.jpg13202048Martin Dannerhttps://www.scieneers.de/wp-content/uploads/2020/04/scieneers-gradient.pngMartin Danner2024-06-11 14:48:302024-06-14 09:30:44Einblicke in die European Society of Human Genetics Konferenz 2024
Am 28.05. ist der Deutsche Diversity Tag, der von dem Charta der Vielfalt e.V. initiiert wurde. Für uns scieneers hat Vielfalt einen sehr hohen Stellenwert und bildet das Fundament für den Umgang untereinander und mit unseren Kund:innen. Deswegen haben wir uns dazu entschieden, die Charta der Vielfalt zu unterschreiben und damit unsere Diversitätsstrategie weiter auszubauen.
Auf der diesjährigen Minds Mastering Machines (M3) Konferenz in Köln standen neben den neuesten Trends im Bereich Machine Learning besonders Sprachmodelle (LLM), aber auch der AI Act, AI Fairness und automatische Datenintegration im Fokus. Wir waren mit zwei talks zu unseren Projekten beteiligt.
Zusammen mit der Carl Remigius Fresenius Education Group (CRFE) entwickelten wir NextGeneration:AI. Dabei handelt es sich um eine datenschutzkonforme Plattform zur Nutzung von Sprachmodellen für alle Studierende und Mitarbeitende der CRFE. Das besondere an NextGeneration:AI ist die Authentifizierung über das Learning Management System Ilias mit Hilfe einer LTI-Schnittstelle, sowie die umfassende Personalisierbarkeit, die Nutzer:innen geboten wird. Im Blogartikel gehen wir auf die Details der Implementierung ein.
In diesem zweiten Teil zu Multi-Agenten-LLM-Systemen wird es um die Umsetzung komplexer Informationsflüsse mit Hilfe von LangGraph gehen. In Teil 1 wurde generell erklärt, warum Multi-Agenten-Systeme hilfreich sind und wie sie mit AutoGen umgesetzt werden können.
LangChain ist das populärste Framework für die Entwicklung von LLM-Applikationen. Es bietet nicht nur eine riesige Auswahl vordefinierter Text-Extraktionstools, Sprachmodelle und sonstiger Tools, sondern vor allem eine Hierarchie von Klassen. Typischerweise kombiniert man ein PromptTemplate mit einem LLM und optional einem Validator in einer Chain. Am einfachsten funktioniert dies durch die Nutzung der LCEL (LangChain Expression-Language), welche zwar etwas Gewöhnung erfordert, dafür aber kompakten und standardisierten Code ermöglicht.
from langchain.output_parsers.boolean import BooleanOutputParser
from langchain.prompts import PromptTemplate
from langchain_openai import AzureChatOpenAI
prompt = PromptTemplate.from_template(
"""Decide if the user question got sufficiently answered within the chat history. Answer only with YES or NO!
Sentences like "I don't know" or "There are no information" are no sufficient answers.
chat history: {messages}
user question: {user_question}
"""
)
llm = AzureChatOpenAI(
openai_api_version="2024-02-15-preview",
azure_deployment="gpt-35-turbo-1106",
streaming=True
)
parser = BooleanOutputParser()
validator_chain = prompt | llm | parser
# Zum Aufruf der Chain müssen alle Prompt-Variablen übergeben werden
validator_chain.invoke({
"user_question": "Was sind die aktuellen Trends in Italien?",
"messages": ["die aktuellen Trends Italiens sind heute Formel 1 und ChatGPT"],
}) # Returns True
Natürlich wird auch die Ausführung von Funktionen (bzw. Tools) von LangChain unterstützt. Hierfür müssen wir zunächst die auszuführende Funktion in ein LangChain-Tool umwandeln. Dies kann explizit oder via Funktionsannotation erfolgen. Der Vorteil hierbei ist, dass die notwendigen Informationen für die Nutzung in einem Sprachmodell automatisch aus den Docstrings der Funktion extrahiert werden und somit Redundanzen vermieden werden können.
from pytrends.request import TrendReq
def get_google_trends(country_name='germany', num_trends=5):
"""
Fetches the current top trending searches for a given country from Google Trends.
Parameters:
- country_name (str): The english name of the country written in lower letters
- num_trends (int): Number of top trends to fetch. Defaults to 5.
Returns:
- Prints the top trending searches.
"""
pytrends = TrendReq(hl='en-US', tz=360)
try:
trending_searches_df = pytrends.trending_searches(pn=country_name)
top_trends = trending_searches_df.head(num_trends)[0].to_list()
return top_trends
except Exception as e:
print(f"An error occurred: {e}")
from langchain.tools import StructuredTool
google_trends_tool = StructuredTool.from_function(get_google_trends)
google_trends_tool.invoke(input={})
Anschließend muss das erstellte Tool dem Modell übergeben werden. Nutzt man ChatGPT, unterstützt das Modell natives function_calling, sodass das Tool lediglich mit Hilfe des Aufrufs bind_functions aktiviert werden muss. Nun kann das Modell einen entsprechenden Funktionsaufruf bei Bedarf triggern, um die Funktion aber auch automatisch auszuführen und die Ergebnisse dem Modell zurückzugeben, muss die Chain in einen Agenten überführt werden. Hierfür existiert eine eigene Klasse, die neben der auszuführenden Chain lediglich einen Namen und die auszuführenden Tools benötigt.
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain.agents import create_openai_functions_agent
from langchain_core.utils.function_calling import convert_to_openai_function
from langchain_core.runnables import RunnablePassthrough
from langchain.agents.output_parsers.openai_functions import OpenAIFunctionsAgentOutputParser
from langchain.agents import AgentExecutor
from langchain_core.messages import HumanMessage
from langchain.agents.format_scratchpad.openai_functions import (
format_to_openai_function_messages,
)
from langchain_community.tools.tavily_search import TavilySearchResults
tavily_tool = TavilySearchResults(max_results=5)
tools = [google_trends_tool, tavily_tool]
system_prompt = "\\nYou task is to get information on the current trends by using your tools."
prompt = ChatPromptTemplate.from_messages([
("system", system_prompt),
MessagesPlaceholder(variable_name="messages"),
MessagesPlaceholder(variable_name="agent_scratchpad"),
])
agent = create_openai_functions_agent(llm, tools, prompt)
llm_with_tools = llm.bind(functions=[convert_to_openai_function(t) for t in tools])
agent = (
RunnablePassthrough.assign(
agent_scratchpad=lambda x: format_to_openai_function_messages(
x["intermediate_steps"]
)
)
| prompt
| llm_with_tools
| OpenAIFunctionsAgentOutputParser()
)
executor = AgentExecutor(name="Analyzer", agent=agent, tools=tools)
Mit der LangChain-Version 0.1 wurde zudem LangGraph als Konzept zur Implementierung von Multi-Agenten-Systemen eingeführt. LangGraph orientiert sich an der Idee von AutoGen, organisiert die Kommunikation jedoch nicht über einen freien Nachrichtenaustausch und geteilte Chat-Historie, sondern mittels eines Graphen. Das Interface orientiert sich an der beliebten NetworkX Python-Bibliothek und ermöglicht so eine flexible Komposition von gerichteten Graphen, welche auch zyklisch sein dürfen, also Schleifen enthalten können.
Zunächst wird ein Graph mit einem definierten Status definiert. Anschließend werden Knoten und Kanten hinzugefügt und ein Startpunkt gewählt. Kanten können statisch oder durch Bedingungen bestimmt werden, wodurch der Graph seine Dynamik erhält. Sowohl die Knoten wie auch die bedingten Kanten können einfache Python-Funktionen sein oder auch mittels LLM-Call bestimmt werden. Sie erhalten dafür jeweils den aktuellen State und geben einen neuen State für den nächsten Knoten zurück. Abschließend wird der Graph mit allen Knoten und Kanten zu einem “Pregel”-Objekt kompiliert.
from langchain_core.prompts import ChatPromptTemplate
from typing import TypedDict, Annotated, Sequence
import operator
from langchain_core.messages import BaseMessage
from langgraph.graph import StateGraph, END
compliance_prompt = ChatPromptTemplate.from_messages([
("system", """Make sure the answer is written in the same language as the user language.
The answer should be well-written in a formal style. It should use gender neutral language.
Modify the answer if necessary.
user question: {user_question}
chat history: {answer}
""")
])
compliance_chain = compliance_prompt | llm
class AgentState(TypedDict):
messages: Annotated[Sequence[BaseMessage], operator.add] = []
round: int = 0
workflow = StateGraph(AgentState)
def call_writer(data):
if data.get("round") is None:
round = 1
else:
round = data["round"] + 1
return {"round": round, "messages": [executor.invoke(data).get("output")]}
def call_compliance(data):
return {"messages": [compliance_chain.invoke({"user_question": data["messages"][0], "answer": data["messages"][-1]})]}
workflow.add_node("writer", call_writer)
workflow.add_node("compliance", call_compliance)
workflow.set_entry_point("writer")
workflow.add_conditional_edges(
"compliance",
lambda x: validator_chain.invoke({"user_question": x["messages"][0], "messages": x["messages"][1:]}) if x["round"]<2 else True,
{
True: END,
Fals4e: "writer"
}
)
workflow.add_edge('writer', 'compliance')
app = workflow.compile().with_config(run_name="Conduct Interviews")
app.invoke({"messages": [HumanMessage("Was sind die derzeit größten Trends in der Türkei?")]})
Dieser Pregel-Graph implementiert selbst das LangChain Runnable Interface, kann also synchron wie asynchron und als Stream- oder Batch-Operation ausgeführt werden. Typisch für LangChain wird die Komplexität selbst also möglichst vor dem Nutzer verborgen, was jedoch auch das Debugging erschwert. Sehr hilfreich ist in diesem Zug LangSmith, die von LangChain entwickelte Monitoring-Lösung. Die Integration erfordert lediglich einen API-Key, anschließend werden sämtliche Events in die Cloud gestreamt und dort in einer benutzerfreundlichen WebUI dargestellt. Diese bietet einen schnellen Einblick in sämtliche ausgeführte Operationen wie LLM-API-Calls, ausgeführte Tools und aufgetretene Fehler. Dazu werden Ausführungszeiten, generierte Tokens bzw. deren Kosten sowie zahlreiche System-Meta-Informationen getrackt.
Wer LangSmith nicht nutzen möchte oder mehr Kontrolle wünscht, kann dem Workflow einen eigenen Callback mitgeben und darin auftretende Events weiterverarbeiten. Beispielsweise eignen sich Callbacks auch, um eine eigene UI anzuschließen. Die Implementierung ist durchaus aufwändig, denn es existieren insgesamt 14 verschiedene Event-Typen, die bei Start, Ende und Fehlern von unterschiedlichen Aktionen relevant sind. In unserem Fall konnten wir leider nicht in jedem Event die gewünschten Informationen extrahieren, sondern mussten teilweise auf verlinkte Parent-Events zurückgreifen, sodass wir selbst einen Graph-Callback entwickelt haben, über den sich auch die Komplexität der versteckten Aufrufe innerhalb eines LangGraph-Calls visualisieren lässt.
Vergleich zwischen LangGraph und AutoGen
AutoGen
LangGraph
Projektstatus
Als erstes Framework für Multi-Agenten-Systeme erfreut sich AutoGen großer Beliebtheit. Das Projekt wird durch Microsoft vorangetrieben, basiert aber architektonisch auf dem dünnen Fundament eines wissenschaftlichen Aufsatzes.
Die Multi-Agenten-Lösung des populärsten LLM-Frameworks wurde im Januar 2024 veröffentlicht. Sie nutzt erste Erfahrungen von AutoGen und kombiniert sie mit Ansätzen aus etablierten Open-Source-Projekten (NetworkX, Pregel). LangGraph wird als eine Komponente des LangChain-Ökosystems fortgeführt.
Function Calling
Bei Autogen werden sämtliche Funktionsausführungen durch einen idee proxy agent ausgeführt. Entweder nativ oder für mehr Sicherheit innerhalb eines Docker Containers.
In LangChain können Funktionen und Agenten selbst in Executables verwandelt werden. Das vereinfacht die Struktur, eine Kapselung von Funktionsausführung in einer separaten Sandbox wie bspw. einem Container ist derzeit nicht vorgesehen..
Nachrichtenfluss
Die Kommunikation zwischen Agenten erfolgt innerhalb eines Gruppenchats prinzipiell frei und wird über einen group chat manager gesteuert. Dies bietet viel Flexibilität für Agenten, aber erschwert explizite Struktur.
Die Kommunikation wird durch einen Graphen abgebildet. Darüber lassen sich auch spezifische Kommunikationspfade einfach und intuitiv abbilden. Durch Conditional Edges sind aber auch komplett offene Gruppengespräche zwischen Agenten abbildbar.
Usability
AutoGen bietet mit seinen Beispielen und dem AutoGen Studio einen einfachen Einstieg in die Nutzung mehrerer Agenten. Möchte man jedoch nicht nur Prompts und Tools modifizieren, müssen die eigentlichen Agentenklassen erweitert werden, was Upgrades und Maintenance erschwert.
LangChain ist ein mächtiges Framework, das versucht, Komplexität vor dem Nutzer zu verstecken, ihn dafür aber abverlangt, zahlreiche Framework-Eigenheiten zu erlernen. Der hohe Grad an Abstraktion führt jedoch gerade zu Beginn oft zu Hindernissen. Hat ein Nutzer jedoch die Spezifika von LangChain verstanden, ist der Einsatz von LangGraph einfach und intuitiv.
Reifegrad
Autogen eignet sich hervorragend für einen Einstieg ins Thema Multi-Agenten, jedoch ist es schwierig, produktive Use-Cases hiermit umzusetzen. Gruppenkonversationen sind wenig verlässlich und es gibt keine Unterstützung bezüglich Monitoring und Ähnlichem. Durch die geteilte Chat-Historie der Agenten werden die ausgeführten Prompts schnell lang und damit teuer und langsam.
LangGraph ist eine noch junge Software auf einem gut durchdachten Fundament. Das LangChain-Ökosystem bietet zahlreiche Output-Parser und Möglichkeiten des Fehlermanagements. LangGraph bietet zudem eine genaue Kontrolle, welcher Knoten zu welchem Zeitpunkt welche Informationen verfügbar haben soll und Business-Anforderungen an den Kommunikationsfluss lassen sich flexibel abbilden. Zudem wird es durch seine Serving- und Monitoring-Infrastruktur unterstützt.
Fazit
AutoGen hat einen wertvollen Beitrag für Multi-Agenten-Systeme geleistet und eignet sich gut für erste Experimente. Wer allerdings eine genauere Kontrolle über die Kommunikation der Agenten wünscht oder eine produktive Anwendung bauen möchte, sollte eher auf LangGraph setzen. Wir selbst haben kürzlich eine existierende Anwendung von AutoGen auf LangGraph umgebaut. Während die Umsetzung der Agenten und Tools relativ einfach war, lagen die größten Aufwände in der Migration der UI-Anbindung, um via LangGraph-Callback alle notwendigen Informationen bezüglich Tool- und LLM-Nutzung abzubilden. Zudem unterstützen beide Frameworks bisher noch nicht nativ die parallele Ausführung von Agenten, wenn anschließend die Ergebnisse zusammengeführt werden sollen. Dennoch lässt sich sagen, dass sich mit LangGraph und LangSmith auch komplexe Workflows unter Einbeziehung von LLMs erstellen und betreiben lassen.
https://www.scieneers.de/wp-content/uploads/2024/03/Screenshot-2024-03-28-at-17.48.35.png17703108Nico Kreilinghttps://www.scieneers.de/wp-content/uploads/2020/04/scieneers-gradient.pngNico Kreiling2024-03-28 17:49:562025-01-31 13:40:05Multi-Agenten-LLM-Systeme kontrollieren mit LangGraph
Nachdem 2023 große Sprachmodelle die Masse erreichten und Retrieval-Augmented-Generation-Use-Cases im Fokus der meisten Anwender lagen, rücken 2024 Agenten deutlicher ins öffentliche Blickfeld. Agenten sind (teil-)autonom arbeitende Instanzen, die es ermöglichen, Chat-Anwendungsfälle flexibler zu gestalten. Soll in einem Chat nicht immer das gleiche Dokumentenarchiv über RAG eingebunden werden, sondern je nach Use-Case unterschiedliche Informationsquellen herangezogen werden, so können Agenten beispielsweise selbstständig entscheiden, welche für eine Abfrage die richtige ist. Es können aber nicht nur Datenbanken bzw. nicht-textuelle Informationen integriert werden, sondern auch jeder IT-Prozess, von der Veröffentlichung von Inhalten auf der Website bis hin zur Erstellung und Ausführung von Softwarecode. Der Fantasie sind bezüglich dessen, was mit generativer KI möglich sein könnte, keine Grenzen gesetzt, doch die praktische Umsetzung stößt schnell auf Herausforderungen in Bezug auf Stabilität und Verlässlichkeit.
Dieser Blog-Post diskutiert, wann mehrere kollaborativ zusammenarbeitende Agenten hilfreich sein können. Er ist der erste einer Serie: In diesem werden die Bausteine eines Multi-Agenten-Systems erklärt sowie deren Umsetzung mit Autogen, der ersten Bibliothek speziell für Multi-Agenten-Setups. Der zweite Teil wird dann auf LangGraph eingehen, die kürzlich erschienene Bibliothek zur Umsetzung von Multi-Agenten-Workflows aufbauend auf die beliebte Bibliothek LangChain.
Wann benötigt man mehrere Agenten
Zunächst sollte klar gestellt werden: Mehrere Agenten helfen nicht, wenn es darum geht, eine einzige Aufgabe besonders gut zu lösen. Ist die Aufgabe hingegen gut in mehrere Teilaufgaben zerteilbar, dann können mehrere, spezialisierte Agenten, die zusammenarbeiten, ein guter Ansatz sein. Wollt ihr beispielsweise Kundenanfragen automatisch beantworten, aber das Modell trifft nicht den Kommunikationsstil des Unternehmens, solltet ihr die Zeit lieber in Fine-Tuning stecken. Wenn für die Beantwortung aber verschiedene Informationsquellen erfragt, zusammengefasst und anschließend nochmal unter Berücksichtigung der Corporate-Communication-Policy validiert werden soll, könnte die Aufteilung auf mehrere Agenten hilfreich sein.
Sprachmodelle wie ChatGPT generieren nicht nur Text, sondern wurden inzwischen auch für Function Calling gefinetuned. Auf diese Art wurde ihnen prinzipiell das Konzept von Funktionsaufrufen erklärt. Allerdings können sie derzeit selbst keine Funktionen direkt aufrufen, sondern sagen lediglich, dass sie eine bestimmte Funktion mit gewissen Parametern aufrufen würden. Die tatsächliche Ausführung der Funktion erfordert dann eine entsprechende Runtime. Kombiniert man diese mit der Intelligenz des Sprachmodells, erhält man einen Agenten, der beispielsweise selbstständig Programmcode erstellen, ausführen und anhand der Fehlermeldungen debuggen kann. Ein solcher Agent ist ein besonders mächtiges Tool, da er im Gegensatz zu einem reinen LLM nicht nur in der Lage ist einen textuellen output zu generieren, sondern darüber hinaus selbstständig Handlungen planen und ausführen kann. Grundsätzlich können derartige Agenten mit den unterschiedlichsten Tools kombiniert werden, etwa zum Suchen von Informationen aus einer Datenbank, zum Abfragen einer WebAPI, zur Analyse von Bildern oder zur Erstellung einer Website. Natürlich kann man diese sehr unterschiedlichen Tools zur Ausführung alle in einem Agenten kombinieren, und einen genrealistischen Agent bauen; jedoch muss man dann Kompromisse machen. Manche Aufgaben erfordern ein besonders gutes und teures Sprachmodell, für andere reicht ein kleines Modell mit Fine-Tuning. Selbst wenn nur ein Modell für alles genutzt wird, empfehlen sich meist unterschiedliche Konfigurationen, etwa ein niedriger Temperature-Wert für Programmieraufgaben, ein höherer für kreatives Schreiben. Darüber hinaus brauchen Agenten, die etwa Informationen aus einer Datenbank extrahieren sollen, ausführliche Informationen zu Tabellenschemata im System-Prompt, sodass unterschiedliche Tools hier stark konkurrieren würden. Zu guter Letzt stellt sich die Frage, warum ein Agent alles gleichzeitig können sollte, wenn sich in der UNIX- und Microservice-Philosophie immer wieder gezeigt hat, dass unterschiedliche Aufgaben in unterschiedlichen Teilen behandelt werden sollten.
Autogen – das erste Framework für Multi-Agent-Systeme
Autogen ist ein Framework zur Erstellung solcher Multi-Agenten-Systeme. Es basiert auf einem 2023 vorgestellten Paper und ist als Open-Source-Repository von Microsoft verfügbar. Im Autogen-Konzept sind Multi-Agenten-Systeme Gruppenkonversationen zwischen verschiedenen conversable_agent Objekte, die durch eine Python-Klasse manifestiert sind. Es gibt 3 Arten von Conversable Agents:
UserProxyAgent: Repräsentieren den Nutzer. Sie senden die Eingaben des Nutzers in die Konversation und geben das Ergebnis zurück. Darüber hinaus sind sie auch zuständig für das eigentliche Ausführen von Funktionen, die von anderen Agenten aufgerufen werden.
GroupChatManager: Verwaltet den Gesprächsfluss zwischen den Agenten. Dieser wähl zudem nach der Antwort eines Agenten den nächsten zuständigen Agenten. Dies erfolgt je nach Konfiguration entweder selbst durch den Aufruf eines Language Models oder nach einfachen Heuristiken (zufällig, round-robin).
AssistantAgent: Die eigentlichen inhaltlichen Agenten, welche spezifisch für die gewünschten Aufgaben konfiguriert werden.
Das Basis-Konzept besteht darin, dass ein Agent einem anderen eine Nachricht sendet, mit der optionalen Bitte um eine Antwort. Kombiniert man nun mehrere solcher Agenten in einen Gruppen-Chat, so werden die Nachrichten nicht nur einem, sondern in der Regel allen Teilnehmern weitergeleitet, sodass eine gemeinsame Chat-Historie entsteht. Auf diese Art haben Agenten einen gemeinsamen Wissenspool und können auf der Arbeit der Vorgänger aufbauen. Hierfür finden sich bei Autogen zahlreiche Beispiele, etwa um mit Hilfe eines Programmierers zunächst relevante Paper herunterzuladen und diese von einem Produktmanager anschließend daraus Produktideen generieren zu lassen. Gleichzeitig führt dieses Vorgehen bei größeren und komplexeren Gruppengesprächen dazu, dass die Chat-Historie schnell wächst und Abfragen langsamer und teurer werden.
llm_config = {"config_list": config_list_gpt4, "cache_seed": 42}
user_proxy = autogen.UserProxyAgent(
name="User_proxy",
system_message="A human admin.",
code_execution_config={
"last_n_messages": 2,
"work_dir": "groupchat",
"use_docker": False,
},
human_input_mode="TERMINATE",
)
coder = autogen.AssistantAgent(
name="Coder",
llm_config=llm_config,
)
pm = autogen.AssistantAgent(
name="Product_manager",
system_message="Creative in software product ideas.",
llm_config=llm_config,
)
groupchat = autogen.GroupChat(agents=[user_proxy, coder, pm], messages=[], max_round=12)
manager = autogen.GroupChatManager(groupchat=groupchat, llm_config=llm_config)
user_proxy.initiate_chat(
manager, message="Find a latest paper about gpt-4 on arxiv and find its potential applications in software.")
Für zahlreiche Applikationen wäre es nützlich, nicht eine offene Gruppendiskussion zwischen allen Agenten zu führen, sondern den Gesprächsverlauf genauer zu kontrollieren. Auch dies ist mit Autogen prinzipiell möglich und es existieren ein paar Beispiele, wie etwa ein Schachspiel, bei dem zwei Spieler einerseits mit dem Spiel, andererseits miteinander kommunizieren. Hierfür müssen speziellere AssistantAgent-Klassen erstellt werden, welche mit Hilfe von register_reply zusätzliche Antworten-Funktionen registrieren. Der erste Parameter ist dabei als ein Filter zu verstehen, für welche Art von Nachrichtensender diese Antwortfunktion genutzt werden soll. In der Antwortfunktion wird im Fall von _generate_board_reply die besondere Logik des Schachspiels abgehandelt und ein Tuple aus True und dem gewählten Zug zurückgegeben. Das True besagt, dass die Funktion eine abschließende Antwort generiert hat und entsprechend keine weiteren registrierten Antwort-Funktionen ausgeführt werden sollen.
sys_msg = """You are an AI-powered chess board agent.
You translate the user's natural language input into legal UCI moves.
You should only reply with a UCI move string extracted from the user's input."""
class BoardAgent(autogen.AssistantAgent):
board: chess.Board
correct_move_messages: Dict[autogen.Agent, List[Dict]]
def __init__(self, board: chess.Board):
super().__init__(
name="BoardAgent",
system_message=sys_msg,
llm_config={"temperature": 0.0, "config_list": config_list_gpt4},
max_consecutive_auto_reply=10,
)
self.register_reply(autogen.ConversableAgent, BoardAgent._generate_board_reply)
self.board = board
self.correct_move_messages = defaultdict(list)
def _generate_board_reply(
self,
messages: Optional[List[Dict]] = None,
sender: Optional[autogen.Agent] = None,
config: Optional[Any] = None,
) -> Union[str, Dict, None]:
message = messages[-1]
# extract a UCI move from player's message
reply = self.generate_reply(
self.correct_move_messages[sender] + [message], sender, exclude=[BoardAgent._generate_board_reply]
)
uci_move = reply if isinstance(reply, str) else str(reply["content"])
try:
self.board.push_uci(uci_move)
except ValueError as e:
# invalid move
return True, f"Error: {e}"
else:
# valid move
m = chess.Move.from_uci(uci_move)
display( # noqa: F821
chess.svg.board(
self.board, arrows=[(m.from_square, m.to_square)], fill={m.from_square: "gray"}, size=200
)
)
self.correct_move_messages[sender].extend([message, self._message_to_dict(uci_move)])
self.correct_move_messages[sender][-1]["role"] = "assistant"
return True, uci_move
Mit Hilfe dieser Logik lassen sich prinzipiell vielfältige Kommunikationsmuster erstellen, in der Praxis wird diese Logik insbesondere bei komplexeren Setups diese Logik aber schnell kompliziert und unübersichtlich, denn der Nachrichtenfluss wird in vielen verschiedenen Klassen zerstreut definiert und hängt von Sender und Position der Antwort-Registration ab. Soll darüber hinaus auch gesteuert werden, wer welche Informationen erhält, so muss dies gesondert innerhalb des GroupChatManagers geregelt werden, was anspruchsvolle Kommunikationsflüsse weiter erschwert.
Fazit
Multi-Agenten-Systeme sind hilfreich, wenn komplexere (teil-)autonome Systeme gebaut werden sollen. Sie ermöglichen es, für jede Teilaufgabe einen speziellen Agenten zu definieren mit Hinblick auf Prompting, Modellauswahl und Konfiguration. Autogen war das erste Framework, das Entwickler bei der Definition solcher Systeme unterstützt und bietet zahlreiche Beispiele, insbesondere für offene Gruppengespräche. Sollen jedoch ein bewusst gesteuerter Informationsfluss realisiert werden, ist Autogen aufgrund seines Designs weniger geeignet. Hierfür empfehlen wir einen Blick in den zweiten Teil dieser Blogpost Reihe: Multi-Agenten-LLM-Systeme kontrollieren mit LangGraph
https://www.scieneers.de/wp-content/uploads/2024/03/DALL·E-2024-03-24-09.52.46-Revise-the-cover-image-for-the-article-Eine-Einfuehrung-in-Multi-Agent-AI-mit-AutoGen-to-focus-on-small-robot-heads-representing-agents-within-a-mult.webp10241792Nico Kreilinghttps://www.scieneers.de/wp-content/uploads/2020/04/scieneers-gradient.pngNico Kreiling2024-03-24 09:55:552025-01-31 13:40:29Eine Einführung in Multi-Agent-AI mit AutoGen
Row-Level-Security (RLS) ist ein Konzept in Power BI, welches es ermöglicht, den Zugriff auf Daten auf Zeilenebene zu steuern. Mit RLS kann festlegt werden, welche Daten bestimmte Reportuser oder Usergruppen sehen dürfen, basierend auf definierten Rollen. Diese Rollen können auf verschiedenen Regeln bzw. Kriterien basieren, wie z.B. Benutzerrollen, Abteilungszugehörigkeit oder individuellen Berechtigungen. So können Sie sicherstellen, dass jeder Reportuser nur die Daten sieht, auf die er zugreifen darf und gleichzeitig die Datensicherheit und -integrität gewährleisten.
Wie implementiert man es & wo gibt es Probleme?
Um zu erklären, wie man RLS implementieren kann, wird als Beispiel ein Auszug der Adventureworks Sales LT DB herangezogen:
AdventureWorks Sales LT ist eine von Microsoft entwickelte fiktive Datenbank. Sie enthält typische Daten eines Unternehmens, insbesondere im Bereich Vertrieb (Sales), wie zum Beispiel Produkte, Bestellungen und Verkaufstransaktionen:
SalesLT.Product: und SalesLT.ProductCategory: Hier werden Produkte kategorisiert und Produktinformationen gespeichert, einschließlich Produktname, Beschreibung, Preis usw.
SalesLT.SalesOrderHeader und SalesLT.SalesOrderDetail: Diese Tabellen enthalten Informationen zu Verkaufsaufträgen, wie Auftragsdatum, Lieferadresse, Bestellpositionen und -details.
SalesLT.Address: Diese Tabelle enthält Adressinformationen, die mit Verkaufsaufträgen verknüpft sind.
Für das Beispiel wird das Modell noch um die Tabelle SalesLT.Employee ergänzt, die Informationen über Mitarbeiter im Vertrieb enthält. Somit können Verkäufe Mitarbeitern zugeordnet werden, um nachzuvollziehen, wer für bestimmte Transaktionen verantwortlich ist.
Datenbank-Schema unseres Test-Use-Cases
EINFACHER USECASE
Ein unkomplizierter und leicht umzusetzender Anwendungsfall für Row-Level-Security liegt vor, wenn der Kontext direkt aus den vorhandenen Daten abgeleitet werden kann. Beispielsweise, wenn Sales-Mitarbeiter Verkäufe tätigen, die in einem Report dargestellt werden sollen, um ihren Fortschritt zu verfolgen. In diesem Szenario ist es wichtig, dass jeder Sales-Mitarbeiter ausschließlich seine eigenen Verkaufszahlen einsehen kann.
Dies lässt sich einfach realisieren, da jedem Verkauf ein bestimmter Sales-Mitarbeiter zugeordnet werden kann. Die Umsetzung und Pflege gestalten sich ebenfalls unkompliziert, da lediglich eine Rolle definiert und verwaltet werden muss, um dieses Szenario abzudecken.
KOMPLIZIERTER USECASE
Es wird komplizierter, wenn der Bezug des Reportusers nicht aus dem vorhandenen Kontext der Daten abgeleitet werden kann, das heißt es keine direkten Verbindungen zwischen Reportuser und Records des Datenmodells gibt. Ein Beispiel hierfür sind Sales-Manager, die für unterschiedliche Regionen, Mitarbeiter oder Vertriebskanäle zuständig sind, jedoch keine eigenen Verkäufe vorweisen können. In solchen Fällen müssen für jede mögliche Ausprägung separate Rollen erstellt, zugewiesen und verwaltet werden, was sowohl zeitaufwändig als auch fehleranfällig sein kann, da dies händisch erfolgt.
Insbesondere bei einer großen Anzahl von Reports erhöht sich der Aufwand erheblich, da für jeden Report die individuellen Rollen gleichermaßen erstellt, zugewiesen und gepflegt werden müssen. Dies steigert das Fehlerpotenzial zusätzlich und erfordert eine umfassende Verwaltung der Zugriffsstruktur.
Lösung: Entwicklung von Security-Tabellen und pflege über eine grafische Oberfläche wie Power Apps
Eine Möglichkeit, diese Zugriffsstruktur bereitzustellen, ist die Entwicklung von Security-Tabellen. Hier werden die Berechtigungsattribute und die User losgelöst vom eigentlichen Datenmodell abgebildet und über Mapping-Tabellen (User_2_) einander zugeordnet.
Die Mapping-Tabellen werden anschließend aufbereitet und im Power BI-Datenmodell per DirectQuery an die entsprechenden Tabellen angebunden, sodass die vorgenommenen Änderungen an der Berechtigung auch sofort vollzogen werden.
Da Attribute immer auf die jeweiligen Email-Adressen der Reportuser gemappt werden, reicht hierfür eine einzige Rolle mit einer einfachen DAX-Formel pro Mapping-Tabelle im Dataset.
Ist diese Rolle allen Reportusern im Power BI Service zugewiesen, müssen die gesetzten Berechtigungen an einem Ort verwaltet werden. Hier kommt Microsoft Power Apps ins Spiel:
Power Apps ist eine Low-Code Plattform von Microsoft, die es Benutzern ermöglicht, benutzerdefinierte Unternehmensanwendungen ohne umfangreiche Programmierkenntnisse zu erstellen. Mit Power Apps können schnell und einfach interaktive Apps erstellt werden, die auf verschiedenen Geräten wie PCs, Tablets oder Smartphones laufen können. Die Plattform bietet eine Vielzahl von Vorlagen und Tools zur Gestaltung von Benutzeroberflächen sowie zur Integration von Daten aus verschiedenen Quellen wie Microsoft 365, SharePoint, SQL-Server und vielen anderen.
In dieser entwickelten Power App werden links in der Liste zu berechtigende Reportuser und rechts die bereits vergebenen Berechtigungen angezeigt. Über die Dropdown-Menüs kann dann die entsprechende Berechtigung gewählt werden. Die getroffene Auswahl wird nach dem Speichern in der App direkt in die Mapping-Tabellen geschrieben. Durch die bereits angesprochene Anbindung der Security-Tabellen via DirectQuery werden Änderungen direkt in das Power BI-Datenmodell übertragen und bietet so die Möglichkeit, schnell und flexibel auf Änderungen in der Berechtigungsstruktur zu reagieren.
Bei einer größeren Anzahl von Reports kann eine solche Lösung als zentrales Verwaltungstool eingesetzt werden und somit das oben erläuterte repetitive Zuweisen der Rollen pro Report durch einfache Klicks ersetzen. Zudem verschafft es einen Überblick aller vergebenen Rechte an einem Ort und beugt somit Fehler in der Zuweisung der Rollen vor.
https://www.scieneers.de/wp-content/uploads/2024/03/Screenshot-2024-03-14-at-14.29.46.png16183004Maximilian Leisthttps://www.scieneers.de/wp-content/uploads/2020/04/scieneers-gradient.pngMaximilian Leist2024-03-19 08:48:562025-01-31 13:40:57Power BI Sicherheit: Wie Power Apps die Verwaltung von Row-Level-Security auf das nächste Level hebt