Alright Leute, Alex Petrov hier, ich melde mich von agntai.net. Heute möchte ich über etwas sprechen, das mir schon seit einiger Zeit durch den Kopf geht, etwas, das viele Teams, auch solche, in denen ich war, ins Straucheln gebracht hat. Es geht nicht um den neuesten Durchbruch bei LLMs oder irgendeine schicke neue Architektur von neuronalen Netzen. Es geht um die schweißtreibende Arbeit, den unglamourösen, aber absolut wesentlichen Teil beim Aufbau von nützlichen AI-Agenten: den Zustand verwalten. Konkret, wie wir es in agentischen Systemen oft vermasseln, was zu brüchigen, unvorhersehbaren und frustrierenden Erfahrungen führt.
Ich bin seit ein paar Jahren tief in der Agentenentwicklung engagiert, von kleinen Automatisierungsskripten, die wie Agenten wirken, bis hin zu komplexen Systemen, die versuchen, komplizierte Workflows zu verwalten. Und fast immer, wenn die Dinge schiefgehen, wenn ein Agent in einer Schleife stecken bleibt, eine unsinnige Entscheidung trifft oder einfach vergisst, was er gerade tut, lässt sich die Ursache oft auf ein Missverständnis oder eine fehlerhafte Handhabung seines internen Zustands zurückführen. Es ist, als würde man versuchen, ein kohärentes Gespräch mit jemandem zu führen, der alle paar Minuten Amnesie hat, oder dessen Gedächtnis auf einem Stapel von Haftnotizen gespeichert ist, die gelegentlich von einer launischen Katze umsortiert werden.
Der Zustand des Zustands unseres Agenten: Eine chaotische Realität
Denken Sie an eine einfache Aufgabe: ein Agent, der Ihnen hilft, einen Flug zu buchen. Er muss Ihre Abflugstadt, das Reiseziel, die Daten, die bevorzugte Airline, das Budget und vielleicht sogar spezielle Sitzplatzwünsche kennen. Das ist alles “Zustand.” Stellen Sie sich nun vor, er fragt nach Ihrer Abflugstadt, Sie geben sie ihm und dann fragt er erneut. Oder er vergisst Ihr Budget mitten in der Suche und schlägt First-Class-Tickets vor. Frustrierend, oder? Das liegt normalerweise nicht am LLM oder am Tool. Es ist, wie wir den Agenten gestaltet haben, um Dinge zu merken oder zu vergessen.
In traditioneller Software ist das Management des Zustands ein gut verstandenes Problem. Wir haben Datenbanken, Sitzungshandler, Caches und klare Datenmodelle. Doch bei AI-Agenten, insbesondere diejenigen, die auf LLMs basieren, verschwimmen die Grenzen. Wir verlassen uns oft zu stark auf das “Kontextfenster” des LLM als primären Speicherort für den Zustand. Und obwohl es mächtig ist, ist es auch ein durchlässiger, teurer und oft unzuverlässiger Behälter für dauerhafte Informationen.
Ich habe das auf die harte Tour bei einem Projekt im letzten Jahr gelernt. Wir haben einen Agenten entwickelt, der den Benutzern dabei half, komplexe Cloud-Infrastruktur zu konfigurieren. Die Interaktion konnte Stunden in Anspruch nehmen und umfasste mehrere hin und her gehende Austausch, API-Anrufe und Benutzerfreigaben. Unser anfänglicher Ansatz bestand darin, den gesamten Gesprächsverlauf sowie alle relevanten Konfigurationsparameter bei jedem Schritt in das LLM zurückzuleiten. Das schien zunächst vernünftig. Das LLM erinnert sich! Außer manchmal tat es das nicht. Manchmal halluzinierte es frühere Entscheidungen. Manchmal ignorierte es einfach wichtige Details, die tief im Gespräch verborgen waren. Und die Token-Kosten? Lass mich gar nicht erst anfangen. Es wurde zu einem spiralförmigen Albtraum des Prompt-Engineerings, um das LLM an Dinge zu “erinnern”, die es hätte wissen sollen.
Jenseits des Kontextfensters: Ein strukturierterer Ansatz
Die Erleuchtung kam, als wir aufhörten, das Kontextfenster des LLM als unsere Datenbank zu betrachten, und anfingen, es als das zu behandeln, was es ist: ein leistungsstarker, aber flüchtiger Denkmechanismus. Die tatsächlichen Fakten, die persistenten Präferenzen, die Zwischenergebnisse einer Aktion – die müssen irgendwo anders, an einem strukturierten und zugänglichen Ort abgelegt werden.
Hier ist die Kernidee: Externalisieren und strukturieren Sie den langfristigen und kritischen kurzfristigen Zustand Ihres Agenten. Verlassen Sie sich nicht ausschließlich auf das LLM, um sich an jedes Detail zu erinnern. Geben Sie ihm ein Gedächtnis, das es abfragen, aktualisieren und auf das es sich verlassen kann, genau wie ein menschliches Gehirn auf externe Notizen, Kalender und sogar andere Personen angewiesen ist.
1. Definieren Sie das “Gedächtnisschema” Ihres Agenten
Bevor Sie eine einzige Zeile Code für den Agenten schreiben, setzen Sie sich hin und überlegen Sie, welche Informationen Ihr Agent unbedingt speichern muss, um seine Aufgabe zu erfüllen. Nicht nur die Gesprächshistorie, sondern auch spezifische Fakten, Präferenzen und Fortschrittsmarker. Das ist das “Gedächtnisschema” Ihres Agenten.
Für unseren Flugbuchungsagenten könnte das ungefähr so aussehen:
user_id(für Personalisierung)departure_citydestination_citydeparture_datereturn_date(optional)preferred_airline(optional)budget_max(optional)search_results_cache(Liste von Flugoptionen)selected_flight_idbooking_status(z.B. ‘pending_payment’, ‘confirmed’)last_user_query_type(z.B. ‘asking_for_dates’, ‘confirming_selection’)
Das ist nicht vollständig, aber Sie bekommen die Idee. Dies sind die kritischen Informationen, die, wenn sie verloren gehen, den Fluss des Agenten unterbrechen oder dazu führen würden, dass Fragen erneut gestellt werden.
2. Wählen Sie den richtigen Zustandsstore
Sobald Sie Ihr Schema haben, benötigen Sie einen Ort, um es abzulegen. Das könnte alles sein, von einem einfachen Python-Wörterbuch für kurzlebige Sitzungen bis hin zu einer vollwertigen Datenbank für persistente, multi-user Agenten.
- In-Memory-Dictionary/Objekt: Ideal für einfache, kurzlebige Interaktionen, bei denen der Zustand nicht über Neustarts oder mehrere Benutzer hinweg bestehen bleiben muss. Seien Sie vorsichtig damit, denn es ist leicht, Daten zu verlieren.
- Dateisystem (JSON/YAML): Ein Schritt nach oben für etwas mehr Persistenz, insbesondere für Einzelbenutzer, lokale Agenten. Nicht skalierbar für viele gleichzeitige Benutzer.
- Key-Value-Store (Redis, Memcached): Ausgezeichnet für den schnellen Zugriff auf zustandsabhängige Daten. Kann mehrere Benutzer verwalten und bietet einige Persistenz. Mein Standard für viele webbasierte Agentenanwendungen.
- Relationale Datenbank (PostgreSQL, MySQL): Am besten für komplexe, strukturierte Zustände, die starke Konsistenz, Transaktionsunterstützung benötigen und auf verschiedene Weisen abgefragt werden können. Ideal für Agenten, die langlaufende Workflows verwalten oder detaillierte historische Daten benötigen.
- NoSQL-Dokumentdatenbank (MongoDB, DynamoDB): Gut für flexible Schemata, bei denen sich der Zustand entwickeln kann. Kann gut geeignet sein, wenn die Gedächtnisstruktur Ihres Agenten nicht von vornherein festgelegt ist.
Für diesen Cloud-Infrastruktur-Agenten haben wir schließlich eine PostgreSQL-Datenbank gewählt. Warum? Weil die Konfigurationen selbst komplex, hoch strukturiert und überprüfbar sein mussten. Wir haben den internen Zustand des Agenten (welche Fragen er gestellt hat, welche Entscheidungen der Benutzer getroffen hat, die Zwischen-API-Antworten) in einer JSONB-Spalte auf einer session Tabelle gespeichert, zusammen mit der Benutzer-ID und anderen Metadaten. Das gab uns die Flexibilität eines Dokumentenspeichers, jedoch innerhalb der Stabilität einer relationalen Datenbank.
3. Explizite Lese-/Schreibmechanismen für den Zustand
Hier kommt es darauf an. Ihr Agent benötigt klare, explizite Wege, um auf seinen externen Zustands-Speicher zu lesen und zu schreiben. Das bedeutet, über das bloße Übergeben einer langen Textzeichenfolge an das LLM hinauszugehen.
Hier ist ein vereinfachtes Python-Beispiel, das zeigt, wie Sie den Zustand für unseren Flugbuchungsagenten mithilfe eines Wörterbuchs verwalten könnten (dies würden Sie in einem realen System durch eine Datenbankinteraktion ersetzen):
“`html
class FlightAgentState:
def __init__(self, session_id):
self.session_id = session_id
self.state = {
"user_id": None,
"departure_city": None,
"destination_city": None,
"departure_date": None,
"return_date": None,
"preferred_airline": None,
"budget_max": None,
"search_results_cache": [],
"selected_flight_id": None,
"booking_status": "neu",
"last_user_query_type": None
}
# In einer realen App, laden Sie den Zustand hier aus DB/Redis
print(f"Zustand für Sitzung {self.session_id} initialisiert")
def update(self, key, value):
if key in self.state:
self.state[key] = value
# In einer realen App, speichern Sie dies in DB/Redis
print(f"Zustand aktualisiert: {key} = {value}")
else:
print(f"Warnung: Versuch, unbekannten Zustands-Schlüssel zu aktualisieren: {key}")
def get(self, key):
return self.state.get(key)
def get_all(self):
return self.state
def to_prompt_context(self):
# Das ist es, was Sie Ihrem LLM für den strukturierten Kontext geben
context = {k: v for k, v in self.state.items() if v is not None and k not in ["search_results_cache", "selected_flight_id"]}
return f"Aktuelle Buchungsdetails: {context}"
# --- Beispiel für die Interaktion mit dem Agenten ---
def process_user_input(session_state: FlightAgentState, user_input: str):
# Simulieren Sie das Verständnis des LLM und die Aufrufe von Tools
if "fliegen von" in user_input.lower():
city = user_input.split("von ")[1].split(" ")[0].strip(".").capitalize()
session_state.update("departure_city", city)
return f"Okay, fliegen von {city}. Wohin?"
elif "nach" in user_input.lower():
city = user_input.split("nach ")[1].split(" ")[0].strip(".").capitalize()
session_state.update("destination_city", city)
return f"Und nach {city}. Wann möchten Sie abreisen?"
elif "am" in user_input.lower() and "datum" not in session_state.get_all():
date_str = user_input.split("am ")[1].split(" ")[0] # Sehr einfache Analyse
session_state.update("departure_date", date_str)
return f"Verstanden, Abflug am {date_str}. Welches Rückdatum?"
elif "flüge finden" in user_input.lower():
# Hier würden Sie ein echtes Flugsuch-Tool aufrufen
# und search_results_cache im Zustand aktualisieren
dep = session_state.get("departure_city")
dest = session_state.get("destination_city")
date = session_state.get("departure_date")
if dep and dest and date:
return f"Suche nach Flügen von {dep} nach {dest} am {date}..."
else:
return "Ich benötige mehr Details, um nach Flügen zu suchen. Was fehlt?"
else:
return "Ich bin mir nicht sicher, wie ich damit helfen kann. Können Sie das klären?"
# --- Simulation ---
session = FlightAgentState("user_123")
print("\nBenutzer: Ich möchte von London fliegen")
response = process_user_input(session, "Ich möchte von London fliegen")
print("Agent:", response)
print("Aktueller Zustand:", session.get_all())
print("\nBenutzer: nach New York")
response = process_user_input(session, "nach New York")
print("Agent:", response)
print("Aktueller Zustand:", session.get_all())
print("\nBenutzer: am 15. März")
response = process_user_input(session, "am 15. März")
print("Agent:", response)
print("Aktueller Zustand:", session.get_all())
print("\nBenutzer: flüge finden")
response = process_user_input(session, "flüge finden")
print("Agent:", response)
print("Aktueller Zustand:", session.get_all())
Beachten Sie, wie die to_prompt_context-Methode explizit auswählt, welche Teile des strukturierten Zustands relevant sind, um sie an das LLM für sein reasoning weiterzugeben. Dies verhindert Kontextüberlastung und stellt sicher, dass das LLM saubere, zusammengefasste Informationen erhält.
4. Zustandsbewusste Werkzeuge
Die Werkzeuge Ihres Agenten sollten ebenfalls über den externen Zustand informiert sein. Anstatt dass die Werkzeuge jeden einzelnen Parameter in ihrem Input benötigen, sollten sie in der Lage sein, den Zustand des Agenten nach fehlenden Informationen abzufragen. Zum Beispiel könnte ein search_flights-Werkzeug nach departure_city, destination_city und departure_date im aktuellen Zustand des Agenten suchen, bevor es den Benutzer nach etwas fragt.
# Vereinfachtes Werkzeugbeispiel
def search_flights_tool(agent_state: FlightAgentState):
departure = agent_state.get("departure_city")
destination = agent_state.get("destination_city")
date = agent_state.get("departure_date")
if not all([departure, destination, date]):
# Das Werkzeug selbst weiß, was es benötigt und kann den Agenten ansprechen
return {"error": "Fehlende Flugdetails. Bitte geben Sie Abflug, Ziel und Datum an."}
print(f"Rufe externe API auf, um nach Flügen zu suchen: {departure} -> {destination} am {date}")
# Simulieren Sie API-Aufruf
results = [
{"flight_id": "AA123", "price": 350, "airline": "American Airlines"},
{"flight_id": "BA456", "price": 400, "airline": "British Airways"}
]
agent_state.update("search_results_cache", results)
return {"success": True, "flights": results}
# In der Denk-Schleife Ihres Agenten:
# wenn das LLM entscheidet, das search_flights_tool aufzurufen:
# tool_output = search_flights_tool(session)
# wenn tool_output.get("success"):
# # Das LLM kann dann die Ergebnisse aus agent_state.get("search_results_cache") zusammenfassen
# # anstatt aus dem Roh-tool_output
# print("Agent: Ich habe diese Flüge gefunden...")
# else:
# print("Agent:", tool_output.get("error"))
Dieser Ansatz bedeutet, dass das LLM nicht alle Fakten speichern muss; es muss nur wissen, wie man sie findet oder wie man danach fragt, wenn sie nicht vorhanden sind. Dies entkopplet das reasoning des Agenten von seiner Erinnerung, wodurch beide effizienter und zuverlässiger werden.
Umsetzbare Erkenntnisse für Ihr nächstes Agentenprojekt
Okay, lassen Sie uns dies mit einigen konkreten Ratschlägen abschließen. Wenn Sie einen KI-Agenten erstellen, insbesondere einen für mehr als eine triviale, einseitige Interaktion, sollten Sie diese Punkte im Hinterkopf behalten:
- Betrachten Sie das Kontextfenster des LLMs nicht als Ihren einzigen Zustandsspeicher. Es ist großartig für sofortiges reasoning und kurzfristige Konversationshistorie, aber schlecht für Persistenz, Struktur und Kosteneffizienz.
- Definieren Sie explizit den langfristigen und kritischen kurzfristigen Zustand Ihres Agenten. Welche spezifischen Informationen muss Ihr Agent sich merken, um seine Kernfunktionen auszuführen? Schreiben Sie sie auf.
- Externalisieren Sie den Zustand Ihres Agenten. Verwenden Sie ein ordentliches Datenspeicher (Redis, PostgreSQL, eine Datei, was auch immer zu Ihrem Maßstab passt), um diese Informationen zu halten. Dies macht Ihren Agenten robuster, debugbar und skalierbar.
- Implementieren Sie klare Lese- und Schreibmechanismen für Ihren Zustand. Ihr Agent sollte wissen, wie Informationen aus seinem Gedächtnis abgerufen werden und wie sie nach einer Aktion oder einer Benutzereingabe aktualisiert werden.
- Fassen Sie den Zustand für das LLM zusammen. Wenn Sie den Zustand an den Kontext des LLM zurückgeben, dumpen Sie nicht einfach alles. Geben Sie eine prägnante, relevante Zusammenfassung oder befragen Sie den Zustandsspeicher nach spezifischen Fakten, die das LLM benötigt, um über die aktuelle Runde nachzudenken.
- Gestalten Sie Ihre Werkzeuge zustandsbewusst. Werkzeuge sollten in der Lage sein, den Zustand des Agenten nach Parametern abzufragen, die sie benötigen, anstatt immer zu erwarten, dass sie als direkte Eingaben vom LLM oder vom Benutzer bereitgestellt werden.
- Denken Sie an Zustandsübergänge. Wie bewegt sich Ihr Agent von einem Zustand (z.B. ‘wartet auf Abflugstadt’) zu einem anderen (z.B. ‘wartet auf Zielstadt’)? Diese explizit zu verfolgen kann helfen, zu verhindern, dass Agenten stecken bleiben.
Das Erstellen von Agenten ist ein wenig wie das Entwerfen einer komplexen Maschine. Sie würden sich nicht darauf verlassen, dass der Motor auch den gesamten Treibstoff, die Passagierlisten und die Flugpläne speichert. Jede Komponente hat ihre Aufgabe. Das LLM ist ein phänomenaler Motor für reasoning und Sprachverständnis, aber es benötigt einen zuverlässigen Tank und eine gut organisierte Manifestliste, um effektiv zu funktionieren. Bekommen Sie Ihr Zustandsmanagement richtig, und Sie werden sich eine Menge Kopfschmerzen, Token-Kosten und Debugging-Zyklen ersparen.
Das war’s für heute. Gehen Sie hinaus und bauen Sie intelligentere, zuverlässigere Agenten! Lassen Sie mich Ihre Gedanken oder etwaige Zustandmanagement-Albträume, die Sie erlebt haben, in den Kommentaren wissen.
“`
🕒 Published: