Milvus
Zilliz
  • Home
  • Blog
  • Warum Clawdbot viral wurde - und wie man mit LangGraph und Milvus produktionsreife, langlebige Agenten erstellt

Warum Clawdbot viral wurde - und wie man mit LangGraph und Milvus produktionsreife, langlebige Agenten erstellt

  • Tutorials
February 03, 2026
Min Yin

Clawdbot (jetzt OpenClaw) ging viral

Clawdbot, jetzt umbenannt in OpenClaw, hat das Internet letzte Woche im Sturm erobert. Der von Peter Steinberger entwickelte Open-Source-KI-Assistent erreichte in nur wenigen Tagen mehr als 110.000 GitHub-Sterne. Nutzer haben Videos gepostet, in denen sie zu sehen sind, wie er selbstständig Flüge eincheckt, E-Mails verwaltet und Smart-Home-Geräte steuert. Andrej Karpathy, der Gründungsingenieur von OpenAI, lobte es. David Sacks, ein Tech-Gründer und Investor, tweetete darüber. Die Leute nannten es "Jarvis, aber echt".

Dann kamen die Sicherheitswarnungen.

Die Forscher fanden Hunderte von ungeschützten Administrationspanels. Der Bot läuft standardmäßig mit Root-Zugriff. Es gibt kein Sandboxing. Schwachstellen bei der Eingabeaufforderung könnten Angreifern die Möglichkeit geben, den Agenten zu kapern. Ein Sicherheitsalbtraum.

Clawdbot wurde nicht ohne Grund viral

Clawdbot wurde nicht ohne Grund zum Verkaufsschlager. Er läuft lokal oder auf Ihrem eigenen Server. Er stellt eine Verbindung zu Messaging-Apps her, die bereits genutzt werden - WhatsApp, Slack, Telegram, iMessage. Es merkt sich den Kontext im Laufe der Zeit, anstatt alles nach jeder Antwort zu vergessen. Es verwaltet Kalender, fasst E-Mails zusammen und automatisiert app-übergreifende Aufgaben.

Die Nutzer haben das Gefühl, eine persönliche KI zu haben, die sich um sie kümmert - und nicht nur ein Prompt-and-Response-Tool. Das quelloffene, selbst gehostete Modell spricht Entwickler an, die Kontrolle und Anpassungsmöglichkeiten wünschen. Und die einfache Integration in bestehende Arbeitsabläufe macht es leicht, sie weiterzugeben und zu empfehlen.

Zwei Herausforderungen bei der Entwicklung langlebiger Agenten

Die Popularität von Clawdbot beweist, dass die Menschen KI wollen, die handelt und nicht nur antwortet. Aber jeder Agent, der über lange Zeiträume läuft und echte Aufgaben erledigt - ob Clawdbot oder etwas, das Sie selbst entwickeln - muss zwei technische Herausforderungen lösen: Speicher und Verifizierung.

Das Speicherproblem zeigt sich auf verschiedene Weise:

  • Agenten erschöpfen ihr Kontextfenster mitten in der Aufgabe und lassen halbfertige Arbeit zurück

  • Sie verlieren den Überblick über die gesamte Aufgabenliste und erklären zu früh "fertig".

  • Sie können den Kontext zwischen Sitzungen nicht weitergeben, so dass jede neue Sitzung bei Null beginnt.

Alle diese Probleme haben die gleiche Ursache: Agenten haben keinen dauerhaften Speicher. Die Kontextfenster sind begrenzt, der sitzungsübergreifende Abruf ist eingeschränkt, und der Fortschritt wird nicht auf eine Weise verfolgt, auf die die Agenten zugreifen können.

Das Problem der Überprüfung ist ein anderes. Selbst wenn der Speicher funktioniert, markieren Agenten Aufgaben nach einem kurzen Unit-Test als abgeschlossen, ohne zu prüfen, ob die Funktion tatsächlich durchgängig funktioniert.

Clawdbot löst beide Probleme. Er speichert Speicher lokal über Sitzungen hinweg und verwendet modulare "Fähigkeiten" zur Automatisierung von Browsern, Dateien und externen Diensten. Der Ansatz funktioniert. Aber er ist nicht produktionstauglich. Für den Einsatz in Unternehmen benötigen Sie eine Struktur, Nachvollziehbarkeit und Sicherheit, die Clawdbot nicht von Haus aus bietet.

Dieser Artikel behandelt die gleichen Probleme mit produktionsreifen Lösungen.

