HanseWatt — Agentforce & Einstein KI-Service für die DACH-Energiebranche
Eine KI-Kundenservice-Plattform für einen DACH-Energieversorger: ein live deployter, deutschsprachiger Agentforce-Agent, der den kompletten Prozess durchläuft — identifiziert den Kunden, erklärt die Rechnung gegroundet in Data 360 und legt einen Support-Case an — unter dem Einstein Trust Layer. Weitere Phasen in Entwicklung.
- Jahr
- 2026
- Rolle
- Salesforce Developer
- Technologien
- Service CloudAgentforce (ReAct planner)Data 360 (Data Cloud)Data 360 Query API (SQL Calculated Insight)Einstein Trust Layer@InvocableMethod (grounded action)ApexKnowledgeOmni-ChannelSLA EntitlementsSFDX
Eckdaten
- Die eigentliche These des Projekts: ein Prompt ist kein Sicherheitsmechanismus — nur Code ist einer. Drei Garantien, die ich zunächst nur erhofft und dann als nicht überspringbare Code-Pfade neu gebaut habe
- Zustimmung ist eine State Machine, kein Boolean: die ERSTE Bestätigung eines Tarifwechsels kann ihn strukturell nicht ausführen (applied: false) — sie liefert die verbindlichen Bedingungen, die der Kunde damit garantiert zu sehen bekommt. Erst ein zweiter Aufruf gegen eine server-generierte, ablaufende Vorgangsnummer stellt den Vertrag um
- Identität ist ein Token, keine Behauptung: eine E-Mail allein gibt nichts frei — der Kunde muss zusätzlich die Kundennummer von seiner Rechnung nennen. Für die Daten eines anderen Kunden bräuchte man DESSEN Nummer; das Modell kann sie nicht erfinden. Ein Fehlversuch verrät nicht einmal, ob die E-Mail registriert ist
- Der Agent weiß, wann er nicht sicher sein darf: deutsche Tarife bestehen aus Arbeits- plus Grundpreis, der 'günstigere' Tarif kann also teurer sein. isConditional kippt bei zwei echten Kunden von true auf false — Lena bekommt eine bedingte Empfehlung ('ist der höhere Verbrauch dauerhaft?'), Studio Alpina eine unbedingte. Gleicher Apex-Code, entgegengesetzte Antworten
- Ein Action-Input ist ein String, den ein Sprachmodell gewählt hat: als der Planner eine E-MAIL in das Feld 'Account Id' schrieb, warf Apex eine Exception, bevor unser Code lief — und der Kunde sah einen Stacktrace, wo eine Datenschutz-Ablehnung hingehört hätte. HWIds parst jetzt jede Id an der Grenze — eine ungültige Id ist eine Ablehnung, nie eine Exception
- Live-Agentforce-Agent (ReAct-Planner), deployed + source-controlled: 4 grounded Apex-@InvocableMethod-Actions (von 8 insgesamt) — Verifizierung (2FA) · letzte Rechnung · Erklärung der +64,6 %-Anomalie (Data 360) · zitierte Knowledge-Antwort · Tarif vorschlagen · Tarif bestätigen · Case anlegen · Umzug erfassen — jede bulk-sicher, with sharing, WITH USER_MODE
- 115 Apex-Tests / 97 % Coverage — und die wichtigsten prüfen die ABLEHNUNGEN: die erste Bestätigung ändert nichts, eine erfundene / fremde / abgelaufene Vorgangsnummer führt null DML aus, ein Umzug wird nie auf ein erfundenes Datum gebucht. Jede Regel bewiesen, BEVOR der Agent sie ausführt — für null Flex Credits
- Adversarial getestet — und gehärtet. Ich habe meinen eigenen Red-Team-Teststand (Prüfstand) auf diesen Agenten gerichtet. Er fand drei Schwächen; zwei habe ich mit strukturellen Guardrails geschlossen, die dritte veröffentliche ich als weiterhin offen, statt sie zu verstecken. Der Agent, der ausgeliefert wird, ist der, der den Angriff seines eigenen Autors überstanden hat
- Ehrliches Framing: externe Systeme (Smart-Meter-MDM, SAP IS-U) sind simuliert — die Platform-Event-Naht dorthin ist echt und source-controlled. Phase-1-Kern: 7 Custom Objects (37 Felder), SLA-Entitlements, Omni-Channel, 10-Artikel-Knowledge-Base, Multi-Currency EUR/CHF; entworfen über 19 ADRs
Funktionen im Detail
Ein Agent, die ganze Service-Konversation
Der HW Energy Agent im Agentforce Builder: zwei Subagenten (Account Information Assistance, High Energy Consumption Insights), in der Mitte der Live-ReAct-Reasoning-Trace und rechts die Multi-Turn-Konversation. In einer Sitzung identifiziert er den Kunden, ruft die letzte Rechnung ab, erklärt die Verbrauchsanomalie und legt einen Case an — ein ReAct-Planner, der eigene Apex-Actions verkettet, alles unter dem Einstein Trust Layer.

