← KI-Engineering und Agentic AI
Multi-Agenten-System · ausgerollt

Agentischer ERP-Copilot für die Lieferkette

Eine Planerin stellt eine Frage zur Beschaffung in normaler Sprache. Das System rechnet exakt, statt zu schätzen, und hält bei allem über 10.000 $ für eine Freigabe an.

14
Modellierte Lieferanten
3-stufiges Netz, 9 Komponenten, 3 Distributionszentren
99 %
Intent-Genauigkeit auf ungesehenen Anfragen
DSPy MIPROv2, 5-fache Kreuzvalidierung auf 100 annotierten Anfragen (Zero-Shot: 91 %)
168
Testfunktionen
Unit, Integration und Red Team
0 $
API-Kosten des Sprachmodells
Gratisstufe von GitHub Models, Keyword-Fallbacks

Das Problem

Planerinnen und Planer in der Lieferkette stellen ihre Fragen in Sätzen. Optimierungssolver lesen Restriktionsmatrizen. Setzen Sie ein Sprachmodell dazwischen und lassen es rechnen, liefert es plausible Antworten, die Geld kosten, wenn sie falsch sind. Ein Transportplan, der optimal aussieht und es nicht ist, taucht später als echte Rechnung auf.

Architektur

Ein LangGraph-StateGraph führt jede Anfrage durch 6 Knoten. Der Intent-Klassifikator bildet natürliche Sprache auf 1 von 10 abgegrenzten Intents ab (mcnf_solve, jsp_schedule, vrp_route, robust_allocate, meio_optimize, bullwhip_analyze, disruption_resource, kg_query, contract_query, multi_step). Ein mit DSPy kompilierter Klassifikator (MIPROv2) übernimmt zur Laufzeit von der Zero-Shot-Basis, sobald sein JSON-Artefakt vorliegt, und der Zero-Shot-Weg bleibt ohne Konfigurationsänderung verfügbar.

Der Think-on-Graph-Agent zieht die Entitäten heraus, wählt Relationen aus einer Whitelist und durchläuft Neo4j mit parametrisiertem Cypher. Der CRAG-Stack (dichte Suche mit BGE-large-en-v1.5, dünnbesetzte BM25-Suche, RRF bei k=60 und ein CrossEncoder-Reranker) holt Vertragsabschnitte und kennzeichnet jeden als Correct, Ambiguous oder Incorrect, bevor der Synthesizer ihn sieht. Ein zweistufiger semantischer Cache auf Redis überspringt bei einer Wiederholungsanfrage den ganzen LangGraph-Durchlauf: zuerst exakter SHA-256-Treffer, dann Kosinusähnlichkeit bei 0,95 mit einer Sperre auf unterscheidende Tokens für Zahlen und Entitätscodes.

Übersteigt ein Solver-Ergebnis 10.000 $, hält der Graph an einem Human-Gate-Knoten an, über interrupt() von LangGraph. Die Entscheidungs-UUID liegt in Redis mit einer Lebensdauer von 24 Stunden. Der Freigabe-Endpunkt verlangt das Passwort der Führungskraft, setzt den Graphen mit der Entscheidung fort und sperrt eine doppelte Einreichung (HTTP 409 beim erneuten Senden). Im Browser sieht die Planerin ein Warnband mit den Schaltflächen Freigeben und Ablehnen, die sich zu einem grünen oder roten Ergebnis auflösen.

Der Stack