Für den Speicher verwenden wir eine Zwei-Agenten-Architektur, die auf der Forschung von Anthropic basiert: einen Initialisierungs-Agenten, der Projekte in überprüfbare Funktionen aufteilt, und einen Kodierungs-Agenten, der sie nacheinander mit sauberen Übergaben abarbeitet. Für den sitzungsübergreifenden semantischen Abruf verwenden wir Milvus, eine Vektordatenbank, mit der Agenten nach Bedeutung und nicht nach Schlüsselwörtern suchen können.

Für die Überprüfung verwenden wir die Browser-Automatisierung. Anstatt sich auf Unit-Tests zu verlassen, testet der Agent Funktionen so, wie es ein echter Benutzer tun würde.

Wir werden die Konzepte erläutern und dann eine funktionierende Implementierung mit LangGraph und Milvus zeigen.

Wie die Zwei-Agenten-Architektur die Erschöpfung des Kontexts verhindert

Jeder LLM hat ein Kontextfenster: eine Grenze, wie viel Text er auf einmal verarbeiten kann. Wenn ein Agent an einer komplexen Aufgabe arbeitet, füllt sich dieses Fenster mit Code, Fehlermeldungen, Gesprächsverlauf und Dokumentation. Sobald das Fenster voll ist, hält der Agent entweder an oder beginnt, den früheren Kontext zu vergessen. Bei langwierigen Aufgaben ist dies unvermeidlich.

Stellen Sie sich einen Agenten vor, der eine einfache Aufforderung erhält: "Erstelle einen Klon von claude.ai." Das Projekt erfordert Authentifizierung, Chat-Schnittstellen, Gesprächsverlauf, Streaming-Antworten und Dutzende anderer Funktionen. Ein einzelner Agent wird versuchen, alles auf einmal in Angriff zu nehmen. Auf halbem Weg zur Implementierung der Chat-Schnittstelle füllt sich das Kontextfenster. Die Sitzung endet mit halb geschriebenem Code, ohne Dokumentation dessen, was versucht wurde, und ohne Hinweise darauf, was funktioniert und was nicht. Die nächste Sitzung erbt ein Chaos. Selbst mit Kontextverdichtung muss der neue Agent erraten, was die vorherige Sitzung gemacht hat, Code debuggen, den er nicht geschrieben hat, und herausfinden, wo er weitermachen soll. Es vergehen Stunden, bevor ein neuer Fortschritt erzielt wird.

Die Zwei-Agenten-Lösung

Die Lösung von Anthropic, die in ihrem technischen Beitrag "Effective harnesses for long-running agents" beschrieben wird , besteht darin, zwei verschiedene Prompting-Modi zu verwenden: einen Initialisierungs-Prompt für die erste Sitzung und einen Coding-Prompt für nachfolgende Sitzungen.

Technisch gesehen verwenden beide Modi denselben zugrundeliegenden Agenten, Systemprompt, Tools und Kabelbaum. Der einzige Unterschied ist die anfängliche Benutzerführung. Da sie jedoch unterschiedliche Aufgaben erfüllen, ist es sinnvoll, sie als zwei separate Agenten zu betrachten. Wir nennen dies die Zwei-Agenten-Architektur.

Der Initialisierer richtet die Umgebung für den schrittweisen Fortschritt ein. Er nimmt eine vage Anfrage entgegen und tut drei Dinge:

  • Er zerlegt das Projekt in spezifische, überprüfbare Funktionen. Keine vagen Anforderungen wie "Erstellen Sie eine Chat-Schnittstelle", sondern konkrete, testbare Schritte: "Benutzer klickt auf die Schaltfläche "Neuer Chat" → neue Unterhaltung erscheint in der Seitenleiste → Chatbereich zeigt den Begrüßungsstatus an." Anthropic's claude.ai clone Beispiel hatte über 200 solcher Funktionen.

  • Erzeugt eine Fortschrittsverfolgungsdatei. Diese Datei zeichnet den Fertigstellungsstatus jeder Funktion auf, so dass jede Sitzung sehen kann, was getan wurde und was noch übrig ist.

  • Schreibt Einrichtungsskripte und nimmt eine erste Git-Übertragung vor. Skripte wie init.sh ermöglichen es zukünftigen Sitzungen, die Entwicklungsumgebung schnell zu starten. Der Git-Commit stellt eine saubere Baseline her.