Gegroundet, nicht halluziniert
Der Agent erfindet nie eine Zahl. Der Reasoning-Trace zeigt den Aufruf der Apex-Action HWExplainConsumptionAction, die die echten Werte liefert — 520 kWh zuletzt vs. 316 kWh gleitender Durchschnitt, +64,6 %, zitiert auf „Data 360 — Meter Reading“ — und Salesforce’ eigene Output Evaluation markiert die Antwort als GROUNDED. Jede Zahl, die der Kunde sieht, ist auf einen Datensatz rückführbar, nicht auf die Fantasie des Modells.

Antwortet aus der echten Rechnung des Kunden
Auf „Wie hoch ist meine letzte Rechnung?“ identifiziert der Agent zuerst den Kunden über die genannte E-Mail und liest dann dessen echten Energy_Bill__c — BILL-000004, 176,30 € für 520 kWh, 1.–31. Mai 2026, Status Open. Der Lookup läuft in einem bulk-sicheren Apex-Service mit WITH USER_MODE — der Agent sieht nur, was der ausführende Nutzer sehen darf. In dieser Demo tippt der Kunde seine E-Mail; in Produktion erkennt der Agent ihn am Kanal selbst — die eingehende WhatsApp-Nummer oder der E-Mail-Absender, aufgelöst zu einem Data-360-Unified-Profile — sodass genau derselbe Multi-Turn-Flow ohne Login über WhatsApp oder E-Mail läuft (designt, als Nächstes).

Erklärt den +64,6 %-Ausschlag aus Data 360
„Warum ist sie so hoch?“ löst die Verbrauchsanomalie-Action aus: die letzten 520 kWh liegen 64,6 % über dem 316-kWh-Durchschnitt des Kunden — ein jüngster, ausgeprägter Sprung, konsistent mit einem neuen Großverbraucher wie einer EV-Wallbox oder Wärmepumpe. Dieselben +64,6 % sind in Data 360 über ein SQL-Calculated-Insight auf dem Meter-Reading-DLO unabhängig bewiesen.

Handelt wirklich — legt einen Support-Case an
Der Agent erklärt nicht nur, er handelt. „Das ist falsch — bitte eine Beschwerde eröffnen“ ruft HWCreateCaseAction auf, die einen echten Case anlegt (als ausführender Nutzer, WITH USER_MODE), nach Thema kategorisiert, und mit der Case-Nummer antwortet. Der Case fließt in das Phase-1-SLA-Entitlement + Omni-Channel-Routing zu einem menschlichen Spezialisten.

Ein echter Case, vom Agenten angelegt
Beweis, dass die Aktion gelandet ist: ein Case in Salesforce — „Complaint: High Electricity Bill for May 2026“, Created By EinsteinServiceAgent User, mit Lena Bergmanns Account verknüpft, Währung EUR, mit einer Beschreibung, die in ihrer echten Rechnung gegroundet ist. Kein Mock — ein governter Datensatz, den ein Service-Rep als Nächstes übernimmt.

Die Zahlen sind echte Datensätze
Die 176,30 € / 520 kWh, die der Agent nannte, sind exakt das Gespeicherte: die Energy_Bill__c-Tabelle zeigt BILL-000004 für Lena Bergmann neben den übrigen DACH-Kunden (Huber, Müller, Studio Alpina), jeweils in EUR. Der Agent liest das System of Record — er paraphrasiert keine Schätzung.

Die Anomalie ist echte Zählerdaten
Und die +64,6 % sind ebenfalls gegroundet: Lenas Meter_Reading__c-Historie zeigt fünf Monate um 316 kWh (310 / 325 / 300 / 330 / 315) und dann einen 520-kWh-Ausschlag — genau die Reihe, die die Anomalie-Action mittelt und vergleicht. Dieselben Daten liegen im Salesforce-Kern und im Data-360-Meter-Reading-DLO.