Schicht Werkzeug Warum
Orchestrierung LangGraph StateGraph 6 Knoten: classify → {kg_agent | contract_agent | solver_dispatch} → human_gate (bedingt) → synthesize, und eine bedingte Kante (route_by_intent) wählt den Zweig. Ein MemorySaver-Checkpoint hält den pausierten Lauf über die Unterbrechung für den Menschen hinweg.
Intent-Klassifikation Zero-Shot, DSPy optional Der Hauptweg ist ein Aufruf mit strukturierter Ausgabe, 10 abgegrenzten Intents und einer Konfidenzschwelle. Die optionale Stufe ist eine mit DSPy MIPROv2 kompilierte ChainOfThought aus einem JSON-Artefakt, und der Zero-Shot-Weg bleibt bestehen, wenn DSPy fehlt oder das Artefakt nicht da ist.
Retrieval (CRAG) BGE-large-en-v1.5, BM25, RRF Dichte Suche mit 1024 Dimensionen über pgvector ivfflat und dünnbesetzte BM25Okapi-Suche, per RRF (k=60) zusammengeführt, dann ein CrossEncoder-Reranker und ein Relevanz-Gate des Sprachmodells, das jede Textstelle als Correct, Ambiguous oder Incorrect kennzeichnet.
Wissensgraph Neo4j 5, Cypher aus Whitelist Think-on-Graph: Entitäten extrahieren, Relationen aus einer Whitelist wählen, mit 1 Wiederholung durchlaufen, die sich bei leerem Teilgraphen selbst korrigiert. Kein roher Modelltext erreicht eine Datenbankabfrage.
Solver OR-Tools, CVXPY, SciPy SLSQP 7 exakte Solver: MCNF (lineare Programmierung), VRP (CVRP), JSP, robustes Min-Max (CVXPY), MEIO GSM (SLSQP, nichtkonvex), Bullwhip-Analyse und Ressourceneinsatz bei Störungen. Ein Solver pro Intent, und das Sprachmodell rechnet nichts davon.
MCP-Verträge 6 FastMCP-Server server_erp, server_kg, server_crag, server_ortools, server_cvxpy, server_scipy. Sie stellen Solver und Datenbanken jedem MCP-Client als typisierte Werkzeuge bereit. Im Graphen prüft solver_dispatch die vom Modell extrahierten Parameter gegen ein Pydantic-Eingabemodell je Solver (SolveMcnfInput und 6 weitere), bevor etwas läuft.
Semantischer Cache Redis, BGE-Kosinus (0,95) Zweistufige Suche: exakter SHA-256-Treffer, dann Kosinusähnlichkeit. Eine Sperre auf unterscheidende Tokens (Multimenge der Zahlen und Menge der Entitätscodes) blockiert falsche Treffer, wenn 2 Anfragen dasselbe Embedding teilen, aber in den Parametern abweichen.
Sicherheit Passwort für Freigaben Der Freigabe-Endpunkt antwortet mit 403 auf ein falsches Passwort und mit 503, solange keines gesetzt ist. JWT-Authentifizierung (HS256, Ablauf nach 60 Minuten), eine RBAC-Tabelle mit 3 Rollen und ein Filter für personenbezogene Daten über reguläre Ausdrücke (E-Mail-Adressen, Telefonnummern, US-Sozialversicherungsnummern) sind geschrieben und getestet, aber noch nicht an die API-Routen angebunden.
CI/CD GitHub-Actions-Pipeline aus 6 Jobs ruff, black, mypy, bandit und pytest-Unittests → tsc im Frontend → Integrationstests → Red Team (promptfoo und pytest) → Build und Push nach ACR → repository_dispatch an das Deployment-Repository.
Fine-Tuning DPO und QLoRA auf Llama 3.1-8B Skripte überführen LangSmith-Traces in Präferenzpaare und trainieren mit LoRA r=16 auf allen Projektionsschichten. Geschrieben, noch nicht gelaufen: Das Training wartet auf 5 000 Präferenzpaare und eine L4-GPU bei Lightning AI.

Was ich gelernt habe

Die Grenze, die am schwersten zu halten ist, liegt dort, wo die Ausgabe des Modells zu ausführbarem Code wird, weit vor dem Agentengraphen. Sobald jede Solver-Eingabe ein typisiertes Pydantic-Modell passieren musste und jede Cypher-Abfrage Relationen aus der Whitelist mit gebundenen Parametern nutzte, verschwanden ganze Fehlerklassen. Das Modell kann eine Anfrage weiterhin falsch lesen und das falsche Werkzeug wählen, und ein Mensch fängt das auf. Eine fehlerhafte Abfrage kann es nicht bilden.

Die Sperre auf unterscheidende Tokens im semantischen Cache war die Korrektur, die ich nicht erwartet hatte. BGE-Embeddings verwischen den Unterschied zwischen „400 Einheiten zuteilen“ und „1000 Einheiten zuteilen“: die Kosinusähnlichkeit übersteigt 0,95, und die richtigen Antworten haben nichts gemeinsam. Die Sperre vergleicht die Zahlen und Entitätscodes beider Anfragen und verweigert die zwischengespeicherte Antwort, sobald sie abweichen.

  • LangGraph
  • FastMCP
  • DSPy
  • CRAG
  • BGE-large-en-v1.5
  • Neo4j
  • pgvector
  • OR-Tools
  • CVXPY
  • SciPy SLSQP
  • Redis
  • FastAPI
  • React/Vite