Der Initialisierer plant nicht nur. Er schafft eine Infrastruktur, die es zukünftigen Sitzungen ermöglicht, sofort mit der Arbeit zu beginnen.

Der Coding Agent kümmert sich um jede nachfolgende Sitzung. Er:

  • Liest die Fortschrittsdatei und die Git-Protokolle, um den aktuellen Zustand zu verstehen

  • Führt einen grundlegenden End-to-End-Test durch, um zu bestätigen, dass die Anwendung noch funktioniert

  • Wählt eine Funktion aus, an der er arbeiten möchte

  • Implementiert die Funktion, testet sie gründlich, überträgt sie mit einer beschreibenden Nachricht an Git und aktualisiert die Fortschrittsdatei

Wenn die Sitzung endet, befindet sich die Codebasis in einem zusammenführbaren Zustand: keine größeren Fehler, ordentlicher Code, klare Dokumentation. Es gibt keine halbfertige Arbeit und kein Geheimnis darüber, was gemacht wurde. Die nächste Sitzung macht genau da weiter, wo die erste aufgehört hat.

Verwenden Sie JSON für das Feature Tracking, nicht Markdown

Ein erwähnenswertes Implementierungsdetail: Die Feature-Liste sollte JSON und nicht Markdown sein.

Bei der Bearbeitung von JSON neigen KI-Modelle dazu, bestimmte Felder chirurgisch zu verändern. Bei der Bearbeitung von Markdown werden oft ganze Abschnitte umgeschrieben. Bei einer Liste von mehr als 200 Funktionen können Markdown-Bearbeitungen versehentlich Ihre Fortschrittsverfolgung beeinträchtigen.

Ein JSON-Eintrag sieht so aus:

json
{
  "category": "functional",
  "description": "New chat button creates a fresh conversation",
  "steps": [
    "Navigate to main interface",
    "Click the 'New Chat' button",
    "Verify a new conversation is created",
    "Check that chat area shows welcome state",
    "Verify conversation appears in sidebar"
  ],
  "passes": false
}

Jede Funktion hat klare Überprüfungsschritte. Das Feld passes verfolgt die Fertigstellung. Scharf formulierte Anweisungen wie "Es ist inakzeptabel, Tests zu entfernen oder zu bearbeiten, da dies zu fehlenden oder fehlerhaften Funktionen führen könnte" werden ebenfalls empfohlen, um zu verhindern, dass der Agent das System durch Löschen schwieriger Funktionen manipuliert.

Wie Milvus den Agenten ein semantisches Gedächtnis über mehrere Sitzungen hinweg verleiht

Die Zwei-Agenten-Architektur löst zwar das Problem der Kontexterschöpfung, nicht aber das des Vergessens. Selbst bei sauberen Übergaben zwischen den Sitzungen verliert der Agent den Überblick über das, was er gelernt hat. Er kann sich nicht daran erinnern, dass "JWT-Refresh-Token" mit "Benutzerauthentifizierung" zusammenhängt, es sei denn, genau diese Wörter tauchen in der Verlaufsdatei auf. Wenn das Projekt wächst, wird die Suche in Hunderten von Git-Commits langsam. Beim Abgleich von Schlüsselwörtern werden Verbindungen übersehen, die für einen Menschen offensichtlich wären.

Hier kommen Vektordatenbanken ins Spiel. Anstatt Text zu speichern und nach Schlüsselwörtern zu suchen, wandelt eine Vektordatenbank Text in numerische Darstellungen der Bedeutung um. Wenn Sie nach "Benutzerauthentifizierung" suchen, finden Sie Einträge über "JWT-Refresh-Tokens" und "Anmeldesitzungsverarbeitung". Nicht weil die Wörter übereinstimmen, sondern weil die Konzepte semantisch ähnlich sind. Der Agent kann fragen: "Habe ich so etwas schon einmal gesehen?" und erhält eine nützliche Antwort.

In der Praxis funktioniert dies, indem Fortschrittsberichte und Git-Commits als Vektoren in die Datenbank eingebettet werden. Wenn eine Coding-Sitzung beginnt, fragt der Agent die Datenbank mit seiner aktuellen Aufgabe ab. Die Datenbank gibt in Millisekunden den relevanten Verlauf zurück: was zuvor versucht wurde, was funktioniert hat und was nicht. Der Agent fängt nicht bei Null an. Er beginnt mit dem Kontext.