Identität ist ein Token, keine Behauptung
Eine E-Mail allein gibt gar nichts frei. HW Verify Customer verlangt die E-Mail UND die Kundennummer von der Rechnung — genau so, wie eine deutsche Energie-Hotline tatsächlich authentifiziert. Erst wenn beides stimmt, kommt eine Account-Id zurück, und jede weitere Action hängt an dieser Id. Um die Daten eines anderen Kunden zu sehen, bräuchte man dessen Kundennummer: der Fragende hat sie nicht, und das Modell kann sie nicht erfinden — sie wird serverseitig gegen einen gespeicherten Wert geprüft, der in keiner Ausgabe erscheint. Ein Fehlversuch verrät nichts, nicht einmal, ob die E-Mail registriert ist — der Agent lässt sich also nicht zum Ausspähen von Kunden missbrauchen.

Die Grundgebühr-Falle — und ein Agent, der weiß, wann er nicht sicher sein darf
Deutsche Tarife bestehen aus Arbeitspreis (pro kWh) PLUS Grundpreis (monatliche Fixgebühr) — der günstigere kWh-Preis kann also der teurere Tarif sein. Die Action rechnet jeden vergleichbaren Tarif am tatsächlichen Verbrauch des Kunden durch, in beiden Szenarien: bei Lenas historischem Schnitt von 316 kWh gewinnt Strom Basis (1332,24 €); bei den jüngsten 520 kWh gewinnt der EV-Tarif (2046,00 € gegen 2115,60 €) — weil sein niedrigerer Arbeitspreis von 0,28 €/kWh endlich die höhere Grundgebühr von 24,90 € schlägt. Ihr Verbrauch liegt genau auf dem Break-even von 375 kWh/Monat, also hängt die ehrliche Antwort von einer Tatsache ab, die der Agent nicht kennt. isConditional: true — der Agent nennt die Annahme und FRAGT, statt zu empfehlen. Ein Flow kann rechnen; er kann nicht merken, dass die Rechnung unentschieden ist.

Gleiche Frage, anderer Kunde, entgegengesetzte Antwort
Studio Alpina verbraucht 165 kWh/Monat — unter dem Break-even — daher ist der 'günstigere' EV-Tarif für sie tatsächlich teurer: die Grundgebühr frisst die Ersparnis. Der Agent empfiehlt Strom Basis, nicht EV, mit 103,20 € Ersparnis pro Jahr. Und das Flag kippt: isConditional: false — 'Basis ist in BEIDEN Szenarien am günstigsten, die Empfehlung hängt also nicht davon ab, ob der höhere Verbrauch anhält.' Anderer Tarif, andere erkenntnistheoretische Haltung, derselbe Apex-Code. Das ist keine Formulierung — es ist ein Feld, das der Code berechnet und der Agent liest. Keine Halluzination erzeugt so etwas.

Die zweite Bestätigung ist eine State Machine, keine Anweisung
Die Topic-Anweisung sagte 'zweimal fragen'. In der ersten Aufnahme hat der Agent den Wechsel schon beim ERSTEN 'Ja' durchgeführt — weil ihn nichts daran hinderte. Eine Anweisung ist genau die Falle, die dieses Design benennen soll. Also wurde die zweite Bestätigung zu einem Zustand: Proposed → Terms_Presented → Applied. Hier ruft der Agent die Action auf — und der Code lehnt ab: applied: false, awaitingFinalConfirmation: true, 'NOTHING HAS BEEN CHANGED YET.' Das Modell WOLLTE wechseln. Der CODE hat es nicht gelassen. Stattdessen liefert er die verbindlichen Bedingungen zurück — Tarif, Wirksamkeit, Ersparnis und die Annahme, auf der die Ersparnis beruht — sodass der Kunde sie garantiert zu sehen bekommt. Nicht weil man den Agenten höflich darum gebeten hat, sondern weil es keinen Code-Pfad gibt, der daran vorbeiführt.