Milvus ist für diesen Anwendungsfall gut geeignet. Milvus ist quelloffen und für die Vektorsuche im Produktionsmaßstab konzipiert, so dass Milliarden von Vektoren ohne Probleme verarbeitet werden können. Für kleinere Projekte oder lokale Entwicklungen kann Milvus Lite direkt in eine Anwendung wie SQLite eingebettet werden. Die Einrichtung eines Clusters ist nicht erforderlich. Wenn das Projekt wächst, können Sie zu verteiltem Milvus migrieren, ohne Ihren Code zu ändern. Für die Erzeugung von Einbettungen können Sie externe Modelle wie den SentenceTransformer für eine feinkörnige Steuerung verwenden oder auf die eingebauten Einbettungsfunktionen für einfachere Setups verweisen. Milvus unterstützt auch die hybride Suche, die Vektorähnlichkeit mit herkömmlicher Filterung kombiniert, so dass Sie mit einem einzigen Aufruf die Abfrage "Finde ähnliche Authentifizierungsprobleme der letzten Woche" stellen können.

Dadurch wird auch das Übertragungsproblem gelöst. Die Vektordatenbank bleibt über eine einzelne Sitzung hinaus bestehen, so dass sich das Wissen im Laufe der Zeit ansammelt. Sitzung 50 hat Zugriff auf alles, was in den Sitzungen 1 bis 49 gelernt wurde. Das Projekt entwickelt ein institutionelles Gedächtnis.

Überprüfung der Fertigstellung mit automatisierten Tests

Selbst mit der Zwei-Agenten-Architektur und dem Langzeitgedächtnis können die Agenten den Sieg zu früh verkünden. Das ist das Problem der Verifizierung.

Hier ist ein häufiger Fehlermodus: Eine Programmiersitzung stellt eine Funktion fertig, führt einen kurzen Einheitstest durch, stellt fest, dass er bestanden wurde, und schaltet "passes": false auf "passes": true. Ein bestandener Einheitstest bedeutet jedoch nicht, dass die Funktion tatsächlich funktioniert. Die API könnte korrekte Daten zurückgeben, während die Benutzeroberfläche aufgrund eines CSS-Fehlers nichts anzeigt. Die Fortschrittsdatei sagt "vollständig", während die Benutzer nichts sehen.

Die Lösung besteht darin, den Agenten wie einen echten Benutzer testen zu lassen. Für jede Funktion in der Funktionsliste gibt es konkrete Prüfschritte: "Benutzer klickt auf die Schaltfläche "Neuer Chat" → neue Konversation erscheint in der Seitenleiste → Chatbereich zeigt Willkommensstatus". Der Agent sollte diese Schritte buchstäblich verifizieren. Anstatt nur Tests auf Code-Ebene durchzuführen, verwendet er Browser-Automatisierungstools wie Puppeteer, um die tatsächliche Nutzung zu simulieren. Er öffnet die Seite, klickt auf Schaltflächen, füllt Formulare aus und überprüft, ob die richtigen Elemente auf dem Bildschirm erscheinen. Erst wenn der gesamte Ablauf erfolgreich war, markiert der Agent die Funktion als vollständig.

Auf diese Weise werden Probleme erkannt, die bei Unit-Tests übersehen werden. Eine Chatfunktion kann über eine perfekte Backend-Logik und korrekte API-Antworten verfügen. Aber wenn das Frontend die Antwort nicht rendert, sehen die Benutzer nichts. Die Browser-Automatisierung kann einen Screenshot des Ergebnisses erstellen und überprüfen, ob das, was auf dem Bildschirm erscheint, mit dem übereinstimmt, was erscheinen sollte. Das Feld passes wird nur dann zu true, wenn die Funktion wirklich von Anfang bis Ende funktioniert.

Allerdings gibt es auch Einschränkungen. Einige browsereigene Funktionen können von Tools wie Puppeteer nicht automatisiert werden. Dateipicker und Systembestätigungsdialoge sind gängige Beispiele. Anthropic merkte an, dass Funktionen, die sich auf browser-native Warnmeldungen stützen, dazu neigen, fehlerhafter zu sein, weil der Agent sie nicht durch Puppeteer sehen kann. Der praktische Workaround besteht darin, diese Einschränkungen zu umgehen. Verwenden Sie, wo immer möglich, benutzerdefinierte UI-Komponenten anstelle von nativen Dialogen, damit der Agent jeden Überprüfungsschritt in der Feature-Liste testen kann.

Zusammenfügen: LangGraph für den Sitzungsstatus, Milvus für das Langzeitgedächtnis

Die oben genannten Konzepte werden in einem funktionierenden System mit zwei Werkzeugen zusammengeführt: LangGraph für den Sitzungsstatus und Milvus für das Langzeitgedächtnis. LangGraph verwaltet, was innerhalb einer einzelnen Sitzung passiert: an welcher Funktion wird gearbeitet, was ist abgeschlossen, was steht als nächstes an. Milvus speichert einen durchsuchbaren Verlauf über mehrere Sitzungen hinweg: was vorher gemacht wurde, welche Probleme aufgetreten sind und welche Lösungen funktioniert haben. Zusammen geben sie den Agenten sowohl ein Kurzzeit- als auch ein Langzeitgedächtnis.

Ein Hinweis zu dieser Implementierung: Der folgende Code ist eine vereinfachte Demonstration. Er zeigt die wichtigsten Muster in einem einzigen Skript, aber er bildet die zuvor beschriebene Trennung der Sitzungen nicht vollständig ab. In einer Produktionsumgebung würde jede Codierungssitzung ein separater Aufruf sein, möglicherweise auf verschiedenen Rechnern oder zu verschiedenen Zeiten. Die MemorySaver und thread_id in LangGraph ermöglichen dies, indem sie den Zustand zwischen den Aufrufen aufrechterhalten. Um das Fortsetzungsverhalten zu verdeutlichen, führen Sie das Skript einmal aus, halten es an und führen es dann erneut mit demselben thread_id aus. Der zweite Durchlauf würde dort weitermachen, wo der erste aufgehört hat.

Python

from sentence_transformers import SentenceTransformer
from pymilvus import MilvusClient
from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph import StateGraph, START, END
from typing import TypedDict, Annotated
import operator
import subprocess
import json

# ==================== Initialization ==================== embedding_model = SentenceTransformer(‘all-MiniLM-L6-v2’) milvus_client = MilvusClient(“./milvus_agent_memory.db”)

# Create collection if not milvus_client.has_collection(“agent_history”): milvus_client.create_collection( collection_name=“agent_history”, dimension=384, auto_id=True )

# ==================== Milvus Operations ==================== def retrieve_context(query: str, top_k: int = 3): """Retrieve relevant history from Milvus (core element: semantic retrieval)“"” query_vec = embedding_model.encode(query).tolist() results = milvus_client.search( collection_name=“agent_history”, data=[query_vec], limit=top_k, output_fields=[“content”] ) if results and results[0]: return [hit[“entity”][“content”] for hit in results[0]] return []