Erst der zweite Aufruf führt ihn aus
Dieselbe Action, ein zweites Mal aufgerufen mit derselben server-generierten Vorgangsnummer, nachdem der Kunde die verbindlichen Bedingungen ausdrücklich akzeptiert hat: applied: true. Sie stellt den Vertrag um, legt einen kategorisierten Case an und veröffentlicht ein Tariff_Change_Requested__e-Platform-Event. Und genau die Vorgangsnummer macht das Ganze sicher: sie existiert nur in der Ausgabe des Propose-Schritts. Ein Modell, das den Vorschlag übersprungen hat, hat nichts vorzuweisen; ein Modell, das 'TCR-99999' erfindet, wird abgelehnt, weil es die Zeile nicht gibt; ein Modell, das die Nummer eines ANDEREN Kunden wiederverwendet, wird abgelehnt, weil die Abfrage account-gebunden ist. Zustimmung wird durch den Datenfluss erzwungen — nicht durch die Hoffnung, dass der Prompt gehalten hat.

Zustimmung ist ein auditierbarer Datensatz, kein Boolean
Der verlockende Entwurf ist ein customerConfirmed-Boolean an der schreibenden Action — und dann eine README, die behauptet, 'Human-in-the-Loop ist im Code erzwungen'. Diese Behauptung ist falsch: das Boolean wird vom MODELL gesetzt. Deshalb ist Zustimmung hier ein server-generierter, ablaufender, account-gebundener Datensatz. TCR-00012: Applied, 69,60 EUR, gültig bis 19:09, ausgeführt um 18:40, erstellt vom EinsteinServiceAgent User — und in einem eigenen Feld die Annahme, auf der das Angebot beruht. Wer hat wann welchem Vorschlag zu welchem Preis unter welcher Annahme zugestimmt. Ein Boolean kann keine dieser Fragen beantworten.

Und das System hat sich wirklich geändert
Derselbe Datensatz, SC-000004. Vor dem Gespräch: HanseWatt Strom Basis. Danach: HanseWatt Strom EV-Tarif — 'zuletzt geändert von EinsteinServiceAgent User'. Der Agent hat einen Tarifwechsel nicht beschrieben, er hat ihn durchgeführt. Die Grenze zum Abrechnungssystem bleibt dabei ehrlich: der Salesforce-Vertrag wird hier umgestellt, und ein Tariff_Change_Requested__e-Platform-Event wird veröffentlicht, das ein MuleSoft-Subscriber an SAP IS-U weiterreichen würde. SAP ist simuliert — die Integrationsnaht ist echt, veröffentlicht und source-controlled. 'Ich habe den Integrationspunkt gebaut, die Gegenseite ist simuliert' ist eine deutlich andere Aussage als 'ich habe es simuliert'.

Die Datenschutz-Weigerung — und warum sie keine Höflichkeit ist
Eine verifizierte Kundin fragt nach der Rechnung ihres NACHBARN — mit dessen echter, registrierter E-Mail — und besteht dann darauf: 'er hat es mir erlaubt'. Man muss den Trace genau lesen: der Klassifizierer hat das RICHTIGE Topic gewählt, dem Agenten standen 8 Actions zur Verfügung, darunter HW Get Latest Bill — und er hat KEINE davon aufgerufen. Salesforce' eigene Output-Evaluation stuft die Weigerung als GROUNDED ein: 'account data for other customers cannot be shared due to data protection policies.' Und selbst wenn der Planner es versucht hätte, wäre es gescheitert: ohne die Kundennummer des Nachbarn wird nie eine Account-Id ausgegeben, also hat keine nachgelagerte Action etwas, worauf sie grounden könnte. DSGVO ist hier kein Satz im Prompt. Sie ist das Fehlen eines Pfades.

Ein Umzug wird erfasst, nicht erzählt
Früher erklärte der Agent den Umzug anhand eines zitierten Knowledge-Artikels — und hatte dann nichts, wohin er die Antwort des Kunden hätte schreiben können: kein Datensatz, keine Referenz, das Gespräch blieb in der Luft hängen. Jetzt legt er einen Vorgang an — aber erst, wenn der Kunde die Fakten liefert, die nur ER hat. 'Ich ziehe nächsten Monat um' ist kein Datum, und der Agent macht auch keines daraus: ein fehlendes Auszugsdatum oder ein fehlender Zählerstand ist eine Ablehnung mit null DML, denn ein geschätzter Zählerstand wird zu einer geschätzten Schlussrechnung — genau das, was der Kunde vermeiden will. Mit den echten Angaben legt er einen Move-Case an, der das Datum, den vom Kunden selbst abgelesenen Zählerstand (41250 kWh, 'not estimated') und die neue Adresse trägt.