def save_progress(content: str): """Save progress to Milvus (long-term memory)“"” embedding = embedding_model.encode(content).tolist() milvus_client.insert( collection_name=“agent_history”, data=[{“vector”: embedding, “content”: content}] )

# ==================== Core Element 1: Git Commit ==================== def git_commit(message: str): """Git commit (core element from the article)“"” try: # In a real project, actual Git commands would be executed # subprocess.run(["git", "add", “.”], check=True) # subprocess.run([“git", “commit", "-m", message], check=True) print(f”[Git Commit] {message}") return True except Exception as e: print(f”[Git Commit Failed] {e}") return False

# ==================== Core Element 2: Test Verification ==================== def run_tests(feature: str): “""Run tests (end-to-end testing emphasized in the article)“"” try: # In a real project, testing tools like Puppeteer would be called # Simplified to simulated testing here print(f”[Test Verification] Testing feature: {feature}") # Simulated test result test_passed = True # In practice, this would return actual test results if test_passed: print(f"[Test Passed] {feature}") return test_passed except Exception as e: print(f"[Test Failed] {e}") return False

# ==================== State Definition ==================== class AgentState(TypedDict): messages: Annotated[list, operator.add] features: list # All features list completed_features: list # Completed features current_feature: str # Currently processing feature session_count: int # Session counter

# ==================== Two-Agent Nodes ==================== def initialize_node(state: AgentState): “""Initializer Agent: Generate feature list and set up work environment""” print(“\n========== Initializer Agent Started ==========”)

<span class="hljs-comment"># Generate feature list (in practice, a detailed feature list would be generated based on requirements)</span>
features = [
    <span class="hljs-string">&quot;Implement user registration&quot;</span>,
    <span class="hljs-string">&quot;Implement user login&quot;</span>,
    <span class="hljs-string">&quot;Implement password reset&quot;</span>,
    <span class="hljs-string">&quot;Implement user profile editing&quot;</span>,
    <span class="hljs-string">&quot;Implement session management&quot;</span>
]

<span class="hljs-comment"># Save initialization info to Milvus</span>
init_summary = <span class="hljs-string">f&quot;Project initialized with <span class="hljs-subst">{<span class="hljs-built_in">len</span>(features)}</span> features&quot;</span>
save_progress(init_summary)

<span class="hljs-built_in">print</span>(<span class="hljs-string">f&quot;[Initialization Complete] Feature list: <span class="hljs-subst">{features}</span>&quot;</span>)

<span class="hljs-keyword">return</span> {
    **state,
    <span class="hljs-string">&quot;features&quot;</span>: features,
    <span class="hljs-string">&quot;completed_features&quot;</span>: [],
    <span class="hljs-string">&quot;current_feature&quot;</span>: features[<span class="hljs-number">0</span>] <span class="hljs-keyword">if</span> features <span class="hljs-keyword">else</span> <span class="hljs-string">&quot;&quot;</span>,
    <span class="hljs-string">&quot;session_count&quot;</span>: <span class="hljs-number">0</span>,
    <span class="hljs-string">&quot;messages&quot;</span>: [init_summary]
}

def code_node(state: AgentState): “""Coding Agent: Implement, test, commit (core loop node)“"” print(f"\n========== Coding Agent Session #{state[‘session_count’] + 1} ==========”)

current_feature = state[<span class="hljs-string">&quot;current_feature&quot;</span>]
<span class="hljs-built_in">print</span>(<span class="hljs-string">f&quot;[Current Task] <span class="hljs-subst">{current_feature}</span>&quot;</span>)

<span class="hljs-comment"># ===== Core Element 3: Retrieve history from Milvus (cross-session memory) =====</span>
<span class="hljs-built_in">print</span>(<span class="hljs-string">f&quot;[Retrieving History] Querying experiences related to &#x27;<span class="hljs-subst">{current_feature}</span>&#x27;...&quot;</span>)
context = retrieve_context(current_feature)
<span class="hljs-keyword">if</span> context:
    <span class="hljs-built_in">print</span>(<span class="hljs-string">f&quot;[Retrieval Results] Found <span class="hljs-subst">{<span class="hljs-built_in">len</span>(context)}</span> relevant records:&quot;</span>)
    <span class="hljs-keyword">for</span> i, ctx <span class="hljs-keyword">in</span> <span class="hljs-built_in">enumerate</span>(context, <span class="hljs-number">1</span>):
        <span class="hljs-built_in">print</span>(<span class="hljs-string">f&quot;  <span class="hljs-subst">{i}</span>. <span class="hljs-subst">{ctx[:<span class="hljs-number">60</span>]}</span>...&quot;</span>)
<span class="hljs-keyword">else</span>:
    <span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;[Retrieval Results] No relevant history (first time implementing this type of feature)&quot;</span>)

<span class="hljs-comment"># ===== Step 1: Implement feature =====</span>
<span class="hljs-built_in">print</span>(<span class="hljs-string">f&quot;[Starting Implementation] <span class="hljs-subst">{current_feature}</span>&quot;</span>)
<span class="hljs-comment"># In practice, an LLM would be called to generate code</span>
implementation_result = <span class="hljs-string">f&quot;Implemented feature: <span class="hljs-subst">{current_feature}</span>&quot;</span>

<span class="hljs-comment"># ===== Step 2: Test verification (core element) =====</span>
test_passed = run_tests(current_feature)
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> test_passed:
    <span class="hljs-built_in">print</span>(<span class="hljs-string">f&quot;[Session End] Tests did not pass, fixes needed&quot;</span>)
    <span class="hljs-keyword">return</span> state  <span class="hljs-comment"># Don&#x27;t proceed if tests fail</span>

<span class="hljs-comment"># ===== Step 3: Git commit (core element) =====</span>
commit_message = <span class="hljs-string">f&quot;feat: <span class="hljs-subst">{current_feature}</span>&quot;</span>
git_commit(commit_message)

<span class="hljs-comment"># ===== Step 4: Update progress file =====</span>
<span class="hljs-built_in">print</span>(<span class="hljs-string">f&quot;[Updating Progress] Marking feature as complete&quot;</span>)

<span class="hljs-comment"># ===== Step 5: Save to Milvus long-term memory =====</span>
progress_record = <span class="hljs-string">f&quot;Completed feature: <span class="hljs-subst">{current_feature}</span> | Commit message: <span class="hljs-subst">{commit_message}</span> | Test status: passed&quot;</span>
save_progress(progress_record)

<span class="hljs-comment"># ===== Step 6: Update state and prepare for next feature =====</span>
new_completed = state[<span class="hljs-string">&quot;completed_features&quot;</span>] + [current_feature]
remaining_features = [f <span class="hljs-keyword">for</span> f <span class="hljs-keyword">in</span> state[<span class="hljs-string">&quot;features&quot;</span>] <span class="hljs-keyword">if</span> f <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> new_completed]

<span class="hljs-built_in">print</span>(<span class="hljs-string">f&quot;[Progress] Completed: <span class="hljs-subst">{<span class="hljs-built_in">len</span>(new_completed)}</span>/<span class="hljs-subst">{<span class="hljs-built_in">len</span>(state[<span class="hljs-string">&#x27;features&#x27;</span>])}</span>&quot;</span>)
<span class="hljs-comment"># ===== Core Element 4: Session end (clear session boundary) =====</span>
<span class="hljs-built_in">print</span>(<span class="hljs-string">f&quot;[Session End] Codebase is in clean state, safe to interrupt\n&quot;</span>)

<span class="hljs-keyword">return</span> {
    **state,
    <span class="hljs-string">&quot;completed_features&quot;</span>: new_completed,
    <span class="hljs-string">&quot;current_feature&quot;</span>: remaining_features[<span class="hljs-number">0</span>] <span class="hljs-keyword">if</span> remaining_features <span class="hljs-keyword">else</span> <span class="hljs-string">&quot;&quot;</span>,
    <span class="hljs-string">&quot;session_count&quot;</span>: state[<span class="hljs-string">&quot;session_count&quot;</span>] + <span class="hljs-number">1</span>,
    <span class="hljs-string">&quot;messages&quot;</span>: [implementation_result]
}

# ==================== Core Element 3: Loop Control ==================== def should_continue(state: AgentState): """Determine whether to continue to next feature (incremental loop development)“"” if state[“current_feature”] and state[“current_feature”] != “”: return “code” # Continue to next feature else: print(“\n========== All Features Complete ==========”) return END

# ==================== Build Workflow ==================== workflow = StateGraph(AgentState)

# Add nodes workflow.add_node(“initialize”, initialize_node) workflow.add_node(“code”, code_node)

# Add edges workflow.add_edge(START, “initialize”) workflow.add_edge(“initialize”, “code”)

# Add conditional edges (implement loop) workflow.add_conditional_edges( “code”, should_continue, { “code”: “code”, # Continue loop END: END # End } )

# Compile workflow (using MemorySaver as checkpointer) app = workflow.compile(checkpointer=MemorySaver())

# ==================== Usage Example: Demonstrating Cross-Session Recovery ==================== if name == "main": print(“=” * 60) print(“Demo Scenario: Multi-Session Development for Long-Running Agents”) print(“=” * 60)

<span class="hljs-comment"># ===== Session 1: Initialize + complete first 2 features =====</span>
<span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;\n[Scenario 1] First launch: Complete first 2 features&quot;</span>)
config = {<span class="hljs-string">&quot;configurable&quot;</span>: {<span class="hljs-string">&quot;thread_id&quot;</span>: <span class="hljs-string">&quot;project_001&quot;</span>}}

result = app.invoke({
    <span class="hljs-string">&quot;messages&quot;</span>: [],
    <span class="hljs-string">&quot;features&quot;</span>: [],
    <span class="hljs-string">&quot;completed_features&quot;</span>: [],
    <span class="hljs-string">&quot;current_feature&quot;</span>: <span class="hljs-string">&quot;&quot;</span>,
    <span class="hljs-string">&quot;session_count&quot;</span>: <span class="hljs-number">0</span>
}, config)

<span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;\n&quot;</span> + <span class="hljs-string">&quot;=&quot;</span> * <span class="hljs-number">60</span>)
<span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;[Simulated Scenario] Developer manually interrupts (Ctrl+C) or context window exhausted&quot;</span>)
<span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;=&quot;</span> * <span class="hljs-number">60</span>)

<span class="hljs-comment"># ===== Session 2: Restore state from checkpoint =====</span>
<span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;\n[Scenario 2] New session starts: Continue from last interruption&quot;</span>)
<span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;Using the same thread_id, LangGraph automatically restores from checkpoint...&quot;</span>)

<span class="hljs-comment"># Using the same thread_id, LangGraph will automatically restore state from checkpoint</span>
result = app.invoke({
    <span class="hljs-string">&quot;messages&quot;</span>: [],
    <span class="hljs-string">&quot;features&quot;</span>: [],
    <span class="hljs-string">&quot;completed_features&quot;</span>: [],
    <span class="hljs-string">&quot;current_feature&quot;</span>: <span class="hljs-string">&quot;&quot;</span>,
    <span class="hljs-string">&quot;session_count&quot;</span>: <span class="hljs-number">0</span>
}, config)

<span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;\n&quot;</span> + <span class="hljs-string">&quot;=&quot;</span> * <span class="hljs-number">60</span>)
<span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;Demo Complete!&quot;</span>)
<span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;=&quot;</span> * <span class="hljs-number">60</span>)
<span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;\nKey Takeaways:&quot;</span>)
<span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;1. ✅ Two-Agent Architecture (initialize + code)&quot;</span>)
<span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;2. ✅ Incremental Loop Development (conditional edges control loop)&quot;</span>)
<span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;3. ✅ Git Commits (commit after each feature)&quot;</span>)
<span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;4. ✅ Test Verification (end-to-end testing)&quot;</span>)
<span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;5. ✅ Session Management (clear session boundaries)&quot;</span>)
<span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;6. ✅ Cross-Session Recovery (thread_id + checkpoint)&quot;</span>)
<span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;7. ✅ Semantic Retrieval (Milvus long-term memory)&quot;</span>)