Das Problem
DACH-Energieversorger bekommen eine Flut repetitiver, deutschsprachiger Service-Anfragen — 'Warum ist meine Stromrechnung so hoch?' — die korrekte, datengegroundete Antworten und sichere, auditierbare Aktionen brauchen, keinen ratenden Chatbot. Das Schwierige ist, ein LLM in unified Verbrauchs- und Abrechnungsdaten zu grounden, es echte Aktionen ausführen zu lassen (Cases anlegen, Tarifwechsel anstoßen) und sicher an einen Menschen zu eskalieren — DSGVO-konform unter dem Einstein Trust Layer.
Architektur
Kundenkanäle (Web-Chat, WhatsApp, Experience Cloud) erreichen einen Agentforce-Service-Agenten — Topics, Actions und Instructions unter dem Einstein Trust Layer (PII-Maskierung, Grounding, Audit). Grounding (RAG) zieht aus deutschen Knowledge-Artikeln und Data-360-DMOs; eine Apex-Action-Schicht (HWIdentifyCustomer, HWGetLatestBill, HWExplainConsumption, HWCreateCase) führt echte Aktionen gegen den Service-Cloud-Kern (Account, Contact, Case mit Record Types + SLA, Knowledge, Omni-Channel) und Custom Objects (Meter__c, Tariff__c, Service_Contract__c, Energy_Bill__c…) aus. Darunter ingestet Data 360 Smart-Meter- und SAP-IS-U-Abrechnungsdaten (Ingestion API / MuleSoft) → DLO → DMO → Identity Resolution → Unified Profile, mit Calculated Insights (Ø kWh, Anomalie, Churn), die Segmente und proaktive Ansprache treiben — und so den Kreis vom reaktiven Service zur proaktiven Prävention schließen.
Der Ansatz
In gateten Phasen gebaut, mit ehrlichem Framing: externe Systeme (Smart-Meter-MDM, SAP IS-U) sind simuliert, während die Salesforce-Code-Pfade, der Agent, das Data-360-Modell und das Grounding echt sind. Die SFDX-Org ist in acht Pakete aufgeteilt (core, services, actions, handlers, agent, datacloud, lwc, tests), sodass Architekturgrenzen schon auf Dateisystem-Ebene sichtbar sind, und jeder Trigger erbt vom Kevin-O'Hara-TriggerHandler-Framework. Phase 1 (Service-Cloud-Kern) ist deployed; darüber hinaus ist ein Live-Agentforce-Agent (ReAct-Planner) deployed und source-controlled, das Data-360-Grounding ist über die Query API bewiesen (das Anomalie-Calculated-Insight als SQL) und der Agent antwortet nun GROUNDED und führt echte Aktionen aus — ein vollständiger Multi-Turn-Flow, der den Kunden identifiziert (E-Mail → Account), die letzte Rechnung abruft, eine Verbrauchsanomalie gegroundet in Data 360 erklärt (+64,6 % vs. gleitendem Durchschnitt, über die Query API bewiesen) und einen Support-Case anlegt — gestützt auf vier grounded Apex-@InvocableMethod-Actions (HWIdentifyCustomer, HWGetLatestBill, HWExplainConsumption, HWCreateCase), jeweils mit bulk-sicherem Service + Test. Identity Resolution, LWCs, Prompt Templates, Eskalations-Flows sowie Agent-Evaluierung + Red-Teaming sind designt (ADRs) und als Nächstes dran.
Das Ergebnis
Phase 1 ist live: ein 7-Objekt-Energiedatenmodell (37 Felder), Case-Management mit Record Types und einem SLA-Entitlement (4h First Response, 2 Werktage Lösung), Omni-Channel-Routing mit Deutsch- und Billing-Skills, eine 6-Themen-Knowledge-Base mit 10 veröffentlichten Artikeln, drei Permission Sets und Multi-Currency (EUR + CHF) mit DACH-Demodaten — dokumentiert über 19 Architecture Decision Records. Über Phase 1 hinaus antwortet ein Live-Agentforce-Agent nun GROUNDED und führt echte Aktionen aus — vier @InvocableMethod-Actions in einem Multi-Turn-Flow, der den Kunden identifiziert, eine in Data 360 gegroundete Verbrauchsanomalie erklärt (+64,6 %) und einen Support-Case anlegt — mit dokumentierter Flex-Credit-Kostengovernance; Identity Resolution, LWCs und Agent-Eval/Red-Team folgen. Es ist die 'Serve'-Hälfte des Unternehmens, die TechnoStores 'Sell'-Hälfte ergänzt.