The key insight is in the last part. By using the same thread_id, LangGraph automatically restores the checkpoint from the previous session. Session 2 picks up exactly where session 1 stopped — no manual state transfer, no lost progress.

Schlussfolgerung

KI-Agenten versagen bei langwierigen Aufgaben, weil ihnen ein dauerhafter Speicher und eine angemessene Überprüfung fehlen. Clawdbot wurde durch die Lösung dieser Probleme viral, aber sein Ansatz ist nicht produktionstauglich.

In diesem Artikel wurden drei Lösungen vorgestellt, die es sind:

  • Zwei-Agenten-Architektur: Ein Initialisierer unterteilt Projekte in überprüfbare Funktionen; ein Kodierungsagent arbeitet sie einzeln mit sauberen Übergaben ab. Dies verhindert die Erschöpfung des Kontexts und macht den Fortschritt nachvollziehbar.

  • Vektordatenbank für semantisches Gedächtnis: Milvus speichert Fortschrittsaufzeichnungen und Git-Commits als Einbettungen, so dass Agenten nach Bedeutung und nicht nach Schlüsselwörtern suchen können. Sitzung 50 merkt sich, was Sitzung 1 gelernt hat.

  • Browser-Automatisierung für echte Verifizierung: Unit-Tests verifizieren, dass der Code läuft. Puppeteer prüft, ob Funktionen tatsächlich funktionieren, indem es testet, was Benutzer auf dem Bildschirm sehen.

Diese Muster sind nicht auf die Softwareentwicklung beschränkt. Wissenschaftliche Forschung, Finanzmodellierung, Überprüfung von Rechtsdokumenten - jede Aufgabe, die sich über mehrere Sitzungen erstreckt und zuverlässige Übergaben erfordert, kann davon profitieren.

Die wichtigsten Grundsätze:

  • Verwenden Sie einen Initialisierer, um die Arbeit in überprüfbare Abschnitte zu unterteilen.

  • Verfolgung des Fortschritts in einem strukturierten, maschinenlesbaren Format

  • Speichern von Erfahrungen in einer Vektordatenbank zum semantischen Abruf

  • Überprüfen Sie die Fertigstellung mit realen Tests, nicht nur mit Unit-Tests

  • Entwurf sauberer Sitzungsgrenzen, damit die Arbeit sicher unterbrochen und fortgesetzt werden kann

Die Werkzeuge sind vorhanden. Die Muster sind erprobt. Was bleibt, ist ihre Anwendung.

Sind Sie bereit anzufangen?

Haben Sie Fragen oder möchten Sie uns mitteilen, was Sie entwickeln?

    Try Managed Milvus for Free

    Zilliz Cloud is hassle-free, powered by Milvus and 10x faster.

    Get Started

    Like the article? Spread the word

    Weiterlesen